aboutsummaryrefslogtreecommitdiffstats
path: root/lib/snmp
diff options
context:
space:
mode:
authorErlang/OTP <[email protected]>2009-11-20 14:54:40 +0000
committerErlang/OTP <[email protected]>2009-11-20 14:54:40 +0000
commit84adefa331c4159d432d22840663c38f155cd4c1 (patch)
treebff9a9c66adda4df2106dfd0e5c053ab182a12bd /lib/snmp
downloadotp-84adefa331c4159d432d22840663c38f155cd4c1.tar.gz
otp-84adefa331c4159d432d22840663c38f155cd4c1.tar.bz2
otp-84adefa331c4159d432d22840663c38f155cd4c1.zip
The R13B03 release.OTP_R13B03
Diffstat (limited to 'lib/snmp')
-rw-r--r--lib/snmp/AUTHORS6
-rw-r--r--lib/snmp/Makefile119
-rw-r--r--lib/snmp/bin/snmp-v2tov1.pl319
-rw-r--r--lib/snmp/bin/snmp-v2tov1.sed9
-rw-r--r--lib/snmp/bin/snmp-v2tov1.src32
-rw-r--r--lib/snmp/configure.in33
-rw-r--r--lib/snmp/doc/html/.gitignore0
-rw-r--r--lib/snmp/doc/man3/.gitignore0
-rw-r--r--lib/snmp/doc/man6/.gitignore0
-rw-r--r--lib/snmp/doc/man7/.gitignore0
-rw-r--r--lib/snmp/doc/pdf/.gitignore0
-rw-r--r--lib/snmp/doc/src/MIB_mechanism.fig73
-rw-r--r--lib/snmp/doc/src/MIB_mechanism.gifbin0 -> 3268 bytes
-rw-r--r--lib/snmp/doc/src/MIB_mechanism.ps217
-rw-r--r--lib/snmp/doc/src/Makefile349
-rw-r--r--lib/snmp/doc/src/book.gifbin0 -> 1081 bytes
-rw-r--r--lib/snmp/doc/src/book.xml49
-rw-r--r--lib/snmp/doc/src/depend.mk82
-rw-r--r--lib/snmp/doc/src/fascicules.xml18
-rw-r--r--lib/snmp/doc/src/files.mk153
-rw-r--r--lib/snmp/doc/src/getnext1.gifbin0 -> 2951 bytes
-rw-r--r--lib/snmp/doc/src/getnext1.ps2923
-rw-r--r--lib/snmp/doc/src/getnext2.gifbin0 -> 3529 bytes
-rw-r--r--lib/snmp/doc/src/getnext2.ps2997
-rw-r--r--lib/snmp/doc/src/getnext3.gifbin0 -> 3876 bytes
-rw-r--r--lib/snmp/doc/src/getnext3.ps3003
-rw-r--r--lib/snmp/doc/src/getnext4.gifbin0 -> 3705 bytes
-rw-r--r--lib/snmp/doc/src/getnext4.ps3002
-rw-r--r--lib/snmp/doc/src/index.html.src98
-rw-r--r--lib/snmp/doc/src/make.dep77
-rw-r--r--lib/snmp/doc/src/min_head.gifbin0 -> 2652 bytes
-rw-r--r--lib/snmp/doc/src/note.gifbin0 -> 1539 bytes
-rw-r--r--lib/snmp/doc/src/notes.gifbin0 -> 2005 bytes
-rw-r--r--lib/snmp/doc/src/notes.xml1024
-rw-r--r--lib/snmp/doc/src/notes_history.xml2151
-rw-r--r--lib/snmp/doc/src/part.xml54
-rw-r--r--lib/snmp/doc/src/part_notes.xml40
-rw-r--r--lib/snmp/doc/src/part_notes_history.xml41
-rw-r--r--lib/snmp/doc/src/ref_man.gifbin0 -> 1530 bytes
-rw-r--r--lib/snmp/doc/src/ref_man.xml71
-rw-r--r--lib/snmp/doc/src/snmp-um-1-image-1.gifbin0 -> 5684 bytes
-rw-r--r--lib/snmp/doc/src/snmp-um-1-image-1.ps2912
-rw-r--r--lib/snmp/doc/src/snmp-um-1-image-2.gifbin0 -> 2407 bytes
-rw-r--r--lib/snmp/doc/src/snmp-um-1-image-2.ps2866
-rw-r--r--lib/snmp/doc/src/snmp-um-1-image-3.gifbin0 -> 10952 bytes
-rw-r--r--lib/snmp/doc/src/snmp-um-1-image-3.ps3400
-rw-r--r--lib/snmp/doc/src/snmp-um-1-image-8.gifbin0 -> 6202 bytes
-rw-r--r--lib/snmp/doc/src/snmp-um-1-image-8.ps2931
-rw-r--r--lib/snmp/doc/src/snmp.gifbin0 -> 15889 bytes
-rw-r--r--lib/snmp/doc/src/snmp.xml608
-rw-r--r--lib/snmp/doc/src/snmp_advanced_agent.xml482
-rw-r--r--lib/snmp/doc/src/snmp_agent_config_files.xml464
-rw-r--r--lib/snmp/doc/src/snmp_agent_funct_descr.xml947
-rw-r--r--lib/snmp/doc/src/snmp_agent_netif.xml268
-rw-r--r--lib/snmp/doc/src/snmp_agent_netif_1.gifbin0 -> 5217 bytes
-rw-r--r--lib/snmp/doc/src/snmp_agent_netif_1.ps2909
-rw-r--r--lib/snmp/doc/src/snmp_app.xml708
-rw-r--r--lib/snmp/doc/src/snmp_app_a.xml108
-rw-r--r--lib/snmp/doc/src/snmp_app_b.xml511
-rw-r--r--lib/snmp/doc/src/snmp_audit_trail_log.xml81
-rw-r--r--lib/snmp/doc/src/snmp_community_mib.xml136
-rw-r--r--lib/snmp/doc/src/snmp_config.xml1030
-rw-r--r--lib/snmp/doc/src/snmp_def_instr_functions.xml477
-rw-r--r--lib/snmp/doc/src/snmp_framework_mib.xml119
-rw-r--r--lib/snmp/doc/src/snmp_generic.xml345
-rw-r--r--lib/snmp/doc/src/snmp_impl_example_agent.xml510
-rw-r--r--lib/snmp/doc/src/snmp_impl_example_manager.xml94
-rw-r--r--lib/snmp/doc/src/snmp_index.xml266
-rw-r--r--lib/snmp/doc/src/snmp_instr_functions.xml456
-rw-r--r--lib/snmp/doc/src/snmp_intro.xml258
-rw-r--r--lib/snmp/doc/src/snmp_manager_config_files.xml249
-rw-r--r--lib/snmp/doc/src/snmp_manager_funct_descr.xml112
-rw-r--r--lib/snmp/doc/src/snmp_manager_netif.xml174
-rw-r--r--lib/snmp/doc/src/snmp_manager_netif_1.gifbin0 -> 2714 bytes
-rw-r--r--lib/snmp/doc/src/snmp_manager_netif_1.ps305
-rw-r--r--lib/snmp/doc/src/snmp_mib_compiler.xml252
-rw-r--r--lib/snmp/doc/src/snmp_notification_mib.xml131
-rw-r--r--lib/snmp/doc/src/snmp_pdus.xml204
-rw-r--r--lib/snmp/doc/src/snmp_standard_mib.xml135
-rw-r--r--lib/snmp/doc/src/snmp_target_mib.xml195
-rw-r--r--lib/snmp/doc/src/snmp_user_based_sm_mib.xml146
-rw-r--r--lib/snmp/doc/src/snmp_view_based_acm_mib.xml201
-rw-r--r--lib/snmp/doc/src/snmpa.xml1252
-rw-r--r--lib/snmp/doc/src/snmpa_conf.xml861
-rw-r--r--lib/snmp/doc/src/snmpa_discovery_handler.xml118
-rw-r--r--lib/snmp/doc/src/snmpa_error.xml91
-rw-r--r--lib/snmp/doc/src/snmpa_error_io.xml88
-rw-r--r--lib/snmp/doc/src/snmpa_error_logger.xml95
-rw-r--r--lib/snmp/doc/src/snmpa_error_report.xml88
-rw-r--r--lib/snmp/doc/src/snmpa_local_db.xml190
-rw-r--r--lib/snmp/doc/src/snmpa_mpd.xml159
-rw-r--r--lib/snmp/doc/src/snmpa_network_interface.xml170
-rw-r--r--lib/snmp/doc/src/snmpa_network_interface_filter.xml163
-rw-r--r--lib/snmp/doc/src/snmpa_notification_delivery_info_receiver.xml120
-rw-r--r--lib/snmp/doc/src/snmpa_notification_filter.xml73
-rw-r--r--lib/snmp/doc/src/snmpa_supervisor.xml117
-rw-r--r--lib/snmp/doc/src/snmpc.xml201
-rw-r--r--lib/snmp/doc/src/snmpm.xml1043
-rw-r--r--lib/snmp/doc/src/snmpm_conf.xml364
-rw-r--r--lib/snmp/doc/src/snmpm_mpd.xml139
-rw-r--r--lib/snmp/doc/src/snmpm_network_interface.xml252
-rw-r--r--lib/snmp/doc/src/snmpm_network_interface_filter.xml158
-rw-r--r--lib/snmp/doc/src/snmpm_user.xml276
-rw-r--r--lib/snmp/doc/src/structure.fig46
-rw-r--r--lib/snmp/doc/src/structure.gifbin0 -> 3878 bytes
-rw-r--r--lib/snmp/doc/src/structure.ps170
-rw-r--r--lib/snmp/doc/src/summary.html.src1
-rw-r--r--lib/snmp/doc/src/user_guide.gifbin0 -> 1581 bytes
-rw-r--r--lib/snmp/doc/src/warning.gifbin0 -> 1498 bytes
-rw-r--r--lib/snmp/ebin/.gitignore0
-rw-r--r--lib/snmp/examples/Makefile35
-rw-r--r--lib/snmp/examples/ex1/EX1-MIB.funcs2
-rw-r--r--lib/snmp/examples/ex1/EX1-MIB.mib90
-rw-r--r--lib/snmp/examples/ex1/EX1-MIBv2.funcs2
-rw-r--r--lib/snmp/examples/ex1/EX1-MIBv2.mib104
-rw-r--r--lib/snmp/examples/ex1/Makefile97
-rw-r--r--lib/snmp/examples/ex1/ex1.erl256
-rw-r--r--lib/snmp/examples/ex2/Makefile93
-rw-r--r--lib/snmp/examples/ex2/snmp_ex2_manager.erl407
-rw-r--r--lib/snmp/examples/ex2/snmp_ex2_simple_standard_test.erl287
-rw-r--r--lib/snmp/examples/mcli/.gitignore0
-rw-r--r--lib/snmp/examples/subdirs.mk21
-rw-r--r--lib/snmp/include/SNMPv2-TC.hrl52
-rw-r--r--lib/snmp/include/snmp_tables.hrl109
-rw-r--r--lib/snmp/include/snmp_types.hrl395
-rw-r--r--lib/snmp/info3
-rw-r--r--lib/snmp/mibs/INET-ADDRESS-MIB.mib402
-rw-r--r--lib/snmp/mibs/Makefile.in194
-rw-r--r--lib/snmp/mibs/OTP-SNMPEA-MIB.mib569
-rw-r--r--lib/snmp/mibs/RFC-1212.mib74
-rw-r--r--lib/snmp/mibs/RFC-1215.mib30
-rw-r--r--lib/snmp/mibs/RFC1155-SMI.mib128
-rw-r--r--lib/snmp/mibs/RFC1213-MIB.mib2888
-rw-r--r--lib/snmp/mibs/SNMP-COMMUNITY-MIB.funcs2
-rw-r--r--lib/snmp/mibs/SNMP-COMMUNITY-MIB.mib377
-rw-r--r--lib/snmp/mibs/SNMP-FRAMEWORK-MIB.funcs4
-rw-r--r--lib/snmp/mibs/SNMP-FRAMEWORK-MIB.mib493
-rw-r--r--lib/snmp/mibs/SNMP-MPD-MIB.funcs6
-rw-r--r--lib/snmp/mibs/SNMP-MPD-MIB.mib140
-rw-r--r--lib/snmp/mibs/SNMP-NOTIFICATION-MIB.funcs3
-rw-r--r--lib/snmp/mibs/SNMP-NOTIFICATION-MIB.mib568
-rw-r--r--lib/snmp/mibs/SNMP-TARGET-MIB.funcs7
-rw-r--r--lib/snmp/mibs/SNMP-TARGET-MIB.mib629
-rw-r--r--lib/snmp/mibs/SNMP-USER-BASED-SM-MIB.funcs14
-rw-r--r--lib/snmp/mibs/SNMP-USER-BASED-SM-MIB.mib887
-rw-r--r--lib/snmp/mibs/SNMP-USM-AES-MIB.mib62
-rw-r--r--lib/snmp/mibs/SNMP-VIEW-BASED-ACM-MIB.funcs7
-rw-r--r--lib/snmp/mibs/SNMP-VIEW-BASED-ACM-MIB.mib805
-rw-r--r--lib/snmp/mibs/SNMPv2-CONF.mib290
-rw-r--r--lib/snmp/mibs/SNMPv2-MIB.funcs28
-rw-r--r--lib/snmp/mibs/SNMPv2-MIB.mib854
-rw-r--r--lib/snmp/mibs/SNMPv2-SMI.mib314
-rw-r--r--lib/snmp/mibs/SNMPv2-TC.mib535
-rw-r--r--lib/snmp/mibs/SNMPv2-TM.mib151
-rw-r--r--lib/snmp/mibs/STANDARD-MIB.funcs36
-rw-r--r--lib/snmp/mibs/STANDARD-MIB.mib528
-rw-r--r--lib/snmp/mibs/prebuild.skip1
-rw-r--r--lib/snmp/mibs/v1/.gitignore0
-rw-r--r--lib/snmp/priv/conf/Makefile35
-rw-r--r--lib/snmp/priv/conf/agent/Makefile63
-rw-r--r--lib/snmp/priv/conf/agent/agent.conf17
-rw-r--r--lib/snmp/priv/conf/agent/community.conf14
-rw-r--r--lib/snmp/priv/conf/agent/context.conf13
-rw-r--r--lib/snmp/priv/conf/agent/files.mk22
-rw-r--r--lib/snmp/priv/conf/agent/notify.conf12
-rw-r--r--lib/snmp/priv/conf/agent/standard.conf20
-rw-r--r--lib/snmp/priv/conf/agent/target_addr.conf18
-rw-r--r--lib/snmp/priv/conf/agent/target_params.conf10
-rw-r--r--lib/snmp/priv/conf/agent/usm.conf15
-rw-r--r--lib/snmp/priv/conf/agent/vacm.conf31
-rw-r--r--lib/snmp/priv/conf/manager/Makefile63
-rw-r--r--lib/snmp/priv/conf/manager/agents.conf40
-rw-r--r--lib/snmp/priv/conf/manager/files.mk20
-rw-r--r--lib/snmp/priv/conf/manager/manager.conf16
-rw-r--r--lib/snmp/priv/conf/manager/users.conf14
-rw-r--r--lib/snmp/priv/conf/manager/usm.conf30
-rw-r--r--lib/snmp/priv/conf/subdirs.mk21
-rw-r--r--lib/snmp/priv/mibs/.gitignore0
-rw-r--r--lib/snmp/src/Makefile35
-rw-r--r--lib/snmp/src/agent/Makefile142
-rw-r--r--lib/snmp/src/agent/depend.mk249
-rw-r--r--lib/snmp/src/agent/modules.mk78
-rw-r--r--lib/snmp/src/agent/snmp_community_mib.erl590
-rw-r--r--lib/snmp/src/agent/snmp_framework_mib.erl440
-rw-r--r--lib/snmp/src/agent/snmp_generic.erl891
-rw-r--r--lib/snmp/src/agent/snmp_generic_mnesia.erl400
-rw-r--r--lib/snmp/src/agent/snmp_index.erl163
-rw-r--r--lib/snmp/src/agent/snmp_notification_mib.erl457
-rw-r--r--lib/snmp/src/agent/snmp_shadow_table.erl187
-rw-r--r--lib/snmp/src/agent/snmp_standard_mib.erl316
-rw-r--r--lib/snmp/src/agent/snmp_target_mib.erl888
-rw-r--r--lib/snmp/src/agent/snmp_user_based_sm_mib.erl1182
-rw-r--r--lib/snmp/src/agent/snmp_view_based_acm_mib.erl832
-rw-r--r--lib/snmp/src/agent/snmpa.erl580
-rw-r--r--lib/snmp/src/agent/snmpa_acm.erl364
-rw-r--r--lib/snmp/src/agent/snmpa_agent.erl3964
-rw-r--r--lib/snmp/src/agent/snmpa_agent_sup.erl116
-rw-r--r--lib/snmp/src/agent/snmpa_app.erl372
-rw-r--r--lib/snmp/src/agent/snmpa_atl.hrl21
-rw-r--r--lib/snmp/src/agent/snmpa_authentication_service.erl57
-rw-r--r--lib/snmp/src/agent/snmpa_conf.erl937
-rw-r--r--lib/snmp/src/agent/snmpa_discovery_handler.erl29
-rw-r--r--lib/snmp/src/agent/snmpa_discovery_handler_default.erl38
-rw-r--r--lib/snmp/src/agent/snmpa_error.erl66
-rw-r--r--lib/snmp/src/agent/snmpa_error_io.erl49
-rw-r--r--lib/snmp/src/agent/snmpa_error_logger.erl50
-rw-r--r--lib/snmp/src/agent/snmpa_error_report.erl27
-rw-r--r--lib/snmp/src/agent/snmpa_general_db.erl578
-rw-r--r--lib/snmp/src/agent/snmpa_internal.hrl32
-rw-r--r--lib/snmp/src/agent/snmpa_local_db.erl1226
-rw-r--r--lib/snmp/src/agent/snmpa_mib.erl892
-rw-r--r--lib/snmp/src/agent/snmpa_mib_data.erl1355
-rw-r--r--lib/snmp/src/agent/snmpa_mib_lib.erl207
-rw-r--r--lib/snmp/src/agent/snmpa_misc_sup.erl158
-rw-r--r--lib/snmp/src/agent/snmpa_mpd.erl1386
-rw-r--r--lib/snmp/src/agent/snmpa_net_if.erl1249
-rw-r--r--lib/snmp/src/agent/snmpa_net_if_filter.erl52
-rw-r--r--lib/snmp/src/agent/snmpa_network_interface.erl45
-rw-r--r--lib/snmp/src/agent/snmpa_network_interface_filter.erl54
-rw-r--r--lib/snmp/src/agent/snmpa_notification_delivery_info_receiver.erl35
-rw-r--r--lib/snmp/src/agent/snmpa_notification_filter.erl36
-rw-r--r--lib/snmp/src/agent/snmpa_set.erl244
-rw-r--r--lib/snmp/src/agent/snmpa_set_lib.erl395
-rw-r--r--lib/snmp/src/agent/snmpa_set_mechanism.erl42
-rw-r--r--lib/snmp/src/agent/snmpa_supervisor.erl564
-rw-r--r--lib/snmp/src/agent/snmpa_svbl.erl159
-rw-r--r--lib/snmp/src/agent/snmpa_symbolic_store.erl711
-rw-r--r--lib/snmp/src/agent/snmpa_target_cache.erl891
-rw-r--r--lib/snmp/src/agent/snmpa_trap.erl1051
-rw-r--r--lib/snmp/src/agent/snmpa_usm.erl745
-rw-r--r--lib/snmp/src/agent/snmpa_vacm.erl399
-rw-r--r--lib/snmp/src/agent/snmpa_vacm.hrl24
-rw-r--r--lib/snmp/src/app/Makefile141
-rw-r--r--lib/snmp/src/app/depend.mk29
-rw-r--r--lib/snmp/src/app/modules.mk28
-rw-r--r--lib/snmp/src/app/snmp.app.src134
-rw-r--r--lib/snmp/src/app/snmp.appup.src73
-rw-r--r--lib/snmp/src/app/snmp.config154
-rw-r--r--lib/snmp/src/app/snmp.erl939
-rw-r--r--lib/snmp/src/app/snmp_app.erl175
-rw-r--r--lib/snmp/src/app/snmp_app_sup.erl119
-rw-r--r--lib/snmp/src/app/snmp_internal.hrl40
-rw-r--r--lib/snmp/src/compile/Makefile125
-rw-r--r--lib/snmp/src/compile/depend.mk46
-rw-r--r--lib/snmp/src/compile/modules.mk36
-rw-r--r--lib/snmp/src/compile/snmpc.erl1358
-rw-r--r--lib/snmp/src/compile/snmpc.hrl153
-rw-r--r--lib/snmp/src/compile/snmpc_lib.erl1819
-rw-r--r--lib/snmp/src/compile/snmpc_lib.hrl37
-rw-r--r--lib/snmp/src/compile/snmpc_mib_gram.yrl973
-rw-r--r--lib/snmp/src/compile/snmpc_mib_to_hrl.erl391
-rw-r--r--lib/snmp/src/compile/snmpc_misc.erl173
-rw-r--r--lib/snmp/src/compile/snmpc_misc.hrl74
-rw-r--r--lib/snmp/src/compile/snmpc_tok.erl357
-rw-r--r--lib/snmp/src/manager/Makefile124
-rw-r--r--lib/snmp/src/manager/depend.mk75
-rw-r--r--lib/snmp/src/manager/modules.mk45
-rw-r--r--lib/snmp/src/manager/snmpm.erl1528
-rw-r--r--lib/snmp/src/manager/snmpm_atl.hrl21
-rw-r--r--lib/snmp/src/manager/snmpm_conf.erl396
-rw-r--r--lib/snmp/src/manager/snmpm_config.erl3116
-rw-r--r--lib/snmp/src/manager/snmpm_internal.hrl32
-rw-r--r--lib/snmp/src/manager/snmpm_misc_sup.erl112
-rw-r--r--lib/snmp/src/manager/snmpm_mpd.erl1024
-rw-r--r--lib/snmp/src/manager/snmpm_net_if.erl1125
-rw-r--r--lib/snmp/src/manager/snmpm_net_if_filter.erl53
-rw-r--r--lib/snmp/src/manager/snmpm_network_interface.erl37
-rw-r--r--lib/snmp/src/manager/snmpm_network_interface_filter.erl54
-rw-r--r--lib/snmp/src/manager/snmpm_server.erl3117
-rw-r--r--lib/snmp/src/manager/snmpm_server_sup.erl110
-rw-r--r--lib/snmp/src/manager/snmpm_supervisor.erl115
-rw-r--r--lib/snmp/src/manager/snmpm_user.erl97
-rw-r--r--lib/snmp/src/manager/snmpm_user_default.erl87
-rw-r--r--lib/snmp/src/manager/snmpm_user_old.erl33
-rw-r--r--lib/snmp/src/manager/snmpm_usm.erl512
-rw-r--r--lib/snmp/src/manager/snmpm_usm.hrl27
-rw-r--r--lib/snmp/src/misc/Makefile122
-rw-r--r--lib/snmp/src/misc/depend.mk58
-rw-r--r--lib/snmp/src/misc/modules.mk33
-rw-r--r--lib/snmp/src/misc/snmp_conf.erl421
-rw-r--r--lib/snmp/src/misc/snmp_config.erl2348
-rw-r--r--lib/snmp/src/misc/snmp_debug.hrl38
-rw-r--r--lib/snmp/src/misc/snmp_log.erl584
-rw-r--r--lib/snmp/src/misc/snmp_mini_mib.erl151
-rw-r--r--lib/snmp/src/misc/snmp_misc.erl465
-rw-r--r--lib/snmp/src/misc/snmp_note_store.erl450
-rw-r--r--lib/snmp/src/misc/snmp_pdus.erl770
-rw-r--r--lib/snmp/src/misc/snmp_usm.erl367
-rw-r--r--lib/snmp/src/misc/snmp_verbosity.erl161
-rw-r--r--lib/snmp/src/misc/snmp_verbosity.hrl64
-rw-r--r--lib/snmp/src/subdirs.mk22
-rw-r--r--lib/snmp/subdirs.mk21
-rw-r--r--lib/snmp/test/Makefile259
-rw-r--r--lib/snmp/test/klas3.erl162
-rw-r--r--lib/snmp/test/modules.mk76
-rw-r--r--lib/snmp/test/sa.erl44
-rw-r--r--lib/snmp/test/snmp.cover15
-rw-r--r--lib/snmp/test/snmp.spec1
-rw-r--r--lib/snmp/test/snmp.spec.vxworks4
-rw-r--r--lib/snmp/test/snmp_SUITE.erl157
-rw-r--r--lib/snmp/test/snmp_agent_bl_test.erl5654
-rw-r--r--lib/snmp/test/snmp_agent_mibs_test.erl721
-rw-r--r--lib/snmp/test/snmp_agent_ms_test.erl5657
-rw-r--r--lib/snmp/test/snmp_agent_mt_test.erl5657
-rw-r--r--lib/snmp/test/snmp_agent_nfilter_test.erl78
-rw-r--r--lib/snmp/test/snmp_agent_test.erl6009
-rw-r--r--lib/snmp/test/snmp_agent_test_lib.erl1480
-rw-r--r--lib/snmp/test/snmp_agent_v1_test.erl2673
-rw-r--r--lib/snmp/test/snmp_agent_v2_test.erl5657
-rw-r--r--lib/snmp/test/snmp_agent_v3_test.erl5657
-rw-r--r--lib/snmp/test/snmp_app_test.erl430
-rw-r--r--lib/snmp/test/snmp_appup_mgr.erl280
-rw-r--r--lib/snmp/test/snmp_appup_test.erl560
-rw-r--r--lib/snmp/test/snmp_compiler_test.erl391
-rw-r--r--lib/snmp/test/snmp_conf_test.erl680
-rw-r--r--lib/snmp/test/snmp_log_test.erl941
-rw-r--r--lib/snmp/test/snmp_manager_config_test.erl2535
-rw-r--r--lib/snmp/test/snmp_manager_test.erl5436
-rw-r--r--lib/snmp/test/snmp_manager_user.erl935
-rwxr-xr-xlib/snmp/test/snmp_manager_user_old.erl264
-rw-r--r--lib/snmp/test/snmp_manager_user_test.erl1244
-rw-r--r--lib/snmp/test/snmp_manager_user_test_lib.erl422
-rw-r--r--lib/snmp/test/snmp_note_store_test.erl306
-rw-r--r--lib/snmp/test/snmp_pdus_test.erl127
-rw-r--r--lib/snmp/test/snmp_test_data/ERICSSON-TOP-MIB.mib36
-rw-r--r--lib/snmp/test/snmp_test_data/EX1-MIB.mib90
-rw-r--r--lib/snmp/test/snmp_test_data/Klas1-v2.mib128
-rw-r--r--lib/snmp/test/snmp_test_data/Klas1.mib116
-rw-r--r--lib/snmp/test/snmp_test_data/Klas2.funcs3
-rw-r--r--lib/snmp/test/snmp_test_data/Klas2.mib128
-rw-r--r--lib/snmp/test/snmp_test_data/Klas3.funcs2
-rw-r--r--lib/snmp/test/snmp_test_data/Klas3.mib40
-rw-r--r--lib/snmp/test/snmp_test_data/Klas4.funcs3
-rw-r--r--lib/snmp/test/snmp_test_data/Klas4.mib156
-rw-r--r--lib/snmp/test/snmp_test_data/OLD-SNMPEA-MIB-v2.mib480
-rw-r--r--lib/snmp/test/snmp_test_data/OLD-SNMPEA-MIB.mib487
-rw-r--r--lib/snmp/test/snmp_test_data/PROXY.mib60
-rw-r--r--lib/snmp/test/snmp_test_data/RFC1213-MIB.mib2888
-rw-r--r--lib/snmp/test/snmp_test_data/SA-MIB.funcs5
-rw-r--r--lib/snmp/test/snmp_test_data/SA-MIB.mib93
-rw-r--r--lib/snmp/test/snmp_test_data/SNMPv2-MIB.funcs28
-rw-r--r--lib/snmp/test/snmp_test_data/SNMPv2-MIB.mib767
-rw-r--r--lib/snmp/test/snmp_test_data/STANDARD-MIB.funcs8
-rw-r--r--lib/snmp/test/snmp_test_data/STANDARD-MIB.mib528
-rw-r--r--lib/snmp/test/snmp_test_data/Test1.funcs7
-rw-r--r--lib/snmp/test/snmp_test_data/Test1.mib370
-rw-r--r--lib/snmp/test/snmp_test_data/Test2.funcs10
-rw-r--r--lib/snmp/test/snmp_test_data/Test2.mib246
-rw-r--r--lib/snmp/test/snmp_test_data/TestTrap.mib44
-rw-r--r--lib/snmp/test/snmp_test_data/TestTrapv2.mib71
-rw-r--r--lib/snmp/test/snmp_test_lib.erl525
-rw-r--r--lib/snmp/test/snmp_test_lib.hrl151
-rw-r--r--lib/snmp/test/snmp_test_manager.erl388
-rw-r--r--lib/snmp/test/snmp_test_mgr.erl1139
-rw-r--r--lib/snmp/test/snmp_test_mgr_misc.erl792
-rw-r--r--lib/snmp/test/snmp_test_server.erl416
-rw-r--r--lib/snmp/test/snmp_test_suite.erl35
-rw-r--r--lib/snmp/test/test-mibs/Bitsindex-error.mib94
-rw-r--r--lib/snmp/test/test-mibs/ENTITY-MIB.mib784
-rw-r--r--lib/snmp/test/test-mibs/INTERNAL-MIB.mib463
-rw-r--r--lib/snmp/test/test-mibs/Klas1.mib118
-rw-r--r--lib/snmp/test/test-mibs/Oid1-error.mib26
-rw-r--r--lib/snmp/test/test-mibs/README19
-rw-r--r--lib/snmp/test/test-mibs/RFC1213-MIB.mib2888
-rw-r--r--lib/snmp/test/test-mibs/RFC1271-MIB.mib3492
-rw-r--r--lib/snmp/test/test-mibs/RMON-MIB.mib3826
-rw-r--r--lib/snmp/test/test-mibs/RMON2-MIB.mib5450
-rw-r--r--lib/snmp/test/test-mibs/SNMPv2-MIB.mib777
-rw-r--r--lib/snmp/test/test-mibs/SNMPv2-TC.mib799
-rw-r--r--lib/snmp/test/test-mibs/SNMPv2-USEC-MIB.mib251
-rw-r--r--lib/snmp/test/test-mibs/SNMPv2-test.mib777
-rw-r--r--lib/snmp/test/test-mibs/STANDARD-MIB.mib518
-rw-r--r--lib/snmp/test/test-mibs/TOKEN-RING-RMON-MIB.mib2406
-rw-r--r--lib/snmp/test/test-mibs/Table1-error.mib97
-rw-r--r--lib/snmp/test/test-mibs/Type-error.mib11
-rw-r--r--lib/snmp/test/test1.erl72
-rw-r--r--lib/snmp/test/test2.erl80
-rw-r--r--lib/snmp/vsn.mk169
378 files changed, 200826 insertions, 0 deletions
diff --git a/lib/snmp/AUTHORS b/lib/snmp/AUTHORS
new file mode 100644
index 0000000000..d6e7223348
--- /dev/null
+++ b/lib/snmp/AUTHORS
@@ -0,0 +1,6 @@
+Original Authors:
+
+Martin Bj�rklund, Klas Eriksson, Peter H�gfeldt
+
+
+Contributors:
diff --git a/lib/snmp/Makefile b/lib/snmp/Makefile
new file mode 100644
index 0000000000..20e3d4692a
--- /dev/null
+++ b/lib/snmp/Makefile
@@ -0,0 +1,119 @@
+#-*-makefile-*- ; force emacs to enter makefile-mode
+
+# %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%
+
+include $(ERL_TOP)/make/target.mk
+include $(ERL_TOP)/make/$(TARGET)/otp.mk
+
+# ----------------------------------------------------
+# Common Macros
+# ----------------------------------------------------
+
+include subdirs.mk
+
+include vsn.mk
+
+VSN = $(SNMP_VSN)
+
+SPECIAL_TARGETS =
+
+DIR_NAME = snmp_src-$(VSN)$(PRE_VSN)
+
+ifndef APP_RELEASE_DIR
+ APP_RELEASE_DIR = /tmp
+endif
+
+ifndef APP_TAR_FILE
+ APP_TAR_FILE = $(APP_RELEASE_DIR)/$(DIR_NAME).tgz
+endif
+
+APP_DIR = $(APP_RELEASE_DIR)/$(DIR_NAME)
+
+ifdef OTP_INSTALL_DIR
+ APP_INSTALL_DIR = $(OTP_INSTALL_DIR)/lib/erlang
+else
+ # If installing into an OTP structure created
+ # by installing an source OTP build, the '/tmp'
+ # shall be replaced with the value of ERL_TOP
+ APP_INSTALL_DIR = /tmp/lib/erlang
+endif
+
+
+# ----------------------------------------------------
+# Default Subdir Targets
+# ----------------------------------------------------
+include $(ERL_TOP)/make/otp_subdir.mk
+
+conf: do_configure
+
+do_configure: configure
+ ./configure
+
+configure: configure.in
+ autoconf
+
+.PHONY: info
+
+info:
+ @echo "OS: $(OS)"
+ @echo "DOCB: $(DOCB)"
+ @echo ""
+ @echo "SNMP_VSN: $(SNMP_VSN)"
+ @echo "APP_VSN: $(APP_VSN)"
+
+
+# ----------------------------------------------------
+# Application (source) release targets
+# ----------------------------------------------------
+app_release: app_doc tar
+
+app_clean:
+ rm -rf $(APP_TAR_FILE) $(APP_DIR)
+
+app_doc:
+ cd doc/src; $(MAKE) html man
+
+app_dir: $(APP_DIR)
+
+$(APP_DIR):
+ cat TAR.exclude | grep -v "snmp/doc" > TAR.exclude2; \
+ echo "snmp/doc/src" >> TAR.exclude2; \
+ echo "snmp/TAR.exclude2" >> TAR.exclude2; \
+ echo "snmp/doc/internal" >> TAR.exclude2; \
+ echo "snmp/mibs/prebuild.skip" >> TAR.exclude2
+ (cd ..; find snmp -name 'findmerge.*' >> snmp/TAR.exclude2)
+ (cd ..; find snmp -name '*.contrib*' >> snmp/TAR.exclude2)
+ (cd ..; find snmp -name '*.keep*' >> snmp/TAR.exclude2)
+ (cd ..; find snmp -name '*~' >> snmp/TAR.exclude2)
+ (cd ..; find snmp -name '*.log' >> snmp/TAR.exclude2)
+ (cd ..; find snmp -name 'erl_crash.dump' >> snmp/TAR.exclude2)
+ mkdir $(APP_DIR); \
+ (cd ..; tar cfX - snmp/TAR.exclude2 snmp) | \
+ (cd $(APP_DIR); tar xf -); \
+ mv $(APP_DIR)/snmp/* $(APP_DIR)/; \
+ find $(APP_DIR)/snmp -name '.cmake.state' | xargs rm -f; \
+ mkdir $(APP_DIR)/autoconf; \
+ cp autoconf/config.guess $(APP_DIR)/autoconf/; \
+ cp autoconf/config.sub $(APP_DIR)/autoconf/; \
+ cp autoconf/install-sh $(APP_DIR)/autoconf/; \
+ rmdir $(APP_DIR)/snmp
+
+tar: $(APP_TAR_FILE)
+
+$(APP_TAR_FILE): $(APP_DIR)
+ (cd $(APP_RELEASE_DIR); gtar zcf $(APP_TAR_FILE) $(DIR_NAME))
diff --git a/lib/snmp/bin/snmp-v2tov1.pl b/lib/snmp/bin/snmp-v2tov1.pl
new file mode 100644
index 0000000000..f9ecfc9dd8
--- /dev/null
+++ b/lib/snmp/bin/snmp-v2tov1.pl
@@ -0,0 +1,319 @@
+# snmp-v2tov1.awk
+# nawk script - pass 1 of translation from SNMP v2 SMI to v1 SMI
+#
+
+# Translate v2 IMPORTs to their v1 equivalents
+$[ = 1; # set array base to 1
+$, = ' '; # set output field separator
+$\ = "\n"; # set output record separator
+
+line: while (<>) {
+ chomp; # strip record separator
+ @Fld = split(' ', $_, 9999);
+ if (/IMPORT/) {
+ $import = 1;
+ $isave = 0;
+ print $_;
+ next line;
+ }
+ if (($import == 1) && ($Fld[1] eq ';')) {
+ $import = 0;
+ }
+ if (($import == 1) && ($Fld[1] ne 'FROM')) {
+ for ($i = 1; $i <= $#Fld; $i++) {
+ $s = ',', $Fld[$i] =~ s/$s//;
+ $imp{$i + $isave} = $Fld[$i];
+ }
+ $isave = $isave + ($i - 1);
+ next line;
+ }
+ if (($import == 1) && ($Fld[1] eq 'FROM')) {
+ &print_imp($Fld[2], *imp, $isave);
+ $isave = 0;
+ next line;
+ }
+
+ # str is 1 if we're inside a string, and 0 otherwise.
+ if (/\"/) {
+ $str = 1;
+ }
+ if ($Fld[$#Fld] =~ /\"$/) {
+ $str = 0;
+ }
+
+ # Just reprint all comments
+ if (/^--/) {
+ print $_;
+ next line;
+ }
+
+ # Place comments around MODULE-IDENTITY
+ if (/MODULE-IDENTITY/ && ($str == 0)) {
+ $moduleid = 1;
+ print '--', $_;
+ next line;
+ }
+ if (($moduleid == 1) && ($Fld[1] eq '::=')) {
+ $moduleid = 0;
+ print '--', $_;
+ next line;
+ }
+ if ($moduleid == 1) {
+ print '--', $_;
+ next line;
+ }
+
+ # Translate TEXTUAL-CONVENTION into an ordinary type assignement.
+ # Place comments around body.
+ if (/TEXTUAL-CONVENTION/ && ($str == 0)) {
+ $textual = 1;
+
+ print $Fld[1], $Fld[2];
+ print '--TEXTUAL-CONVENTION';
+ next line;
+ }
+ if (($textual == 1) && ($Fld[1] eq 'SYNTAX')) {
+ $textual = 0;
+ print "--SYNTAX\n";
+ for ($i = 2; $i <= $#Fld; $i++) {
+ print $Fld[$i];
+ }
+ next line;
+ }
+ if ($textual == 1) {
+ $s = '--', s/$s/-- --/;
+ print '--', $_;
+ next line;
+ }
+
+ # Translate OBJECT-IDENTITY into an OBJECT IDENTIFIER.
+ # Place comments around body.
+ if (/OBJECT-IDENTITY/ && ($str == 0)) {
+ $objid = 1;
+
+ print $Fld[1], 'OBJECT IDENTIFIER';
+ print '--OBJECT-IDENTITY';
+ next line;
+ }
+ if (($objid == 1) && ($Fld[1] eq '::=')) {
+ $objid = 0;
+ print $_;
+ next line;
+ }
+ if ($objid == 1) {
+ $s = '--', s/$s/-- --/;
+ print '--', $_;
+ next line;
+ }
+
+ # Place comments around MODULE-COMPLIANCE
+ if (/MODULE-COMPLIANCE/ && ($str == 0)) {
+ $modcomp = 1;
+ print '--', $_;
+ next line;
+ }
+ if (($modcomp == 1) && ($Fld[1] eq '::=')) {
+ $modcomp = 0;
+ print '--', $_;
+ next line;
+ }
+ if ($modcomp == 1) {
+ $s = '--', s/$s/-- --/;
+ print '--', $_;
+ next line;
+ }
+
+ # Place comments around OBJECT-GROUP
+ if (/OBJECT-GROUP/ && ($str == 0)) {
+ $objgr = 1;
+ print '--', $_;
+ next line;
+ }
+ if (($objgr == 1) && ($Fld[1] eq '::=')) {
+ $objgr = 0;
+ print '--', $_;
+ next line;
+ }
+ if ($objgr == 1) {
+ $s = '--', s/$s/-- --/;
+ print '--', $_;
+ next line;
+ }
+
+ if (/OBJECT-GROUP/) {
+ print 'tjolaopp';
+ }
+
+ # Place comments around NOTIFICATION-GROUP
+ if (/NOTIFICATION-GROUP/ && ($str == 0)) {
+ $notgr = 1;
+ print '--', $_;
+ next line;
+ }
+ if (($notgr == 1) && ($Fld[1] eq '::=')) {
+ $notgr = 0;
+ print '--', $_;
+ next line;
+ }
+ if ($notgr == 1) {
+ $s = '--', s/$s/-- --/;
+ print '--', $_;
+ next line;
+ }
+
+ # Translate NOTIFICATION-TYPE into a TRAP-TYPE.
+ if (/NOTIFICATION-TYPE/ && ($str == 0)) {
+ $trap = 1;
+ print $Fld[1], ' TRAP-TYPE';
+ printf ' ENTERPRISE ';
+ $tri = 1;
+ next line;
+ }
+ if (($trap == 1) && ($Fld[1] eq 'OBJECTS')) {
+ $tra{$tri++} = $_;
+ next line;
+ }
+ if (($trap == 1) && ($Fld[1] eq 'STATUS')) {
+ next line;
+ }
+ if (($trap == 1) && ($Fld[1] eq '::=')) {
+ print $Fld[3];
+ &pr_trap(*tra, $tri);
+ printf ' ::= ';
+ print $Fld[4];
+ $tri = 1;
+ $trap = 0;
+ next line;
+ }
+ if ($trap == 1) {
+ $tra{$tri++} = $_;
+ next line;
+ }
+
+ if (/UNITS/) {
+ $s = '--', s/$s/-- --/;
+ print '--', $_;
+ next line;
+ }
+
+ print $_;
+
+ # Print v1 IMPORT statements
+
+ # Print a trap
+}
+
+sub print_imp {
+ local($mib, *imp, $isave) = @_;
+ for ($i = 1; $i <= $isave; $i++) {
+ if ($imp{$i} eq 'Counter32') {
+ print ' ', $imp{$i};
+ print ' FROM RFC1155-SMI';
+ }
+ elsif ($imp{$i} eq 'Gauge32') {
+ print ' ', $imp{$i};
+ print ' FROM RFC1155-SMI';
+ }
+ elsif ($imp{$i} eq 'TimeTicks') {
+ print ' ', $imp{$i};
+ print ' FROM RFC1155-SMI';
+ }
+ elsif ($imp{$i} eq 'Opaque') {
+ print ' ', $imp{$i};
+ print ' FROM RFC1155-SMI';
+ }
+ elsif ($imp{$i} eq 'IpAddress') {
+ print ' ', $imp{$i};
+ print ' FROM RFC1155-SMI';
+ }
+ elsif ($imp{$i} eq 'NetworkAddress') {
+ print ' ', $imp{$i};
+ print ' FROM RFC1155-SMI';
+ }
+ elsif ($imp{$i} eq 'enterprises') {
+ print ' ', $imp{$i};
+ print ' FROM RFC1155-SMI';
+ }
+ elsif ($imp{$i} eq 'private') {
+ print ' ', $imp{$i};
+ print ' FROM RFC1155-SMI';
+ }
+ elsif ($imp{$i} eq 'experimental') {
+ print ' ', $imp{$i};
+ print ' FROM RFC1155-SMI';
+ }
+ elsif ($imp{$i} eq 'mgmt') {
+ print ' ', $imp{$i};
+ print ' FROM RFC1155-SMI';
+ }
+ elsif ($imp{$i} eq 'internet') {
+ print ' ', $imp{$i};
+ print ' FROM RFC1155-SMI';
+ }
+ elsif ($imp{$i} eq 'directory') {
+ print ' ', $imp{$i};
+ print ' FROM RFC1155-SMI';
+ }
+ elsif ($imp{$i} eq 'DisplayString') {
+ print ' ', $imp{$i};
+ print ' FROM RFC1213-MIB';
+ }
+ elsif ($imp{$i} eq 'mib-2') {
+ print ' ', $imp{$i};
+ print ' FROM RFC1213-MIB';
+ }
+ elsif ($imp{$i} eq 'OBJECT-TYPE') {
+ print ' ', $imp{$i};
+ print ' FROM RFC-1212';
+ }
+ elsif ($imp{$i} eq 'Integer32') {
+ ;
+ }
+ elsif ($imp{$i} eq 'MODULE-IDENTITY') {
+ ;
+ }
+ elsif ($imp{$i} eq 'TEXTUAL-CONVENTION') {
+ ;
+ }
+ elsif ($imp{$i} eq 'OBJECT-IDENTITY') {
+ ;
+ }
+ elsif ($imp{$i} eq 'OBJECT-GROUP') {
+ ;
+ }
+ elsif ($imp{$i} eq 'MODULE-COMPLIANCE') {
+ ;
+ }
+ elsif ($imp{$i} eq 'NOTIFICATION-GROUP') {
+ ;
+ }
+ elsif ($imp{$i} eq 'NOTIFICATION-TYPE') {
+ print ' TRAP-TYPE';
+ print ' FROM RFC-1215';
+ }
+ elsif ($imp{$i} eq 'DateAndTime') {
+ print ' ', $imp{$i};
+ print ' FROM STANDARD-MIB';
+ }
+ elsif ($imp{$i} eq 'TruthValue') {
+ print ' ', $imp{$i};
+ print ' FROM STANDARD-MIB';
+ }
+ elsif ($imp{$i} eq 'RowStatus') {
+ print ' ', $imp{$i};
+ print ' FROM STANDARD-MIB';
+ }
+ else {
+ print ' ', $imp{$i};
+ print ' FROM', $mib;
+ }
+ }
+}
+
+sub pr_trap {
+ local(*tra, $tri) = @_;
+ for ($i = 1; $i < $tri; $i++) {
+ print $tra{$i};
+ }
+}
diff --git a/lib/snmp/bin/snmp-v2tov1.sed b/lib/snmp/bin/snmp-v2tov1.sed
new file mode 100644
index 0000000000..f940295d69
--- /dev/null
+++ b/lib/snmp/bin/snmp-v2tov1.sed
@@ -0,0 +1,9 @@
+s/Integer32/INTEGER/g
+s/Counter32/Counter/g
+s/Gauge32/Gauge/g
+s/MAX-ACCESS/ACCESS /g
+s/OBJECTS/VARIABLES/g
+s/current[^a-zA-Z0-9]/mandatory/g
+s/current$/mandatory/g
+s/accessible-for-notify/not-accessible/g
+s/read-create/read-write/g
diff --git a/lib/snmp/bin/snmp-v2tov1.src b/lib/snmp/bin/snmp-v2tov1.src
new file mode 100644
index 0000000000..891487af2a
--- /dev/null
+++ b/lib/snmp/bin/snmp-v2tov1.src
@@ -0,0 +1,32 @@
+#!/bin/sh
+#
+# Converts a SNMPv2 MIB to a SNMPv1 MIB
+# Some kind of ad hoc algorithm is used - the
+# v2 MIBs must be well-formatted.
+
+Out=nope
+
+while [ $# -gt 0 ];
+do
+ case $1 in
+ -h*)
+ echo "Usage: snmp-v2tov1 [-o OutFile] FileName"
+ echo " Converts a SNMPv2 MIB to a SNMPv1 MIB"
+ exit;;
+ -o)
+ Out=$2
+ shift;
+ shift;;
+ *)
+ File=$1
+ shift;;
+ esac
+done
+
+if [ "X$Out" = "Xnope" ]
+then
+ Out=$File.v1
+fi
+
+%PERL% $ERL_TOP/lib/snmp/bin/snmp-v2tov1.pl $File | sed -f $ERL_TOP/lib/snmp/bin/snmp-v2tov1.sed > $Out
diff --git a/lib/snmp/configure.in b/lib/snmp/configure.in
new file mode 100644
index 0000000000..f9ca8f9ac4
--- /dev/null
+++ b/lib/snmp/configure.in
@@ -0,0 +1,33 @@
+
+define([AC_CACHE_LOAD], )dnl
+define([AC_CACHE_SAVE], )dnl
+
+AC_INIT(vsn.mk)
+
+if test -z "$ERL_TOP" || test ! -d $ERL_TOP ; then
+ AC_CONFIG_AUX_DIRS(autoconf)
+else
+ erl_top=${ERL_TOP}
+ AC_CONFIG_AUX_DIRS($erl_top/erts/autoconf)
+fi
+
+if test "X$host" != "Xfree_source" -a "X$host" != "Xwin32"; then
+ AC_CANONICAL_HOST
+else
+ host_os=win32
+fi
+
+
+dnl ----------------------------------------------------------------------
+dnl Checks for programs.
+dnl ----------------------------------------------------------------------
+
+
+AC_CHECK_PROG(PERL, perl, perl, no_perl)
+if test "$PERL" = no_perl; then
+ AC_MSG_ERROR([Perl is required to generate v2 to v1 mib converter script])
+fi
+
+
+AC_OUTPUT(mibs/Makefile:mibs/Makefile.in)
+
diff --git a/lib/snmp/doc/html/.gitignore b/lib/snmp/doc/html/.gitignore
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/lib/snmp/doc/html/.gitignore
diff --git a/lib/snmp/doc/man3/.gitignore b/lib/snmp/doc/man3/.gitignore
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/lib/snmp/doc/man3/.gitignore
diff --git a/lib/snmp/doc/man6/.gitignore b/lib/snmp/doc/man6/.gitignore
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/lib/snmp/doc/man6/.gitignore
diff --git a/lib/snmp/doc/man7/.gitignore b/lib/snmp/doc/man7/.gitignore
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/lib/snmp/doc/man7/.gitignore
diff --git a/lib/snmp/doc/pdf/.gitignore b/lib/snmp/doc/pdf/.gitignore
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/lib/snmp/doc/pdf/.gitignore
diff --git a/lib/snmp/doc/src/MIB_mechanism.fig b/lib/snmp/doc/src/MIB_mechanism.fig
new file mode 100644
index 0000000000..38d4c7c5e6
--- /dev/null
+++ b/lib/snmp/doc/src/MIB_mechanism.fig
@@ -0,0 +1,73 @@
+#FIG 3.1
+Landscape
+Center
+Inches
+1200 2
+6 1725 525 3375 1875
+2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2
+ 3000 600 3000 1800
+2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 1 0 2
+ 0 0 1.00 60.00 120.00
+ 3000 600 3300 600
+2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 1 0 2
+ 0 0 1.00 60.00 120.00
+ 3000 1800 3300 1800
+2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2
+ 1725 1200 3000 1200
+-6
+6 1725 2925 3375 4275
+2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2
+ 3000 3000 3000 4200
+2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 1 0 2
+ 0 0 1.00 60.00 120.00
+ 3000 3000 3300 3000
+2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 1 0 2
+ 0 0 1.00 60.00 120.00
+ 3000 4200 3300 4200
+2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2
+ 1725 3600 3000 3600
+-6
+2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2
+ 5250 600 5250 1800
+2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2
+ 4950 1800 5250 1800
+2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2
+ 4950 600 5250 600
+2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 1 0 2
+ 0 0 1.00 60.00 120.00
+ 5250 1200 6000 1200
+2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 1 0 2
+ 0 0 1.00 60.00 120.00
+ 1800 2400 3300 2400
+2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2
+ 4950 2400 7800 2400
+2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2
+ 7200 1200 7800 1200
+2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2
+ 4950 3000 7800 3000
+2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2
+ 4950 4200 7800 4200
+2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 1 0 2
+ 0 0 1.00 60.00 120.00
+ 1800 4800 3300 4800
+2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2
+ 6000 4800 7800 4800
+2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2
+ 7800 1200 7800 4800
+2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 1 0 2
+ 0 0 1.00 60.00 120.00
+ 7800 2700 8400 2700
+2 2 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 5
+ 900 225 9450 225 9450 5175 900 5175 900 225
+4 0 -1 0 0 0 12 0.0000 4 135 315 1200 1275 who\001
+4 0 -1 0 0 0 12 0.0000 4 135 465 1200 2400 where\001
+4 0 -1 0 0 0 12 0.0000 4 180 870 6150 1200 groupName\001
+4 0 -1 0 0 0 12 0.0000 4 135 1020 3600 2400 contexrName\001
+4 0 -1 0 0 0 12 0.0000 4 135 315 1200 3600 who\001
+4 0 -1 0 0 0 12 0.0000 4 180 315 1275 4800 why\001
+4 0 -1 0 0 0 12 0.0000 4 135 810 8475 2700 viewName\001
+4 0 -1 0 0 0 12 0.0000 4 180 1095 3600 600 securityModel\001
+4 0 -1 0 0 0 12 0.0000 4 180 1065 3600 1800 securityName\001
+4 0 -1 0 0 0 12 0.0000 4 180 1095 3600 3000 securityModel\001
+4 0 -1 0 0 0 12 0.0000 4 180 1035 3600 4200 securityLevel\001
+4 0 -1 0 0 0 12 0.0000 4 180 2175 3600 4800 viewType (read/write/notify)\001
diff --git a/lib/snmp/doc/src/MIB_mechanism.gif b/lib/snmp/doc/src/MIB_mechanism.gif
new file mode 100644
index 0000000000..2a25c6e44f
--- /dev/null
+++ b/lib/snmp/doc/src/MIB_mechanism.gif
Binary files differ
diff --git a/lib/snmp/doc/src/MIB_mechanism.ps b/lib/snmp/doc/src/MIB_mechanism.ps
new file mode 100644
index 0000000000..e45e7d0bad
--- /dev/null
+++ b/lib/snmp/doc/src/MIB_mechanism.ps
@@ -0,0 +1,217 @@
+%!PS-Adobe-2.0 EPSF-2.0
+%%Title: bild1.fig
+%%Creator: fig2dev Version 3.1 Patchlevel 2
+%%CreationDate: Tue Dec 28 16:12:39 1999
+%%For: nibe@gundor (Bengt Nilsson, ETX/DN/SP)
+%Magnification: 1.00
+%%Orientation: Portrait
+%%BoundingBox: 0 0 515 300
+%%Pages: 0
+%%BeginSetup
+%%IncludeFeature: *PageSize Letter
+%%EndSetup
+%%EndComments
+/$F2psDict 200 dict def
+$F2psDict begin
+$F2psDict /mtrx matrix put
+/col-1 {0 setgray} bind def
+/col0 {0.000 0.000 0.000 srgb} bind def
+/col1 {0.000 0.000 1.000 srgb} bind def
+/col2 {0.000 1.000 0.000 srgb} bind def
+/col3 {0.000 1.000 1.000 srgb} bind def
+/col4 {1.000 0.000 0.000 srgb} bind def
+/col5 {1.000 0.000 1.000 srgb} bind def
+/col6 {1.000 1.000 0.000 srgb} bind def
+/col7 {1.000 1.000 1.000 srgb} bind def
+/col8 {0.000 0.000 0.560 srgb} bind def
+/col9 {0.000 0.000 0.690 srgb} bind def
+/col10 {0.000 0.000 0.820 srgb} bind def
+/col11 {0.530 0.810 1.000 srgb} bind def
+/col12 {0.000 0.560 0.000 srgb} bind def
+/col13 {0.000 0.690 0.000 srgb} bind def
+/col14 {0.000 0.820 0.000 srgb} bind def
+/col15 {0.000 0.560 0.560 srgb} bind def
+/col16 {0.000 0.690 0.690 srgb} bind def
+/col17 {0.000 0.820 0.820 srgb} bind def
+/col18 {0.560 0.000 0.000 srgb} bind def
+/col19 {0.690 0.000 0.000 srgb} bind def
+/col20 {0.820 0.000 0.000 srgb} bind def
+/col21 {0.560 0.000 0.560 srgb} bind def
+/col22 {0.690 0.000 0.690 srgb} bind def
+/col23 {0.820 0.000 0.820 srgb} bind def
+/col24 {0.500 0.190 0.000 srgb} bind def
+/col25 {0.630 0.250 0.000 srgb} bind def
+/col26 {0.750 0.380 0.000 srgb} bind def
+/col27 {1.000 0.500 0.500 srgb} bind def
+/col28 {1.000 0.630 0.630 srgb} bind def
+/col29 {1.000 0.750 0.750 srgb} bind def
+/col30 {1.000 0.880 0.880 srgb} bind def
+/col31 {1.000 0.840 0.000 srgb} bind def
+
+end
+save
+-53.0 312.0 translate
+1 -1 scale
+
+/cp {closepath} bind def
+/ef {eofill} bind def
+/gr {grestore} bind def
+/gs {gsave} bind def
+/sa {save} bind def
+/rs {restore} bind def
+/l {lineto} bind def
+/m {moveto} bind def
+/rm {rmoveto} bind def
+/n {newpath} bind def
+/s {stroke} bind def
+/sh {show} bind def
+/slc {setlinecap} bind def
+/slj {setlinejoin} bind def
+/slw {setlinewidth} bind def
+/srgb {setrgbcolor} bind def
+/rot {rotate} bind def
+/sc {scale} bind def
+/sd {setdash} bind def
+/ff {findfont} bind def
+/sf {setfont} bind def
+/scf {scalefont} bind def
+/sw {stringwidth} bind def
+/tr {translate} bind def
+/tnt {dup dup currentrgbcolor
+ 4 -2 roll dup 1 exch sub 3 -1 roll mul add
+ 4 -2 roll dup 1 exch sub 3 -1 roll mul add
+ 4 -2 roll dup 1 exch sub 3 -1 roll mul add srgb}
+ bind def
+/shd {dup dup currentrgbcolor 4 -2 roll mul 4 -2 roll mul
+ 4 -2 roll mul srgb} bind def
+/$F2psBegin {$F2psDict begin /$F2psEnteredState save def} def
+/$F2psEnd {$F2psEnteredState restore end} def
+%%EndProlog
+
+$F2psBegin
+10 setmiterlimit
+n 0 792 m 0 0 l 612 0 l 612 792 l cp clip
+ 0.06000 0.06000 sc
+7.500 slw
+% Polyline
+n 3000 600 m 3000 1800 l gs col-1 s gr
+% Polyline
+gs clippath
+3153 570 m 3273 600 l 3153 630 l 3315 630 l 3315 570 l cp clip
+n 3000 600 m 3300 600 l gs col-1 s gr gr
+
+% arrowhead
+n 3153 570 m 3273 600 l 3153 630 l col-1 s
+% Polyline
+gs clippath
+3153 1770 m 3273 1800 l 3153 1830 l 3315 1830 l 3315 1770 l cp clip
+n 3000 1800 m 3300 1800 l gs col-1 s gr gr
+
+% arrowhead
+n 3153 1770 m 3273 1800 l 3153 1830 l col-1 s
+% Polyline
+n 1725 1200 m 3000 1200 l gs col-1 s gr
+% Polyline
+n 3000 3000 m 3000 4200 l gs col-1 s gr
+% Polyline
+gs clippath
+3153 2970 m 3273 3000 l 3153 3030 l 3315 3030 l 3315 2970 l cp clip
+n 3000 3000 m 3300 3000 l gs col-1 s gr gr
+
+% arrowhead
+n 3153 2970 m 3273 3000 l 3153 3030 l col-1 s
+% Polyline
+gs clippath
+3153 4170 m 3273 4200 l 3153 4230 l 3315 4230 l 3315 4170 l cp clip
+n 3000 4200 m 3300 4200 l gs col-1 s gr gr
+
+% arrowhead
+n 3153 4170 m 3273 4200 l 3153 4230 l col-1 s
+% Polyline
+n 1725 3600 m 3000 3600 l gs col-1 s gr
+% Polyline
+n 5250 600 m 5250 1800 l gs col-1 s gr
+% Polyline
+n 4950 1800 m 5250 1800 l gs col-1 s gr
+% Polyline
+n 4950 600 m 5250 600 l gs col-1 s gr
+% Polyline
+gs clippath
+5853 1170 m 5973 1200 l 5853 1230 l 6015 1230 l 6015 1170 l cp clip
+n 5250 1200 m 6000 1200 l gs col-1 s gr gr
+
+% arrowhead
+n 5853 1170 m 5973 1200 l 5853 1230 l col-1 s
+% Polyline
+gs clippath
+3153 2370 m 3273 2400 l 3153 2430 l 3315 2430 l 3315 2370 l cp clip
+n 1800 2400 m 3300 2400 l gs col-1 s gr gr
+
+% arrowhead
+n 3153 2370 m 3273 2400 l 3153 2430 l col-1 s
+% Polyline
+n 4950 2400 m 7800 2400 l gs col-1 s gr
+% Polyline
+n 7200 1200 m 7800 1200 l gs col-1 s gr
+% Polyline
+n 4950 3000 m 7800 3000 l gs col-1 s gr
+% Polyline
+n 4950 4200 m 7800 4200 l gs col-1 s gr
+% Polyline
+gs clippath
+3153 4770 m 3273 4800 l 3153 4830 l 3315 4830 l 3315 4770 l cp clip
+n 1800 4800 m 3300 4800 l gs col-1 s gr gr
+
+% arrowhead
+n 3153 4770 m 3273 4800 l 3153 4830 l col-1 s
+% Polyline
+n 6000 4800 m 7800 4800 l gs col-1 s gr
+% Polyline
+n 7800 1200 m 7800 4800 l gs col-1 s gr
+% Polyline
+gs clippath
+8253 2670 m 8373 2700 l 8253 2730 l 8415 2730 l 8415 2670 l cp clip
+n 7800 2700 m 8400 2700 l gs col-1 s gr gr
+
+% arrowhead
+n 8253 2670 m 8373 2700 l 8253 2730 l col-1 s
+% Polyline
+n 900 225 m 9450 225 l 9450 5175 l 900 5175 l cp gs col-1 s gr
+/Times-Roman ff 180.00 scf sf
+1200 1275 m
+gs 1 -1 sc (who) col-1 sh gr
+/Times-Roman ff 180.00 scf sf
+1200 2400 m
+gs 1 -1 sc (where) col-1 sh gr
+/Times-Roman ff 180.00 scf sf
+6150 1200 m
+gs 1 -1 sc (groupName) col-1 sh gr
+/Times-Roman ff 180.00 scf sf
+3600 2400 m
+gs 1 -1 sc (contexrName) col-1 sh gr
+/Times-Roman ff 180.00 scf sf
+1200 3600 m
+gs 1 -1 sc (who) col-1 sh gr
+/Times-Roman ff 180.00 scf sf
+1275 4800 m
+gs 1 -1 sc (why) col-1 sh gr
+/Times-Roman ff 180.00 scf sf
+8475 2700 m
+gs 1 -1 sc (viewName) col-1 sh gr
+/Times-Roman ff 180.00 scf sf
+3600 600 m
+gs 1 -1 sc (securityModel) col-1 sh gr
+/Times-Roman ff 180.00 scf sf
+3600 1800 m
+gs 1 -1 sc (securityName) col-1 sh gr
+/Times-Roman ff 180.00 scf sf
+3600 3000 m
+gs 1 -1 sc (securityModel) col-1 sh gr
+/Times-Roman ff 180.00 scf sf
+3600 4200 m
+gs 1 -1 sc (securityLevel) col-1 sh gr
+/Times-Roman ff 180.00 scf sf
+3600 4800 m
+gs 1 -1 sc (viewType \(read/write/notify\)) col-1 sh gr
+$F2psEnd
+rs
diff --git a/lib/snmp/doc/src/Makefile b/lib/snmp/doc/src/Makefile
new file mode 100644
index 0000000000..e1e3c7f41a
--- /dev/null
+++ b/lib/snmp/doc/src/Makefile
@@ -0,0 +1,349 @@
+#-*-makefile-*- ; force emacs to enter makefile-mode
+
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 1997-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%
+
+include $(ERL_TOP)/make/target.mk
+include $(ERL_TOP)/make/$(TARGET)/otp.mk
+
+# ----------------------------------------------------
+# Application version
+# ----------------------------------------------------
+include ../../vsn.mk
+VSN = $(SNMP_VSN)
+APPLICATION=snmp
+
+# ----------------------------------------------------
+# Include dependency
+# ----------------------------------------------------
+
+ifndef DOCSUPPORT
+include make.dep
+endif
+
+# ----------------------------------------------------
+# Release directory specification
+# ----------------------------------------------------
+RELSYSDIR = $(RELEASE_PATH)/lib/$(APPLICATION)-$(VSN)
+
+# ----------------------------------------------------
+# Target Specs
+# ----------------------------------------------------
+
+MIBSDIR = ../../mibs
+include files.mk
+
+# ----------------------------------------------------
+
+HTML_APP_FILES = $(XML_APPLICATION_FILES:%.xml=$(HTMLDIR)/%.html)
+XML_PART_FILE2 = $(XML_PART_FILES) notes_history.xml
+HTML_PART_FILES = \
+ ../html/notes_history.html \
+ $(XML_PART_FILES:%.xml=$(HTMLDIR)/%.html)
+
+HTML_FILES = \
+ $(HTML_APP_FILES) \
+ $(HTML_PART_FILES)
+
+XML_ERRS = $(XML_FILES:%.xml=%.latex.xmls_errs) \
+ $(XML_FILES:%.xml=%.html.xmls_errs)
+
+XML_OUTPUT = $(XML_FILES:%.xml=%.latex.xmls_output) \
+ $(XML_FILES:%.xml=%.html.xmls_output)
+
+INFO_FILE = ../../info
+
+HTML_REF3_FILES = $(XML_REF3_FILES:%.xml=$(HTMLDIR)/%.html)
+HTML_REF6_FILES = $(XML_REF6_FILES:%.xml=$(HTMLDIR)/%.html)
+HTML_CHAP_FILES = $(XML_CHAPTER_FILES:%.xml=$(HTMLDIR)/%.html)
+
+EXTRA_FILES = summary.html.src \
+ $(DEFAULT_HTML_FILES) \
+ $(HTML_REF3_FILES) \
+ $(HTML_REF6_FILES) \
+ $(HTML_CHAP_FILES)
+
+
+MAN7DIR = $(DOCDIR)/man7
+
+MAN3_FILES = $(XML_REF3_FILES:%.xml=$(MAN3DIR)/%.3)
+MAN6_FILES = $(XML_REF6_FILES:%_app.xml=$(MAN6DIR)/%.6)
+MAN7_FILES = $(MIB_FILES:$(MIBSDIR)/%.mib=$(MAN7DIR)/%.7)
+
+ifdef DOCSUPPORT
+
+HTML_REF_MAN_FILE = $(HTMLDIR)/index.html
+
+TOP_PDF_FILE = $(PDFDIR)/$(APPLICATION)-$(VSN).pdf
+
+else
+
+TEX_FILES_BOOK = \
+ $(BOOK_FILES:%.xml=%.tex)
+TEX_FILES_REF_MAN = \
+ $(XML_REF3_FILES:%.xml=%.tex) \
+ $(XML_REF6_FILES:%.xml=%.tex) \
+ $(XML_APPLICATION_FILES:%.xml=%.tex)
+TEX_PART_FILES = $(XML_PART_FILES:%.xml=%.tex)
+TEX_FILES_USERS_GUIDE = \
+ $(XML_CHAPTER_FILES:%.xml=%.tex)
+
+TOP_PDF_FILE = snmp-$(VSN).pdf
+TOP_PS_FILE = snmp-$(VSN).ps
+
+$(TOP_PDF_FILE): book.dvi ../../vsn.mk
+ @echo "building $(TOP_PDF_FILE)"
+ $(DVI2PS) $(DVIPS_FLAGS) -f $< | $(DISTILL) $(DISTILL_FLAGS) > $@
+
+$(TOP_PS_FILE): book.dvi ../../vsn.mk
+ @echo "building $(TOP_PS_FILE)"
+ $(DVI2PS) $(DVIPS_FLAGS) -f $< > $@
+
+TOP_HTML_FILES = $(INDEX_TARGET)
+
+endif
+
+INDEX_FILE = index.html
+INDEX_SRC = $(INDEX_FILE).src
+INDEX_TARGET = $(DOCDIR)/$(INDEX_FILE)
+
+GIF_TARGETS = $(GIF_FILES:%=$(HTMLDIR)/%)
+
+
+# ----------------------------------------------------
+# FLAGS
+# ----------------------------------------------------
+XML_FLAGS +=
+DVIPS_FLAGS +=
+
+# ----------------------------------------------------
+# Targets
+# ----------------------------------------------------
+$(HTMLDIR)/%.gif: %.gif # Copy them to ../html
+ $(INSTALL_DATA) $< $@
+
+ifdef DOCSUPPORT
+
+docs: pdf html man
+
+ldocs: local_docs $(INDEX_TARGET)
+
+$(TOP_PDF_FILE): $(XML_FILES)
+
+pdf: $(TOP_PDF_FILE)
+
+html: gifs $(HTML_REF_MAN_FILE)
+
+clean clean_docs: clean_html clean_man clean_pdf
+ rm -f errs core *~
+
+else
+
+ifeq ($(DOCTYPE),pdf)
+docs: pdf
+else
+ifeq ($(DOCTYPE),ps)
+docs: ps
+else
+docs: html gifs man
+endif
+endif
+
+pdf: $(TOP_PDF_FILE)
+
+ps: $(TOP_PS_FILE)
+
+html: $(HTML_FILES) $(TOP_HTML_FILES) gifs
+
+html2: gifs $(TOP_HTML_FILES) $(HTML_FILES) $(HTML_REF3_FILES) $(HTML_REF6_FILES) $(HTML_CHAP_FILES)
+
+clean: clean_tex clean_html clean_man clean_docs
+
+
+clean_tex:
+ @echo "cleaning tex:"
+ rm -f $(TEX_FILES_USERS_GUIDE)
+ rm -f $(TEX_FILES_REF_MAN)
+ rm -f $(TEX_PART_FILES)
+ rm -f $(TEX_FILES_BOOK)
+
+clean_docs:
+ @echo "cleaning docs:"
+ rm -f $(TOP_PDF_FILE)
+ rm -f $(TOP_PS_FILE)
+ rm -f core $(LATEX_CLEAN)
+
+
+$(HTML_PART_FILES): notes.xml
+
+endif
+
+$(INDEX_TARGET): $(INDEX_SRC) ../../vsn.mk # Create top make file
+ sed -e 's;%VSN%;$(VSN);' $< > $@ # inserting version number
+
+man: man3 man6 man7
+
+man3: $(MAN3_FILES)
+
+man6: $(MAN6_FILES)
+
+man7: $(MAN7_FILES)
+
+gifs: $(GIF_TARGETS)
+
+debug opt:
+
+clean_pdf:
+ @echo "cleaning pdf:"
+ rm -f $(TOP_PDF_FILE) $(TOP_PDF_FILE:%.pdf=%.fo)
+
+clean_man:
+ @echo "cleaning man:"
+ rm -f $(MAN3DIR)/*
+ rm -f $(MAN6DIR)/*
+ rm -f $(MAN7DIR)/*
+
+clean_html:
+ @echo "cleaning html:"
+ rm -rf $(HTMLDIR)/*
+
+$(MAN7DIR)/%.7: $(MIBSDIR)/%.mib
+ @echo "processing $*"
+ @echo ".TH $* 7 \"SNMP\" \"Erlang/OTP\" \"MIB\"" > $@
+ @echo ".nf" >> $@
+ @cat $< >> $@
+ @echo ".fi" >> $@
+ @echo "" >> $@
+
+
+# ----------------------------------------------------
+# Release Target
+# ----------------------------------------------------
+include $(ERL_TOP)/make/otp_release_targets.mk
+
+ifdef DOCSUPPORT
+
+release_docs_spec: docs
+ $(INSTALL_DIR) $(RELSYSDIR)/doc/pdf
+ $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELSYSDIR)/doc/pdf
+ $(INSTALL_DIR) $(RELSYSDIR)/doc/html
+ $(INSTALL_DATA) $(HTMLDIR)/* \
+ $(RELSYSDIR)/doc/html
+ $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR)
+ $(INSTALL_DIR) $(RELEASE_PATH)/man/man3
+ $(INSTALL_DATA) $(MAN3DIR)/* $(RELEASE_PATH)/man/man3
+ $(INSTALL_DIR) $(RELEASE_PATH)/man/man6
+ $(INSTALL_DATA) $(MAN3DIR)/* $(RELEASE_PATH)/man/man6
+ $(INSTALL_DIR) $(RELEASE_PATH)/man/man7
+ $(INSTALL_DATA) $(MAN3DIR)/* $(RELEASE_PATH)/man/man7
+
+else
+
+
+ifeq ($(DOCTYPE),pdf)
+release_docs_spec: pdf
+ $(INSTALL_DIR) $(RELEASE_PATH)/pdf
+ $(INSTALL_DATA) $(TOP_PDF_FILE) $(RELEASE_PATH)/pdf
+else
+ifeq ($(DOCTYPE),ps)
+release_docs_spec: ps
+ $(INSTALL_DIR) $(RELEASE_PATH)/ps
+ $(INSTALL_DATA) $(TOP_PS_FILE) $(RELEASE_PATH)/ps
+else
+release_docs_spec: docs
+ $(INSTALL_DIR) $(RELSYSDIR)/doc/html
+ $(INSTALL_DATA) $(GIF_FILES) $(EXTRA_FILES) $(HTML_FILES) \
+ $(RELSYSDIR)/doc/html
+ $(INSTALL_DATA) $(INFO_FILE) $(RELSYSDIR)
+ $(INSTALL_DIR) $(RELEASE_PATH)/man/man3
+ $(INSTALL_DATA) $(MAN3_FILES) $(RELEASE_PATH)/man/man3
+ $(INSTALL_DIR) $(RELEASE_PATH)/man/man6
+ $(INSTALL_DATA) $(MAN6_FILES) $(RELEASE_PATH)/man/man6
+ $(INSTALL_DIR) $(RELEASE_PATH)/man/man7
+ $(INSTALL_DATA) $(MAN7_FILES) $(RELEASE_PATH)/man/man7
+ $(INSTALL_DATA) $(TOP_HTML_FILES) \
+ $(RELSYSDIR)/doc
+endif
+endif
+
+endif
+
+release_spec:
+
+ifdef DOCSUPPORT
+info: info_xml info_man info_html
+else
+info: info_xml info_man info_html info_tex
+ @echo "DVI2PS = $(DVI2PS)"
+ @echo "DVIPS_FLAGS = $(DVIPS_FLAGS)"
+ @echo ""
+ @echo "DISTILL = $(DISTILL)"
+ @echo "DISTILL_FLAGS = $(DISTILL_FLAGS)"
+endif
+
+info_man:
+ @echo "man files:"
+ @echo "MAN3_FILES = $(MAN3_FILES)"
+ @echo "MAN6_FILES = $(MAN6_FILES)"
+ @echo "MAN7_FILES = $(MAN7_FILES)"
+ @echo ""
+ @echo "MIB_FILES = $(MIB_FILES)"
+
+info_xml:
+ @echo "xml files:"
+ @echo "XML_REF3_FILES = $(XML_REF3_FILES)"
+ @echo "XML_REF6_FILES = $(XML_REF6_FILES)"
+ @echo "XML_PART_FILES = $(XML_PART_FILES)"
+ @echo "XML_CHAPTER_FILES = $(XML_CHAPTER_FILES)"
+ @echo "XML_APPLICATION_FILES = $(XML_APPLICATION_FILES)"
+ @echo ""
+ @echo "BOOK_FILES = $(BOOK_FILES)"
+ @echo ""
+ @echo "XML_FILES = $(XML_FILES)"
+ @echo "XML_ERRS = $(XML_ERRS)"
+ @echo "XML_OUTPUT = $(XML_OUTPUT)"
+
+info_html:
+ @echo "html files:"
+ @echo "DOCDIR = $(DOCDIR)"
+ @echo "INDEX_FILE = $(INDEX_FILE)"
+ @echo "INDEX_SRC = $(INDEX_SRC)"
+ @echo "INDEX_TARGET = $(INDEX_TARGET)"
+ @echo ""
+ @echo "HTMLDIR = $(HTMLDIR)"
+ @echo "HTML_APP_FILES = $(HTML_APP_FILES)"
+ @echo "HTML_PART_FILES = $(HTML_PART_FILES)"
+ @echo "HTML_FILES = $(HTML_FILES)"
+ @echo ""
+ @echo "EXTRA_FILES = $(EXTRA_FILES)"
+ @echo ""
+ @echo "DEFAULT_HTML_FILES = $(DEFAULT_HTML_FILES)"
+ @echo ""
+ @echo "HTML_REF3_FILES = $(HTML_REF3_FILES)"
+ @echo "HTML_REF6_FILES = $(HTML_REF6_FILES)"
+ @echo "HTML_CHAP_FILES = $(HTML_CHAP_FILES)"
+
+info_tex:
+ @echo "tex files:"
+ @echo "TEX_FILES_USERS_GUIDE = $(TEX_FILES_USERS_GUIDE)"
+ @echo "TEX_FILES_REF_MAN = $(TEX_FILES_REF_MAN)"
+ @echo "TEX_PART_FILES = $(TEX_PART_FILES)"
+ @echo "TEX_FILES_BOOK = $(TEX_FILES_BOOK)"
+
+ifndef DOCSUPPORT
+include depend.mk
+endif
diff --git a/lib/snmp/doc/src/book.gif b/lib/snmp/doc/src/book.gif
new file mode 100644
index 0000000000..94b3868792
--- /dev/null
+++ b/lib/snmp/doc/src/book.gif
Binary files differ
diff --git a/lib/snmp/doc/src/book.xml b/lib/snmp/doc/src/book.xml
new file mode 100644
index 0000000000..2897d25d55
--- /dev/null
+++ b/lib/snmp/doc/src/book.xml
@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE book SYSTEM "book.dtd">
+
+<book xmlns:xi="http://www.w3.org/2001/XInclude">
+ <header titlestyle="normal">
+ <copyright>
+ <year>1997</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ 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.
+
+ </legalnotice>
+
+ <title>Simple Network Management Protocol (SNMP)</title>
+ <prepared></prepared>
+ <docno></docno>
+ <date></date>
+ <rev></rev>
+ <file>book.xml</file>
+ </header>
+ <insidecover>
+ </insidecover>
+ <pagetext>Simple Network Management Protocol (SNMP)</pagetext>
+ <preamble>
+ <contents level="2"></contents>
+ </preamble>
+ <parts lift="no">
+ <xi:include href="part.xml"/>
+ </parts>
+ <applications>
+ <xi:include href="ref_man.xml"/>
+ </applications>
+ <releasenotes>
+ <xi:include href="notes.xml"/>
+ </releasenotes>
+ <listofterms></listofterms>
+ <index></index>
+</book>
+
diff --git a/lib/snmp/doc/src/depend.mk b/lib/snmp/doc/src/depend.mk
new file mode 100644
index 0000000000..bf9833274d
--- /dev/null
+++ b/lib/snmp/doc/src/depend.mk
@@ -0,0 +1,82 @@
+#-*-makefile-*- ; force emacs to enter makefile-mode
+
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2004-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%
+
+$(HTMLDIR)/part_notes.html: \
+ part_notes_history.xml \
+ part_notes.xml \
+ notes_history.xml \
+ notes.xml
+
+$(HTMLDIR)/part.html: \
+ part.xml \
+ snmp_intro.xml \
+ snmp_agent_funct_descr.xml \
+ snmp_manager_funct_descr.xml \
+ snmp_mib_compiler.xml \
+ snmp_config.xml \
+ snmp_agent_config_files.xml \
+ snmp_manager_config_files.xml \
+ snmp_impl_example_agent.xml \
+ snmp_impl_example_manager.xml \
+ snmp_instr_functions.xml \
+ snmp_def_instr_functions.xml \
+ snmp_agent_netif.xml \
+ snmp_manager_netif.xml \
+ snmp_audit_trail_log.xml \
+ snmp_advanced_agent.xml \
+ snmp_app_a.xml \
+ snmp_app_b.xml
+
+$(HTMLDIR)/ref_man.html: \
+ ref_man.xml \
+ snmp_app.xml \
+ snmp.xml \
+ snmpc.xml \
+ snmpa.xml \
+ snmpa_conf.xml \
+ snmpa_discovery_handler.xml \
+ snmpa_error_report.xml \
+ snmpa_error.xml \
+ snmpa_error_io.xml \
+ snmpa_error_logger.xml \
+ snmpa_local_db.xml \
+ snmpa_mpd.xml \
+ snmpa_network_interface.xml \
+ snmpa_network_interface_filter.xml \
+ snmpa_notification_delivery_info_receiver.xml \
+ snmpa_notification_filter.xml \
+ snmpa_supervisor.xml \
+ snmp_community_mib.xml \
+ snmp_framework_mib.xml \
+ snmp_generic.xml \
+ snmp_index.xml \
+ snmp_notification_mib.xml \
+ snmp_pdus.xml \
+ snmp_standard_mib.xml \
+ snmp_target_mib.xml \
+ snmp_user_based_sm_mib.xml \
+ snmp_view_based_acm_mib.xml \
+ snmpm.xml \
+ snmpm_conf.xml \
+ snmpm_mpd.xml \
+ snmpm_network_interface.xml \
+ snmpm_network_interface_filter.xml \
+ snmpm_user.xml
+
+
diff --git a/lib/snmp/doc/src/fascicules.xml b/lib/snmp/doc/src/fascicules.xml
new file mode 100644
index 0000000000..0678195e07
--- /dev/null
+++ b/lib/snmp/doc/src/fascicules.xml
@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE fascicules SYSTEM "fascicules.dtd">
+
+<fascicules>
+ <fascicule file="part" href="part_frame.html" entry="no">
+ User's Guide
+ </fascicule>
+ <fascicule file="ref_man" href="ref_man_frame.html" entry="yes">
+ Reference Manual
+ </fascicule>
+ <fascicule file="part_notes" href="part_notes_frame.html" entry="no">
+ Release Notes
+ </fascicule>
+ <fascicule file="" href="../../../../doc/print.html" entry="no">
+ Off-Print
+ </fascicule>
+</fascicules>
+
diff --git a/lib/snmp/doc/src/files.mk b/lib/snmp/doc/src/files.mk
new file mode 100644
index 0000000000..293fb52ce0
--- /dev/null
+++ b/lib/snmp/doc/src/files.mk
@@ -0,0 +1,153 @@
+#-*-makefile-*- ; force emacs to enter makefile-mode
+
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2001-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%
+
+XML_APPLICATION_FILES = \
+ ref_man.xml
+
+XML_APP_REF3_FILES = \
+ snmp.xml
+
+XML_COMP_REF3_FILES = \
+ snmpc.xml
+
+XML_MISC_REF3_FILES = \
+ snmp_pdus.xml
+
+XML_AGENT_REF3_FILES = \
+ snmpa.xml \
+ snmpa_conf.xml \
+ snmpa_discovery_handler.xml \
+ snmpa_error_report.xml \
+ snmpa_error.xml \
+ snmpa_error_io.xml \
+ snmpa_error_logger.xml \
+ snmpa_local_db.xml \
+ snmpa_mpd.xml \
+ snmpa_network_interface.xml \
+ snmpa_network_interface_filter.xml \
+ snmpa_notification_delivery_info_receiver.xml \
+ snmpa_notification_filter.xml \
+ snmpa_supervisor.xml \
+ snmp_community_mib.xml \
+ snmp_framework_mib.xml \
+ snmp_generic.xml \
+ snmp_index.xml \
+ snmp_notification_mib.xml \
+ snmp_standard_mib.xml \
+ snmp_target_mib.xml \
+ snmp_user_based_sm_mib.xml \
+ snmp_view_based_acm_mib.xml
+
+XML_MANAGER_REF3_FILES = \
+ snmpm.xml \
+ snmpm_conf.xml \
+ snmpm_mpd.xml \
+ snmpm_network_interface.xml \
+ snmpm_network_interface_filter.xml \
+ snmpm_user.xml
+
+XML_REF3_FILES = \
+ $(XML_APP_REF3_FILES) \
+ $(XML_COMP_REF3_FILES) \
+ $(XML_MISC_REF3_FILES) \
+ $(XML_AGENT_REF3_FILES) \
+ $(XML_MANAGER_REF3_FILES)
+
+XML_REF6_FILES = snmp_app.xml
+
+XML_PART_FILES = \
+ part.xml \
+ part_notes.xml \
+ part_notes_history.xml
+
+XML_CHAPTER_FILES = \
+ snmp_intro.xml \
+ snmp_agent_funct_descr.xml \
+ snmp_manager_funct_descr.xml \
+ snmp_mib_compiler.xml \
+ snmp_config.xml \
+ snmp_agent_config_files.xml \
+ snmp_manager_config_files.xml \
+ snmp_impl_example_agent.xml \
+ snmp_impl_example_manager.xml \
+ snmp_instr_functions.xml \
+ snmp_def_instr_functions.xml \
+ snmp_agent_netif.xml \
+ snmp_manager_netif.xml \
+ snmp_audit_trail_log.xml \
+ snmp_advanced_agent.xml \
+ snmp_app_a.xml \
+ snmp_app_b.xml \
+ notes.xml
+
+BOOK_FILES = book.xml
+
+XML_FILES = $(BOOK_FILES) \
+ $(XML_CHAPTER_FILES) \
+ $(XML_PART_FILES) \
+ $(XML_REF6_FILES) \
+ $(XML_REF3_FILES) \
+ $(XML_APPLICATION_FILES)
+
+GIF_FILES = book.gif \
+ getnext1.gif \
+ getnext2.gif \
+ getnext3.gif \
+ getnext4.gif \
+ snmp_agent_netif_1.gif \
+ snmp_manager_netif_1.gif \
+ min_head.gif \
+ note.gif \
+ notes.gif \
+ ref_man.gif \
+ snmp-um-1-image-1.gif \
+ snmp-um-1-image-2.gif \
+ snmp-um-1-image-3.gif \
+ snmp.gif \
+ user_guide.gif \
+ warning.gif \
+ MIB_mechanism.gif
+
+PS_FILES = getnext1.ps \
+ getnext2.ps \
+ getnext3.ps \
+ getnext4.ps \
+ snmp_agent_netif.ps \
+ snmp-um-1-image-1.ps \
+ snmp-um-1-image-2.ps \
+ snmp-um-1-image-3.ps \
+ snmp-um-1-image-8.ps \
+ MIB_mechanism.ps
+
+
+MIB_FILES = \
+ $(MIBSDIR)/RFC1213-MIB.mib \
+ $(MIBSDIR)/STANDARD-MIB.mib \
+ $(MIBSDIR)/SNMPv2-TM.mib \
+ $(MIBSDIR)/SNMPv2-MIB.mib \
+ $(MIBSDIR)/SNMP-FRAMEWORK-MIB.mib \
+ $(MIBSDIR)/SNMP-MPD-MIB.mib \
+ $(MIBSDIR)/SNMP-TARGET-MIB.mib \
+ $(MIBSDIR)/SNMP-NOTIFICATION-MIB.mib \
+ $(MIBSDIR)/SNMP-COMMUNITY-MIB.mib \
+ $(MIBSDIR)/SNMP-USER-BASED-SM-MIB.mib \
+ $(MIBSDIR)/SNMP-VIEW-BASED-ACM-MIB.mib \
+ $(MIBSDIR)/SNMP-USM-AES-MIB.mib \
+ $(MIBSDIR)/INET-ADDRESS-MIB.mib \
+ $(MIBSDIR)/OTP-SNMPEA-MIB.mib
diff --git a/lib/snmp/doc/src/getnext1.gif b/lib/snmp/doc/src/getnext1.gif
new file mode 100644
index 0000000000..21725f4388
--- /dev/null
+++ b/lib/snmp/doc/src/getnext1.gif
Binary files differ
diff --git a/lib/snmp/doc/src/getnext1.ps b/lib/snmp/doc/src/getnext1.ps
new file mode 100644
index 0000000000..ba6bf18fec
--- /dev/null
+++ b/lib/snmp/doc/src/getnext1.ps
@@ -0,0 +1,2923 @@
+%!PS-Adobe-3.0 EPSF-3.0
+%%Creator: Adobe Illustrator(r) 6.0
+%%For: (Anna Fedoriw) (Ericsson Telecom)
+%%Title: (Contents.eps)
+%%CreationDate: (97-05-23) (14.03)
+%%BoundingBox: 112 623 440 757
+%%HiResBoundingBox: 112.5 623.5 439.5 756.8677
+%%DocumentProcessColors: Black
+%%DocumentFonts: Univers
+%%DocumentSuppliedResources: procset Adobe_level2_AI5 1.0 0
+%%+ procset Adobe_typography_AI5 1.0 0
+%%+ procset Adobe_Illustrator_AI6_vars Adobe_Illustrator_AI6
+%%+ procset Adobe_Illustrator_AI5 1.0 0
+%AI5_FileFormat 2.0
+%AI3_ColorUsage: Black&White
+%%AI6_ColorSeparationSet: 1 1 (AI6 Default Color Separation Set)
+%%+ Options: 1 16 0 1 0 1 1 1 0 1 1 1 1 18 0 0 0 0 0 0 0 0 -1 -1
+%%+ PPD: 1 21 0 0 60 45 2 2 1 0 0 1 0 0 0 0 0 0 0 0 0 0 ()
+%AI3_TemplateBox: 306 396 306 396
+%AI3_TileBox: 21 -12 588 802
+%AI3_DocumentPreview: Macintosh_ColorPic
+%AI5_ArtSize: 595.2756 841.8898
+%AI5_RulerUnits: 1
+%AI5_ArtFlags: 0 0 0 1 0 0 1 1 0
+%AI5_TargetResolution: 800
+%AI5_NumLayers: 1
+%AI5_OpenToView: 54 804 2 1146 827 58 1 1 3 40
+%AI5_OpenViewLayers: 7
+%%EndComments
+%%BeginProlog
+%%BeginResource: procset Adobe_level2_AI5 1.2 0
+%%Title: (Adobe Illustrator (R) Version 5.0 Level 2 Emulation)
+%%Version: 1.2
+%%CreationDate: (04/10/93) ()
+%%Copyright: ((C) 1987-1993 Adobe Systems Incorporated All Rights Reserved)
+userdict /Adobe_level2_AI5 23 dict dup begin
+ put
+ /packedarray where not
+ {
+ userdict begin
+ /packedarray
+ {
+ array astore readonly
+ } bind def
+ /setpacking /pop load def
+ /currentpacking false def
+ end
+ 0
+ } if
+ pop
+ userdict /defaultpacking currentpacking put true setpacking
+ /initialize
+ {
+ Adobe_level2_AI5 begin
+ } bind def
+ /terminate
+ {
+ currentdict Adobe_level2_AI5 eq
+ {
+ end
+ } if
+ } bind def
+ mark
+ /setcustomcolor where not
+ {
+ /findcmykcustomcolor
+ {
+ 5 packedarray
+ } bind def
+ /setcustomcolor
+ {
+ exch aload pop pop
+ 4
+ {
+ 4 index mul 4 1 roll
+ } repeat
+ 5 -1 roll pop
+ setcmykcolor
+ }
+ def
+ } if
+
+ /gt38? mark {version cvr cvx exec} stopped {cleartomark true} {38 gt exch pop} ifelse def
+ userdict /deviceDPI 72 0 matrix defaultmatrix dtransform dup mul exch dup mul add sqrt put
+ userdict /level2?
+ systemdict /languagelevel known dup
+ {
+ pop systemdict /languagelevel get 2 ge
+ } if
+ put
+/level2ScreenFreq
+{
+ begin
+ 60
+ HalftoneType 1 eq
+ {
+ pop Frequency
+ } if
+ HalftoneType 2 eq
+ {
+ pop GrayFrequency
+ } if
+ HalftoneType 5 eq
+ {
+ pop Default level2ScreenFreq
+ } if
+ end
+} bind def
+userdict /currentScreenFreq
+ level2? {currenthalftone level2ScreenFreq} {currentscreen pop pop} ifelse put
+level2? not
+ {
+ /setcmykcolor where not
+ {
+ /setcmykcolor
+ {
+ exch .11 mul add exch .59 mul add exch .3 mul add
+ 1 exch sub setgray
+ } def
+ } if
+ /currentcmykcolor where not
+ {
+ /currentcmykcolor
+ {
+ 0 0 0 1 currentgray sub
+ } def
+ } if
+ /setoverprint where not
+ {
+ /setoverprint /pop load def
+ } if
+ /selectfont where not
+ {
+ /selectfont
+ {
+ exch findfont exch
+ dup type /arraytype eq
+ {
+ makefont
+ }
+ {
+ scalefont
+ } ifelse
+ setfont
+ } bind def
+ } if
+ /cshow where not
+ {
+ /cshow
+ {
+ [
+ 0 0 5 -1 roll aload pop
+ ] cvx bind forall
+ } bind def
+ } if
+ } if
+ cleartomark
+ /anyColor?
+ {
+ add add add 0 ne
+ } bind def
+ /testColor
+ {
+ gsave
+ setcmykcolor currentcmykcolor
+ grestore
+ } bind def
+ /testCMYKColorThrough
+ {
+ testColor anyColor?
+ } bind def
+ userdict /composite?
+ level2?
+ {
+ gsave 1 1 1 1 setcmykcolor currentcmykcolor grestore
+ add add add 4 eq
+ }
+ {
+ 1 0 0 0 testCMYKColorThrough
+ 0 1 0 0 testCMYKColorThrough
+ 0 0 1 0 testCMYKColorThrough
+ 0 0 0 1 testCMYKColorThrough
+ and and and
+ } ifelse
+ put
+ composite? not
+ {
+ userdict begin
+ gsave
+ /cyan? 1 0 0 0 testCMYKColorThrough def
+ /magenta? 0 1 0 0 testCMYKColorThrough def
+ /yellow? 0 0 1 0 testCMYKColorThrough def
+ /black? 0 0 0 1 testCMYKColorThrough def
+ grestore
+ /isCMYKSep? cyan? magenta? yellow? black? or or or def
+ /customColor? isCMYKSep? not def
+ end
+ } if
+ end defaultpacking setpacking
+%%EndResource
+%%BeginResource: procset Adobe_typography_AI5 1.0 1
+%%Title: (Typography Operators)
+%%Version: 1.0
+%%CreationDate:(03/26/93) ()
+%%Copyright: ((C) 1987-1993 Adobe Systems Incorporated All Rights Reserved)
+currentpacking true setpacking
+userdict /Adobe_typography_AI5 54 dict dup begin
+put
+/initialize
+{
+ begin
+ begin
+ Adobe_typography_AI5 begin
+ Adobe_typography_AI5
+ {
+ dup xcheck
+ {
+ bind
+ } if
+ pop pop
+ } forall
+ end
+ end
+ end
+ Adobe_typography_AI5 begin
+} def
+/terminate
+{
+ currentdict Adobe_typography_AI5 eq
+ {
+ end
+ } if
+} def
+/modifyEncoding
+{
+ /_tempEncode exch ddef
+ /_pntr 0 ddef
+ {
+ counttomark -1 roll
+ dup type dup /marktype eq
+ {
+ pop pop exit
+ }
+ {
+ /nametype eq
+ {
+ _tempEncode /_pntr dup load dup 3 1 roll 1 add ddef 3 -1 roll
+ put
+ }
+ {
+ /_pntr exch ddef
+ } ifelse
+ } ifelse
+ } loop
+ _tempEncode
+} def
+/TE
+{
+ StandardEncoding 256 array copy modifyEncoding
+ /_nativeEncoding exch def
+} def
+%
+/TZ
+{
+ dup type /arraytype eq
+ {
+ /_wv exch def
+ }
+ {
+ /_wv 0 def
+ } ifelse
+ /_useNativeEncoding exch def
+ pop pop
+ findfont _wv type /arraytype eq
+ {
+ _wv makeblendedfont
+ } if
+ dup length 2 add dict
+ begin
+ mark exch
+ {
+ 1 index /FID ne
+ {
+ def
+ } if
+ cleartomark mark
+ } forall
+ pop
+ /FontName exch def
+ counttomark 0 eq
+ {
+ 1 _useNativeEncoding eq
+ {
+ /Encoding _nativeEncoding def
+ } if
+ cleartomark
+ }
+ {
+ /Encoding load 256 array copy
+ modifyEncoding /Encoding exch def
+ } ifelse
+ FontName currentdict
+ end
+ definefont pop
+} def
+/tr
+{
+ _ax _ay 3 2 roll
+} def
+/trj
+{
+ _cx _cy _sp _ax _ay 6 5 roll
+} def
+/a0
+{
+ /Tx
+ {
+ dup
+ currentpoint 3 2 roll
+ tr _psf
+ newpath moveto
+ tr _ctm _pss
+ } ddef
+ /Tj
+ {
+ dup
+ currentpoint 3 2 roll
+ trj _pjsf
+ newpath moveto
+ trj _ctm _pjss
+ } ddef
+} def
+/a1
+{
+ /Tx
+ {
+ dup currentpoint 4 2 roll gsave
+ dup currentpoint 3 2 roll
+ tr _psf
+ newpath moveto
+ tr _ctm _pss
+ grestore 3 1 roll moveto tr sp
+ } ddef
+ /Tj
+ {
+ dup currentpoint 4 2 roll gsave
+ dup currentpoint 3 2 roll
+ trj _pjsf
+ newpath moveto
+ trj _ctm _pjss
+ grestore 3 1 roll moveto tr jsp
+ } ddef
+} def
+/e0
+{
+ /Tx
+ {
+ tr _psf
+ } ddef
+ /Tj
+ {
+ trj _pjsf
+ } ddef
+} def
+/e1
+{
+ /Tx
+ {
+ dup currentpoint 4 2 roll gsave
+ tr _psf
+ grestore 3 1 roll moveto tr sp
+ } ddef
+ /Tj
+ {
+ dup currentpoint 4 2 roll gsave
+ trj _pjsf
+ grestore 3 1 roll moveto tr jsp
+ } ddef
+} def
+/i0
+{
+ /Tx
+ {
+ tr sp
+ } ddef
+ /Tj
+ {
+ trj jsp
+ } ddef
+} def
+/i1
+{
+ W N
+} def
+/o0
+{
+ /Tx
+ {
+ tr sw rmoveto
+ } ddef
+ /Tj
+ {
+ trj swj rmoveto
+ } ddef
+} def
+/r0
+{
+ /Tx
+ {
+ tr _ctm _pss
+ } ddef
+ /Tj
+ {
+ trj _ctm _pjss
+ } ddef
+} def
+/r1
+{
+ /Tx
+ {
+ dup currentpoint 4 2 roll currentpoint gsave newpath moveto
+ tr _ctm _pss
+ grestore 3 1 roll moveto tr sp
+ } ddef
+ /Tj
+ {
+ dup currentpoint 4 2 roll currentpoint gsave newpath moveto
+ trj _ctm _pjss
+ grestore 3 1 roll moveto tr jsp
+ } ddef
+} def
+/To
+{
+ pop _ctm currentmatrix pop
+} def
+/TO
+{
+ iTe _ctm setmatrix newpath
+} def
+/Tp
+{
+ pop _tm astore pop _ctm setmatrix
+ _tDict begin
+ /W
+ {
+ } def
+ /h
+ {
+ } def
+} def
+/TP
+{
+ end
+ iTm 0 0 moveto
+} def
+/Tr
+{
+ _render 3 le
+ {
+ currentpoint newpath moveto
+ } if
+ dup 8 eq
+ {
+ pop 0
+ }
+ {
+ dup 9 eq
+ {
+ pop 1
+ } if
+ } ifelse
+ dup /_render exch ddef
+ _renderStart exch get load exec
+} def
+/iTm
+{
+ _ctm setmatrix _tm concat 0 _rise translate _hs 1 scale
+} def
+/Tm
+{
+ _tm astore pop iTm 0 0 moveto
+} def
+/Td
+{
+ _mtx translate _tm _tm concatmatrix pop iTm 0 0 moveto
+} def
+/iTe
+{
+ _render -1 eq
+ {
+ }
+ {
+ _renderEnd _render get dup null ne
+ {
+ load exec
+ }
+ {
+ pop
+ } ifelse
+ } ifelse
+ /_render -1 ddef
+} def
+/Ta
+{
+ pop
+} def
+/Tf
+{
+ dup 1000 div /_fScl exch ddef
+%
+ selectfont
+} def
+/Tl
+{
+ pop
+ 0 exch _leading astore pop
+} def
+/Tt
+{
+ pop
+} def
+/TW
+{
+ 3 npop
+} def
+/Tw
+{
+ /_cx exch ddef
+} def
+/TC
+{
+ 3 npop
+} def
+/Tc
+{
+ /_ax exch ddef
+} def
+/Ts
+{
+ /_rise exch ddef
+ currentpoint
+ iTm
+ moveto
+} def
+/Ti
+{
+ 3 npop
+} def
+/Tz
+{
+ 100 div /_hs exch ddef
+ iTm
+} def
+/TA
+{
+ pop
+} def
+/Tq
+{
+ pop
+} def
+/Th
+{
+ pop pop pop pop pop
+} def
+/TX
+{
+ pop
+} def
+/Tk
+{
+ exch pop _fScl mul neg 0 rmoveto
+} def
+/TK
+{
+ 2 npop
+} def
+/T*
+{
+ _leading aload pop neg Td
+} def
+/T*-
+{
+ _leading aload pop Td
+} def
+/T-
+{
+ _ax neg 0 rmoveto
+ _hyphen Tx
+} def
+/T+
+{
+} def
+/TR
+{
+ _ctm currentmatrix pop
+ _tm astore pop
+ iTm 0 0 moveto
+} def
+/TS
+{
+ currentfont 3 1 roll
+ /_Symbol_ _fScl 1000 mul selectfont
+
+ 0 eq
+ {
+ Tx
+ }
+ {
+ Tj
+ } ifelse
+ setfont
+} def
+/Xb
+{
+ pop pop
+} def
+/Tb /Xb load def
+/Xe
+{
+ pop pop pop pop
+} def
+/Te /Xe load def
+/XB
+{
+} def
+/TB /XB load def
+currentdict readonly pop
+end
+setpacking
+%%EndResource
+%%BeginProcSet: Adobe_ColorImage_AI6 1.0 0
+userdict /Adobe_ColorImage_AI6 known not
+{
+ userdict /Adobe_ColorImage_AI6 17 dict put
+} if
+userdict /Adobe_ColorImage_AI6 get begin
+
+ /initialize
+ {
+ Adobe_ColorImage_AI6 begin
+ Adobe_ColorImage_AI6
+ {
+ dup type /arraytype eq
+ {
+ dup xcheck
+ {
+ bind
+ } if
+ } if
+ pop pop
+ } forall
+ } def
+ /terminate { end } def
+
+ currentdict /Adobe_ColorImage_AI6_Vars known not
+ {
+ /Adobe_ColorImage_AI6_Vars 14 dict def
+ } if
+
+ Adobe_ColorImage_AI6_Vars begin
+ /channelcount 0 def
+ /sourcecount 0 def
+ /sourcearray 4 array def
+ /plateindex -1 def
+ /XIMask 0 def
+ /XIBinary 0 def
+ /XIChannelCount 0 def
+ /XIBitsPerPixel 0 def
+ /XIImageHeight 0 def
+ /XIImageWidth 0 def
+ /XIImageMatrix null def
+ /XIBuffer null def
+ /XIDataProc null def
+ end
+
+ /WalkRGBString null def
+ /WalkCMYKString null def
+
+ /StuffRGBIntoGrayString null def
+ /RGBToGrayImageProc null def
+ /StuffCMYKIntoGrayString null def
+ /CMYKToGrayImageProc null def
+ /ColorImageCompositeEmulator null def
+
+ /SeparateCMYKImageProc null def
+
+ /FourEqual null def
+ /TestPlateIndex null def
+
+ currentdict /_colorimage known not
+ {
+ /colorimage where
+ {
+ /colorimage get /_colorimage exch def
+ }
+ {
+ /_colorimage null def
+ } ifelse
+ } if
+
+ /_currenttransfer systemdict /currenttransfer get def
+
+ /colorimage null def
+ /XI null def
+
+
+ /WalkRGBString
+ {
+ 0 3 index
+
+ dup length 1 sub 0 3 3 -1 roll
+ {
+ 3 getinterval { } forall
+
+ 5 index exec
+
+ 3 index
+ } for
+
+ 5 { pop } repeat
+
+ } def
+
+
+ /WalkCMYKString
+ {
+ 0 3 index
+
+ dup length 1 sub 0 4 3 -1 roll
+ {
+ 4 getinterval { } forall
+
+ 6 index exec
+
+ 3 index
+
+ } for
+
+ 5 { pop } repeat
+
+ } def
+
+
+ /StuffRGBIntoGrayString
+ {
+ .11 mul exch
+
+ .59 mul add exch
+
+ .3 mul add
+
+ cvi 3 copy put
+
+ pop 1 add
+ } def
+
+
+ /RGBToGrayImageProc
+ {
+ Adobe_ColorImage_AI6_Vars begin
+ sourcearray 0 get exec
+ dup length 3 idiv string
+ dup 3 1 roll
+
+ /StuffRGBIntoGrayString load exch
+ WalkRGBString
+ end
+ } def
+
+
+ /StuffCMYKIntoGrayString
+ {
+ exch .11 mul add
+
+ exch .59 mul add
+
+ exch .3 mul add
+
+ dup 255 gt { pop 255 } if
+
+ 255 exch sub cvi 3 copy put
+
+ pop 1 add
+ } def
+
+
+ /CMYKToGrayImageProc
+ {
+ Adobe_ColorImage_AI6_Vars begin
+ sourcearray 0 get exec
+ dup length 4 idiv string
+ dup 3 1 roll
+
+ /StuffCMYKIntoGrayString load exch
+ WalkCMYKString
+ end
+ } def
+
+
+ /ColorImageCompositeEmulator
+ {
+ pop true eq
+ {
+ Adobe_ColorImage_AI6_Vars /sourcecount get 5 add { pop } repeat
+ }
+ {
+ Adobe_ColorImage_AI6_Vars /channelcount get 1 ne
+ {
+ Adobe_ColorImage_AI6_Vars begin
+ sourcearray 0 3 -1 roll put
+
+ channelcount 3 eq
+ {
+ /RGBToGrayImageProc
+ }
+ {
+ /CMYKToGrayImageProc
+ } ifelse
+ load
+ end
+ } if
+ image
+ } ifelse
+ } def
+
+
+ /SeparateCMYKImageProc
+ {
+ Adobe_ColorImage_AI6_Vars begin
+
+ sourcecount 0 ne
+ {
+ sourcearray plateindex get exec
+ }
+ {
+ sourcearray 0 get exec
+
+ dup length 4 idiv string
+
+ 0 2 index
+
+ plateindex 4 2 index length 1 sub
+ {
+ get 255 exch sub
+
+ 3 copy put pop 1 add
+
+ 2 index
+ } for
+
+ pop pop exch pop
+ } ifelse
+ end
+ } def
+
+
+ /FourEqual
+ {
+ 4 index ne
+ {
+ pop pop pop false
+ }
+ {
+ 4 index ne
+ {
+ pop pop false
+ }
+ {
+ 4 index ne
+ {
+ pop false
+ }
+ {
+ 4 index eq
+ } ifelse
+ } ifelse
+ } ifelse
+ } def
+
+
+ /TestPlateIndex
+ {
+ Adobe_ColorImage_AI6_Vars begin
+ /plateindex -1 def
+
+ /setcmykcolor where
+ {
+ pop
+ gsave
+ 1 0 0 0 setcmykcolor systemdict /currentgray get exec 1 exch sub
+ 0 1 0 0 setcmykcolor systemdict /currentgray get exec 1 exch sub
+ 0 0 1 0 setcmykcolor systemdict /currentgray get exec 1 exch sub
+ 0 0 0 1 setcmykcolor systemdict /currentgray get exec 1 exch sub
+ grestore
+
+ 1 0 0 0 FourEqual
+ {
+ /plateindex 0 def
+ }
+ {
+ 0 1 0 0 FourEqual
+ {
+ /plateindex 1 def
+ }
+ {
+ 0 0 1 0 FourEqual
+ {
+ /plateindex 2 def
+ }
+ {
+ 0 0 0 1 FourEqual
+ {
+ /plateindex 3 def
+ }
+ {
+ 0 0 0 0 FourEqual
+ {
+ /plateindex 5 def
+ } if
+ } ifelse
+ } ifelse
+ } ifelse
+ } ifelse
+ pop pop pop pop
+ } if
+ plateindex
+ end
+ } def
+
+
+ /colorimage
+ {
+ Adobe_ColorImage_AI6_Vars begin
+ /channelcount 1 index def
+ /sourcecount 2 index 1 eq { channelcount 1 sub } { 0 } ifelse def
+
+ 4 sourcecount add index dup
+ 8 eq exch 1 eq or not
+ end
+
+ {
+ /_colorimage load null ne
+ {
+ _colorimage
+ }
+ {
+ Adobe_ColorImage_AI6_Vars /sourcecount get
+ 7 add { pop } repeat
+ } ifelse
+ }
+ {
+ dup 3 eq
+ TestPlateIndex
+ dup -1 eq exch 5 eq or or
+ {
+ /_colorimage load null eq
+ {
+ ColorImageCompositeEmulator
+ }
+ {
+ dup 1 eq
+ {
+ pop pop image
+ }
+ {
+ Adobe_ColorImage_AI6_Vars /plateindex get 5 eq
+ {
+ gsave
+
+ 0 _currenttransfer exec
+ 1 _currenttransfer exec
+ eq
+ { 0 _currenttransfer exec 0.5 lt }
+ { 0 _currenttransfer exec 1 _currenttransfer exec gt } ifelse
+
+ { { pop 0 } } { { pop 1 } } ifelse
+ systemdict /settransfer get exec
+ } if
+
+ _colorimage
+
+ Adobe_ColorImage_AI6_Vars /plateindex get 5 eq
+ {
+ grestore
+ } if
+ } ifelse
+ } ifelse
+ }
+ {
+ dup 1 eq
+ {
+ pop pop
+ image
+ }
+ {
+ pop pop
+
+ Adobe_ColorImage_AI6_Vars begin
+ sourcecount -1 0
+ {
+ exch sourcearray 3 1 roll put
+ } for
+
+ /SeparateCMYKImageProc load
+ end
+
+ systemdict /image get exec
+ } ifelse
+ } ifelse
+ } ifelse
+ } def
+
+ /XI
+ {
+ Adobe_ColorImage_AI6_Vars begin
+ gsave
+ /XIMask exch 0 ne def
+ /XIBinary exch 0 ne def
+ pop
+ pop
+ /XIChannelCount exch def
+ /XIBitsPerPixel exch def
+ /XIImageHeight exch def
+ /XIImageWidth exch def
+ pop pop pop pop
+ /XIImageMatrix exch def
+
+ XIBitsPerPixel 1 eq
+ {
+ XIImageWidth 8 div ceiling cvi
+ }
+ {
+ XIImageWidth XIChannelCount mul
+ } ifelse
+ /XIBuffer exch string def
+
+ XIBinary
+ {
+ /XIDataProc { currentfile XIBuffer readstring pop } def
+ currentfile 128 string readline pop pop
+ }
+ {
+ /XIDataProc { currentfile XIBuffer readhexstring pop } def
+ } ifelse
+
+ 0 0 moveto
+ XIImageMatrix concat
+ XIImageWidth XIImageHeight scale
+
+ XIMask
+ {
+ XIImageWidth XIImageHeight
+ false
+ [ XIImageWidth 0 0 XIImageHeight neg 0 0 ]
+ /XIDataProc load
+
+ /_lp /null ddef
+ _fc
+ /_lp /imagemask ddef
+
+ imagemask
+ }
+ {
+ XIImageWidth XIImageHeight
+ XIBitsPerPixel
+ [ XIImageWidth 0 0 XIImageHeight neg 0 0 ]
+ /XIDataProc load
+
+ XIChannelCount 1 eq
+ {
+
+ gsave
+ 0 setgray
+
+ image
+
+ grestore
+ }
+ {
+ false
+ XIChannelCount
+ colorimage
+ } ifelse
+ } ifelse
+ grestore
+ end
+ } def
+
+end
+%%EndProcSet
+%%BeginResource: procset Adobe_Illustrator_AI5 1.1 0
+%%Title: (Adobe Illustrator (R) Version 5.0 Full Prolog)
+%%Version: 1.1
+%%CreationDate: (3/7/1994) ()
+%%Copyright: ((C) 1987-1994 Adobe Systems Incorporated All Rights Reserved)
+currentpacking true setpacking
+userdict /Adobe_Illustrator_AI5_vars 81 dict dup begin
+put
+/_eo false def
+/_lp /none def
+/_pf
+{
+} def
+/_ps
+{
+} def
+/_psf
+{
+} def
+/_pss
+{
+} def
+/_pjsf
+{
+} def
+/_pjss
+{
+} def
+/_pola 0 def
+/_doClip 0 def
+/cf currentflat def
+/_tm matrix def
+/_renderStart
+[
+/e0 /r0 /a0 /o0 /e1 /r1 /a1 /i0
+] def
+/_renderEnd
+[
+null null null null /i1 /i1 /i1 /i1
+] def
+/_render -1 def
+/_rise 0 def
+/_ax 0 def
+/_ay 0 def
+/_cx 0 def
+/_cy 0 def
+/_leading
+[
+0 0
+] def
+/_ctm matrix def
+/_mtx matrix def
+/_sp 16#020 def
+/_hyphen (-) def
+/_fScl 0 def
+/_cnt 0 def
+/_hs 1 def
+/_nativeEncoding 0 def
+/_useNativeEncoding 0 def
+/_tempEncode 0 def
+/_pntr 0 def
+/_tDict 2 dict def
+/_wv 0 def
+/Tx
+{
+} def
+/Tj
+{
+} def
+/CRender
+{
+} def
+/_AI3_savepage
+{
+} def
+/_gf null def
+/_cf 4 array def
+/_if null def
+/_of false def
+/_fc
+{
+} def
+/_gs null def
+/_cs 4 array def
+/_is null def
+/_os false def
+/_sc
+{
+} def
+/_pd 1 dict def
+/_ed 15 dict def
+/_pm matrix def
+/_fm null def
+/_fd null def
+/_fdd null def
+/_sm null def
+/_sd null def
+/_sdd null def
+/_i null def
+/discardSave null def
+/buffer 256 string def
+/beginString null def
+/endString null def
+/endStringLength null def
+/layerCnt 1 def
+/layerCount 1 def
+/perCent (%) 0 get def
+/perCentSeen? false def
+/newBuff null def
+/newBuffButFirst null def
+/newBuffLast null def
+/clipForward? false def
+end
+userdict /Adobe_Illustrator_AI5 known not {
+ userdict /Adobe_Illustrator_AI5 91 dict put
+} if
+userdict /Adobe_Illustrator_AI5 get begin
+/initialize
+{
+ Adobe_Illustrator_AI5 dup begin
+ Adobe_Illustrator_AI5_vars begin
+ discardDict
+ {
+ bind pop pop
+ } forall
+ dup /nc get begin
+ {
+ dup xcheck 1 index type /operatortype ne and
+ {
+ bind
+ } if
+ pop pop
+ } forall
+ end
+ newpath
+} def
+/terminate
+{
+ end
+ end
+} def
+/_
+null def
+/ddef
+{
+ Adobe_Illustrator_AI5_vars 3 1 roll put
+} def
+/xput
+{
+ dup load dup length exch maxlength eq
+ {
+ dup dup load dup
+ length 2 mul dict copy def
+ } if
+ load begin
+ def
+ end
+} def
+/npop
+{
+ {
+ pop
+ } repeat
+} def
+/sw
+{
+ dup length exch stringwidth
+ exch 5 -1 roll 3 index mul add
+ 4 1 roll 3 1 roll mul add
+} def
+/swj
+{
+ dup 4 1 roll
+ dup length exch stringwidth
+ exch 5 -1 roll 3 index mul add
+ 4 1 roll 3 1 roll mul add
+ 6 2 roll /_cnt 0 ddef
+ {
+ 1 index eq
+ {
+ /_cnt _cnt 1 add ddef
+ } if
+ } forall
+ pop
+ exch _cnt mul exch _cnt mul 2 index add 4 1 roll 2 index add 4 1 roll pop pop
+} def
+/ss
+{
+ 4 1 roll
+ {
+ 2 npop
+ (0) exch 2 copy 0 exch put pop
+ gsave
+ false charpath currentpoint
+ 4 index setmatrix
+ stroke
+ grestore
+ moveto
+ 2 copy rmoveto
+ } exch cshow
+ 3 npop
+} def
+/jss
+{
+ 4 1 roll
+ {
+ 2 npop
+ (0) exch 2 copy 0 exch put
+ gsave
+ _sp eq
+ {
+ exch 6 index 6 index 6 index 5 -1 roll widthshow
+ currentpoint
+ }
+ {
+ false charpath currentpoint
+ 4 index setmatrix stroke
+ } ifelse
+ grestore
+ moveto
+ 2 copy rmoveto
+ } exch cshow
+ 6 npop
+} def
+/sp
+{
+ {
+ 2 npop (0) exch
+ 2 copy 0 exch put pop
+ false charpath
+ 2 copy rmoveto
+ } exch cshow
+ 2 npop
+} def
+/jsp
+{
+ {
+ 2 npop
+ (0) exch 2 copy 0 exch put
+ _sp eq
+ {
+ exch 5 index 5 index 5 index 5 -1 roll widthshow
+ }
+ {
+ false charpath
+ } ifelse
+ 2 copy rmoveto
+ } exch cshow
+ 5 npop
+} def
+/pl
+{
+ transform
+ 0.25 sub round 0.25 add exch
+ 0.25 sub round 0.25 add exch
+ itransform
+} def
+/setstrokeadjust where
+{
+ pop true setstrokeadjust
+ /c
+ {
+ curveto
+ } def
+ /C
+ /c load def
+ /v
+ {
+ currentpoint 6 2 roll curveto
+ } def
+ /V
+ /v load def
+ /y
+ {
+ 2 copy curveto
+ } def
+ /Y
+ /y load def
+ /l
+ {
+ lineto
+ } def
+ /L
+ /l load def
+ /m
+ {
+ moveto
+ } def
+}
+{
+ /c
+ {
+ pl curveto
+ } def
+ /C
+ /c load def
+ /v
+ {
+ currentpoint 6 2 roll pl curveto
+ } def
+ /V
+ /v load def
+ /y
+ {
+ pl 2 copy curveto
+ } def
+ /Y
+ /y load def
+ /l
+ {
+ pl lineto
+ } def
+ /L
+ /l load def
+ /m
+ {
+ pl moveto
+ } def
+} ifelse
+/d
+{
+ setdash
+} def
+/cf
+{
+} def
+/i
+{
+ dup 0 eq
+ {
+ pop cf
+ } if
+ setflat
+} def
+/j
+{
+ setlinejoin
+} def
+/J
+{
+ setlinecap
+} def
+/M
+{
+ setmiterlimit
+} def
+/w
+{
+ setlinewidth
+} def
+/XR
+{
+ 0 ne
+ /_eo exch ddef
+} def
+/H
+{
+} def
+/h
+{
+ closepath
+} def
+/N
+{
+ _pola 0 eq
+ {
+ _doClip 1 eq
+ {
+ _eo {eoclip} {clip} ifelse /_doClip 0 ddef
+ } if
+ newpath
+ }
+ {
+ /CRender
+ {
+ N
+ } ddef
+ } ifelse
+} def
+/n
+{
+ N
+} def
+/F
+{
+ _pola 0 eq
+ {
+ _doClip 1 eq
+ {
+ gsave _pf grestore _eo {eoclip} {clip} ifelse newpath /_lp /none ddef _fc
+ /_doClip 0 ddef
+ }
+ {
+ _pf
+ } ifelse
+ }
+ {
+ /CRender
+ {
+ F
+ } ddef
+ } ifelse
+} def
+/f
+{
+ closepath
+ F
+} def
+/S
+{
+ _pola 0 eq
+ {
+ _doClip 1 eq
+ {
+ gsave _ps grestore _eo {eoclip} {clip} ifelse newpath /_lp /none ddef _sc
+ /_doClip 0 ddef
+ }
+ {
+ _ps
+ } ifelse
+ }
+ {
+ /CRender
+ {
+ S
+ } ddef
+ } ifelse
+} def
+/s
+{
+ closepath
+ S
+} def
+/B
+{
+ _pola 0 eq
+ {
+ _doClip 1 eq
+ gsave F grestore
+ {
+ gsave S grestore _eo {eoclip} {clip} ifelse newpath /_lp /none ddef _sc
+ /_doClip 0 ddef
+ }
+ {
+ S
+ } ifelse
+ }
+ {
+ /CRender
+ {
+ B
+ } ddef
+ } ifelse
+} def
+/b
+{
+ closepath
+ B
+} def
+/W
+{
+ /_doClip 1 ddef
+} def
+/*
+{
+ count 0 ne
+ {
+ dup type /stringtype eq
+ {
+ pop
+ } if
+ } if
+ newpath
+} def
+/u
+{
+} def
+/U
+{
+} def
+/q
+{
+ _pola 0 eq
+ {
+ gsave
+ } if
+} def
+/Q
+{
+ _pola 0 eq
+ {
+ grestore
+ } if
+} def
+/*u
+{
+ _pola 1 add /_pola exch ddef
+} def
+/*U
+{
+ _pola 1 sub /_pola exch ddef
+ _pola 0 eq
+ {
+ CRender
+ } if
+} def
+/D
+{
+ pop
+} def
+/*w
+{
+} def
+/*W
+{
+} def
+/`
+{
+ /_i save ddef
+ clipForward?
+ {
+ nulldevice
+ } if
+ 6 1 roll 4 npop
+ concat pop
+ userdict begin
+ /showpage
+ {
+ } def
+ 0 setgray
+ 0 setlinecap
+ 1 setlinewidth
+ 0 setlinejoin
+ 10 setmiterlimit
+ [] 0 setdash
+ /setstrokeadjust where {pop false setstrokeadjust} if
+ newpath
+ 0 setgray
+ false setoverprint
+} def
+/~
+{
+ end
+ _i restore
+} def
+/O
+{
+ 0 ne
+ /_of exch ddef
+ /_lp /none ddef
+} def
+/R
+{
+ 0 ne
+ /_os exch ddef
+ /_lp /none ddef
+} def
+/g
+{
+ /_gf exch ddef
+ /_fc
+ {
+ _lp /fill ne
+ {
+ _of setoverprint
+ _gf setgray
+ /_lp /fill ddef
+ } if
+ } ddef
+ /_pf
+ {
+ _fc
+ _eo {eofill} {fill} ifelse
+ } ddef
+ /_psf
+ {
+ _fc
+ ashow
+ } ddef
+ /_pjsf
+ {
+ _fc
+ awidthshow
+ } ddef
+ /_lp /none ddef
+} def
+/G
+{
+ /_gs exch ddef
+ /_sc
+ {
+ _lp /stroke ne
+ {
+ _os setoverprint
+ _gs setgray
+ /_lp /stroke ddef
+ } if
+ } ddef
+ /_ps
+ {
+ _sc
+ stroke
+ } ddef
+ /_pss
+ {
+ _sc
+ ss
+ } ddef
+ /_pjss
+ {
+ _sc
+ jss
+ } ddef
+ /_lp /none ddef
+} def
+/k
+{
+ _cf astore pop
+ /_fc
+ {
+ _lp /fill ne
+ {
+ _of setoverprint
+ _cf aload pop setcmykcolor
+ /_lp /fill ddef
+ } if
+ } ddef
+ /_pf
+ {
+ _fc
+ _eo {eofill} {fill} ifelse
+ } ddef
+ /_psf
+ {
+ _fc
+ ashow
+ } ddef
+ /_pjsf
+ {
+ _fc
+ awidthshow
+ } ddef
+ /_lp /none ddef
+} def
+/K
+{
+ _cs astore pop
+ /_sc
+ {
+ _lp /stroke ne
+ {
+ _os setoverprint
+ _cs aload pop setcmykcolor
+ /_lp /stroke ddef
+ } if
+ } ddef
+ /_ps
+ {
+ _sc
+ stroke
+ } ddef
+ /_pss
+ {
+ _sc
+ ss
+ } ddef
+ /_pjss
+ {
+ _sc
+ jss
+ } ddef
+ /_lp /none ddef
+} def
+/x
+{
+ /_gf exch ddef
+ findcmykcustomcolor
+ /_if exch ddef
+ /_fc
+ {
+ _lp /fill ne
+ {
+ _of setoverprint
+ _if _gf 1 exch sub setcustomcolor
+ /_lp /fill ddef
+ } if
+ } ddef
+ /_pf
+ {
+ _fc
+ _eo {eofill} {fill} ifelse
+ } ddef
+ /_psf
+ {
+ _fc
+ ashow
+ } ddef
+ /_pjsf
+ {
+ _fc
+ awidthshow
+ } ddef
+ /_lp /none ddef
+} def
+/X
+{
+ /_gs exch ddef
+ findcmykcustomcolor
+ /_is exch ddef
+ /_sc
+ {
+ _lp /stroke ne
+ {
+ _os setoverprint
+ _is _gs 1 exch sub setcustomcolor
+ /_lp /stroke ddef
+ } if
+ } ddef
+ /_ps
+ {
+ _sc
+ stroke
+ } ddef
+ /_pss
+ {
+ _sc
+ ss
+ } ddef
+ /_pjss
+ {
+ _sc
+ jss
+ } ddef
+ /_lp /none ddef
+} def
+/A
+{
+ pop
+} def
+/annotatepage
+{
+userdict /annotatepage 2 copy known {get exec} {pop pop} ifelse
+} def
+/XT {
+ pop pop
+} def
+/discard
+{
+ save /discardSave exch store
+ discardDict begin
+ /endString exch store
+ gt38?
+ {
+ 2 add
+ } if
+ load
+ stopped
+ pop
+ end
+ discardSave restore
+} bind def
+userdict /discardDict 7 dict dup begin
+put
+/pre38Initialize
+{
+ /endStringLength endString length store
+ /newBuff buffer 0 endStringLength getinterval store
+ /newBuffButFirst newBuff 1 endStringLength 1 sub getinterval store
+ /newBuffLast newBuff endStringLength 1 sub 1 getinterval store
+} def
+/shiftBuffer
+{
+ newBuff 0 newBuffButFirst putinterval
+ newBuffLast 0
+ currentfile read not
+ {
+ stop
+ } if
+ put
+} def
+0
+{
+ pre38Initialize
+ mark
+ currentfile newBuff readstring exch pop
+ {
+ {
+ newBuff endString eq
+ {
+ cleartomark stop
+ } if
+ shiftBuffer
+ } loop
+ }
+ {
+ stop
+ } ifelse
+} def
+1
+{
+ pre38Initialize
+ /beginString exch store
+ mark
+ currentfile newBuff readstring exch pop
+ {
+ {
+ newBuff beginString eq
+ {
+ /layerCount dup load 1 add store
+ }
+ {
+ newBuff endString eq
+ {
+ /layerCount dup load 1 sub store
+ layerCount 0 eq
+ {
+ cleartomark stop
+ } if
+ } if
+ } ifelse
+ shiftBuffer
+ } loop
+ } if
+} def
+2
+{
+ mark
+ {
+ currentfile buffer readline not
+ {
+ stop
+ } if
+ endString eq
+ {
+ cleartomark stop
+ } if
+ } loop
+} def
+3
+{
+ /beginString exch store
+ /layerCnt 1 store
+ mark
+ {
+ currentfile buffer readline not
+ {
+ stop
+ } if
+ dup beginString eq
+ {
+ pop /layerCnt dup load 1 add store
+ }
+ {
+ endString eq
+ {
+ layerCnt 1 eq
+ {
+ cleartomark stop
+ }
+ {
+ /layerCnt dup load 1 sub store
+ } ifelse
+ } if
+ } ifelse
+ } loop
+} def
+end
+userdict /clipRenderOff 15 dict dup begin
+put
+{
+ /n /N /s /S /f /F /b /B
+}
+{
+ {
+ _doClip 1 eq
+ {
+ /_doClip 0 ddef _eo {eoclip} {clip} ifelse
+ } if
+ newpath
+ } def
+} forall
+/Tr /pop load def
+/Bb {} def
+/BB /pop load def
+/Bg {12 npop} def
+/Bm {6 npop} def
+/Bc /Bm load def
+/Bh {4 npop} def
+end
+/Lb
+{
+ 4 npop
+ 6 1 roll
+ pop
+ 4 1 roll
+ pop pop pop
+ 0 eq
+ {
+ 0 eq
+ {
+ (%AI5_BeginLayer) 1 (%AI5_EndLayer--) discard
+ }
+ {
+
+ /clipForward? true def
+
+ /Tx /pop load def
+ /Tj /pop load def
+
+ currentdict end clipRenderOff begin begin
+ } ifelse
+ }
+ {
+ 0 eq
+ {
+ save /discardSave exch store
+ } if
+ } ifelse
+} bind def
+/LB
+{
+ discardSave dup null ne
+ {
+ restore
+ }
+ {
+ pop
+ clipForward?
+ {
+ currentdict
+ end
+ end
+ begin
+
+ /clipForward? false ddef
+ } if
+ } ifelse
+} bind def
+/Pb
+{
+ pop pop
+ 0 (%AI5_EndPalette) discard
+} bind def
+/Np
+{
+ 0 (%AI5_End_NonPrinting--) discard
+} bind def
+/Ln /pop load def
+/Ap
+/pop load def
+/Ar
+{
+ 72 exch div
+ 0 dtransform dup mul exch dup mul add sqrt
+ dup 1 lt
+ {
+ pop 1
+ } if
+ setflat
+} def
+/Mb
+{
+ q
+} def
+/Md
+{
+} def
+/MB
+{
+ Q
+} def
+/nc 3 dict def
+nc begin
+/setgray
+{
+ pop
+} bind def
+/setcmykcolor
+{
+ 4 npop
+} bind def
+/setcustomcolor
+{
+ 2 npop
+} bind def
+currentdict readonly pop
+end
+end
+setpacking
+%%EndResource
+%%EndProlog
+%%BeginSetup
+%%IncludeFont: Univers
+Adobe_level2_AI5 /initialize get exec
+Adobe_Illustrator_AI5_vars Adobe_Illustrator_AI5 Adobe_typography_AI5 /initialize get exec
+Adobe_ColorImage_AI6 /initialize get exec
+Adobe_Illustrator_AI5 /initialize get exec
+[
+39/quotesingle 96/grave 128/Adieresis/Aring/Ccedilla/Eacute/Ntilde/Odieresis
+/Udieresis/aacute/agrave/acircumflex/adieresis/atilde/aring/ccedilla/eacute
+/egrave/ecircumflex/edieresis/iacute/igrave/icircumflex/idieresis/ntilde
+/oacute/ograve/ocircumflex/odieresis/otilde/uacute/ugrave/ucircumflex
+/udieresis/dagger/degree/cent/sterling/section/bullet/paragraph/germandbls
+/registered/copyright/trademark/acute/dieresis/.notdef/AE/Oslash
+/.notdef/plusminus/.notdef/.notdef/yen/mu/.notdef/.notdef
+/.notdef/.notdef/.notdef/ordfeminine/ordmasculine/.notdef/ae/oslash
+/questiondown/exclamdown/logicalnot/.notdef/florin/.notdef/.notdef
+/guillemotleft/guillemotright/ellipsis/.notdef/Agrave/Atilde/Otilde/OE/oe
+/endash/emdash/quotedblleft/quotedblright/quoteleft/quoteright/divide
+/.notdef/ydieresis/Ydieresis/fraction/currency/guilsinglleft/guilsinglright
+/fi/fl/daggerdbl/periodcentered/quotesinglbase/quotedblbase/perthousand
+/Acircumflex/Ecircumflex/Aacute/Edieresis/Egrave/Iacute/Icircumflex
+/Idieresis/Igrave/Oacute/Ocircumflex/.notdef/Ograve/Uacute/Ucircumflex
+/Ugrave/dotlessi/circumflex/tilde/macron/breve/dotaccent/ring/cedilla
+/hungarumlaut/ogonek/caron
+TE
+%AI3_BeginEncoding: _Univers Univers
+[/_Univers/Univers 0 0 1 TZ
+%AI3_EndEncoding AdobeType
+%AI5_Begin_NonPrinting
+Np
+8 Bn
+%AI5_BeginGradient: (Black & White)
+(Black & White) 0 2 Bd
+[
+<
+FFFEFDFCFBFAF9F8F7F6F5F4F3F2F1F0EFEEEDECEBEAE9E8E7E6E5E4E3E2E1E0DFDEDDDCDBDAD9D8
+D7D6D5D4D3D2D1D0CFCECDCCCBCAC9C8C7C6C5C4C3C2C1C0BFBEBDBCBBBAB9B8B7B6B5B4B3B2B1B0
+AFAEADACABAAA9A8A7A6A5A4A3A2A1A09F9E9D9C9B9A999897969594939291908F8E8D8C8B8A8988
+87868584838281807F7E7D7C7B7A797877767574737271706F6E6D6C6B6A69686766656463626160
+5F5E5D5C5B5A595857565554535251504F4E4D4C4B4A494847464544434241403F3E3D3C3B3A3938
+37363534333231302F2E2D2C2B2A292827262524232221201F1E1D1C1B1A19181716151413121110
+0F0E0D0C0B0A09080706050403020100
+>
+0 %_Br
+[
+0 0 50 100 %_Bs
+1 0 50 0 %_Bs
+BD
+%AI5_EndGradient
+%AI5_BeginGradient: (Green & Blue)
+(Green & Blue) 0 2 Bd
+[
+<
+99999A9A9B9B9B9C9C9D9D9D9E9E9F9F9FA0A0A1A1A1A2A2A3A3A3A4A4A5A5A5A6A6A7A7A7A8A8A9
+A9A9AAAAABABABACACADADADAEAEAFAFAFB0B0B1B1B1B2B2B3B3B3B4B4B5B5B5B6B6B7B7B7B8B8B9
+B9B9BABABBBBBBBCBCBDBDBDBEBEBFBFBFC0C0C1C1C1C2C2C3C3C3C4C4C5C5C5C6C6C7C7C7C8C8C9
+C9C9CACACBCBCBCCCCCDCDCDCECECFCFCFD0D0D1D1D1D2D2D3D3D3D4D4D5D5D5D6D6D7D7D7D8D8D9
+D9D9DADADBDBDBDCDCDDDDDDDEDEDFDFDFE0E0E1E1E1E2E2E3E3E3E4E4E5E5E5E6E6E7E7E7E8E8E9
+E9E9EAEAEBEBEBECECEDEDEDEEEEEFEFEFF0F0F1F1F1F2F2F3F3F3F4F4F5F5F5F6F6F7F7F7F8F8F9
+F9F9FAFAFBFBFBFCFCFDFDFDFEFEFFFF
+>
+<
+000102020304050506070808090A0B0B0C0D0E0E0F101111121314141516171718191A1A1B1C1D1D
+1E1F20202122232324252626272829292A2B2C2C2D2E2F2F303132323334353536373838393A3B3B
+3C3D3E3E3F404141424344444546474748494A4A4B4C4D4D4E4F5050515253535455565657585959
+5A5B5C5C5D5E5F5F606162626364656566676868696A6B6B6C6D6E6E6F7071717273747475767777
+78797A7A7B7C7D7D7E7F80808182828384858586878888898A8B8B8C8D8E8E8F9091919293949495
+96979798999A9A9B9C9D9D9E9FA0A0A1A2A3A3A4A5A6A6A7A8A9A9AAABACACADAEAFAFB0B1B2B2B3
+B4B5B5B6B7B8B8B9BABBBBBCBDBEBEBF
+>
+<
+FFFEFDFCFBFAF9F8F7F6F5F4F3F2F1F0EFEEEDECEBEAE9E8E7E6E5E4E3E2E1E0DFDEDDDCDBDAD9D8
+D7D6D5D4D3D2D1D0CFCECDCCCBCAC9C8C7C6C5C4C3C2C1C0BFBEBDBCBBBAB9B8B7B6B5B4B3B2B1B0
+AFAEADACABAAA9A8A7A6A5A4A3A2A1A09F9E9D9C9B9A999897969594939291908F8E8D8C8B8A8988
+87868584838281807F7E7D7C7B7A797877767574737271706F6E6D6C6B6A69686766656463626160
+5F5E5D5C5B5A595857565554535251504F4E4D4C4B4A494847464544434241403F3E3D3C3B3A3938
+37363534333231302F2E2D2C2B2A292827262524232221201F1E1D1C1B1A19181716151413121110
+0F0E0D0C0B0A09080706050403020100
+>
+0
+1 %_Br
+[
+1 0.75 0 0 1 50 100 %_Bs
+0.6 0 1 0 1 50 0 %_Bs
+BD
+%AI5_EndGradient
+%AI5_BeginGradient: (Pink, Yellow, Green)
+(Pink, Yellow, Green) 0 3 Bd
+[
+<
+00000000000000000000000000000000000000010101010101010101010101010101010101010101
+01010101010202020202020202020202020202020202020202020203030303030303030303030303
+03030303030303030404040404040404040404040404040404040404050505050505050505050505
+05050505050505060606060606060606060606060606060606060707070707070707070707070707
+07070707080808080808080808080808080808080809090909090909090909090909090909090A0A
+0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0C0C0C0C0C0C0C0C0C
+0C0C0C0C0C0C0C0D0D0D0D0D
+>
+<
+050506060606070708080809090A0A0A0B0B0C0C0D0D0E0E0F0F1010111112121313141415151617
+17181819191A1A1B1C1C1D1D1E1F1F202021222223232425252626272828292A2A2B2C2C2D2D2E2F
+2F3031313233333435353637373839393A3B3B3C3D3E3E3F4040414242434445454647474849494A
+4B4C4C4D4E4F4F505151525354545556575758595A5A5B5C5C5D5E5F5F6061626363646566666768
+69696A6B6C6C6D6E6F707071727373747576777778797A7B7B7C7D7E7F7F80818283838485868787
+88898A8B8B8C8D8E8F8F9091929394949596979898999A9B9C9D9D9E9FA0A1A2A2A3A4A5A6A7A7A8
+A9AAABACADADAEAFB0B1B2B2
+>
+<
+CCCCCBCBCBCACACAC9C9C8C8C7C7C6C6C5C5C4C4C3C2C2C1C1C0C0BFBEBEBDBDBCBBBBBAB9B9B8B7
+B7B6B6B5B4B4B3B2B1B1B0AFAFAEADADACABAAAAA9A8A8A7A6A5A5A4A3A2A2A1A0A09F9E9D9C9C9B
+9A999998979696959493929291908F8E8E8D8C8B8A8A8988878686858483828181807F7E7D7C7C7B
+7A7978777776757473727171706F6E6D6C6B6A6A69686766656463636261605F5E5D5C5B5B5A5958
+5756555453525151504F4E4D4C4B4A49484746464544434241403F3E3D3C3B3A3938383736353433
+3231302F2E2D2C2B2A29282726252423222221201F1E1D1C1B1A191817161514131211100F0E0D0C
+0B0A09080706050403020100
+>
+0
+1 %_Br
+<
+737271706F6E6D6C6B6A696867666564636261605F5E5D5C5B5B5A59585756555453525150504F4E
+4D4C4B4A4949484746454443434241403F3E3E3D3C3B3A3A393837363635343333323130302F2E2D
+2D2C2B2A2A29282827262525242323222121201F1F1E1D1D1C1C1B1A1A1918181717161615141413
+1312121111100F0F0E0E0D0D0C0C0C0B0B0A0A090908080807070606060505050404040303030202
+020201010101010000000000
+>
+<
+00000000000000000000000001010101010101010101010101010101010101010101010102020202
+02020202020202020202020202020202020202020202030303030303030303030303030303030303
+03030303030303030303030303040404040404040404040404040404040404040404040404040404
+04040404040404040404050505050505050505050505050505050505050505050505050505050505
+050505050505050505050505
+>
+<
+BFBFBFC0C0C0C0C0C0C0C0C0C1C1C1C1C1C1C1C1C1C2C2C2C2C2C2C2C2C2C2C3C3C3C3C3C3C3C3C3
+C3C4C4C4C4C4C4C4C4C4C4C5C5C5C5C5C5C5C5C5C5C5C6C6C6C6C6C6C6C6C6C6C6C6C7C7C7C7C7C7
+C7C7C7C7C7C7C8C8C8C8C8C8C8C8C8C8C8C8C8C9C9C9C9C9C9C9C9C9C9C9C9C9C9C9CACACACACACA
+CACACACACACACACACACACBCBCBCBCBCBCBCBCBCBCBCBCBCBCBCBCBCBCBCBCBCBCCCCCCCCCCCCCCCC
+CCCCCCCCCCCCCCCCCCCCCCCC
+>
+0
+1 %_Br
+[
+0.05 0.7 0 0 1 50 100 %_Bs
+0 0.02 0.8 0 1 57 36 %_Bs
+0.45 0 0.75 0 1 37 0 %_Bs
+BD
+%AI5_EndGradient
+%AI5_BeginGradient: (Purple, Red & Yellow)
+(Purple, Red & Yellow) 0 3 Bd
+[
+0
+<
+FFFEFDFCFBFAF9F8F7F6F5F4F3F2F1F0EFEEEDECEBEAE9E8E7E6E5E4E3E2E1E0DFDEDDDCDBDAD9D8
+D7D6D5D4D3D2D1D0CFCECDCCCBCAC9C8C7C6C5C4C3C2C1C0BFBEBDBCBBBAB9B8B7B6B5B4B3B2B1B0
+AFAEADACABAAA9A8A7A6A5A4A3A2A1A09F9E9D9C9B9A999897969594939291908F8E8D8C8B8A8988
+87868584838281807F7E7D7C7B7A797877767574737271706F6E6D6C6B6A69686766656463626160
+5F5E5D5C5B5A595857565554535251504F4E4D4C4B4A494847464544434241403F3E3D3C3B3A3938
+37363534333231302F2E2D2C2B2A292827262524232221201F1E1D1C1B1A19181716151413121110
+0F0E0D0C0B0A
+>
+<
+CCCCCCCDCDCDCDCDCECECECECECFCFCFCFD0D0D0D0D0D1D1D1D1D1D2D2D2D2D2D3D3D3D3D3D4D4D4
+D4D5D5D5D5D5D6D6D6D6D6D7D7D7D7D7D8D8D8D8D8D9D9D9D9DADADADADADBDBDBDBDBDCDCDCDCDC
+DDDDDDDDDDDEDEDEDEDFDFDFDFDFE0E0E0E0E0E1E1E1E1E1E2E2E2E2E2E3E3E3E3E4E4E4E4E4E5E5
+E5E5E5E6E6E6E6E6E7E7E7E7E7E8E8E8E8E9E9E9E9E9EAEAEAEAEAEBEBEBEBEBECECECECECEDEDED
+EDEEEEEEEEEEEFEFEFEFEFF0F0F0F0F0F1F1F1F1F1F2F2F2F2F3F3F3F3F3F4F4F4F4F4F5F5F5F5F5
+F6F6F6F6F6F7F7F7F7F8F8F8F8F8F9F9F9F9F9FAFAFAFAFAFBFBFBFBFBFCFCFCFCFDFDFDFDFDFEFE
+FEFEFEFFFFFF
+>
+0
+1 %_Br
+<
+E5E4E3E2E1E0DFDEDDDCDBDAD9D8D7D6D5D4D3D2D1D0CFCECDCCCBCAC9C8C7C6C5C4C3C2C1C0BFBE
+BDBCBBBAB9B8B7B6B5B4B3B2B1B0AFAEADACABAAA9A8A7A6A5A4A3A2A1A09F9E9D9C9B9A99989796
+9594939291908F8E8D8C8B8A898887868584838281807F7E7D7C7B7A797877767574737271706F6E
+6D6C6B6A696867666564636261605F5E5D5C5B5A595857565554535251504F4E4D4C4B4A49484746
+4544434241403F3E3D3C3B3A393837363534333231302F2E2D2C2B2A292827262524232221201F1E
+1D1C1B1A191817161514131211100F0E0D0C0B0A09080706050403020100
+>
+<
+E5E6E6E6E6E6E6E6E6E7E7E7E7E7E7E7E7E7E8E8E8E8E8E8E8E8E8E9E9E9E9E9E9E9E9E9EAEAEAEA
+EAEAEAEAEAEBEBEBEBEBEBEBEBEBECECECECECECECECECEDEDEDEDEDEDEDEDEDEEEEEEEEEEEEEEEE
+EEEFEFEFEFEFEFEFEFEFF0F0F0F0F0F0F0F0F0F1F1F1F1F1F1F1F1F1F2F2F2F2F2F2F2F2F2F3F3F3
+F3F3F3F3F3F3F4F4F4F4F4F4F4F4F4F5F5F5F5F5F5F5F5F5F6F6F6F6F6F6F6F6F6F7F7F7F7F7F7F7
+F7F7F8F8F8F8F8F8F8F8F8F9F9F9F9F9F9F9F9F9FAFAFAFAFAFAFAFAFAFBFBFBFBFBFBFBFBFBFCFC
+FCFCFCFCFCFCFCFDFDFDFDFDFDFDFDFDFEFEFEFEFEFEFEFEFEFFFFFFFFFF
+>
+<
+00010203040405060708090A0B0C0C0D0E0F10111213141415161718191A1B1C1D1D1E1F20212223
+242525262728292A2B2C2D2D2E2F30313233343535363738393A3B3C3D3D3E3F4041424344454546
+4748494A4B4C4D4E4E4F50515253545556565758595A5B5C5D5E5E5F60616263646566666768696A
+6B6C6D6E6E6F70717273747576767778797A7B7C7D7E7F7F80818283848586878788898A8B8C8D8E
+8F8F90919293949596979798999A9B9C9D9E9F9FA0A1A2A3A4A5A6A7A7A8A9AAABACADAEAFAFB0B1
+B2B3B4B5B6B7B8B8B9BABBBCBDBEBFC0C0C1C2C3C4C5C6C7C8C8C9CACBCC
+>
+0
+1 %_Br
+[
+0 0.04 1 0 1 50 100 %_Bs
+0 1 0.8 0 1 50 50 %_Bs
+0.9 0.9 0 0 1 50 0 %_Bs
+BD
+%AI5_EndGradient
+%AI5_BeginGradient: (Rainbow)
+(Rainbow) 0 6 Bd
+[
+<
+FFFEFDFCFBFAF9F8F7F6F5F4F3F2F1F0EFEEEDECEBEAE9E8E7E6E5E4E3E2E1E0DFDEDDDCDBDAD9D8
+D7D6D5D4D3D2D1D0CFCECDCCCBCAC9C8C7C6C5C4C3C2C1C0BFBEBDBCBBBAB9B8B7B6B5B4B3B2B1B0
+AFAEADACABAAA9A8A7A6A5A4A3A2A1A09F9E9D9C9B9A999897969594939291908F8E8D8C8B8A8988
+87868584838281807F7E7D7C7B7A797877767574737271706F6E6D6C6B6A69686766656463626160
+5F5E5D5C5B5A595857565554535251504F4E4D4C4B4A494847464544434241403F3E3D3C3B3A3938
+37363534333231302F2E2D2C2B2A292827262524232221201F1E1D1C1B1A19181716151413121110
+0F0E0D0C0B0A09080706050403020100
+>
+1
+0
+0
+1 %_Br
+1
+<
+0708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E
+2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F50515253545556
+5758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E
+7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6
+A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7C8C9CACBCCCDCE
+CFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6
+F7F8F9FAFBFCFDFEFF
+>
+0
+0
+1 %_Br
+1
+<
+00000000000000000000000000000000000001010101010101010101010101010101010101010101
+01010101010101010101010101010202020202020202020202020202020202020202020202020202
+02020202020202020202030303030303030303030303030303030303030303030303030303030303
+03030303030304040404040404040404040404040404040404040404040404040404040404040404
+04040505050505050505050505050505050505050505050505050505050505050505050505050606
+06060606060606060606060606060606060606060606060606060606060606060606070707070707
+07070707070707070707070707070707
+>
+<
+FFFEFDFCFBFAF9F8F7F6F5F4F3F2F1F0EFEEEDECEBEAE9E8E7E6E5E4E3E2E1E0DFDEDDDCDBDAD9D8
+D7D6D5D4D3D2D1D0CFCECDCCCBCAC9C8C7C6C5C4C3C2C1C0BFBEBDBCBBBAB9B8B7B6B5B4B3B2B1B0
+AFAEADACABAAA9A8A7A6A5A4A3A2A1A09F9E9D9C9B9A999897969594939291908F8E8D8C8B8A8988
+87868584838281807F7E7D7C7B7A797877767574737271706F6E6D6C6B6A69686766656463626160
+5F5E5D5C5B5A595857565554535251504F4E4D4C4B4A494847464544434241403F3E3D3C3B3A3938
+37363534333231302F2E2D2C2B2A292827262524232221201F1E1D1C1B1A19181716151413121110
+0F0E0D0C0B0A09080706050403020100
+>
+0
+1 %_Br
+<
+000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627
+28292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F
+505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F7071727374757677
+78797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9F
+A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7
+C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEF
+F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF
+>
+0
+1
+0
+1 %_Br
+0
+<
+FFFEFDFCFBFAF9F8F7F6F5F4F3F2F1F0EFEEEDECEBEAE9E8E7E6E5E4E3E2E1E0DFDEDDDCDBDAD9D8
+D7D6D5D4D3D2D1D0CFCECDCCCBCAC9C8C7C6C5C4C3C2C1C0BFBEBDBCBBBAB9B8B7B6B5B4B3B2B1B0
+AFAEADACABAAA9A8A7A6A5A4A3A2A1A09F9E9D9C9B9A999897969594939291908F8E8D8C8B8A8988
+87868584838281807F7E7D7C7B7A797877767574737271706F6E6D6C6B6A69686766656463626160
+5F5E5D5C5B5A595857565554535251504F4E4D4C4B4A494847464544434241403F3E3D3C3B3A3938
+37363534333231302F2E2D2C2B2A292827262524232221201F1E1D1C1B1A19181716151413121110
+0F0E0D0C0B0A09080706050403020100
+>
+1
+0
+1 %_Br
+[
+0 1 0 0 1 50 100 %_Bs
+1 1 0 0 1 50 80 %_Bs
+1 0.0279 0 0 1 50 60 %_Bs
+1 0 1 0 1 50 40 %_Bs
+0 0 1 0 1 50 20 %_Bs
+0 1 1 0 1 50 0 %_Bs
+BD
+%AI5_EndGradient
+%AI5_BeginGradient: (Steel Bar)
+(Steel Bar) 0 3 Bd
+[
+<
+FFFEFDFCFBFAF9F8F7F6F5F4F3F2F1F0EFEEEDECEBEAE9E8E7E6E5E4E3E2E1E0DFDEDDDCDBDAD9D8
+D7D6D5D4D3D2D1D0CFCECDCCCBCAC9C8C7C6C5C4C3C2C1C0BFBEBDBCBBBAB9B8B7B6B5B4B3B2B1B0
+AFAEADACABAAA9A8A7A6A5A4A3A2A1A09F9E9D9C9B9A999897969594939291908F8E8D8C8B8A8988
+87868584838281807F7E7D7C7B7A797877767574737271706F6E6D6C6B6A69686766656463626160
+5F5E5D5C5B5A595857565554535251504F4E4D4C4B4A494847464544434241403F3E3D3C3B3A3938
+37363534333231302F2E2D2C2B2A292827262524232221201F1E1D1C1B1A19181716151413121110
+0F0E0D0C0B0A09080706050403020100
+>
+0 %_Br
+<
+000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627
+28292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F
+505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F7071727374757677
+78797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9F
+A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7
+C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEF
+F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF
+>
+0 %_Br
+[
+0 0 50 100 %_Bs
+1 0 50 70 %_Bs
+0 0 50 0 %_Bs
+BD
+%AI5_EndGradient
+%AI5_BeginGradient: (Yellow & Orange Radial)
+(Yellow & Orange Radial) 1 2 Bd
+[
+0
+<
+0001010203040506060708090A0B0C0C0D0E0F10111213131415161718191A1B1C1D1D1E1F202122
+232425262728292A2B2B2C2D2E2F303132333435363738393A3B3C3D3E3E3F404142434445464748
+494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F60606162636465666768696A6B6C6D6E6F
+707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C
+>
+<
+FFFFFFFFFEFEFEFEFEFEFEFDFDFDFDFDFDFCFCFCFCFCFCFBFBFBFBFBFBFAFAFAFAFAFAF9F9F9F9F9
+F9F8F8F8F8F8F8F7F7F7F7F7F7F6F6F6F6F6F6F5F5F5F5F5F5F4F4F4F4F4F3F3F3F3F3F3F2F2F2F2
+F2F2F1F1F1F1F1F0F0F0F0F0F0EFEFEFEFEFEFEEEEEEEEEEEDEDEDEDEDEDECECECECECEBEBEBEBEB
+EBEAEAEAEAEAE9E9E9E9E9E9E8E8E8E8E8E8E7E7E7E7E7E6E6E6E6E6E5
+>
+0
+1 %_Br
+[
+0 0 1 0 1 52 19 %_Bs
+0 0.55 0.9 0 1 50 100 %_Bs
+BD
+%AI5_EndGradient
+%AI5_BeginGradient: (Yellow & Purple Radial)
+(Yellow & Purple Radial) 1 2 Bd
+[
+<
+000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627
+28292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F
+505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F7071727374757677
+78797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9F
+A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7
+C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEF
+F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF
+>
+<
+1415161718191A1B1C1D1E1F1F202122232425262728292A2A2B2C2D2E2F30313233343536363738
+393A3B3C3D3E3F40414142434445464748494A4B4C4D4D4E4F50515253545556575858595A5B5C5D
+5E5F60616263646465666768696A6B6C6D6E6F6F707172737475767778797A7B7B7C7D7E7F808182
+83848586868788898A8B8C8D8E8F90919292939495969798999A9B9C9D9D9E9FA0A1A2A3A4A5A6A7
+A8A9A9AAABACADAEAFB0B1B2B3B4B4B5B6B7B8B9BABBBCBDBEBFC0C0C1C2C3C4C5C6C7C8C9CACBCB
+CCCDCECFD0D1D2D3D4D5D6D7D7D8D9DADBDCDDDEDFE0E1E2E2E3E4E5E6E7E8E9EAEBECEDEEEEEFF0
+F1F2F3F4F5F6F7F8F9F9FAFBFCFDFEFF
+>
+<
+ABAAAAA9A8A7A7A6A5A5A4A3A3A2A1A1A09F9F9E9D9D9C9B9B9A9999989797969595949393929191
+908F8F8E8D8D8C8B8B8A8989888787868585848383828181807F7F7E7D7D7C7B7B7A797978777776
+7575747373727171706F6F6E6D6D6C6B6B6A6969686767666565646362626160605F5E5E5D5C5C5B
+5A5A5958585756565554545352525150504F4E4E4D4C4C4B4A4A4948484746464544444342424140
+403F3E3E3D3C3C3B3A3A3938383736363534343332323130302F2E2E2D2C2C2B2A2A292828272626
+25242423222121201F1F1E1D1D1C1B1B1A1919181717161515141313121111100F0F0E0D0D0C0B0B
+0A090908070706050504030302010100
+>
+0
+1 %_Br
+[
+0 0.08 0.67 0 1 50 14 %_Bs
+1 1 0 0 1 50 100 %_Bs
+BD
+%AI5_EndGradient
+%AI5_End_NonPrinting--
+%AI5_BeginPalette
+0 0 Pb
+Pn
+Pc
+1 g
+Pc
+0 g
+Pc
+0 0 0 0 k
+Pc
+0.75 g
+Pc
+0.5 g
+Pc
+0.25 g
+Pc
+0 g
+Pc
+Bb
+2 (Black & White) -4014 4716 0 0 1 0 0 1 0 0 Bg
+0 BB
+Pc
+0.25 0 0 0 k
+Pc
+0.5 0 0 0 k
+Pc
+0.75 0 0 0 k
+Pc
+1 0 0 0 k
+Pc
+0.25 0.25 0 0 k
+Pc
+0.5 0.5 0 0 k
+Pc
+0.75 0.75 0 0 k
+Pc
+1 1 0 0 k
+Pc
+Bb
+2 (Pink, Yellow, Green) -4014 4716 0 0 1 0 0 1 0 0 Bg
+0 BB
+Pc
+0 0.25 0 0 k
+Pc
+0 0.5 0 0 k
+Pc
+0 0.75 0 0 k
+Pc
+0 1 0 0 k
+Pc
+0 0.25 0.25 0 k
+Pc
+0 0.5 0.5 0 k
+Pc
+0 0.75 0.75 0 k
+Pc
+0 1 1 0 k
+Pc
+Bb
+0 0 0 0 Bh
+2 (Yellow & Purple Radial) -4014 4716 0 0 1 0 0 1 0 0 Bg
+0 BB
+Pc
+0 0 0.25 0 k
+Pc
+0 0 0.5 0 k
+Pc
+0 0 0.75 0 k
+Pc
+0 0 1 0 k
+Pc
+0.25 0 0.25 0 k
+Pc
+0.5 0 0.5 0 k
+Pc
+0.75 0 0.75 0 k
+Pc
+1 0 1 0 k
+Pc
+Bb
+2 (Rainbow) -4014 4716 0 0 1 0 0 1 0 0 Bg
+0 BB
+Pc
+0.25 0.125 0 0 k
+Pc
+0.5 0.25 0 0 k
+Pc
+0.75 0.375 0 0 k
+Pc
+1 0.5 0 0 k
+Pc
+0.125 0.25 0 0 k
+Pc
+0.25 0.5 0 0 k
+Pc
+0.375 0.75 0 0 k
+Pc
+0.5 1 0 0 k
+Pc
+Bb
+2 (Steel Bar) -4014 4716 0 0 1 0 0 1 0 0 Bg
+0 BB
+Pc
+0 0.25 0.125 0 k
+Pc
+0 0.5 0.25 0 k
+Pc
+0 0.75 0.375 0 k
+Pc
+0 1 0.5 0 k
+Pc
+0 0.125 0.25 0 k
+Pc
+0 0.25 0.5 0 k
+Pc
+0 0.375 0.75 0 k
+Pc
+0 0.5 1 0 k
+Pc
+Bb
+2 (Purple, Red & Yellow) -4014 4716 0 0 1 0 0 1 0 0 Bg
+0 BB
+Pc
+0.125 0 0.25 0 k
+Pc
+0.25 0 0.5 0 k
+Pc
+0.375 0 0.75 0 k
+Pc
+0.5 0 1 0 k
+Pc
+0.25 0 0.125 0 k
+Pc
+0.5 0 0.25 0 k
+Pc
+0.75 0 0.375 0 k
+Pc
+1 0 0.5 0 k
+Pc
+Bb
+2 (Green & Blue) -4014 4716 0 0 1 0 0 1 0 0 Bg
+0 BB
+Pc
+0.25 0.125 0.125 0 k
+Pc
+0.5 0.25 0.25 0 k
+Pc
+0.75 0.375 0.375 0 k
+Pc
+1 0.5 0.5 0 k
+Pc
+0.25 0.25 0.125 0 k
+Pc
+0.5 0.5 0.25 0 k
+Pc
+0.75 0.75 0.375 0 k
+Pc
+1 1 0.5 0 k
+Pc
+Bb
+0 0 0 0 Bh
+2 (Yellow & Orange Radial) -4014 4716 0 0 1 0 0 1 0 0 Bg
+0 BB
+Pc
+0.125 0.25 0.125 0 k
+Pc
+0.25 0.5 0.25 0 k
+Pc
+0.375 0.75 0.375 0 k
+Pc
+0.5 1 0.5 0 k
+Pc
+0.125 0.25 0.25 0 k
+Pc
+0.25 0.5 0.5 0 k
+Pc
+0.375 0.75 0.75 0 k
+Pc
+0.5 1 1 0 k
+Pc
+0 0 0 0 k
+Pc
+0.125 0.125 0.25 0 k
+Pc
+0.25 0.25 0.5 0 k
+Pc
+0.375 0.375 0.75 0 k
+Pc
+0.5 0.5 1 0 k
+Pc
+0.25 0.125 0.25 0 k
+Pc
+0.5 0.25 0.5 0 k
+Pc
+0.75 0.375 0.75 0 k
+Pc
+1 0.5 1 0 k
+Pc
+PB
+%AI5_EndPalette
+%%EndSetup
+%AI5_BeginLayer
+1 1 1 1 0 0 0 79 128 255 Lb
+(Layer 1) Ln
+0 A
+800 Ar
+0 J 0 j 1 w 4 M []0 d
+%AI3_Note:
+0 D
+0 XR
+-4014 283.5 m
+4626 283.5 L
+(N) *
+453.5 4716 m
+453.5 -3924 L
+(N) *
+85 4716 m
+85 -3924 L
+(N) *
+-4014 765.5 m
+4626 765.5 L
+(N) *
+0 R
+0 G
+113 683.5 m
+439 683.5 l
+S
+113 663.5 m
+439 663.5 l
+S
+113 643.5 m
+439 643.5 l
+S
+113 686 m
+439 686 l
+S
+1 Ap
+439 624 m
+439 709 L
+113 709 L
+113 624 L
+439 624 L
+s
+0 Ap
+178.5 709 m
+178.5 624 l
+S
+243 709 m
+243 624 l
+S
+374 709 m
+374 624 l
+S
+308.5 709 m
+308.5 624 l
+S
+0 To
+1 0 0 1 146 692 0 Tp
+TP
+-12.2278 0 Td
+0 Tr
+0 O
+0 g
+/_Univers 10 Tf
+0 Ts
+100 Tz
+0 Tt
+1 TA
+%_ 0 XL
+36 0 Xb
+XB
+0 0 5 TC
+100 100 200 TW
+0 0 0 Ti
+1 Ta
+0 0 2 2 3 Th
+0 Tq
+0 0 Tl
+0 Tc
+0 Tw
+(key 1) Tx
+(\r) TX
+TO
+0 To
+1 0 0 1 213 692 0 Tp
+TP
+-12.2278 0 Td
+0 Tr
+(key 2) Tx
+(\r) TX
+TO
+0 To
+1 0 0 1 276 692 0 Tp
+TP
+-11.1121 0 Td
+0 Tr
+(col 3) Tx
+(\r) TX
+TO
+0 To
+1 0 0 1 225.5 747.5 0 Tp
+TP
+0 Tr
+(\r) Tx
+TO
+0 To
+1 0 0 1 336.5 693.5 0 Tp
+TP
+0 Tr
+(\r) Tx
+TO
+0 To
+1 0 0 1 341 692 0 Tp
+TP
+-11.1121 0 Td
+0 Tr
+(col 4) Tx
+(\r) TX
+TO
+0 To
+1 0 0 1 407.5 692 0 Tp
+TP
+-11.1121 0 Td
+0 Tr
+(col 5) Tx
+(\r) TX
+TO
+0 To
+1 0 0 1 185.5 736 0 Tp
+TP
+0 Tr
+(\r) Tx
+TO
+0 To
+1 0 0 1 145 669.5 0 Tp
+TP
+-2.7795 0 Td
+0 Tr
+(1) Tx
+(\r) TX
+TO
+0 To
+1 0 0 1 144.5 650.5 0 Tp
+TP
+-2.7795 0 Td
+0 Tr
+(1) Tx
+(\r) TX
+TO
+0 To
+1 0 0 1 145 630 0 Tp
+TP
+-2.7795 0 Td
+0 Tr
+(2) Tx
+(\r) TX
+TO
+0 To
+1 0 0 1 209.5 669 0 Tp
+TP
+-2.7795 0 Td
+0 Tr
+(1) Tx
+(\r) TX
+TO
+0 To
+1 0 0 1 209.5 649.5 0 Tp
+TP
+-2.7795 0 Td
+0 Tr
+(2) Tx
+(\r) TX
+TO
+0 To
+1 0 0 1 209.5 629.5 0 Tp
+TP
+-2.7795 0 Td
+0 Tr
+(1) Tx
+(\r) TX
+TO
+0 To
+1 0 0 1 274.5 669 0 Tp
+TP
+-2.7795 0 Td
+0 Tr
+(a) Tx
+(\r) TX
+TO
+0 To
+1 0 0 1 274.5 649.5 0 Tp
+TP
+-3.0542 0 Td
+0 Tr
+(d) Tx
+(\r) TX
+TO
+0 To
+1 0 0 1 274.5 629.5 0 Tp
+TP
+-3.0542 0 Td
+0 Tr
+(g) Tx
+(\r) TX
+TO
+0 To
+1 0 0 1 340 669 0 Tp
+TP
+-3.0542 0 Td
+0 Tr
+(b) Tx
+(\r) TX
+TO
+0 To
+1 0 0 1 340 649.5 0 Tp
+TP
+-2.7795 0 Td
+0 Tr
+(e) Tx
+(\r) TX
+TO
+0 To
+1 0 0 1 340 629.5 0 Tp
+TP
+-8.8879 0 Td
+0 Tr
+(N/A) Tx
+(\r) TX
+TO
+0 To
+1 0 0 1 405 669 0 Tp
+TP
+-2.5 0 Td
+0 Tr
+(c) Tx
+(\r) TX
+TO
+0 To
+1 0 0 1 405 649.5 0 Tp
+TP
+-1.6638 0 Td
+0 Tr
+(f) Tx
+(\r) TX
+TO
+0 To
+1 0 0 1 405 629.5 0 Tp
+TP
+-1.3892 0 Td
+0 Tr
+(i) Tx
+(\r) TX
+TO
+LB
+%AI5_EndLayer--
+%%PageTrailer
+gsave annotatepage grestore showpage
+%%Trailer
+Adobe_Illustrator_AI5 /terminate get exec
+Adobe_ColorImage_AI6 /terminate get exec
+Adobe_typography_AI5 /terminate get exec
+Adobe_level2_AI5 /terminate get exec
+%%EOF
diff --git a/lib/snmp/doc/src/getnext2.gif b/lib/snmp/doc/src/getnext2.gif
new file mode 100644
index 0000000000..caf44e93aa
--- /dev/null
+++ b/lib/snmp/doc/src/getnext2.gif
Binary files differ
diff --git a/lib/snmp/doc/src/getnext2.ps b/lib/snmp/doc/src/getnext2.ps
new file mode 100644
index 0000000000..49721647cf
--- /dev/null
+++ b/lib/snmp/doc/src/getnext2.ps
@@ -0,0 +1,2997 @@
+%!PS-Adobe-3.0 EPSF-3.0
+%%Creator: Adobe Illustrator(r) 6.0
+%%For: (Anna Fedoriw) (Ericsson Telecom)
+%%Title: (GetNext311.eps)
+%%CreationDate: (97-05-23) (14.04)
+%%BoundingBox: 112 623 440 757
+%%HiResBoundingBox: 112.5 623.5 439.5 756.8677
+%%DocumentProcessColors: Black
+%%DocumentFonts: Univers
+%%DocumentSuppliedResources: procset Adobe_level2_AI5 1.0 0
+%%+ procset Adobe_typography_AI5 1.0 0
+%%+ procset Adobe_Illustrator_AI6_vars Adobe_Illustrator_AI6
+%%+ procset Adobe_Illustrator_AI5 1.0 0
+%AI5_FileFormat 2.0
+%AI3_ColorUsage: Black&White
+%%AI6_ColorSeparationSet: 1 1 (AI6 Default Color Separation Set)
+%%+ Options: 1 16 0 1 0 1 1 1 0 1 1 1 1 18 0 0 0 0 0 0 0 0 -1 -1
+%%+ PPD: 1 21 0 0 60 45 2 2 1 0 0 1 0 0 0 0 0 0 0 0 0 0 ()
+%AI3_TemplateBox: 306 396 306 396
+%AI3_TileBox: 21 -12 588 802
+%AI3_DocumentPreview: Macintosh_ColorPic
+%AI5_ArtSize: 595.2756 841.8898
+%AI5_RulerUnits: 1
+%AI5_ArtFlags: 0 0 0 1 0 0 1 1 0
+%AI5_TargetResolution: 800
+%AI5_NumLayers: 1
+%AI5_OpenToView: 54 804 2 1146 827 58 1 1 3 40
+%AI5_OpenViewLayers: 7
+%%EndComments
+%%BeginProlog
+%%BeginResource: procset Adobe_level2_AI5 1.2 0
+%%Title: (Adobe Illustrator (R) Version 5.0 Level 2 Emulation)
+%%Version: 1.2
+%%CreationDate: (04/10/93) ()
+%%Copyright: ((C) 1987-1993 Adobe Systems Incorporated All Rights Reserved)
+userdict /Adobe_level2_AI5 23 dict dup begin
+ put
+ /packedarray where not
+ {
+ userdict begin
+ /packedarray
+ {
+ array astore readonly
+ } bind def
+ /setpacking /pop load def
+ /currentpacking false def
+ end
+ 0
+ } if
+ pop
+ userdict /defaultpacking currentpacking put true setpacking
+ /initialize
+ {
+ Adobe_level2_AI5 begin
+ } bind def
+ /terminate
+ {
+ currentdict Adobe_level2_AI5 eq
+ {
+ end
+ } if
+ } bind def
+ mark
+ /setcustomcolor where not
+ {
+ /findcmykcustomcolor
+ {
+ 5 packedarray
+ } bind def
+ /setcustomcolor
+ {
+ exch aload pop pop
+ 4
+ {
+ 4 index mul 4 1 roll
+ } repeat
+ 5 -1 roll pop
+ setcmykcolor
+ }
+ def
+ } if
+
+ /gt38? mark {version cvr cvx exec} stopped {cleartomark true} {38 gt exch pop} ifelse def
+ userdict /deviceDPI 72 0 matrix defaultmatrix dtransform dup mul exch dup mul add sqrt put
+ userdict /level2?
+ systemdict /languagelevel known dup
+ {
+ pop systemdict /languagelevel get 2 ge
+ } if
+ put
+/level2ScreenFreq
+{
+ begin
+ 60
+ HalftoneType 1 eq
+ {
+ pop Frequency
+ } if
+ HalftoneType 2 eq
+ {
+ pop GrayFrequency
+ } if
+ HalftoneType 5 eq
+ {
+ pop Default level2ScreenFreq
+ } if
+ end
+} bind def
+userdict /currentScreenFreq
+ level2? {currenthalftone level2ScreenFreq} {currentscreen pop pop} ifelse put
+level2? not
+ {
+ /setcmykcolor where not
+ {
+ /setcmykcolor
+ {
+ exch .11 mul add exch .59 mul add exch .3 mul add
+ 1 exch sub setgray
+ } def
+ } if
+ /currentcmykcolor where not
+ {
+ /currentcmykcolor
+ {
+ 0 0 0 1 currentgray sub
+ } def
+ } if
+ /setoverprint where not
+ {
+ /setoverprint /pop load def
+ } if
+ /selectfont where not
+ {
+ /selectfont
+ {
+ exch findfont exch
+ dup type /arraytype eq
+ {
+ makefont
+ }
+ {
+ scalefont
+ } ifelse
+ setfont
+ } bind def
+ } if
+ /cshow where not
+ {
+ /cshow
+ {
+ [
+ 0 0 5 -1 roll aload pop
+ ] cvx bind forall
+ } bind def
+ } if
+ } if
+ cleartomark
+ /anyColor?
+ {
+ add add add 0 ne
+ } bind def
+ /testColor
+ {
+ gsave
+ setcmykcolor currentcmykcolor
+ grestore
+ } bind def
+ /testCMYKColorThrough
+ {
+ testColor anyColor?
+ } bind def
+ userdict /composite?
+ level2?
+ {
+ gsave 1 1 1 1 setcmykcolor currentcmykcolor grestore
+ add add add 4 eq
+ }
+ {
+ 1 0 0 0 testCMYKColorThrough
+ 0 1 0 0 testCMYKColorThrough
+ 0 0 1 0 testCMYKColorThrough
+ 0 0 0 1 testCMYKColorThrough
+ and and and
+ } ifelse
+ put
+ composite? not
+ {
+ userdict begin
+ gsave
+ /cyan? 1 0 0 0 testCMYKColorThrough def
+ /magenta? 0 1 0 0 testCMYKColorThrough def
+ /yellow? 0 0 1 0 testCMYKColorThrough def
+ /black? 0 0 0 1 testCMYKColorThrough def
+ grestore
+ /isCMYKSep? cyan? magenta? yellow? black? or or or def
+ /customColor? isCMYKSep? not def
+ end
+ } if
+ end defaultpacking setpacking
+%%EndResource
+%%BeginResource: procset Adobe_typography_AI5 1.0 1
+%%Title: (Typography Operators)
+%%Version: 1.0
+%%CreationDate:(03/26/93) ()
+%%Copyright: ((C) 1987-1993 Adobe Systems Incorporated All Rights Reserved)
+currentpacking true setpacking
+userdict /Adobe_typography_AI5 54 dict dup begin
+put
+/initialize
+{
+ begin
+ begin
+ Adobe_typography_AI5 begin
+ Adobe_typography_AI5
+ {
+ dup xcheck
+ {
+ bind
+ } if
+ pop pop
+ } forall
+ end
+ end
+ end
+ Adobe_typography_AI5 begin
+} def
+/terminate
+{
+ currentdict Adobe_typography_AI5 eq
+ {
+ end
+ } if
+} def
+/modifyEncoding
+{
+ /_tempEncode exch ddef
+ /_pntr 0 ddef
+ {
+ counttomark -1 roll
+ dup type dup /marktype eq
+ {
+ pop pop exit
+ }
+ {
+ /nametype eq
+ {
+ _tempEncode /_pntr dup load dup 3 1 roll 1 add ddef 3 -1 roll
+ put
+ }
+ {
+ /_pntr exch ddef
+ } ifelse
+ } ifelse
+ } loop
+ _tempEncode
+} def
+/TE
+{
+ StandardEncoding 256 array copy modifyEncoding
+ /_nativeEncoding exch def
+} def
+%
+/TZ
+{
+ dup type /arraytype eq
+ {
+ /_wv exch def
+ }
+ {
+ /_wv 0 def
+ } ifelse
+ /_useNativeEncoding exch def
+ pop pop
+ findfont _wv type /arraytype eq
+ {
+ _wv makeblendedfont
+ } if
+ dup length 2 add dict
+ begin
+ mark exch
+ {
+ 1 index /FID ne
+ {
+ def
+ } if
+ cleartomark mark
+ } forall
+ pop
+ /FontName exch def
+ counttomark 0 eq
+ {
+ 1 _useNativeEncoding eq
+ {
+ /Encoding _nativeEncoding def
+ } if
+ cleartomark
+ }
+ {
+ /Encoding load 256 array copy
+ modifyEncoding /Encoding exch def
+ } ifelse
+ FontName currentdict
+ end
+ definefont pop
+} def
+/tr
+{
+ _ax _ay 3 2 roll
+} def
+/trj
+{
+ _cx _cy _sp _ax _ay 6 5 roll
+} def
+/a0
+{
+ /Tx
+ {
+ dup
+ currentpoint 3 2 roll
+ tr _psf
+ newpath moveto
+ tr _ctm _pss
+ } ddef
+ /Tj
+ {
+ dup
+ currentpoint 3 2 roll
+ trj _pjsf
+ newpath moveto
+ trj _ctm _pjss
+ } ddef
+} def
+/a1
+{
+ /Tx
+ {
+ dup currentpoint 4 2 roll gsave
+ dup currentpoint 3 2 roll
+ tr _psf
+ newpath moveto
+ tr _ctm _pss
+ grestore 3 1 roll moveto tr sp
+ } ddef
+ /Tj
+ {
+ dup currentpoint 4 2 roll gsave
+ dup currentpoint 3 2 roll
+ trj _pjsf
+ newpath moveto
+ trj _ctm _pjss
+ grestore 3 1 roll moveto tr jsp
+ } ddef
+} def
+/e0
+{
+ /Tx
+ {
+ tr _psf
+ } ddef
+ /Tj
+ {
+ trj _pjsf
+ } ddef
+} def
+/e1
+{
+ /Tx
+ {
+ dup currentpoint 4 2 roll gsave
+ tr _psf
+ grestore 3 1 roll moveto tr sp
+ } ddef
+ /Tj
+ {
+ dup currentpoint 4 2 roll gsave
+ trj _pjsf
+ grestore 3 1 roll moveto tr jsp
+ } ddef
+} def
+/i0
+{
+ /Tx
+ {
+ tr sp
+ } ddef
+ /Tj
+ {
+ trj jsp
+ } ddef
+} def
+/i1
+{
+ W N
+} def
+/o0
+{
+ /Tx
+ {
+ tr sw rmoveto
+ } ddef
+ /Tj
+ {
+ trj swj rmoveto
+ } ddef
+} def
+/r0
+{
+ /Tx
+ {
+ tr _ctm _pss
+ } ddef
+ /Tj
+ {
+ trj _ctm _pjss
+ } ddef
+} def
+/r1
+{
+ /Tx
+ {
+ dup currentpoint 4 2 roll currentpoint gsave newpath moveto
+ tr _ctm _pss
+ grestore 3 1 roll moveto tr sp
+ } ddef
+ /Tj
+ {
+ dup currentpoint 4 2 roll currentpoint gsave newpath moveto
+ trj _ctm _pjss
+ grestore 3 1 roll moveto tr jsp
+ } ddef
+} def
+/To
+{
+ pop _ctm currentmatrix pop
+} def
+/TO
+{
+ iTe _ctm setmatrix newpath
+} def
+/Tp
+{
+ pop _tm astore pop _ctm setmatrix
+ _tDict begin
+ /W
+ {
+ } def
+ /h
+ {
+ } def
+} def
+/TP
+{
+ end
+ iTm 0 0 moveto
+} def
+/Tr
+{
+ _render 3 le
+ {
+ currentpoint newpath moveto
+ } if
+ dup 8 eq
+ {
+ pop 0
+ }
+ {
+ dup 9 eq
+ {
+ pop 1
+ } if
+ } ifelse
+ dup /_render exch ddef
+ _renderStart exch get load exec
+} def
+/iTm
+{
+ _ctm setmatrix _tm concat 0 _rise translate _hs 1 scale
+} def
+/Tm
+{
+ _tm astore pop iTm 0 0 moveto
+} def
+/Td
+{
+ _mtx translate _tm _tm concatmatrix pop iTm 0 0 moveto
+} def
+/iTe
+{
+ _render -1 eq
+ {
+ }
+ {
+ _renderEnd _render get dup null ne
+ {
+ load exec
+ }
+ {
+ pop
+ } ifelse
+ } ifelse
+ /_render -1 ddef
+} def
+/Ta
+{
+ pop
+} def
+/Tf
+{
+ dup 1000 div /_fScl exch ddef
+%
+ selectfont
+} def
+/Tl
+{
+ pop
+ 0 exch _leading astore pop
+} def
+/Tt
+{
+ pop
+} def
+/TW
+{
+ 3 npop
+} def
+/Tw
+{
+ /_cx exch ddef
+} def
+/TC
+{
+ 3 npop
+} def
+/Tc
+{
+ /_ax exch ddef
+} def
+/Ts
+{
+ /_rise exch ddef
+ currentpoint
+ iTm
+ moveto
+} def
+/Ti
+{
+ 3 npop
+} def
+/Tz
+{
+ 100 div /_hs exch ddef
+ iTm
+} def
+/TA
+{
+ pop
+} def
+/Tq
+{
+ pop
+} def
+/Th
+{
+ pop pop pop pop pop
+} def
+/TX
+{
+ pop
+} def
+/Tk
+{
+ exch pop _fScl mul neg 0 rmoveto
+} def
+/TK
+{
+ 2 npop
+} def
+/T*
+{
+ _leading aload pop neg Td
+} def
+/T*-
+{
+ _leading aload pop Td
+} def
+/T-
+{
+ _ax neg 0 rmoveto
+ _hyphen Tx
+} def
+/T+
+{
+} def
+/TR
+{
+ _ctm currentmatrix pop
+ _tm astore pop
+ iTm 0 0 moveto
+} def
+/TS
+{
+ currentfont 3 1 roll
+ /_Symbol_ _fScl 1000 mul selectfont
+
+ 0 eq
+ {
+ Tx
+ }
+ {
+ Tj
+ } ifelse
+ setfont
+} def
+/Xb
+{
+ pop pop
+} def
+/Tb /Xb load def
+/Xe
+{
+ pop pop pop pop
+} def
+/Te /Xe load def
+/XB
+{
+} def
+/TB /XB load def
+currentdict readonly pop
+end
+setpacking
+%%EndResource
+%%BeginProcSet: Adobe_ColorImage_AI6 1.0 0
+userdict /Adobe_ColorImage_AI6 known not
+{
+ userdict /Adobe_ColorImage_AI6 17 dict put
+} if
+userdict /Adobe_ColorImage_AI6 get begin
+
+ /initialize
+ {
+ Adobe_ColorImage_AI6 begin
+ Adobe_ColorImage_AI6
+ {
+ dup type /arraytype eq
+ {
+ dup xcheck
+ {
+ bind
+ } if
+ } if
+ pop pop
+ } forall
+ } def
+ /terminate { end } def
+
+ currentdict /Adobe_ColorImage_AI6_Vars known not
+ {
+ /Adobe_ColorImage_AI6_Vars 14 dict def
+ } if
+
+ Adobe_ColorImage_AI6_Vars begin
+ /channelcount 0 def
+ /sourcecount 0 def
+ /sourcearray 4 array def
+ /plateindex -1 def
+ /XIMask 0 def
+ /XIBinary 0 def
+ /XIChannelCount 0 def
+ /XIBitsPerPixel 0 def
+ /XIImageHeight 0 def
+ /XIImageWidth 0 def
+ /XIImageMatrix null def
+ /XIBuffer null def
+ /XIDataProc null def
+ end
+
+ /WalkRGBString null def
+ /WalkCMYKString null def
+
+ /StuffRGBIntoGrayString null def
+ /RGBToGrayImageProc null def
+ /StuffCMYKIntoGrayString null def
+ /CMYKToGrayImageProc null def
+ /ColorImageCompositeEmulator null def
+
+ /SeparateCMYKImageProc null def
+
+ /FourEqual null def
+ /TestPlateIndex null def
+
+ currentdict /_colorimage known not
+ {
+ /colorimage where
+ {
+ /colorimage get /_colorimage exch def
+ }
+ {
+ /_colorimage null def
+ } ifelse
+ } if
+
+ /_currenttransfer systemdict /currenttransfer get def
+
+ /colorimage null def
+ /XI null def
+
+
+ /WalkRGBString
+ {
+ 0 3 index
+
+ dup length 1 sub 0 3 3 -1 roll
+ {
+ 3 getinterval { } forall
+
+ 5 index exec
+
+ 3 index
+ } for
+
+ 5 { pop } repeat
+
+ } def
+
+
+ /WalkCMYKString
+ {
+ 0 3 index
+
+ dup length 1 sub 0 4 3 -1 roll
+ {
+ 4 getinterval { } forall
+
+ 6 index exec
+
+ 3 index
+
+ } for
+
+ 5 { pop } repeat
+
+ } def
+
+
+ /StuffRGBIntoGrayString
+ {
+ .11 mul exch
+
+ .59 mul add exch
+
+ .3 mul add
+
+ cvi 3 copy put
+
+ pop 1 add
+ } def
+
+
+ /RGBToGrayImageProc
+ {
+ Adobe_ColorImage_AI6_Vars begin
+ sourcearray 0 get exec
+ dup length 3 idiv string
+ dup 3 1 roll
+
+ /StuffRGBIntoGrayString load exch
+ WalkRGBString
+ end
+ } def
+
+
+ /StuffCMYKIntoGrayString
+ {
+ exch .11 mul add
+
+ exch .59 mul add
+
+ exch .3 mul add
+
+ dup 255 gt { pop 255 } if
+
+ 255 exch sub cvi 3 copy put
+
+ pop 1 add
+ } def
+
+
+ /CMYKToGrayImageProc
+ {
+ Adobe_ColorImage_AI6_Vars begin
+ sourcearray 0 get exec
+ dup length 4 idiv string
+ dup 3 1 roll
+
+ /StuffCMYKIntoGrayString load exch
+ WalkCMYKString
+ end
+ } def
+
+
+ /ColorImageCompositeEmulator
+ {
+ pop true eq
+ {
+ Adobe_ColorImage_AI6_Vars /sourcecount get 5 add { pop } repeat
+ }
+ {
+ Adobe_ColorImage_AI6_Vars /channelcount get 1 ne
+ {
+ Adobe_ColorImage_AI6_Vars begin
+ sourcearray 0 3 -1 roll put
+
+ channelcount 3 eq
+ {
+ /RGBToGrayImageProc
+ }
+ {
+ /CMYKToGrayImageProc
+ } ifelse
+ load
+ end
+ } if
+ image
+ } ifelse
+ } def
+
+
+ /SeparateCMYKImageProc
+ {
+ Adobe_ColorImage_AI6_Vars begin
+
+ sourcecount 0 ne
+ {
+ sourcearray plateindex get exec
+ }
+ {
+ sourcearray 0 get exec
+
+ dup length 4 idiv string
+
+ 0 2 index
+
+ plateindex 4 2 index length 1 sub
+ {
+ get 255 exch sub
+
+ 3 copy put pop 1 add
+
+ 2 index
+ } for
+
+ pop pop exch pop
+ } ifelse
+ end
+ } def
+
+
+ /FourEqual
+ {
+ 4 index ne
+ {
+ pop pop pop false
+ }
+ {
+ 4 index ne
+ {
+ pop pop false
+ }
+ {
+ 4 index ne
+ {
+ pop false
+ }
+ {
+ 4 index eq
+ } ifelse
+ } ifelse
+ } ifelse
+ } def
+
+
+ /TestPlateIndex
+ {
+ Adobe_ColorImage_AI6_Vars begin
+ /plateindex -1 def
+
+ /setcmykcolor where
+ {
+ pop
+ gsave
+ 1 0 0 0 setcmykcolor systemdict /currentgray get exec 1 exch sub
+ 0 1 0 0 setcmykcolor systemdict /currentgray get exec 1 exch sub
+ 0 0 1 0 setcmykcolor systemdict /currentgray get exec 1 exch sub
+ 0 0 0 1 setcmykcolor systemdict /currentgray get exec 1 exch sub
+ grestore
+
+ 1 0 0 0 FourEqual
+ {
+ /plateindex 0 def
+ }
+ {
+ 0 1 0 0 FourEqual
+ {
+ /plateindex 1 def
+ }
+ {
+ 0 0 1 0 FourEqual
+ {
+ /plateindex 2 def
+ }
+ {
+ 0 0 0 1 FourEqual
+ {
+ /plateindex 3 def
+ }
+ {
+ 0 0 0 0 FourEqual
+ {
+ /plateindex 5 def
+ } if
+ } ifelse
+ } ifelse
+ } ifelse
+ } ifelse
+ pop pop pop pop
+ } if
+ plateindex
+ end
+ } def
+
+
+ /colorimage
+ {
+ Adobe_ColorImage_AI6_Vars begin
+ /channelcount 1 index def
+ /sourcecount 2 index 1 eq { channelcount 1 sub } { 0 } ifelse def
+
+ 4 sourcecount add index dup
+ 8 eq exch 1 eq or not
+ end
+
+ {
+ /_colorimage load null ne
+ {
+ _colorimage
+ }
+ {
+ Adobe_ColorImage_AI6_Vars /sourcecount get
+ 7 add { pop } repeat
+ } ifelse
+ }
+ {
+ dup 3 eq
+ TestPlateIndex
+ dup -1 eq exch 5 eq or or
+ {
+ /_colorimage load null eq
+ {
+ ColorImageCompositeEmulator
+ }
+ {
+ dup 1 eq
+ {
+ pop pop image
+ }
+ {
+ Adobe_ColorImage_AI6_Vars /plateindex get 5 eq
+ {
+ gsave
+
+ 0 _currenttransfer exec
+ 1 _currenttransfer exec
+ eq
+ { 0 _currenttransfer exec 0.5 lt }
+ { 0 _currenttransfer exec 1 _currenttransfer exec gt } ifelse
+
+ { { pop 0 } } { { pop 1 } } ifelse
+ systemdict /settransfer get exec
+ } if
+
+ _colorimage
+
+ Adobe_ColorImage_AI6_Vars /plateindex get 5 eq
+ {
+ grestore
+ } if
+ } ifelse
+ } ifelse
+ }
+ {
+ dup 1 eq
+ {
+ pop pop
+ image
+ }
+ {
+ pop pop
+
+ Adobe_ColorImage_AI6_Vars begin
+ sourcecount -1 0
+ {
+ exch sourcearray 3 1 roll put
+ } for
+
+ /SeparateCMYKImageProc load
+ end
+
+ systemdict /image get exec
+ } ifelse
+ } ifelse
+ } ifelse
+ } def
+
+ /XI
+ {
+ Adobe_ColorImage_AI6_Vars begin
+ gsave
+ /XIMask exch 0 ne def
+ /XIBinary exch 0 ne def
+ pop
+ pop
+ /XIChannelCount exch def
+ /XIBitsPerPixel exch def
+ /XIImageHeight exch def
+ /XIImageWidth exch def
+ pop pop pop pop
+ /XIImageMatrix exch def
+
+ XIBitsPerPixel 1 eq
+ {
+ XIImageWidth 8 div ceiling cvi
+ }
+ {
+ XIImageWidth XIChannelCount mul
+ } ifelse
+ /XIBuffer exch string def
+
+ XIBinary
+ {
+ /XIDataProc { currentfile XIBuffer readstring pop } def
+ currentfile 128 string readline pop pop
+ }
+ {
+ /XIDataProc { currentfile XIBuffer readhexstring pop } def
+ } ifelse
+
+ 0 0 moveto
+ XIImageMatrix concat
+ XIImageWidth XIImageHeight scale
+
+ XIMask
+ {
+ XIImageWidth XIImageHeight
+ false
+ [ XIImageWidth 0 0 XIImageHeight neg 0 0 ]
+ /XIDataProc load
+
+ /_lp /null ddef
+ _fc
+ /_lp /imagemask ddef
+
+ imagemask
+ }
+ {
+ XIImageWidth XIImageHeight
+ XIBitsPerPixel
+ [ XIImageWidth 0 0 XIImageHeight neg 0 0 ]
+ /XIDataProc load
+
+ XIChannelCount 1 eq
+ {
+
+ gsave
+ 0 setgray
+
+ image
+
+ grestore
+ }
+ {
+ false
+ XIChannelCount
+ colorimage
+ } ifelse
+ } ifelse
+ grestore
+ end
+ } def
+
+end
+%%EndProcSet
+%%BeginResource: procset Adobe_Illustrator_AI5 1.1 0
+%%Title: (Adobe Illustrator (R) Version 5.0 Full Prolog)
+%%Version: 1.1
+%%CreationDate: (3/7/1994) ()
+%%Copyright: ((C) 1987-1994 Adobe Systems Incorporated All Rights Reserved)
+currentpacking true setpacking
+userdict /Adobe_Illustrator_AI5_vars 81 dict dup begin
+put
+/_eo false def
+/_lp /none def
+/_pf
+{
+} def
+/_ps
+{
+} def
+/_psf
+{
+} def
+/_pss
+{
+} def
+/_pjsf
+{
+} def
+/_pjss
+{
+} def
+/_pola 0 def
+/_doClip 0 def
+/cf currentflat def
+/_tm matrix def
+/_renderStart
+[
+/e0 /r0 /a0 /o0 /e1 /r1 /a1 /i0
+] def
+/_renderEnd
+[
+null null null null /i1 /i1 /i1 /i1
+] def
+/_render -1 def
+/_rise 0 def
+/_ax 0 def
+/_ay 0 def
+/_cx 0 def
+/_cy 0 def
+/_leading
+[
+0 0
+] def
+/_ctm matrix def
+/_mtx matrix def
+/_sp 16#020 def
+/_hyphen (-) def
+/_fScl 0 def
+/_cnt 0 def
+/_hs 1 def
+/_nativeEncoding 0 def
+/_useNativeEncoding 0 def
+/_tempEncode 0 def
+/_pntr 0 def
+/_tDict 2 dict def
+/_wv 0 def
+/Tx
+{
+} def
+/Tj
+{
+} def
+/CRender
+{
+} def
+/_AI3_savepage
+{
+} def
+/_gf null def
+/_cf 4 array def
+/_if null def
+/_of false def
+/_fc
+{
+} def
+/_gs null def
+/_cs 4 array def
+/_is null def
+/_os false def
+/_sc
+{
+} def
+/_pd 1 dict def
+/_ed 15 dict def
+/_pm matrix def
+/_fm null def
+/_fd null def
+/_fdd null def
+/_sm null def
+/_sd null def
+/_sdd null def
+/_i null def
+/discardSave null def
+/buffer 256 string def
+/beginString null def
+/endString null def
+/endStringLength null def
+/layerCnt 1 def
+/layerCount 1 def
+/perCent (%) 0 get def
+/perCentSeen? false def
+/newBuff null def
+/newBuffButFirst null def
+/newBuffLast null def
+/clipForward? false def
+end
+userdict /Adobe_Illustrator_AI5 known not {
+ userdict /Adobe_Illustrator_AI5 91 dict put
+} if
+userdict /Adobe_Illustrator_AI5 get begin
+/initialize
+{
+ Adobe_Illustrator_AI5 dup begin
+ Adobe_Illustrator_AI5_vars begin
+ discardDict
+ {
+ bind pop pop
+ } forall
+ dup /nc get begin
+ {
+ dup xcheck 1 index type /operatortype ne and
+ {
+ bind
+ } if
+ pop pop
+ } forall
+ end
+ newpath
+} def
+/terminate
+{
+ end
+ end
+} def
+/_
+null def
+/ddef
+{
+ Adobe_Illustrator_AI5_vars 3 1 roll put
+} def
+/xput
+{
+ dup load dup length exch maxlength eq
+ {
+ dup dup load dup
+ length 2 mul dict copy def
+ } if
+ load begin
+ def
+ end
+} def
+/npop
+{
+ {
+ pop
+ } repeat
+} def
+/sw
+{
+ dup length exch stringwidth
+ exch 5 -1 roll 3 index mul add
+ 4 1 roll 3 1 roll mul add
+} def
+/swj
+{
+ dup 4 1 roll
+ dup length exch stringwidth
+ exch 5 -1 roll 3 index mul add
+ 4 1 roll 3 1 roll mul add
+ 6 2 roll /_cnt 0 ddef
+ {
+ 1 index eq
+ {
+ /_cnt _cnt 1 add ddef
+ } if
+ } forall
+ pop
+ exch _cnt mul exch _cnt mul 2 index add 4 1 roll 2 index add 4 1 roll pop pop
+} def
+/ss
+{
+ 4 1 roll
+ {
+ 2 npop
+ (0) exch 2 copy 0 exch put pop
+ gsave
+ false charpath currentpoint
+ 4 index setmatrix
+ stroke
+ grestore
+ moveto
+ 2 copy rmoveto
+ } exch cshow
+ 3 npop
+} def
+/jss
+{
+ 4 1 roll
+ {
+ 2 npop
+ (0) exch 2 copy 0 exch put
+ gsave
+ _sp eq
+ {
+ exch 6 index 6 index 6 index 5 -1 roll widthshow
+ currentpoint
+ }
+ {
+ false charpath currentpoint
+ 4 index setmatrix stroke
+ } ifelse
+ grestore
+ moveto
+ 2 copy rmoveto
+ } exch cshow
+ 6 npop
+} def
+/sp
+{
+ {
+ 2 npop (0) exch
+ 2 copy 0 exch put pop
+ false charpath
+ 2 copy rmoveto
+ } exch cshow
+ 2 npop
+} def
+/jsp
+{
+ {
+ 2 npop
+ (0) exch 2 copy 0 exch put
+ _sp eq
+ {
+ exch 5 index 5 index 5 index 5 -1 roll widthshow
+ }
+ {
+ false charpath
+ } ifelse
+ 2 copy rmoveto
+ } exch cshow
+ 5 npop
+} def
+/pl
+{
+ transform
+ 0.25 sub round 0.25 add exch
+ 0.25 sub round 0.25 add exch
+ itransform
+} def
+/setstrokeadjust where
+{
+ pop true setstrokeadjust
+ /c
+ {
+ curveto
+ } def
+ /C
+ /c load def
+ /v
+ {
+ currentpoint 6 2 roll curveto
+ } def
+ /V
+ /v load def
+ /y
+ {
+ 2 copy curveto
+ } def
+ /Y
+ /y load def
+ /l
+ {
+ lineto
+ } def
+ /L
+ /l load def
+ /m
+ {
+ moveto
+ } def
+}
+{
+ /c
+ {
+ pl curveto
+ } def
+ /C
+ /c load def
+ /v
+ {
+ currentpoint 6 2 roll pl curveto
+ } def
+ /V
+ /v load def
+ /y
+ {
+ pl 2 copy curveto
+ } def
+ /Y
+ /y load def
+ /l
+ {
+ pl lineto
+ } def
+ /L
+ /l load def
+ /m
+ {
+ pl moveto
+ } def
+} ifelse
+/d
+{
+ setdash
+} def
+/cf
+{
+} def
+/i
+{
+ dup 0 eq
+ {
+ pop cf
+ } if
+ setflat
+} def
+/j
+{
+ setlinejoin
+} def
+/J
+{
+ setlinecap
+} def
+/M
+{
+ setmiterlimit
+} def
+/w
+{
+ setlinewidth
+} def
+/XR
+{
+ 0 ne
+ /_eo exch ddef
+} def
+/H
+{
+} def
+/h
+{
+ closepath
+} def
+/N
+{
+ _pola 0 eq
+ {
+ _doClip 1 eq
+ {
+ _eo {eoclip} {clip} ifelse /_doClip 0 ddef
+ } if
+ newpath
+ }
+ {
+ /CRender
+ {
+ N
+ } ddef
+ } ifelse
+} def
+/n
+{
+ N
+} def
+/F
+{
+ _pola 0 eq
+ {
+ _doClip 1 eq
+ {
+ gsave _pf grestore _eo {eoclip} {clip} ifelse newpath /_lp /none ddef _fc
+ /_doClip 0 ddef
+ }
+ {
+ _pf
+ } ifelse
+ }
+ {
+ /CRender
+ {
+ F
+ } ddef
+ } ifelse
+} def
+/f
+{
+ closepath
+ F
+} def
+/S
+{
+ _pola 0 eq
+ {
+ _doClip 1 eq
+ {
+ gsave _ps grestore _eo {eoclip} {clip} ifelse newpath /_lp /none ddef _sc
+ /_doClip 0 ddef
+ }
+ {
+ _ps
+ } ifelse
+ }
+ {
+ /CRender
+ {
+ S
+ } ddef
+ } ifelse
+} def
+/s
+{
+ closepath
+ S
+} def
+/B
+{
+ _pola 0 eq
+ {
+ _doClip 1 eq
+ gsave F grestore
+ {
+ gsave S grestore _eo {eoclip} {clip} ifelse newpath /_lp /none ddef _sc
+ /_doClip 0 ddef
+ }
+ {
+ S
+ } ifelse
+ }
+ {
+ /CRender
+ {
+ B
+ } ddef
+ } ifelse
+} def
+/b
+{
+ closepath
+ B
+} def
+/W
+{
+ /_doClip 1 ddef
+} def
+/*
+{
+ count 0 ne
+ {
+ dup type /stringtype eq
+ {
+ pop
+ } if
+ } if
+ newpath
+} def
+/u
+{
+} def
+/U
+{
+} def
+/q
+{
+ _pola 0 eq
+ {
+ gsave
+ } if
+} def
+/Q
+{
+ _pola 0 eq
+ {
+ grestore
+ } if
+} def
+/*u
+{
+ _pola 1 add /_pola exch ddef
+} def
+/*U
+{
+ _pola 1 sub /_pola exch ddef
+ _pola 0 eq
+ {
+ CRender
+ } if
+} def
+/D
+{
+ pop
+} def
+/*w
+{
+} def
+/*W
+{
+} def
+/`
+{
+ /_i save ddef
+ clipForward?
+ {
+ nulldevice
+ } if
+ 6 1 roll 4 npop
+ concat pop
+ userdict begin
+ /showpage
+ {
+ } def
+ 0 setgray
+ 0 setlinecap
+ 1 setlinewidth
+ 0 setlinejoin
+ 10 setmiterlimit
+ [] 0 setdash
+ /setstrokeadjust where {pop false setstrokeadjust} if
+ newpath
+ 0 setgray
+ false setoverprint
+} def
+/~
+{
+ end
+ _i restore
+} def
+/O
+{
+ 0 ne
+ /_of exch ddef
+ /_lp /none ddef
+} def
+/R
+{
+ 0 ne
+ /_os exch ddef
+ /_lp /none ddef
+} def
+/g
+{
+ /_gf exch ddef
+ /_fc
+ {
+ _lp /fill ne
+ {
+ _of setoverprint
+ _gf setgray
+ /_lp /fill ddef
+ } if
+ } ddef
+ /_pf
+ {
+ _fc
+ _eo {eofill} {fill} ifelse
+ } ddef
+ /_psf
+ {
+ _fc
+ ashow
+ } ddef
+ /_pjsf
+ {
+ _fc
+ awidthshow
+ } ddef
+ /_lp /none ddef
+} def
+/G
+{
+ /_gs exch ddef
+ /_sc
+ {
+ _lp /stroke ne
+ {
+ _os setoverprint
+ _gs setgray
+ /_lp /stroke ddef
+ } if
+ } ddef
+ /_ps
+ {
+ _sc
+ stroke
+ } ddef
+ /_pss
+ {
+ _sc
+ ss
+ } ddef
+ /_pjss
+ {
+ _sc
+ jss
+ } ddef
+ /_lp /none ddef
+} def
+/k
+{
+ _cf astore pop
+ /_fc
+ {
+ _lp /fill ne
+ {
+ _of setoverprint
+ _cf aload pop setcmykcolor
+ /_lp /fill ddef
+ } if
+ } ddef
+ /_pf
+ {
+ _fc
+ _eo {eofill} {fill} ifelse
+ } ddef
+ /_psf
+ {
+ _fc
+ ashow
+ } ddef
+ /_pjsf
+ {
+ _fc
+ awidthshow
+ } ddef
+ /_lp /none ddef
+} def
+/K
+{
+ _cs astore pop
+ /_sc
+ {
+ _lp /stroke ne
+ {
+ _os setoverprint
+ _cs aload pop setcmykcolor
+ /_lp /stroke ddef
+ } if
+ } ddef
+ /_ps
+ {
+ _sc
+ stroke
+ } ddef
+ /_pss
+ {
+ _sc
+ ss
+ } ddef
+ /_pjss
+ {
+ _sc
+ jss
+ } ddef
+ /_lp /none ddef
+} def
+/x
+{
+ /_gf exch ddef
+ findcmykcustomcolor
+ /_if exch ddef
+ /_fc
+ {
+ _lp /fill ne
+ {
+ _of setoverprint
+ _if _gf 1 exch sub setcustomcolor
+ /_lp /fill ddef
+ } if
+ } ddef
+ /_pf
+ {
+ _fc
+ _eo {eofill} {fill} ifelse
+ } ddef
+ /_psf
+ {
+ _fc
+ ashow
+ } ddef
+ /_pjsf
+ {
+ _fc
+ awidthshow
+ } ddef
+ /_lp /none ddef
+} def
+/X
+{
+ /_gs exch ddef
+ findcmykcustomcolor
+ /_is exch ddef
+ /_sc
+ {
+ _lp /stroke ne
+ {
+ _os setoverprint
+ _is _gs 1 exch sub setcustomcolor
+ /_lp /stroke ddef
+ } if
+ } ddef
+ /_ps
+ {
+ _sc
+ stroke
+ } ddef
+ /_pss
+ {
+ _sc
+ ss
+ } ddef
+ /_pjss
+ {
+ _sc
+ jss
+ } ddef
+ /_lp /none ddef
+} def
+/A
+{
+ pop
+} def
+/annotatepage
+{
+userdict /annotatepage 2 copy known {get exec} {pop pop} ifelse
+} def
+/XT {
+ pop pop
+} def
+/discard
+{
+ save /discardSave exch store
+ discardDict begin
+ /endString exch store
+ gt38?
+ {
+ 2 add
+ } if
+ load
+ stopped
+ pop
+ end
+ discardSave restore
+} bind def
+userdict /discardDict 7 dict dup begin
+put
+/pre38Initialize
+{
+ /endStringLength endString length store
+ /newBuff buffer 0 endStringLength getinterval store
+ /newBuffButFirst newBuff 1 endStringLength 1 sub getinterval store
+ /newBuffLast newBuff endStringLength 1 sub 1 getinterval store
+} def
+/shiftBuffer
+{
+ newBuff 0 newBuffButFirst putinterval
+ newBuffLast 0
+ currentfile read not
+ {
+ stop
+ } if
+ put
+} def
+0
+{
+ pre38Initialize
+ mark
+ currentfile newBuff readstring exch pop
+ {
+ {
+ newBuff endString eq
+ {
+ cleartomark stop
+ } if
+ shiftBuffer
+ } loop
+ }
+ {
+ stop
+ } ifelse
+} def
+1
+{
+ pre38Initialize
+ /beginString exch store
+ mark
+ currentfile newBuff readstring exch pop
+ {
+ {
+ newBuff beginString eq
+ {
+ /layerCount dup load 1 add store
+ }
+ {
+ newBuff endString eq
+ {
+ /layerCount dup load 1 sub store
+ layerCount 0 eq
+ {
+ cleartomark stop
+ } if
+ } if
+ } ifelse
+ shiftBuffer
+ } loop
+ } if
+} def
+2
+{
+ mark
+ {
+ currentfile buffer readline not
+ {
+ stop
+ } if
+ endString eq
+ {
+ cleartomark stop
+ } if
+ } loop
+} def
+3
+{
+ /beginString exch store
+ /layerCnt 1 store
+ mark
+ {
+ currentfile buffer readline not
+ {
+ stop
+ } if
+ dup beginString eq
+ {
+ pop /layerCnt dup load 1 add store
+ }
+ {
+ endString eq
+ {
+ layerCnt 1 eq
+ {
+ cleartomark stop
+ }
+ {
+ /layerCnt dup load 1 sub store
+ } ifelse
+ } if
+ } ifelse
+ } loop
+} def
+end
+userdict /clipRenderOff 15 dict dup begin
+put
+{
+ /n /N /s /S /f /F /b /B
+}
+{
+ {
+ _doClip 1 eq
+ {
+ /_doClip 0 ddef _eo {eoclip} {clip} ifelse
+ } if
+ newpath
+ } def
+} forall
+/Tr /pop load def
+/Bb {} def
+/BB /pop load def
+/Bg {12 npop} def
+/Bm {6 npop} def
+/Bc /Bm load def
+/Bh {4 npop} def
+end
+/Lb
+{
+ 4 npop
+ 6 1 roll
+ pop
+ 4 1 roll
+ pop pop pop
+ 0 eq
+ {
+ 0 eq
+ {
+ (%AI5_BeginLayer) 1 (%AI5_EndLayer--) discard
+ }
+ {
+
+ /clipForward? true def
+
+ /Tx /pop load def
+ /Tj /pop load def
+
+ currentdict end clipRenderOff begin begin
+ } ifelse
+ }
+ {
+ 0 eq
+ {
+ save /discardSave exch store
+ } if
+ } ifelse
+} bind def
+/LB
+{
+ discardSave dup null ne
+ {
+ restore
+ }
+ {
+ pop
+ clipForward?
+ {
+ currentdict
+ end
+ end
+ begin
+
+ /clipForward? false ddef
+ } if
+ } ifelse
+} bind def
+/Pb
+{
+ pop pop
+ 0 (%AI5_EndPalette) discard
+} bind def
+/Np
+{
+ 0 (%AI5_End_NonPrinting--) discard
+} bind def
+/Ln /pop load def
+/Ap
+/pop load def
+/Ar
+{
+ 72 exch div
+ 0 dtransform dup mul exch dup mul add sqrt
+ dup 1 lt
+ {
+ pop 1
+ } if
+ setflat
+} def
+/Mb
+{
+ q
+} def
+/Md
+{
+} def
+/MB
+{
+ Q
+} def
+/nc 3 dict def
+nc begin
+/setgray
+{
+ pop
+} bind def
+/setcmykcolor
+{
+ 4 npop
+} bind def
+/setcustomcolor
+{
+ 2 npop
+} bind def
+currentdict readonly pop
+end
+end
+setpacking
+%%EndResource
+%%EndProlog
+%%BeginSetup
+%%IncludeFont: Univers
+Adobe_level2_AI5 /initialize get exec
+Adobe_Illustrator_AI5_vars Adobe_Illustrator_AI5 Adobe_typography_AI5 /initialize get exec
+Adobe_ColorImage_AI6 /initialize get exec
+Adobe_Illustrator_AI5 /initialize get exec
+[
+39/quotesingle 96/grave 128/Adieresis/Aring/Ccedilla/Eacute/Ntilde/Odieresis
+/Udieresis/aacute/agrave/acircumflex/adieresis/atilde/aring/ccedilla/eacute
+/egrave/ecircumflex/edieresis/iacute/igrave/icircumflex/idieresis/ntilde
+/oacute/ograve/ocircumflex/odieresis/otilde/uacute/ugrave/ucircumflex
+/udieresis/dagger/degree/cent/sterling/section/bullet/paragraph/germandbls
+/registered/copyright/trademark/acute/dieresis/.notdef/AE/Oslash
+/.notdef/plusminus/.notdef/.notdef/yen/mu/.notdef/.notdef
+/.notdef/.notdef/.notdef/ordfeminine/ordmasculine/.notdef/ae/oslash
+/questiondown/exclamdown/logicalnot/.notdef/florin/.notdef/.notdef
+/guillemotleft/guillemotright/ellipsis/.notdef/Agrave/Atilde/Otilde/OE/oe
+/endash/emdash/quotedblleft/quotedblright/quoteleft/quoteright/divide
+/.notdef/ydieresis/Ydieresis/fraction/currency/guilsinglleft/guilsinglright
+/fi/fl/daggerdbl/periodcentered/quotesinglbase/quotedblbase/perthousand
+/Acircumflex/Ecircumflex/Aacute/Edieresis/Egrave/Iacute/Icircumflex
+/Idieresis/Igrave/Oacute/Ocircumflex/.notdef/Ograve/Uacute/Ucircumflex
+/Ugrave/dotlessi/circumflex/tilde/macron/breve/dotaccent/ring/cedilla
+/hungarumlaut/ogonek/caron
+TE
+%AI3_BeginEncoding: _Univers Univers
+[/_Univers/Univers 0 0 1 TZ
+%AI3_EndEncoding AdobeType
+%AI5_Begin_NonPrinting
+Np
+8 Bn
+%AI5_BeginGradient: (Black & White)
+(Black & White) 0 2 Bd
+[
+<
+FFFEFDFCFBFAF9F8F7F6F5F4F3F2F1F0EFEEEDECEBEAE9E8E7E6E5E4E3E2E1E0DFDEDDDCDBDAD9D8
+D7D6D5D4D3D2D1D0CFCECDCCCBCAC9C8C7C6C5C4C3C2C1C0BFBEBDBCBBBAB9B8B7B6B5B4B3B2B1B0
+AFAEADACABAAA9A8A7A6A5A4A3A2A1A09F9E9D9C9B9A999897969594939291908F8E8D8C8B8A8988
+87868584838281807F7E7D7C7B7A797877767574737271706F6E6D6C6B6A69686766656463626160
+5F5E5D5C5B5A595857565554535251504F4E4D4C4B4A494847464544434241403F3E3D3C3B3A3938
+37363534333231302F2E2D2C2B2A292827262524232221201F1E1D1C1B1A19181716151413121110
+0F0E0D0C0B0A09080706050403020100
+>
+0 %_Br
+[
+0 0 50 100 %_Bs
+1 0 50 0 %_Bs
+BD
+%AI5_EndGradient
+%AI5_BeginGradient: (Green & Blue)
+(Green & Blue) 0 2 Bd
+[
+<
+99999A9A9B9B9B9C9C9D9D9D9E9E9F9F9FA0A0A1A1A1A2A2A3A3A3A4A4A5A5A5A6A6A7A7A7A8A8A9
+A9A9AAAAABABABACACADADADAEAEAFAFAFB0B0B1B1B1B2B2B3B3B3B4B4B5B5B5B6B6B7B7B7B8B8B9
+B9B9BABABBBBBBBCBCBDBDBDBEBEBFBFBFC0C0C1C1C1C2C2C3C3C3C4C4C5C5C5C6C6C7C7C7C8C8C9
+C9C9CACACBCBCBCCCCCDCDCDCECECFCFCFD0D0D1D1D1D2D2D3D3D3D4D4D5D5D5D6D6D7D7D7D8D8D9
+D9D9DADADBDBDBDCDCDDDDDDDEDEDFDFDFE0E0E1E1E1E2E2E3E3E3E4E4E5E5E5E6E6E7E7E7E8E8E9
+E9E9EAEAEBEBEBECECEDEDEDEEEEEFEFEFF0F0F1F1F1F2F2F3F3F3F4F4F5F5F5F6F6F7F7F7F8F8F9
+F9F9FAFAFBFBFBFCFCFDFDFDFEFEFFFF
+>
+<
+000102020304050506070808090A0B0B0C0D0E0E0F101111121314141516171718191A1A1B1C1D1D
+1E1F20202122232324252626272829292A2B2C2C2D2E2F2F303132323334353536373838393A3B3B
+3C3D3E3E3F404141424344444546474748494A4A4B4C4D4D4E4F5050515253535455565657585959
+5A5B5C5C5D5E5F5F606162626364656566676868696A6B6B6C6D6E6E6F7071717273747475767777
+78797A7A7B7C7D7D7E7F80808182828384858586878888898A8B8B8C8D8E8E8F9091919293949495
+96979798999A9A9B9C9D9D9E9FA0A0A1A2A3A3A4A5A6A6A7A8A9A9AAABACACADAEAFAFB0B1B2B2B3
+B4B5B5B6B7B8B8B9BABBBBBCBDBEBEBF
+>
+<
+FFFEFDFCFBFAF9F8F7F6F5F4F3F2F1F0EFEEEDECEBEAE9E8E7E6E5E4E3E2E1E0DFDEDDDCDBDAD9D8
+D7D6D5D4D3D2D1D0CFCECDCCCBCAC9C8C7C6C5C4C3C2C1C0BFBEBDBCBBBAB9B8B7B6B5B4B3B2B1B0
+AFAEADACABAAA9A8A7A6A5A4A3A2A1A09F9E9D9C9B9A999897969594939291908F8E8D8C8B8A8988
+87868584838281807F7E7D7C7B7A797877767574737271706F6E6D6C6B6A69686766656463626160
+5F5E5D5C5B5A595857565554535251504F4E4D4C4B4A494847464544434241403F3E3D3C3B3A3938
+37363534333231302F2E2D2C2B2A292827262524232221201F1E1D1C1B1A19181716151413121110
+0F0E0D0C0B0A09080706050403020100
+>
+0
+1 %_Br
+[
+1 0.75 0 0 1 50 100 %_Bs
+0.6 0 1 0 1 50 0 %_Bs
+BD
+%AI5_EndGradient
+%AI5_BeginGradient: (Pink, Yellow, Green)
+(Pink, Yellow, Green) 0 3 Bd
+[
+<
+00000000000000000000000000000000000000010101010101010101010101010101010101010101
+01010101010202020202020202020202020202020202020202020203030303030303030303030303
+03030303030303030404040404040404040404040404040404040404050505050505050505050505
+05050505050505060606060606060606060606060606060606060707070707070707070707070707
+07070707080808080808080808080808080808080809090909090909090909090909090909090A0A
+0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0C0C0C0C0C0C0C0C0C
+0C0C0C0C0C0C0C0D0D0D0D0D
+>
+<
+050506060606070708080809090A0A0A0B0B0C0C0D0D0E0E0F0F1010111112121313141415151617
+17181819191A1A1B1C1C1D1D1E1F1F202021222223232425252626272828292A2A2B2C2C2D2D2E2F
+2F3031313233333435353637373839393A3B3B3C3D3E3E3F4040414242434445454647474849494A
+4B4C4C4D4E4F4F505151525354545556575758595A5A5B5C5C5D5E5F5F6061626363646566666768
+69696A6B6C6C6D6E6F707071727373747576777778797A7B7B7C7D7E7F7F80818283838485868787
+88898A8B8B8C8D8E8F8F9091929394949596979898999A9B9C9D9D9E9FA0A1A2A2A3A4A5A6A7A7A8
+A9AAABACADADAEAFB0B1B2B2
+>
+<
+CCCCCBCBCBCACACAC9C9C8C8C7C7C6C6C5C5C4C4C3C2C2C1C1C0C0BFBEBEBDBDBCBBBBBAB9B9B8B7
+B7B6B6B5B4B4B3B2B1B1B0AFAFAEADADACABAAAAA9A8A8A7A6A5A5A4A3A2A2A1A0A09F9E9D9C9C9B
+9A999998979696959493929291908F8E8E8D8C8B8A8A8988878686858483828181807F7E7D7C7C7B
+7A7978777776757473727171706F6E6D6C6B6A6A69686766656463636261605F5E5D5C5B5B5A5958
+5756555453525151504F4E4D4C4B4A49484746464544434241403F3E3D3C3B3A3938383736353433
+3231302F2E2D2C2B2A29282726252423222221201F1E1D1C1B1A191817161514131211100F0E0D0C
+0B0A09080706050403020100
+>
+0
+1 %_Br
+<
+737271706F6E6D6C6B6A696867666564636261605F5E5D5C5B5B5A59585756555453525150504F4E
+4D4C4B4A4949484746454443434241403F3E3E3D3C3B3A3A393837363635343333323130302F2E2D
+2D2C2B2A2A29282827262525242323222121201F1F1E1D1D1C1C1B1A1A1918181717161615141413
+1312121111100F0F0E0E0D0D0C0C0C0B0B0A0A090908080807070606060505050404040303030202
+020201010101010000000000
+>
+<
+00000000000000000000000001010101010101010101010101010101010101010101010102020202
+02020202020202020202020202020202020202020202030303030303030303030303030303030303
+03030303030303030303030303040404040404040404040404040404040404040404040404040404
+04040404040404040404050505050505050505050505050505050505050505050505050505050505
+050505050505050505050505
+>
+<
+BFBFBFC0C0C0C0C0C0C0C0C0C1C1C1C1C1C1C1C1C1C2C2C2C2C2C2C2C2C2C2C3C3C3C3C3C3C3C3C3
+C3C4C4C4C4C4C4C4C4C4C4C5C5C5C5C5C5C5C5C5C5C5C6C6C6C6C6C6C6C6C6C6C6C6C7C7C7C7C7C7
+C7C7C7C7C7C7C8C8C8C8C8C8C8C8C8C8C8C8C8C9C9C9C9C9C9C9C9C9C9C9C9C9C9C9CACACACACACA
+CACACACACACACACACACACBCBCBCBCBCBCBCBCBCBCBCBCBCBCBCBCBCBCBCBCBCBCCCCCCCCCCCCCCCC
+CCCCCCCCCCCCCCCCCCCCCCCC
+>
+0
+1 %_Br
+[
+0.05 0.7 0 0 1 50 100 %_Bs
+0 0.02 0.8 0 1 57 36 %_Bs
+0.45 0 0.75 0 1 37 0 %_Bs
+BD
+%AI5_EndGradient
+%AI5_BeginGradient: (Purple, Red & Yellow)
+(Purple, Red & Yellow) 0 3 Bd
+[
+0
+<
+FFFEFDFCFBFAF9F8F7F6F5F4F3F2F1F0EFEEEDECEBEAE9E8E7E6E5E4E3E2E1E0DFDEDDDCDBDAD9D8
+D7D6D5D4D3D2D1D0CFCECDCCCBCAC9C8C7C6C5C4C3C2C1C0BFBEBDBCBBBAB9B8B7B6B5B4B3B2B1B0
+AFAEADACABAAA9A8A7A6A5A4A3A2A1A09F9E9D9C9B9A999897969594939291908F8E8D8C8B8A8988
+87868584838281807F7E7D7C7B7A797877767574737271706F6E6D6C6B6A69686766656463626160
+5F5E5D5C5B5A595857565554535251504F4E4D4C4B4A494847464544434241403F3E3D3C3B3A3938
+37363534333231302F2E2D2C2B2A292827262524232221201F1E1D1C1B1A19181716151413121110
+0F0E0D0C0B0A
+>
+<
+CCCCCCCDCDCDCDCDCECECECECECFCFCFCFD0D0D0D0D0D1D1D1D1D1D2D2D2D2D2D3D3D3D3D3D4D4D4
+D4D5D5D5D5D5D6D6D6D6D6D7D7D7D7D7D8D8D8D8D8D9D9D9D9DADADADADADBDBDBDBDBDCDCDCDCDC
+DDDDDDDDDDDEDEDEDEDFDFDFDFDFE0E0E0E0E0E1E1E1E1E1E2E2E2E2E2E3E3E3E3E4E4E4E4E4E5E5
+E5E5E5E6E6E6E6E6E7E7E7E7E7E8E8E8E8E9E9E9E9E9EAEAEAEAEAEBEBEBEBEBECECECECECEDEDED
+EDEEEEEEEEEEEFEFEFEFEFF0F0F0F0F0F1F1F1F1F1F2F2F2F2F3F3F3F3F3F4F4F4F4F4F5F5F5F5F5
+F6F6F6F6F6F7F7F7F7F8F8F8F8F8F9F9F9F9F9FAFAFAFAFAFBFBFBFBFBFCFCFCFCFDFDFDFDFDFEFE
+FEFEFEFFFFFF
+>
+0
+1 %_Br
+<
+E5E4E3E2E1E0DFDEDDDCDBDAD9D8D7D6D5D4D3D2D1D0CFCECDCCCBCAC9C8C7C6C5C4C3C2C1C0BFBE
+BDBCBBBAB9B8B7B6B5B4B3B2B1B0AFAEADACABAAA9A8A7A6A5A4A3A2A1A09F9E9D9C9B9A99989796
+9594939291908F8E8D8C8B8A898887868584838281807F7E7D7C7B7A797877767574737271706F6E
+6D6C6B6A696867666564636261605F5E5D5C5B5A595857565554535251504F4E4D4C4B4A49484746
+4544434241403F3E3D3C3B3A393837363534333231302F2E2D2C2B2A292827262524232221201F1E
+1D1C1B1A191817161514131211100F0E0D0C0B0A09080706050403020100
+>
+<
+E5E6E6E6E6E6E6E6E6E7E7E7E7E7E7E7E7E7E8E8E8E8E8E8E8E8E8E9E9E9E9E9E9E9E9E9EAEAEAEA
+EAEAEAEAEAEBEBEBEBEBEBEBEBEBECECECECECECECECECEDEDEDEDEDEDEDEDEDEEEEEEEEEEEEEEEE
+EEEFEFEFEFEFEFEFEFEFF0F0F0F0F0F0F0F0F0F1F1F1F1F1F1F1F1F1F2F2F2F2F2F2F2F2F2F3F3F3
+F3F3F3F3F3F3F4F4F4F4F4F4F4F4F4F5F5F5F5F5F5F5F5F5F6F6F6F6F6F6F6F6F6F7F7F7F7F7F7F7
+F7F7F8F8F8F8F8F8F8F8F8F9F9F9F9F9F9F9F9F9FAFAFAFAFAFAFAFAFAFBFBFBFBFBFBFBFBFBFCFC
+FCFCFCFCFCFCFCFDFDFDFDFDFDFDFDFDFEFEFEFEFEFEFEFEFEFFFFFFFFFF
+>
+<
+00010203040405060708090A0B0C0C0D0E0F10111213141415161718191A1B1C1D1D1E1F20212223
+242525262728292A2B2C2D2D2E2F30313233343535363738393A3B3C3D3D3E3F4041424344454546
+4748494A4B4C4D4E4E4F50515253545556565758595A5B5C5D5E5E5F60616263646566666768696A
+6B6C6D6E6E6F70717273747576767778797A7B7C7D7E7F7F80818283848586878788898A8B8C8D8E
+8F8F90919293949596979798999A9B9C9D9E9F9FA0A1A2A3A4A5A6A7A7A8A9AAABACADAEAFAFB0B1
+B2B3B4B5B6B7B8B8B9BABBBCBDBEBFC0C0C1C2C3C4C5C6C7C8C8C9CACBCC
+>
+0
+1 %_Br
+[
+0 0.04 1 0 1 50 100 %_Bs
+0 1 0.8 0 1 50 50 %_Bs
+0.9 0.9 0 0 1 50 0 %_Bs
+BD
+%AI5_EndGradient
+%AI5_BeginGradient: (Rainbow)
+(Rainbow) 0 6 Bd
+[
+<
+FFFEFDFCFBFAF9F8F7F6F5F4F3F2F1F0EFEEEDECEBEAE9E8E7E6E5E4E3E2E1E0DFDEDDDCDBDAD9D8
+D7D6D5D4D3D2D1D0CFCECDCCCBCAC9C8C7C6C5C4C3C2C1C0BFBEBDBCBBBAB9B8B7B6B5B4B3B2B1B0
+AFAEADACABAAA9A8A7A6A5A4A3A2A1A09F9E9D9C9B9A999897969594939291908F8E8D8C8B8A8988
+87868584838281807F7E7D7C7B7A797877767574737271706F6E6D6C6B6A69686766656463626160
+5F5E5D5C5B5A595857565554535251504F4E4D4C4B4A494847464544434241403F3E3D3C3B3A3938
+37363534333231302F2E2D2C2B2A292827262524232221201F1E1D1C1B1A19181716151413121110
+0F0E0D0C0B0A09080706050403020100
+>
+1
+0
+0
+1 %_Br
+1
+<
+0708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E
+2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F50515253545556
+5758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E
+7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6
+A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7C8C9CACBCCCDCE
+CFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6
+F7F8F9FAFBFCFDFEFF
+>
+0
+0
+1 %_Br
+1
+<
+00000000000000000000000000000000000001010101010101010101010101010101010101010101
+01010101010101010101010101010202020202020202020202020202020202020202020202020202
+02020202020202020202030303030303030303030303030303030303030303030303030303030303
+03030303030304040404040404040404040404040404040404040404040404040404040404040404
+04040505050505050505050505050505050505050505050505050505050505050505050505050606
+06060606060606060606060606060606060606060606060606060606060606060606070707070707
+07070707070707070707070707070707
+>
+<
+FFFEFDFCFBFAF9F8F7F6F5F4F3F2F1F0EFEEEDECEBEAE9E8E7E6E5E4E3E2E1E0DFDEDDDCDBDAD9D8
+D7D6D5D4D3D2D1D0CFCECDCCCBCAC9C8C7C6C5C4C3C2C1C0BFBEBDBCBBBAB9B8B7B6B5B4B3B2B1B0
+AFAEADACABAAA9A8A7A6A5A4A3A2A1A09F9E9D9C9B9A999897969594939291908F8E8D8C8B8A8988
+87868584838281807F7E7D7C7B7A797877767574737271706F6E6D6C6B6A69686766656463626160
+5F5E5D5C5B5A595857565554535251504F4E4D4C4B4A494847464544434241403F3E3D3C3B3A3938
+37363534333231302F2E2D2C2B2A292827262524232221201F1E1D1C1B1A19181716151413121110
+0F0E0D0C0B0A09080706050403020100
+>
+0
+1 %_Br
+<
+000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627
+28292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F
+505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F7071727374757677
+78797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9F
+A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7
+C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEF
+F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF
+>
+0
+1
+0
+1 %_Br
+0
+<
+FFFEFDFCFBFAF9F8F7F6F5F4F3F2F1F0EFEEEDECEBEAE9E8E7E6E5E4E3E2E1E0DFDEDDDCDBDAD9D8
+D7D6D5D4D3D2D1D0CFCECDCCCBCAC9C8C7C6C5C4C3C2C1C0BFBEBDBCBBBAB9B8B7B6B5B4B3B2B1B0
+AFAEADACABAAA9A8A7A6A5A4A3A2A1A09F9E9D9C9B9A999897969594939291908F8E8D8C8B8A8988
+87868584838281807F7E7D7C7B7A797877767574737271706F6E6D6C6B6A69686766656463626160
+5F5E5D5C5B5A595857565554535251504F4E4D4C4B4A494847464544434241403F3E3D3C3B3A3938
+37363534333231302F2E2D2C2B2A292827262524232221201F1E1D1C1B1A19181716151413121110
+0F0E0D0C0B0A09080706050403020100
+>
+1
+0
+1 %_Br
+[
+0 1 0 0 1 50 100 %_Bs
+1 1 0 0 1 50 80 %_Bs
+1 0.0279 0 0 1 50 60 %_Bs
+1 0 1 0 1 50 40 %_Bs
+0 0 1 0 1 50 20 %_Bs
+0 1 1 0 1 50 0 %_Bs
+BD
+%AI5_EndGradient
+%AI5_BeginGradient: (Steel Bar)
+(Steel Bar) 0 3 Bd
+[
+<
+FFFEFDFCFBFAF9F8F7F6F5F4F3F2F1F0EFEEEDECEBEAE9E8E7E6E5E4E3E2E1E0DFDEDDDCDBDAD9D8
+D7D6D5D4D3D2D1D0CFCECDCCCBCAC9C8C7C6C5C4C3C2C1C0BFBEBDBCBBBAB9B8B7B6B5B4B3B2B1B0
+AFAEADACABAAA9A8A7A6A5A4A3A2A1A09F9E9D9C9B9A999897969594939291908F8E8D8C8B8A8988
+87868584838281807F7E7D7C7B7A797877767574737271706F6E6D6C6B6A69686766656463626160
+5F5E5D5C5B5A595857565554535251504F4E4D4C4B4A494847464544434241403F3E3D3C3B3A3938
+37363534333231302F2E2D2C2B2A292827262524232221201F1E1D1C1B1A19181716151413121110
+0F0E0D0C0B0A09080706050403020100
+>
+0 %_Br
+<
+000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627
+28292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F
+505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F7071727374757677
+78797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9F
+A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7
+C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEF
+F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF
+>
+0 %_Br
+[
+0 0 50 100 %_Bs
+1 0 50 70 %_Bs
+0 0 50 0 %_Bs
+BD
+%AI5_EndGradient
+%AI5_BeginGradient: (Yellow & Orange Radial)
+(Yellow & Orange Radial) 1 2 Bd
+[
+0
+<
+0001010203040506060708090A0B0C0C0D0E0F10111213131415161718191A1B1C1D1D1E1F202122
+232425262728292A2B2B2C2D2E2F303132333435363738393A3B3C3D3E3E3F404142434445464748
+494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F60606162636465666768696A6B6C6D6E6F
+707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C
+>
+<
+FFFFFFFFFEFEFEFEFEFEFEFDFDFDFDFDFDFCFCFCFCFCFCFBFBFBFBFBFBFAFAFAFAFAFAF9F9F9F9F9
+F9F8F8F8F8F8F8F7F7F7F7F7F7F6F6F6F6F6F6F5F5F5F5F5F5F4F4F4F4F4F3F3F3F3F3F3F2F2F2F2
+F2F2F1F1F1F1F1F0F0F0F0F0F0EFEFEFEFEFEFEEEEEEEEEEEDEDEDEDEDEDECECECECECEBEBEBEBEB
+EBEAEAEAEAEAE9E9E9E9E9E9E8E8E8E8E8E8E7E7E7E7E7E6E6E6E6E6E5
+>
+0
+1 %_Br
+[
+0 0 1 0 1 52 19 %_Bs
+0 0.55 0.9 0 1 50 100 %_Bs
+BD
+%AI5_EndGradient
+%AI5_BeginGradient: (Yellow & Purple Radial)
+(Yellow & Purple Radial) 1 2 Bd
+[
+<
+000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627
+28292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F
+505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F7071727374757677
+78797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9F
+A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7
+C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEF
+F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF
+>
+<
+1415161718191A1B1C1D1E1F1F202122232425262728292A2A2B2C2D2E2F30313233343536363738
+393A3B3C3D3E3F40414142434445464748494A4B4C4D4D4E4F50515253545556575858595A5B5C5D
+5E5F60616263646465666768696A6B6C6D6E6F6F707172737475767778797A7B7B7C7D7E7F808182
+83848586868788898A8B8C8D8E8F90919292939495969798999A9B9C9D9D9E9FA0A1A2A3A4A5A6A7
+A8A9A9AAABACADAEAFB0B1B2B3B4B4B5B6B7B8B9BABBBCBDBEBFC0C0C1C2C3C4C5C6C7C8C9CACBCB
+CCCDCECFD0D1D2D3D4D5D6D7D7D8D9DADBDCDDDEDFE0E1E2E2E3E4E5E6E7E8E9EAEBECEDEEEEEFF0
+F1F2F3F4F5F6F7F8F9F9FAFBFCFDFEFF
+>
+<
+ABAAAAA9A8A7A7A6A5A5A4A3A3A2A1A1A09F9F9E9D9D9C9B9B9A9999989797969595949393929191
+908F8F8E8D8D8C8B8B8A8989888787868585848383828181807F7F7E7D7D7C7B7B7A797978777776
+7575747373727171706F6F6E6D6D6C6B6B6A6969686767666565646362626160605F5E5E5D5C5C5B
+5A5A5958585756565554545352525150504F4E4E4D4C4C4B4A4A4948484746464544444342424140
+403F3E3E3D3C3C3B3A3A3938383736363534343332323130302F2E2E2D2C2C2B2A2A292828272626
+25242423222121201F1F1E1D1D1C1B1B1A1919181717161515141313121111100F0F0E0D0D0C0B0B
+0A090908070706050504030302010100
+>
+0
+1 %_Br
+[
+0 0.08 0.67 0 1 50 14 %_Bs
+1 1 0 0 1 50 100 %_Bs
+BD
+%AI5_EndGradient
+%AI5_End_NonPrinting--
+%AI5_BeginPalette
+0 2 Pb
+Pn
+Pc
+1 g
+Pc
+0 g
+Pc
+0 0 0 0 k
+Pc
+0.75 g
+Pc
+0.5 g
+Pc
+0.25 g
+Pc
+0 g
+Pc
+Bb
+2 (Black & White) -4014 4716 0 0 1 0 0 1 0 0 Bg
+0 BB
+Pc
+0.25 0 0 0 k
+Pc
+0.5 0 0 0 k
+Pc
+0.75 0 0 0 k
+Pc
+1 0 0 0 k
+Pc
+0.25 0.25 0 0 k
+Pc
+0.5 0.5 0 0 k
+Pc
+0.75 0.75 0 0 k
+Pc
+1 1 0 0 k
+Pc
+Bb
+2 (Pink, Yellow, Green) -4014 4716 0 0 1 0 0 1 0 0 Bg
+0 BB
+Pc
+0 0.25 0 0 k
+Pc
+0 0.5 0 0 k
+Pc
+0 0.75 0 0 k
+Pc
+0 1 0 0 k
+Pc
+0 0.25 0.25 0 k
+Pc
+0 0.5 0.5 0 k
+Pc
+0 0.75 0.75 0 k
+Pc
+0 1 1 0 k
+Pc
+Bb
+0 0 0 0 Bh
+2 (Yellow & Purple Radial) -4014 4716 0 0 1 0 0 1 0 0 Bg
+0 BB
+Pc
+0 0 0.25 0 k
+Pc
+0 0 0.5 0 k
+Pc
+0 0 0.75 0 k
+Pc
+0 0 1 0 k
+Pc
+0.25 0 0.25 0 k
+Pc
+0.5 0 0.5 0 k
+Pc
+0.75 0 0.75 0 k
+Pc
+1 0 1 0 k
+Pc
+Bb
+2 (Rainbow) -4014 4716 0 0 1 0 0 1 0 0 Bg
+0 BB
+Pc
+0.25 0.125 0 0 k
+Pc
+0.5 0.25 0 0 k
+Pc
+0.75 0.375 0 0 k
+Pc
+1 0.5 0 0 k
+Pc
+0.125 0.25 0 0 k
+Pc
+0.25 0.5 0 0 k
+Pc
+0.375 0.75 0 0 k
+Pc
+0.5 1 0 0 k
+Pc
+Bb
+2 (Steel Bar) -4014 4716 0 0 1 0 0 1 0 0 Bg
+0 BB
+Pc
+0 0.25 0.125 0 k
+Pc
+0 0.5 0.25 0 k
+Pc
+0 0.75 0.375 0 k
+Pc
+0 1 0.5 0 k
+Pc
+0 0.125 0.25 0 k
+Pc
+0 0.25 0.5 0 k
+Pc
+0 0.375 0.75 0 k
+Pc
+0 0.5 1 0 k
+Pc
+Bb
+2 (Purple, Red & Yellow) -4014 4716 0 0 1 0 0 1 0 0 Bg
+0 BB
+Pc
+0.125 0 0.25 0 k
+Pc
+0.25 0 0.5 0 k
+Pc
+0.375 0 0.75 0 k
+Pc
+0.5 0 1 0 k
+Pc
+0.25 0 0.125 0 k
+Pc
+0.5 0 0.25 0 k
+Pc
+0.75 0 0.375 0 k
+Pc
+1 0 0.5 0 k
+Pc
+Bb
+2 (Green & Blue) -4014 4716 0 0 1 0 0 1 0 0 Bg
+0 BB
+Pc
+0.25 0.125 0.125 0 k
+Pc
+0.5 0.25 0.25 0 k
+Pc
+0.75 0.375 0.375 0 k
+Pc
+1 0.5 0.5 0 k
+Pc
+0.25 0.25 0.125 0 k
+Pc
+0.5 0.5 0.25 0 k
+Pc
+0.75 0.75 0.375 0 k
+Pc
+1 1 0.5 0 k
+Pc
+Bb
+0 0 0 0 Bh
+2 (Yellow & Orange Radial) -4014 4716 0 0 1 0 0 1 0 0 Bg
+0 BB
+Pc
+0.125 0.25 0.125 0 k
+Pc
+0.25 0.5 0.25 0 k
+Pc
+0.375 0.75 0.375 0 k
+Pc
+0.5 1 0.5 0 k
+Pc
+0.125 0.25 0.25 0 k
+Pc
+0.25 0.5 0.5 0 k
+Pc
+0.375 0.75 0.75 0 k
+Pc
+0.5 1 1 0 k
+Pc
+0 0 0 0 k
+Pc
+0.125 0.125 0.25 0 k
+Pc
+0.25 0.25 0.5 0 k
+Pc
+0.375 0.375 0.75 0 k
+Pc
+0.5 0.5 1 0 k
+Pc
+0.25 0.125 0.25 0 k
+Pc
+0.5 0.25 0.5 0 k
+Pc
+0.75 0.375 0.75 0 k
+Pc
+1 0.5 1 0 k
+Pc
+PB
+%AI5_EndPalette
+%%EndSetup
+%AI5_BeginLayer
+1 1 1 1 0 0 0 79 128 255 Lb
+(Layer 1) Ln
+0 A
+800 Ar
+0 J 0 j 1 w 4 M []0 d
+%AI3_Note:
+0 D
+0 XR
+-4014 283.5 m
+4626 283.5 L
+(N) *
+453.5 4716 m
+453.5 -3924 L
+(N) *
+85 4716 m
+85 -3924 L
+(N) *
+-4014 765.5 m
+4626 765.5 L
+(N) *
+0 R
+0 G
+113 683.5 m
+439 683.5 l
+S
+113 663.5 m
+439 663.5 l
+S
+113 643.5 m
+439 643.5 l
+S
+113 686 m
+439 686 l
+S
+1 Ap
+439 624 m
+439 709 L
+113 709 L
+113 624 L
+439 624 L
+s
+0 Ap
+178.5 709 m
+178.5 624 l
+S
+243 709 m
+243 624 l
+S
+374 709 m
+374 624 l
+S
+308.5 709 m
+308.5 624 l
+S
+0 To
+1 0 0 1 146 692 0 Tp
+TP
+-12.2278 0 Td
+0 Tr
+0 O
+0 g
+/_Univers 10 Tf
+0 Ts
+100 Tz
+0 Tt
+1 TA
+%_ 0 XL
+36 0 Xb
+XB
+0 0 5 TC
+100 100 200 TW
+0 0 0 Ti
+1 Ta
+0 0 2 2 3 Th
+0 Tq
+0 0 Tl
+0 Tc
+0 Tw
+(key 1) Tx
+(\r) TX
+TO
+0 To
+1 0 0 1 213 692 0 Tp
+TP
+-12.2278 0 Td
+0 Tr
+(key 2) Tx
+(\r) TX
+TO
+0 To
+1 0 0 1 276 692 0 Tp
+TP
+-11.1121 0 Td
+0 Tr
+(col 3) Tx
+(\r) TX
+TO
+0 To
+1 0 0 1 225.5 747.5 0 Tp
+TP
+0 Tr
+(\r) Tx
+TO
+0 To
+1 0 0 1 336.5 693.5 0 Tp
+TP
+0 Tr
+(\r) Tx
+TO
+0 To
+1 0 0 1 341 692 0 Tp
+TP
+-11.1121 0 Td
+0 Tr
+(col 4) Tx
+(\r) TX
+TO
+0 To
+1 0 0 1 407.5 692 0 Tp
+TP
+-11.1121 0 Td
+0 Tr
+(col 5) Tx
+(\r) TX
+TO
+0 To
+1 0 0 1 185.5 736 0 Tp
+TP
+0 Tr
+(\r) Tx
+TO
+0 To
+1 0 0 1 145 669.5 0 Tp
+TP
+-2.7795 0 Td
+0 Tr
+(1) Tx
+(\r) TX
+TO
+0 To
+1 0 0 1 144.5 650.5 0 Tp
+TP
+-2.7795 0 Td
+0 Tr
+(1) Tx
+(\r) TX
+TO
+0 To
+1 0 0 1 145 630 0 Tp
+TP
+-2.7795 0 Td
+0 Tr
+(2) Tx
+(\r) TX
+TO
+0 To
+1 0 0 1 209.5 669 0 Tp
+TP
+-2.7795 0 Td
+0 Tr
+(1) Tx
+(\r) TX
+TO
+0 To
+1 0 0 1 209.5 649.5 0 Tp
+TP
+-2.7795 0 Td
+0 Tr
+(2) Tx
+(\r) TX
+TO
+0 To
+1 0 0 1 209.5 629.5 0 Tp
+TP
+-2.7795 0 Td
+0 Tr
+(1) Tx
+(\r) TX
+TO
+0 To
+1 0 0 1 274.5 669 0 Tp
+TP
+-2.7795 0 Td
+0 Tr
+(a) Tx
+(\r) TX
+TO
+0 To
+1 0 0 1 274.5 649.5 0 Tp
+TP
+-3.0542 0 Td
+0 Tr
+(d) Tx
+(\r) TX
+TO
+0 To
+1 0 0 1 274.5 629.5 0 Tp
+TP
+-3.0542 0 Td
+0 Tr
+(g) Tx
+(\r) TX
+TO
+0 To
+1 0 0 1 340 669 0 Tp
+TP
+-3.0542 0 Td
+0 Tr
+(b) Tx
+(\r) TX
+TO
+0 To
+1 0 0 1 340 649.5 0 Tp
+TP
+-2.7795 0 Td
+0 Tr
+(e) Tx
+(\r) TX
+TO
+0 To
+1 0 0 1 340 629.5 0 Tp
+TP
+-8.8879 0 Td
+0 Tr
+(N/A) Tx
+(\r) TX
+TO
+0 To
+1 0 0 1 405 669 0 Tp
+TP
+-2.5 0 Td
+0 Tr
+(c) Tx
+(\r) TX
+TO
+0 To
+1 0 0 1 405 649.5 0 Tp
+TP
+-1.6638 0 Td
+0 Tr
+(f) Tx
+(\r) TX
+TO
+0 To
+1 0 0 1 405 629.5 0 Tp
+TP
+-1.3892 0 Td
+0 Tr
+(i) Tx
+(\r) TX
+TO
+u
+1 Ap
+0 R
+0 G
+274.4998 662.9963 m
+279.1963 662.9963 283.0037 666.8037 283.0037 671.5002 c
+283.0037 676.1968 279.1963 680.0042 274.4998 680.0042 c
+269.8032 680.0042 265.9958 676.1968 265.9958 671.5002 c
+265.9958 666.8037 269.8032 662.9963 274.4998 662.9963 c
+s
+[3 4 3 4 3 4 ]0 d
+274.4998 643.4963 m
+279.1963 643.4963 283.0037 647.3037 283.0037 652.0002 c
+283.0037 656.6968 279.1963 660.5042 274.4998 660.5042 c
+269.8032 660.5042 265.9958 656.6968 265.9958 652.0002 c
+265.9958 647.3037 269.8032 643.4963 274.4998 643.4963 c
+s
+u
+u
+0 Ap
+[]0 d
+265.9958 671.5002 m
+251 671.5 250.5 662 v
+250.1312 654.9919 257.5 653 y
+S
+0 O
+0 g
+260.0476 653.373 m
+258.5818 654.2863 257.6645 655.0108 256.5229 655.8709 c
+255.2066 651.0014 l
+255.7237 651.0949 257.7835 651.333 259.5097 651.3831 c
+261.3573 651.4376 263.0016 651.3718 264.0403 651.2262 c
+263.0697 651.6237 261.6162 652.3953 260.0476 653.373 c
+f
+U
+U
+U
+u
+1 Ap
+0 R
+0 G
+404.9998 662.9963 m
+409.6963 662.9963 413.5037 666.8037 413.5037 671.5002 c
+413.5037 676.1968 409.6963 680.0042 404.9998 680.0042 c
+400.3032 680.0042 396.4958 676.1968 396.4958 671.5002 c
+396.4958 666.8037 400.3032 662.9963 404.9998 662.9963 c
+s
+[3 4 3 4 3 4 ]0 d
+404.9998 643.4963 m
+409.6963 643.4963 413.5037 647.3037 413.5037 652.0002 c
+413.5037 656.6968 409.6963 660.5042 404.9998 660.5042 c
+400.3032 660.5042 396.4958 656.6968 396.4958 652.0002 c
+396.4958 647.3037 400.3032 643.4963 404.9998 643.4963 c
+s
+u
+u
+0 Ap
+[]0 d
+396.4958 671.5002 m
+381.5 671.5 381 662 v
+380.6312 654.9919 388 653 y
+S
+0 O
+0 g
+390.5476 653.373 m
+389.0818 654.2863 388.1645 655.0108 387.0229 655.8709 c
+385.7066 651.0014 l
+386.2237 651.0949 388.2835 651.333 390.0097 651.3831 c
+391.8573 651.4376 393.5016 651.3718 394.5403 651.2262 c
+393.5697 651.6237 392.1162 652.3953 390.5476 653.373 c
+f
+U
+U
+U
+LB
+%AI5_EndLayer--
+%%PageTrailer
+gsave annotatepage grestore showpage
+%%Trailer
+Adobe_Illustrator_AI5 /terminate get exec
+Adobe_ColorImage_AI6 /terminate get exec
+Adobe_typography_AI5 /terminate get exec
+Adobe_level2_AI5 /terminate get exec
+%%EOF
diff --git a/lib/snmp/doc/src/getnext3.gif b/lib/snmp/doc/src/getnext3.gif
new file mode 100644
index 0000000000..2e37cbc6dd
--- /dev/null
+++ b/lib/snmp/doc/src/getnext3.gif
Binary files differ
diff --git a/lib/snmp/doc/src/getnext3.ps b/lib/snmp/doc/src/getnext3.ps
new file mode 100644
index 0000000000..1d1be88a12
--- /dev/null
+++ b/lib/snmp/doc/src/getnext3.ps
@@ -0,0 +1,3003 @@
+%!PS-Adobe-3.0 EPSF-3.0
+%%Creator: Adobe Illustrator(r) 6.0
+%%For: (Anna Fedoriw) (Ericsson Telecom)
+%%Title: (GetNext321.eps)
+%%CreationDate: (97-05-23) (14.04)
+%%BoundingBox: 112 579 440 757
+%%HiResBoundingBox: 112.5 579.5 439.5 756.8677
+%%DocumentProcessColors: Black
+%%DocumentFonts: Univers
+%%DocumentSuppliedResources: procset Adobe_level2_AI5 1.0 0
+%%+ procset Adobe_typography_AI5 1.0 0
+%%+ procset Adobe_Illustrator_AI6_vars Adobe_Illustrator_AI6
+%%+ procset Adobe_Illustrator_AI5 1.0 0
+%AI5_FileFormat 2.0
+%AI3_ColorUsage: Black&White
+%%AI6_ColorSeparationSet: 1 1 (AI6 Default Color Separation Set)
+%%+ Options: 1 16 0 1 0 1 1 1 0 1 1 1 1 18 0 0 0 0 0 0 0 0 -1 -1
+%%+ PPD: 1 21 0 0 60 45 2 2 1 0 0 1 0 0 0 0 0 0 0 0 0 0 ()
+%AI3_TemplateBox: 306 396 306 396
+%AI3_TileBox: 21 -12 588 802
+%AI3_DocumentPreview: Macintosh_ColorPic
+%AI5_ArtSize: 595.2756 841.8898
+%AI5_RulerUnits: 1
+%AI5_ArtFlags: 0 0 0 1 0 0 1 1 0
+%AI5_TargetResolution: 800
+%AI5_NumLayers: 1
+%AI5_OpenToView: 54 804 2 1146 827 58 1 1 3 40
+%AI5_OpenViewLayers: 7
+%%EndComments
+%%BeginProlog
+%%BeginResource: procset Adobe_level2_AI5 1.2 0
+%%Title: (Adobe Illustrator (R) Version 5.0 Level 2 Emulation)
+%%Version: 1.2
+%%CreationDate: (04/10/93) ()
+%%Copyright: ((C) 1987-1993 Adobe Systems Incorporated All Rights Reserved)
+userdict /Adobe_level2_AI5 23 dict dup begin
+ put
+ /packedarray where not
+ {
+ userdict begin
+ /packedarray
+ {
+ array astore readonly
+ } bind def
+ /setpacking /pop load def
+ /currentpacking false def
+ end
+ 0
+ } if
+ pop
+ userdict /defaultpacking currentpacking put true setpacking
+ /initialize
+ {
+ Adobe_level2_AI5 begin
+ } bind def
+ /terminate
+ {
+ currentdict Adobe_level2_AI5 eq
+ {
+ end
+ } if
+ } bind def
+ mark
+ /setcustomcolor where not
+ {
+ /findcmykcustomcolor
+ {
+ 5 packedarray
+ } bind def
+ /setcustomcolor
+ {
+ exch aload pop pop
+ 4
+ {
+ 4 index mul 4 1 roll
+ } repeat
+ 5 -1 roll pop
+ setcmykcolor
+ }
+ def
+ } if
+
+ /gt38? mark {version cvr cvx exec} stopped {cleartomark true} {38 gt exch pop} ifelse def
+ userdict /deviceDPI 72 0 matrix defaultmatrix dtransform dup mul exch dup mul add sqrt put
+ userdict /level2?
+ systemdict /languagelevel known dup
+ {
+ pop systemdict /languagelevel get 2 ge
+ } if
+ put
+/level2ScreenFreq
+{
+ begin
+ 60
+ HalftoneType 1 eq
+ {
+ pop Frequency
+ } if
+ HalftoneType 2 eq
+ {
+ pop GrayFrequency
+ } if
+ HalftoneType 5 eq
+ {
+ pop Default level2ScreenFreq
+ } if
+ end
+} bind def
+userdict /currentScreenFreq
+ level2? {currenthalftone level2ScreenFreq} {currentscreen pop pop} ifelse put
+level2? not
+ {
+ /setcmykcolor where not
+ {
+ /setcmykcolor
+ {
+ exch .11 mul add exch .59 mul add exch .3 mul add
+ 1 exch sub setgray
+ } def
+ } if
+ /currentcmykcolor where not
+ {
+ /currentcmykcolor
+ {
+ 0 0 0 1 currentgray sub
+ } def
+ } if
+ /setoverprint where not
+ {
+ /setoverprint /pop load def
+ } if
+ /selectfont where not
+ {
+ /selectfont
+ {
+ exch findfont exch
+ dup type /arraytype eq
+ {
+ makefont
+ }
+ {
+ scalefont
+ } ifelse
+ setfont
+ } bind def
+ } if
+ /cshow where not
+ {
+ /cshow
+ {
+ [
+ 0 0 5 -1 roll aload pop
+ ] cvx bind forall
+ } bind def
+ } if
+ } if
+ cleartomark
+ /anyColor?
+ {
+ add add add 0 ne
+ } bind def
+ /testColor
+ {
+ gsave
+ setcmykcolor currentcmykcolor
+ grestore
+ } bind def
+ /testCMYKColorThrough
+ {
+ testColor anyColor?
+ } bind def
+ userdict /composite?
+ level2?
+ {
+ gsave 1 1 1 1 setcmykcolor currentcmykcolor grestore
+ add add add 4 eq
+ }
+ {
+ 1 0 0 0 testCMYKColorThrough
+ 0 1 0 0 testCMYKColorThrough
+ 0 0 1 0 testCMYKColorThrough
+ 0 0 0 1 testCMYKColorThrough
+ and and and
+ } ifelse
+ put
+ composite? not
+ {
+ userdict begin
+ gsave
+ /cyan? 1 0 0 0 testCMYKColorThrough def
+ /magenta? 0 1 0 0 testCMYKColorThrough def
+ /yellow? 0 0 1 0 testCMYKColorThrough def
+ /black? 0 0 0 1 testCMYKColorThrough def
+ grestore
+ /isCMYKSep? cyan? magenta? yellow? black? or or or def
+ /customColor? isCMYKSep? not def
+ end
+ } if
+ end defaultpacking setpacking
+%%EndResource
+%%BeginResource: procset Adobe_typography_AI5 1.0 1
+%%Title: (Typography Operators)
+%%Version: 1.0
+%%CreationDate:(03/26/93) ()
+%%Copyright: ((C) 1987-1993 Adobe Systems Incorporated All Rights Reserved)
+currentpacking true setpacking
+userdict /Adobe_typography_AI5 54 dict dup begin
+put
+/initialize
+{
+ begin
+ begin
+ Adobe_typography_AI5 begin
+ Adobe_typography_AI5
+ {
+ dup xcheck
+ {
+ bind
+ } if
+ pop pop
+ } forall
+ end
+ end
+ end
+ Adobe_typography_AI5 begin
+} def
+/terminate
+{
+ currentdict Adobe_typography_AI5 eq
+ {
+ end
+ } if
+} def
+/modifyEncoding
+{
+ /_tempEncode exch ddef
+ /_pntr 0 ddef
+ {
+ counttomark -1 roll
+ dup type dup /marktype eq
+ {
+ pop pop exit
+ }
+ {
+ /nametype eq
+ {
+ _tempEncode /_pntr dup load dup 3 1 roll 1 add ddef 3 -1 roll
+ put
+ }
+ {
+ /_pntr exch ddef
+ } ifelse
+ } ifelse
+ } loop
+ _tempEncode
+} def
+/TE
+{
+ StandardEncoding 256 array copy modifyEncoding
+ /_nativeEncoding exch def
+} def
+%
+/TZ
+{
+ dup type /arraytype eq
+ {
+ /_wv exch def
+ }
+ {
+ /_wv 0 def
+ } ifelse
+ /_useNativeEncoding exch def
+ pop pop
+ findfont _wv type /arraytype eq
+ {
+ _wv makeblendedfont
+ } if
+ dup length 2 add dict
+ begin
+ mark exch
+ {
+ 1 index /FID ne
+ {
+ def
+ } if
+ cleartomark mark
+ } forall
+ pop
+ /FontName exch def
+ counttomark 0 eq
+ {
+ 1 _useNativeEncoding eq
+ {
+ /Encoding _nativeEncoding def
+ } if
+ cleartomark
+ }
+ {
+ /Encoding load 256 array copy
+ modifyEncoding /Encoding exch def
+ } ifelse
+ FontName currentdict
+ end
+ definefont pop
+} def
+/tr
+{
+ _ax _ay 3 2 roll
+} def
+/trj
+{
+ _cx _cy _sp _ax _ay 6 5 roll
+} def
+/a0
+{
+ /Tx
+ {
+ dup
+ currentpoint 3 2 roll
+ tr _psf
+ newpath moveto
+ tr _ctm _pss
+ } ddef
+ /Tj
+ {
+ dup
+ currentpoint 3 2 roll
+ trj _pjsf
+ newpath moveto
+ trj _ctm _pjss
+ } ddef
+} def
+/a1
+{
+ /Tx
+ {
+ dup currentpoint 4 2 roll gsave
+ dup currentpoint 3 2 roll
+ tr _psf
+ newpath moveto
+ tr _ctm _pss
+ grestore 3 1 roll moveto tr sp
+ } ddef
+ /Tj
+ {
+ dup currentpoint 4 2 roll gsave
+ dup currentpoint 3 2 roll
+ trj _pjsf
+ newpath moveto
+ trj _ctm _pjss
+ grestore 3 1 roll moveto tr jsp
+ } ddef
+} def
+/e0
+{
+ /Tx
+ {
+ tr _psf
+ } ddef
+ /Tj
+ {
+ trj _pjsf
+ } ddef
+} def
+/e1
+{
+ /Tx
+ {
+ dup currentpoint 4 2 roll gsave
+ tr _psf
+ grestore 3 1 roll moveto tr sp
+ } ddef
+ /Tj
+ {
+ dup currentpoint 4 2 roll gsave
+ trj _pjsf
+ grestore 3 1 roll moveto tr jsp
+ } ddef
+} def
+/i0
+{
+ /Tx
+ {
+ tr sp
+ } ddef
+ /Tj
+ {
+ trj jsp
+ } ddef
+} def
+/i1
+{
+ W N
+} def
+/o0
+{
+ /Tx
+ {
+ tr sw rmoveto
+ } ddef
+ /Tj
+ {
+ trj swj rmoveto
+ } ddef
+} def
+/r0
+{
+ /Tx
+ {
+ tr _ctm _pss
+ } ddef
+ /Tj
+ {
+ trj _ctm _pjss
+ } ddef
+} def
+/r1
+{
+ /Tx
+ {
+ dup currentpoint 4 2 roll currentpoint gsave newpath moveto
+ tr _ctm _pss
+ grestore 3 1 roll moveto tr sp
+ } ddef
+ /Tj
+ {
+ dup currentpoint 4 2 roll currentpoint gsave newpath moveto
+ trj _ctm _pjss
+ grestore 3 1 roll moveto tr jsp
+ } ddef
+} def
+/To
+{
+ pop _ctm currentmatrix pop
+} def
+/TO
+{
+ iTe _ctm setmatrix newpath
+} def
+/Tp
+{
+ pop _tm astore pop _ctm setmatrix
+ _tDict begin
+ /W
+ {
+ } def
+ /h
+ {
+ } def
+} def
+/TP
+{
+ end
+ iTm 0 0 moveto
+} def
+/Tr
+{
+ _render 3 le
+ {
+ currentpoint newpath moveto
+ } if
+ dup 8 eq
+ {
+ pop 0
+ }
+ {
+ dup 9 eq
+ {
+ pop 1
+ } if
+ } ifelse
+ dup /_render exch ddef
+ _renderStart exch get load exec
+} def
+/iTm
+{
+ _ctm setmatrix _tm concat 0 _rise translate _hs 1 scale
+} def
+/Tm
+{
+ _tm astore pop iTm 0 0 moveto
+} def
+/Td
+{
+ _mtx translate _tm _tm concatmatrix pop iTm 0 0 moveto
+} def
+/iTe
+{
+ _render -1 eq
+ {
+ }
+ {
+ _renderEnd _render get dup null ne
+ {
+ load exec
+ }
+ {
+ pop
+ } ifelse
+ } ifelse
+ /_render -1 ddef
+} def
+/Ta
+{
+ pop
+} def
+/Tf
+{
+ dup 1000 div /_fScl exch ddef
+%
+ selectfont
+} def
+/Tl
+{
+ pop
+ 0 exch _leading astore pop
+} def
+/Tt
+{
+ pop
+} def
+/TW
+{
+ 3 npop
+} def
+/Tw
+{
+ /_cx exch ddef
+} def
+/TC
+{
+ 3 npop
+} def
+/Tc
+{
+ /_ax exch ddef
+} def
+/Ts
+{
+ /_rise exch ddef
+ currentpoint
+ iTm
+ moveto
+} def
+/Ti
+{
+ 3 npop
+} def
+/Tz
+{
+ 100 div /_hs exch ddef
+ iTm
+} def
+/TA
+{
+ pop
+} def
+/Tq
+{
+ pop
+} def
+/Th
+{
+ pop pop pop pop pop
+} def
+/TX
+{
+ pop
+} def
+/Tk
+{
+ exch pop _fScl mul neg 0 rmoveto
+} def
+/TK
+{
+ 2 npop
+} def
+/T*
+{
+ _leading aload pop neg Td
+} def
+/T*-
+{
+ _leading aload pop Td
+} def
+/T-
+{
+ _ax neg 0 rmoveto
+ _hyphen Tx
+} def
+/T+
+{
+} def
+/TR
+{
+ _ctm currentmatrix pop
+ _tm astore pop
+ iTm 0 0 moveto
+} def
+/TS
+{
+ currentfont 3 1 roll
+ /_Symbol_ _fScl 1000 mul selectfont
+
+ 0 eq
+ {
+ Tx
+ }
+ {
+ Tj
+ } ifelse
+ setfont
+} def
+/Xb
+{
+ pop pop
+} def
+/Tb /Xb load def
+/Xe
+{
+ pop pop pop pop
+} def
+/Te /Xe load def
+/XB
+{
+} def
+/TB /XB load def
+currentdict readonly pop
+end
+setpacking
+%%EndResource
+%%BeginProcSet: Adobe_ColorImage_AI6 1.0 0
+userdict /Adobe_ColorImage_AI6 known not
+{
+ userdict /Adobe_ColorImage_AI6 17 dict put
+} if
+userdict /Adobe_ColorImage_AI6 get begin
+
+ /initialize
+ {
+ Adobe_ColorImage_AI6 begin
+ Adobe_ColorImage_AI6
+ {
+ dup type /arraytype eq
+ {
+ dup xcheck
+ {
+ bind
+ } if
+ } if
+ pop pop
+ } forall
+ } def
+ /terminate { end } def
+
+ currentdict /Adobe_ColorImage_AI6_Vars known not
+ {
+ /Adobe_ColorImage_AI6_Vars 14 dict def
+ } if
+
+ Adobe_ColorImage_AI6_Vars begin
+ /channelcount 0 def
+ /sourcecount 0 def
+ /sourcearray 4 array def
+ /plateindex -1 def
+ /XIMask 0 def
+ /XIBinary 0 def
+ /XIChannelCount 0 def
+ /XIBitsPerPixel 0 def
+ /XIImageHeight 0 def
+ /XIImageWidth 0 def
+ /XIImageMatrix null def
+ /XIBuffer null def
+ /XIDataProc null def
+ end
+
+ /WalkRGBString null def
+ /WalkCMYKString null def
+
+ /StuffRGBIntoGrayString null def
+ /RGBToGrayImageProc null def
+ /StuffCMYKIntoGrayString null def
+ /CMYKToGrayImageProc null def
+ /ColorImageCompositeEmulator null def
+
+ /SeparateCMYKImageProc null def
+
+ /FourEqual null def
+ /TestPlateIndex null def
+
+ currentdict /_colorimage known not
+ {
+ /colorimage where
+ {
+ /colorimage get /_colorimage exch def
+ }
+ {
+ /_colorimage null def
+ } ifelse
+ } if
+
+ /_currenttransfer systemdict /currenttransfer get def
+
+ /colorimage null def
+ /XI null def
+
+
+ /WalkRGBString
+ {
+ 0 3 index
+
+ dup length 1 sub 0 3 3 -1 roll
+ {
+ 3 getinterval { } forall
+
+ 5 index exec
+
+ 3 index
+ } for
+
+ 5 { pop } repeat
+
+ } def
+
+
+ /WalkCMYKString
+ {
+ 0 3 index
+
+ dup length 1 sub 0 4 3 -1 roll
+ {
+ 4 getinterval { } forall
+
+ 6 index exec
+
+ 3 index
+
+ } for
+
+ 5 { pop } repeat
+
+ } def
+
+
+ /StuffRGBIntoGrayString
+ {
+ .11 mul exch
+
+ .59 mul add exch
+
+ .3 mul add
+
+ cvi 3 copy put
+
+ pop 1 add
+ } def
+
+
+ /RGBToGrayImageProc
+ {
+ Adobe_ColorImage_AI6_Vars begin
+ sourcearray 0 get exec
+ dup length 3 idiv string
+ dup 3 1 roll
+
+ /StuffRGBIntoGrayString load exch
+ WalkRGBString
+ end
+ } def
+
+
+ /StuffCMYKIntoGrayString
+ {
+ exch .11 mul add
+
+ exch .59 mul add
+
+ exch .3 mul add
+
+ dup 255 gt { pop 255 } if
+
+ 255 exch sub cvi 3 copy put
+
+ pop 1 add
+ } def
+
+
+ /CMYKToGrayImageProc
+ {
+ Adobe_ColorImage_AI6_Vars begin
+ sourcearray 0 get exec
+ dup length 4 idiv string
+ dup 3 1 roll
+
+ /StuffCMYKIntoGrayString load exch
+ WalkCMYKString
+ end
+ } def
+
+
+ /ColorImageCompositeEmulator
+ {
+ pop true eq
+ {
+ Adobe_ColorImage_AI6_Vars /sourcecount get 5 add { pop } repeat
+ }
+ {
+ Adobe_ColorImage_AI6_Vars /channelcount get 1 ne
+ {
+ Adobe_ColorImage_AI6_Vars begin
+ sourcearray 0 3 -1 roll put
+
+ channelcount 3 eq
+ {
+ /RGBToGrayImageProc
+ }
+ {
+ /CMYKToGrayImageProc
+ } ifelse
+ load
+ end
+ } if
+ image
+ } ifelse
+ } def
+
+
+ /SeparateCMYKImageProc
+ {
+ Adobe_ColorImage_AI6_Vars begin
+
+ sourcecount 0 ne
+ {
+ sourcearray plateindex get exec
+ }
+ {
+ sourcearray 0 get exec
+
+ dup length 4 idiv string
+
+ 0 2 index
+
+ plateindex 4 2 index length 1 sub
+ {
+ get 255 exch sub
+
+ 3 copy put pop 1 add
+
+ 2 index
+ } for
+
+ pop pop exch pop
+ } ifelse
+ end
+ } def
+
+
+ /FourEqual
+ {
+ 4 index ne
+ {
+ pop pop pop false
+ }
+ {
+ 4 index ne
+ {
+ pop pop false
+ }
+ {
+ 4 index ne
+ {
+ pop false
+ }
+ {
+ 4 index eq
+ } ifelse
+ } ifelse
+ } ifelse
+ } def
+
+
+ /TestPlateIndex
+ {
+ Adobe_ColorImage_AI6_Vars begin
+ /plateindex -1 def
+
+ /setcmykcolor where
+ {
+ pop
+ gsave
+ 1 0 0 0 setcmykcolor systemdict /currentgray get exec 1 exch sub
+ 0 1 0 0 setcmykcolor systemdict /currentgray get exec 1 exch sub
+ 0 0 1 0 setcmykcolor systemdict /currentgray get exec 1 exch sub
+ 0 0 0 1 setcmykcolor systemdict /currentgray get exec 1 exch sub
+ grestore
+
+ 1 0 0 0 FourEqual
+ {
+ /plateindex 0 def
+ }
+ {
+ 0 1 0 0 FourEqual
+ {
+ /plateindex 1 def
+ }
+ {
+ 0 0 1 0 FourEqual
+ {
+ /plateindex 2 def
+ }
+ {
+ 0 0 0 1 FourEqual
+ {
+ /plateindex 3 def
+ }
+ {
+ 0 0 0 0 FourEqual
+ {
+ /plateindex 5 def
+ } if
+ } ifelse
+ } ifelse
+ } ifelse
+ } ifelse
+ pop pop pop pop
+ } if
+ plateindex
+ end
+ } def
+
+
+ /colorimage
+ {
+ Adobe_ColorImage_AI6_Vars begin
+ /channelcount 1 index def
+ /sourcecount 2 index 1 eq { channelcount 1 sub } { 0 } ifelse def
+
+ 4 sourcecount add index dup
+ 8 eq exch 1 eq or not
+ end
+
+ {
+ /_colorimage load null ne
+ {
+ _colorimage
+ }
+ {
+ Adobe_ColorImage_AI6_Vars /sourcecount get
+ 7 add { pop } repeat
+ } ifelse
+ }
+ {
+ dup 3 eq
+ TestPlateIndex
+ dup -1 eq exch 5 eq or or
+ {
+ /_colorimage load null eq
+ {
+ ColorImageCompositeEmulator
+ }
+ {
+ dup 1 eq
+ {
+ pop pop image
+ }
+ {
+ Adobe_ColorImage_AI6_Vars /plateindex get 5 eq
+ {
+ gsave
+
+ 0 _currenttransfer exec
+ 1 _currenttransfer exec
+ eq
+ { 0 _currenttransfer exec 0.5 lt }
+ { 0 _currenttransfer exec 1 _currenttransfer exec gt } ifelse
+
+ { { pop 0 } } { { pop 1 } } ifelse
+ systemdict /settransfer get exec
+ } if
+
+ _colorimage
+
+ Adobe_ColorImage_AI6_Vars /plateindex get 5 eq
+ {
+ grestore
+ } if
+ } ifelse
+ } ifelse
+ }
+ {
+ dup 1 eq
+ {
+ pop pop
+ image
+ }
+ {
+ pop pop
+
+ Adobe_ColorImage_AI6_Vars begin
+ sourcecount -1 0
+ {
+ exch sourcearray 3 1 roll put
+ } for
+
+ /SeparateCMYKImageProc load
+ end
+
+ systemdict /image get exec
+ } ifelse
+ } ifelse
+ } ifelse
+ } def
+
+ /XI
+ {
+ Adobe_ColorImage_AI6_Vars begin
+ gsave
+ /XIMask exch 0 ne def
+ /XIBinary exch 0 ne def
+ pop
+ pop
+ /XIChannelCount exch def
+ /XIBitsPerPixel exch def
+ /XIImageHeight exch def
+ /XIImageWidth exch def
+ pop pop pop pop
+ /XIImageMatrix exch def
+
+ XIBitsPerPixel 1 eq
+ {
+ XIImageWidth 8 div ceiling cvi
+ }
+ {
+ XIImageWidth XIChannelCount mul
+ } ifelse
+ /XIBuffer exch string def
+
+ XIBinary
+ {
+ /XIDataProc { currentfile XIBuffer readstring pop } def
+ currentfile 128 string readline pop pop
+ }
+ {
+ /XIDataProc { currentfile XIBuffer readhexstring pop } def
+ } ifelse
+
+ 0 0 moveto
+ XIImageMatrix concat
+ XIImageWidth XIImageHeight scale
+
+ XIMask
+ {
+ XIImageWidth XIImageHeight
+ false
+ [ XIImageWidth 0 0 XIImageHeight neg 0 0 ]
+ /XIDataProc load
+
+ /_lp /null ddef
+ _fc
+ /_lp /imagemask ddef
+
+ imagemask
+ }
+ {
+ XIImageWidth XIImageHeight
+ XIBitsPerPixel
+ [ XIImageWidth 0 0 XIImageHeight neg 0 0 ]
+ /XIDataProc load
+
+ XIChannelCount 1 eq
+ {
+
+ gsave
+ 0 setgray
+
+ image
+
+ grestore
+ }
+ {
+ false
+ XIChannelCount
+ colorimage
+ } ifelse
+ } ifelse
+ grestore
+ end
+ } def
+
+end
+%%EndProcSet
+%%BeginResource: procset Adobe_Illustrator_AI5 1.1 0
+%%Title: (Adobe Illustrator (R) Version 5.0 Full Prolog)
+%%Version: 1.1
+%%CreationDate: (3/7/1994) ()
+%%Copyright: ((C) 1987-1994 Adobe Systems Incorporated All Rights Reserved)
+currentpacking true setpacking
+userdict /Adobe_Illustrator_AI5_vars 81 dict dup begin
+put
+/_eo false def
+/_lp /none def
+/_pf
+{
+} def
+/_ps
+{
+} def
+/_psf
+{
+} def
+/_pss
+{
+} def
+/_pjsf
+{
+} def
+/_pjss
+{
+} def
+/_pola 0 def
+/_doClip 0 def
+/cf currentflat def
+/_tm matrix def
+/_renderStart
+[
+/e0 /r0 /a0 /o0 /e1 /r1 /a1 /i0
+] def
+/_renderEnd
+[
+null null null null /i1 /i1 /i1 /i1
+] def
+/_render -1 def
+/_rise 0 def
+/_ax 0 def
+/_ay 0 def
+/_cx 0 def
+/_cy 0 def
+/_leading
+[
+0 0
+] def
+/_ctm matrix def
+/_mtx matrix def
+/_sp 16#020 def
+/_hyphen (-) def
+/_fScl 0 def
+/_cnt 0 def
+/_hs 1 def
+/_nativeEncoding 0 def
+/_useNativeEncoding 0 def
+/_tempEncode 0 def
+/_pntr 0 def
+/_tDict 2 dict def
+/_wv 0 def
+/Tx
+{
+} def
+/Tj
+{
+} def
+/CRender
+{
+} def
+/_AI3_savepage
+{
+} def
+/_gf null def
+/_cf 4 array def
+/_if null def
+/_of false def
+/_fc
+{
+} def
+/_gs null def
+/_cs 4 array def
+/_is null def
+/_os false def
+/_sc
+{
+} def
+/_pd 1 dict def
+/_ed 15 dict def
+/_pm matrix def
+/_fm null def
+/_fd null def
+/_fdd null def
+/_sm null def
+/_sd null def
+/_sdd null def
+/_i null def
+/discardSave null def
+/buffer 256 string def
+/beginString null def
+/endString null def
+/endStringLength null def
+/layerCnt 1 def
+/layerCount 1 def
+/perCent (%) 0 get def
+/perCentSeen? false def
+/newBuff null def
+/newBuffButFirst null def
+/newBuffLast null def
+/clipForward? false def
+end
+userdict /Adobe_Illustrator_AI5 known not {
+ userdict /Adobe_Illustrator_AI5 91 dict put
+} if
+userdict /Adobe_Illustrator_AI5 get begin
+/initialize
+{
+ Adobe_Illustrator_AI5 dup begin
+ Adobe_Illustrator_AI5_vars begin
+ discardDict
+ {
+ bind pop pop
+ } forall
+ dup /nc get begin
+ {
+ dup xcheck 1 index type /operatortype ne and
+ {
+ bind
+ } if
+ pop pop
+ } forall
+ end
+ newpath
+} def
+/terminate
+{
+ end
+ end
+} def
+/_
+null def
+/ddef
+{
+ Adobe_Illustrator_AI5_vars 3 1 roll put
+} def
+/xput
+{
+ dup load dup length exch maxlength eq
+ {
+ dup dup load dup
+ length 2 mul dict copy def
+ } if
+ load begin
+ def
+ end
+} def
+/npop
+{
+ {
+ pop
+ } repeat
+} def
+/sw
+{
+ dup length exch stringwidth
+ exch 5 -1 roll 3 index mul add
+ 4 1 roll 3 1 roll mul add
+} def
+/swj
+{
+ dup 4 1 roll
+ dup length exch stringwidth
+ exch 5 -1 roll 3 index mul add
+ 4 1 roll 3 1 roll mul add
+ 6 2 roll /_cnt 0 ddef
+ {
+ 1 index eq
+ {
+ /_cnt _cnt 1 add ddef
+ } if
+ } forall
+ pop
+ exch _cnt mul exch _cnt mul 2 index add 4 1 roll 2 index add 4 1 roll pop pop
+} def
+/ss
+{
+ 4 1 roll
+ {
+ 2 npop
+ (0) exch 2 copy 0 exch put pop
+ gsave
+ false charpath currentpoint
+ 4 index setmatrix
+ stroke
+ grestore
+ moveto
+ 2 copy rmoveto
+ } exch cshow
+ 3 npop
+} def
+/jss
+{
+ 4 1 roll
+ {
+ 2 npop
+ (0) exch 2 copy 0 exch put
+ gsave
+ _sp eq
+ {
+ exch 6 index 6 index 6 index 5 -1 roll widthshow
+ currentpoint
+ }
+ {
+ false charpath currentpoint
+ 4 index setmatrix stroke
+ } ifelse
+ grestore
+ moveto
+ 2 copy rmoveto
+ } exch cshow
+ 6 npop
+} def
+/sp
+{
+ {
+ 2 npop (0) exch
+ 2 copy 0 exch put pop
+ false charpath
+ 2 copy rmoveto
+ } exch cshow
+ 2 npop
+} def
+/jsp
+{
+ {
+ 2 npop
+ (0) exch 2 copy 0 exch put
+ _sp eq
+ {
+ exch 5 index 5 index 5 index 5 -1 roll widthshow
+ }
+ {
+ false charpath
+ } ifelse
+ 2 copy rmoveto
+ } exch cshow
+ 5 npop
+} def
+/pl
+{
+ transform
+ 0.25 sub round 0.25 add exch
+ 0.25 sub round 0.25 add exch
+ itransform
+} def
+/setstrokeadjust where
+{
+ pop true setstrokeadjust
+ /c
+ {
+ curveto
+ } def
+ /C
+ /c load def
+ /v
+ {
+ currentpoint 6 2 roll curveto
+ } def
+ /V
+ /v load def
+ /y
+ {
+ 2 copy curveto
+ } def
+ /Y
+ /y load def
+ /l
+ {
+ lineto
+ } def
+ /L
+ /l load def
+ /m
+ {
+ moveto
+ } def
+}
+{
+ /c
+ {
+ pl curveto
+ } def
+ /C
+ /c load def
+ /v
+ {
+ currentpoint 6 2 roll pl curveto
+ } def
+ /V
+ /v load def
+ /y
+ {
+ pl 2 copy curveto
+ } def
+ /Y
+ /y load def
+ /l
+ {
+ pl lineto
+ } def
+ /L
+ /l load def
+ /m
+ {
+ pl moveto
+ } def
+} ifelse
+/d
+{
+ setdash
+} def
+/cf
+{
+} def
+/i
+{
+ dup 0 eq
+ {
+ pop cf
+ } if
+ setflat
+} def
+/j
+{
+ setlinejoin
+} def
+/J
+{
+ setlinecap
+} def
+/M
+{
+ setmiterlimit
+} def
+/w
+{
+ setlinewidth
+} def
+/XR
+{
+ 0 ne
+ /_eo exch ddef
+} def
+/H
+{
+} def
+/h
+{
+ closepath
+} def
+/N
+{
+ _pola 0 eq
+ {
+ _doClip 1 eq
+ {
+ _eo {eoclip} {clip} ifelse /_doClip 0 ddef
+ } if
+ newpath
+ }
+ {
+ /CRender
+ {
+ N
+ } ddef
+ } ifelse
+} def
+/n
+{
+ N
+} def
+/F
+{
+ _pola 0 eq
+ {
+ _doClip 1 eq
+ {
+ gsave _pf grestore _eo {eoclip} {clip} ifelse newpath /_lp /none ddef _fc
+ /_doClip 0 ddef
+ }
+ {
+ _pf
+ } ifelse
+ }
+ {
+ /CRender
+ {
+ F
+ } ddef
+ } ifelse
+} def
+/f
+{
+ closepath
+ F
+} def
+/S
+{
+ _pola 0 eq
+ {
+ _doClip 1 eq
+ {
+ gsave _ps grestore _eo {eoclip} {clip} ifelse newpath /_lp /none ddef _sc
+ /_doClip 0 ddef
+ }
+ {
+ _ps
+ } ifelse
+ }
+ {
+ /CRender
+ {
+ S
+ } ddef
+ } ifelse
+} def
+/s
+{
+ closepath
+ S
+} def
+/B
+{
+ _pola 0 eq
+ {
+ _doClip 1 eq
+ gsave F grestore
+ {
+ gsave S grestore _eo {eoclip} {clip} ifelse newpath /_lp /none ddef _sc
+ /_doClip 0 ddef
+ }
+ {
+ S
+ } ifelse
+ }
+ {
+ /CRender
+ {
+ B
+ } ddef
+ } ifelse
+} def
+/b
+{
+ closepath
+ B
+} def
+/W
+{
+ /_doClip 1 ddef
+} def
+/*
+{
+ count 0 ne
+ {
+ dup type /stringtype eq
+ {
+ pop
+ } if
+ } if
+ newpath
+} def
+/u
+{
+} def
+/U
+{
+} def
+/q
+{
+ _pola 0 eq
+ {
+ gsave
+ } if
+} def
+/Q
+{
+ _pola 0 eq
+ {
+ grestore
+ } if
+} def
+/*u
+{
+ _pola 1 add /_pola exch ddef
+} def
+/*U
+{
+ _pola 1 sub /_pola exch ddef
+ _pola 0 eq
+ {
+ CRender
+ } if
+} def
+/D
+{
+ pop
+} def
+/*w
+{
+} def
+/*W
+{
+} def
+/`
+{
+ /_i save ddef
+ clipForward?
+ {
+ nulldevice
+ } if
+ 6 1 roll 4 npop
+ concat pop
+ userdict begin
+ /showpage
+ {
+ } def
+ 0 setgray
+ 0 setlinecap
+ 1 setlinewidth
+ 0 setlinejoin
+ 10 setmiterlimit
+ [] 0 setdash
+ /setstrokeadjust where {pop false setstrokeadjust} if
+ newpath
+ 0 setgray
+ false setoverprint
+} def
+/~
+{
+ end
+ _i restore
+} def
+/O
+{
+ 0 ne
+ /_of exch ddef
+ /_lp /none ddef
+} def
+/R
+{
+ 0 ne
+ /_os exch ddef
+ /_lp /none ddef
+} def
+/g
+{
+ /_gf exch ddef
+ /_fc
+ {
+ _lp /fill ne
+ {
+ _of setoverprint
+ _gf setgray
+ /_lp /fill ddef
+ } if
+ } ddef
+ /_pf
+ {
+ _fc
+ _eo {eofill} {fill} ifelse
+ } ddef
+ /_psf
+ {
+ _fc
+ ashow
+ } ddef
+ /_pjsf
+ {
+ _fc
+ awidthshow
+ } ddef
+ /_lp /none ddef
+} def
+/G
+{
+ /_gs exch ddef
+ /_sc
+ {
+ _lp /stroke ne
+ {
+ _os setoverprint
+ _gs setgray
+ /_lp /stroke ddef
+ } if
+ } ddef
+ /_ps
+ {
+ _sc
+ stroke
+ } ddef
+ /_pss
+ {
+ _sc
+ ss
+ } ddef
+ /_pjss
+ {
+ _sc
+ jss
+ } ddef
+ /_lp /none ddef
+} def
+/k
+{
+ _cf astore pop
+ /_fc
+ {
+ _lp /fill ne
+ {
+ _of setoverprint
+ _cf aload pop setcmykcolor
+ /_lp /fill ddef
+ } if
+ } ddef
+ /_pf
+ {
+ _fc
+ _eo {eofill} {fill} ifelse
+ } ddef
+ /_psf
+ {
+ _fc
+ ashow
+ } ddef
+ /_pjsf
+ {
+ _fc
+ awidthshow
+ } ddef
+ /_lp /none ddef
+} def
+/K
+{
+ _cs astore pop
+ /_sc
+ {
+ _lp /stroke ne
+ {
+ _os setoverprint
+ _cs aload pop setcmykcolor
+ /_lp /stroke ddef
+ } if
+ } ddef
+ /_ps
+ {
+ _sc
+ stroke
+ } ddef
+ /_pss
+ {
+ _sc
+ ss
+ } ddef
+ /_pjss
+ {
+ _sc
+ jss
+ } ddef
+ /_lp /none ddef
+} def
+/x
+{
+ /_gf exch ddef
+ findcmykcustomcolor
+ /_if exch ddef
+ /_fc
+ {
+ _lp /fill ne
+ {
+ _of setoverprint
+ _if _gf 1 exch sub setcustomcolor
+ /_lp /fill ddef
+ } if
+ } ddef
+ /_pf
+ {
+ _fc
+ _eo {eofill} {fill} ifelse
+ } ddef
+ /_psf
+ {
+ _fc
+ ashow
+ } ddef
+ /_pjsf
+ {
+ _fc
+ awidthshow
+ } ddef
+ /_lp /none ddef
+} def
+/X
+{
+ /_gs exch ddef
+ findcmykcustomcolor
+ /_is exch ddef
+ /_sc
+ {
+ _lp /stroke ne
+ {
+ _os setoverprint
+ _is _gs 1 exch sub setcustomcolor
+ /_lp /stroke ddef
+ } if
+ } ddef
+ /_ps
+ {
+ _sc
+ stroke
+ } ddef
+ /_pss
+ {
+ _sc
+ ss
+ } ddef
+ /_pjss
+ {
+ _sc
+ jss
+ } ddef
+ /_lp /none ddef
+} def
+/A
+{
+ pop
+} def
+/annotatepage
+{
+userdict /annotatepage 2 copy known {get exec} {pop pop} ifelse
+} def
+/XT {
+ pop pop
+} def
+/discard
+{
+ save /discardSave exch store
+ discardDict begin
+ /endString exch store
+ gt38?
+ {
+ 2 add
+ } if
+ load
+ stopped
+ pop
+ end
+ discardSave restore
+} bind def
+userdict /discardDict 7 dict dup begin
+put
+/pre38Initialize
+{
+ /endStringLength endString length store
+ /newBuff buffer 0 endStringLength getinterval store
+ /newBuffButFirst newBuff 1 endStringLength 1 sub getinterval store
+ /newBuffLast newBuff endStringLength 1 sub 1 getinterval store
+} def
+/shiftBuffer
+{
+ newBuff 0 newBuffButFirst putinterval
+ newBuffLast 0
+ currentfile read not
+ {
+ stop
+ } if
+ put
+} def
+0
+{
+ pre38Initialize
+ mark
+ currentfile newBuff readstring exch pop
+ {
+ {
+ newBuff endString eq
+ {
+ cleartomark stop
+ } if
+ shiftBuffer
+ } loop
+ }
+ {
+ stop
+ } ifelse
+} def
+1
+{
+ pre38Initialize
+ /beginString exch store
+ mark
+ currentfile newBuff readstring exch pop
+ {
+ {
+ newBuff beginString eq
+ {
+ /layerCount dup load 1 add store
+ }
+ {
+ newBuff endString eq
+ {
+ /layerCount dup load 1 sub store
+ layerCount 0 eq
+ {
+ cleartomark stop
+ } if
+ } if
+ } ifelse
+ shiftBuffer
+ } loop
+ } if
+} def
+2
+{
+ mark
+ {
+ currentfile buffer readline not
+ {
+ stop
+ } if
+ endString eq
+ {
+ cleartomark stop
+ } if
+ } loop
+} def
+3
+{
+ /beginString exch store
+ /layerCnt 1 store
+ mark
+ {
+ currentfile buffer readline not
+ {
+ stop
+ } if
+ dup beginString eq
+ {
+ pop /layerCnt dup load 1 add store
+ }
+ {
+ endString eq
+ {
+ layerCnt 1 eq
+ {
+ cleartomark stop
+ }
+ {
+ /layerCnt dup load 1 sub store
+ } ifelse
+ } if
+ } ifelse
+ } loop
+} def
+end
+userdict /clipRenderOff 15 dict dup begin
+put
+{
+ /n /N /s /S /f /F /b /B
+}
+{
+ {
+ _doClip 1 eq
+ {
+ /_doClip 0 ddef _eo {eoclip} {clip} ifelse
+ } if
+ newpath
+ } def
+} forall
+/Tr /pop load def
+/Bb {} def
+/BB /pop load def
+/Bg {12 npop} def
+/Bm {6 npop} def
+/Bc /Bm load def
+/Bh {4 npop} def
+end
+/Lb
+{
+ 4 npop
+ 6 1 roll
+ pop
+ 4 1 roll
+ pop pop pop
+ 0 eq
+ {
+ 0 eq
+ {
+ (%AI5_BeginLayer) 1 (%AI5_EndLayer--) discard
+ }
+ {
+
+ /clipForward? true def
+
+ /Tx /pop load def
+ /Tj /pop load def
+
+ currentdict end clipRenderOff begin begin
+ } ifelse
+ }
+ {
+ 0 eq
+ {
+ save /discardSave exch store
+ } if
+ } ifelse
+} bind def
+/LB
+{
+ discardSave dup null ne
+ {
+ restore
+ }
+ {
+ pop
+ clipForward?
+ {
+ currentdict
+ end
+ end
+ begin
+
+ /clipForward? false ddef
+ } if
+ } ifelse
+} bind def
+/Pb
+{
+ pop pop
+ 0 (%AI5_EndPalette) discard
+} bind def
+/Np
+{
+ 0 (%AI5_End_NonPrinting--) discard
+} bind def
+/Ln /pop load def
+/Ap
+/pop load def
+/Ar
+{
+ 72 exch div
+ 0 dtransform dup mul exch dup mul add sqrt
+ dup 1 lt
+ {
+ pop 1
+ } if
+ setflat
+} def
+/Mb
+{
+ q
+} def
+/Md
+{
+} def
+/MB
+{
+ Q
+} def
+/nc 3 dict def
+nc begin
+/setgray
+{
+ pop
+} bind def
+/setcmykcolor
+{
+ 4 npop
+} bind def
+/setcustomcolor
+{
+ 2 npop
+} bind def
+currentdict readonly pop
+end
+end
+setpacking
+%%EndResource
+%%EndProlog
+%%BeginSetup
+%%IncludeFont: Univers
+Adobe_level2_AI5 /initialize get exec
+Adobe_Illustrator_AI5_vars Adobe_Illustrator_AI5 Adobe_typography_AI5 /initialize get exec
+Adobe_ColorImage_AI6 /initialize get exec
+Adobe_Illustrator_AI5 /initialize get exec
+[
+39/quotesingle 96/grave 128/Adieresis/Aring/Ccedilla/Eacute/Ntilde/Odieresis
+/Udieresis/aacute/agrave/acircumflex/adieresis/atilde/aring/ccedilla/eacute
+/egrave/ecircumflex/edieresis/iacute/igrave/icircumflex/idieresis/ntilde
+/oacute/ograve/ocircumflex/odieresis/otilde/uacute/ugrave/ucircumflex
+/udieresis/dagger/degree/cent/sterling/section/bullet/paragraph/germandbls
+/registered/copyright/trademark/acute/dieresis/.notdef/AE/Oslash
+/.notdef/plusminus/.notdef/.notdef/yen/mu/.notdef/.notdef
+/.notdef/.notdef/.notdef/ordfeminine/ordmasculine/.notdef/ae/oslash
+/questiondown/exclamdown/logicalnot/.notdef/florin/.notdef/.notdef
+/guillemotleft/guillemotright/ellipsis/.notdef/Agrave/Atilde/Otilde/OE/oe
+/endash/emdash/quotedblleft/quotedblright/quoteleft/quoteright/divide
+/.notdef/ydieresis/Ydieresis/fraction/currency/guilsinglleft/guilsinglright
+/fi/fl/daggerdbl/periodcentered/quotesinglbase/quotedblbase/perthousand
+/Acircumflex/Ecircumflex/Aacute/Edieresis/Egrave/Iacute/Icircumflex
+/Idieresis/Igrave/Oacute/Ocircumflex/.notdef/Ograve/Uacute/Ucircumflex
+/Ugrave/dotlessi/circumflex/tilde/macron/breve/dotaccent/ring/cedilla
+/hungarumlaut/ogonek/caron
+TE
+%AI3_BeginEncoding: _Univers Univers
+[/_Univers/Univers 0 0 1 TZ
+%AI3_EndEncoding AdobeType
+%AI5_Begin_NonPrinting
+Np
+8 Bn
+%AI5_BeginGradient: (Black & White)
+(Black & White) 0 2 Bd
+[
+<
+FFFEFDFCFBFAF9F8F7F6F5F4F3F2F1F0EFEEEDECEBEAE9E8E7E6E5E4E3E2E1E0DFDEDDDCDBDAD9D8
+D7D6D5D4D3D2D1D0CFCECDCCCBCAC9C8C7C6C5C4C3C2C1C0BFBEBDBCBBBAB9B8B7B6B5B4B3B2B1B0
+AFAEADACABAAA9A8A7A6A5A4A3A2A1A09F9E9D9C9B9A999897969594939291908F8E8D8C8B8A8988
+87868584838281807F7E7D7C7B7A797877767574737271706F6E6D6C6B6A69686766656463626160
+5F5E5D5C5B5A595857565554535251504F4E4D4C4B4A494847464544434241403F3E3D3C3B3A3938
+37363534333231302F2E2D2C2B2A292827262524232221201F1E1D1C1B1A19181716151413121110
+0F0E0D0C0B0A09080706050403020100
+>
+0 %_Br
+[
+0 0 50 100 %_Bs
+1 0 50 0 %_Bs
+BD
+%AI5_EndGradient
+%AI5_BeginGradient: (Green & Blue)
+(Green & Blue) 0 2 Bd
+[
+<
+99999A9A9B9B9B9C9C9D9D9D9E9E9F9F9FA0A0A1A1A1A2A2A3A3A3A4A4A5A5A5A6A6A7A7A7A8A8A9
+A9A9AAAAABABABACACADADADAEAEAFAFAFB0B0B1B1B1B2B2B3B3B3B4B4B5B5B5B6B6B7B7B7B8B8B9
+B9B9BABABBBBBBBCBCBDBDBDBEBEBFBFBFC0C0C1C1C1C2C2C3C3C3C4C4C5C5C5C6C6C7C7C7C8C8C9
+C9C9CACACBCBCBCCCCCDCDCDCECECFCFCFD0D0D1D1D1D2D2D3D3D3D4D4D5D5D5D6D6D7D7D7D8D8D9
+D9D9DADADBDBDBDCDCDDDDDDDEDEDFDFDFE0E0E1E1E1E2E2E3E3E3E4E4E5E5E5E6E6E7E7E7E8E8E9
+E9E9EAEAEBEBEBECECEDEDEDEEEEEFEFEFF0F0F1F1F1F2F2F3F3F3F4F4F5F5F5F6F6F7F7F7F8F8F9
+F9F9FAFAFBFBFBFCFCFDFDFDFEFEFFFF
+>
+<
+000102020304050506070808090A0B0B0C0D0E0E0F101111121314141516171718191A1A1B1C1D1D
+1E1F20202122232324252626272829292A2B2C2C2D2E2F2F303132323334353536373838393A3B3B
+3C3D3E3E3F404141424344444546474748494A4A4B4C4D4D4E4F5050515253535455565657585959
+5A5B5C5C5D5E5F5F606162626364656566676868696A6B6B6C6D6E6E6F7071717273747475767777
+78797A7A7B7C7D7D7E7F80808182828384858586878888898A8B8B8C8D8E8E8F9091919293949495
+96979798999A9A9B9C9D9D9E9FA0A0A1A2A3A3A4A5A6A6A7A8A9A9AAABACACADAEAFAFB0B1B2B2B3
+B4B5B5B6B7B8B8B9BABBBBBCBDBEBEBF
+>
+<
+FFFEFDFCFBFAF9F8F7F6F5F4F3F2F1F0EFEEEDECEBEAE9E8E7E6E5E4E3E2E1E0DFDEDDDCDBDAD9D8
+D7D6D5D4D3D2D1D0CFCECDCCCBCAC9C8C7C6C5C4C3C2C1C0BFBEBDBCBBBAB9B8B7B6B5B4B3B2B1B0
+AFAEADACABAAA9A8A7A6A5A4A3A2A1A09F9E9D9C9B9A999897969594939291908F8E8D8C8B8A8988
+87868584838281807F7E7D7C7B7A797877767574737271706F6E6D6C6B6A69686766656463626160
+5F5E5D5C5B5A595857565554535251504F4E4D4C4B4A494847464544434241403F3E3D3C3B3A3938
+37363534333231302F2E2D2C2B2A292827262524232221201F1E1D1C1B1A19181716151413121110
+0F0E0D0C0B0A09080706050403020100
+>
+0
+1 %_Br
+[
+1 0.75 0 0 1 50 100 %_Bs
+0.6 0 1 0 1 50 0 %_Bs
+BD
+%AI5_EndGradient
+%AI5_BeginGradient: (Pink, Yellow, Green)
+(Pink, Yellow, Green) 0 3 Bd
+[
+<
+00000000000000000000000000000000000000010101010101010101010101010101010101010101
+01010101010202020202020202020202020202020202020202020203030303030303030303030303
+03030303030303030404040404040404040404040404040404040404050505050505050505050505
+05050505050505060606060606060606060606060606060606060707070707070707070707070707
+07070707080808080808080808080808080808080809090909090909090909090909090909090A0A
+0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0C0C0C0C0C0C0C0C0C
+0C0C0C0C0C0C0C0D0D0D0D0D
+>
+<
+050506060606070708080809090A0A0A0B0B0C0C0D0D0E0E0F0F1010111112121313141415151617
+17181819191A1A1B1C1C1D1D1E1F1F202021222223232425252626272828292A2A2B2C2C2D2D2E2F
+2F3031313233333435353637373839393A3B3B3C3D3E3E3F4040414242434445454647474849494A
+4B4C4C4D4E4F4F505151525354545556575758595A5A5B5C5C5D5E5F5F6061626363646566666768
+69696A6B6C6C6D6E6F707071727373747576777778797A7B7B7C7D7E7F7F80818283838485868787
+88898A8B8B8C8D8E8F8F9091929394949596979898999A9B9C9D9D9E9FA0A1A2A2A3A4A5A6A7A7A8
+A9AAABACADADAEAFB0B1B2B2
+>
+<
+CCCCCBCBCBCACACAC9C9C8C8C7C7C6C6C5C5C4C4C3C2C2C1C1C0C0BFBEBEBDBDBCBBBBBAB9B9B8B7
+B7B6B6B5B4B4B3B2B1B1B0AFAFAEADADACABAAAAA9A8A8A7A6A5A5A4A3A2A2A1A0A09F9E9D9C9C9B
+9A999998979696959493929291908F8E8E8D8C8B8A8A8988878686858483828181807F7E7D7C7C7B
+7A7978777776757473727171706F6E6D6C6B6A6A69686766656463636261605F5E5D5C5B5B5A5958
+5756555453525151504F4E4D4C4B4A49484746464544434241403F3E3D3C3B3A3938383736353433
+3231302F2E2D2C2B2A29282726252423222221201F1E1D1C1B1A191817161514131211100F0E0D0C
+0B0A09080706050403020100
+>
+0
+1 %_Br
+<
+737271706F6E6D6C6B6A696867666564636261605F5E5D5C5B5B5A59585756555453525150504F4E
+4D4C4B4A4949484746454443434241403F3E3E3D3C3B3A3A393837363635343333323130302F2E2D
+2D2C2B2A2A29282827262525242323222121201F1F1E1D1D1C1C1B1A1A1918181717161615141413
+1312121111100F0F0E0E0D0D0C0C0C0B0B0A0A090908080807070606060505050404040303030202
+020201010101010000000000
+>
+<
+00000000000000000000000001010101010101010101010101010101010101010101010102020202
+02020202020202020202020202020202020202020202030303030303030303030303030303030303
+03030303030303030303030303040404040404040404040404040404040404040404040404040404
+04040404040404040404050505050505050505050505050505050505050505050505050505050505
+050505050505050505050505
+>
+<
+BFBFBFC0C0C0C0C0C0C0C0C0C1C1C1C1C1C1C1C1C1C2C2C2C2C2C2C2C2C2C2C3C3C3C3C3C3C3C3C3
+C3C4C4C4C4C4C4C4C4C4C4C5C5C5C5C5C5C5C5C5C5C5C6C6C6C6C6C6C6C6C6C6C6C6C7C7C7C7C7C7
+C7C7C7C7C7C7C8C8C8C8C8C8C8C8C8C8C8C8C8C9C9C9C9C9C9C9C9C9C9C9C9C9C9C9CACACACACACA
+CACACACACACACACACACACBCBCBCBCBCBCBCBCBCBCBCBCBCBCBCBCBCBCBCBCBCBCCCCCCCCCCCCCCCC
+CCCCCCCCCCCCCCCCCCCCCCCC
+>
+0
+1 %_Br
+[
+0.05 0.7 0 0 1 50 100 %_Bs
+0 0.02 0.8 0 1 57 36 %_Bs
+0.45 0 0.75 0 1 37 0 %_Bs
+BD
+%AI5_EndGradient
+%AI5_BeginGradient: (Purple, Red & Yellow)
+(Purple, Red & Yellow) 0 3 Bd
+[
+0
+<
+FFFEFDFCFBFAF9F8F7F6F5F4F3F2F1F0EFEEEDECEBEAE9E8E7E6E5E4E3E2E1E0DFDEDDDCDBDAD9D8
+D7D6D5D4D3D2D1D0CFCECDCCCBCAC9C8C7C6C5C4C3C2C1C0BFBEBDBCBBBAB9B8B7B6B5B4B3B2B1B0
+AFAEADACABAAA9A8A7A6A5A4A3A2A1A09F9E9D9C9B9A999897969594939291908F8E8D8C8B8A8988
+87868584838281807F7E7D7C7B7A797877767574737271706F6E6D6C6B6A69686766656463626160
+5F5E5D5C5B5A595857565554535251504F4E4D4C4B4A494847464544434241403F3E3D3C3B3A3938
+37363534333231302F2E2D2C2B2A292827262524232221201F1E1D1C1B1A19181716151413121110
+0F0E0D0C0B0A
+>
+<
+CCCCCCCDCDCDCDCDCECECECECECFCFCFCFD0D0D0D0D0D1D1D1D1D1D2D2D2D2D2D3D3D3D3D3D4D4D4
+D4D5D5D5D5D5D6D6D6D6D6D7D7D7D7D7D8D8D8D8D8D9D9D9D9DADADADADADBDBDBDBDBDCDCDCDCDC
+DDDDDDDDDDDEDEDEDEDFDFDFDFDFE0E0E0E0E0E1E1E1E1E1E2E2E2E2E2E3E3E3E3E4E4E4E4E4E5E5
+E5E5E5E6E6E6E6E6E7E7E7E7E7E8E8E8E8E9E9E9E9E9EAEAEAEAEAEBEBEBEBEBECECECECECEDEDED
+EDEEEEEEEEEEEFEFEFEFEFF0F0F0F0F0F1F1F1F1F1F2F2F2F2F3F3F3F3F3F4F4F4F4F4F5F5F5F5F5
+F6F6F6F6F6F7F7F7F7F8F8F8F8F8F9F9F9F9F9FAFAFAFAFAFBFBFBFBFBFCFCFCFCFDFDFDFDFDFEFE
+FEFEFEFFFFFF
+>
+0
+1 %_Br
+<
+E5E4E3E2E1E0DFDEDDDCDBDAD9D8D7D6D5D4D3D2D1D0CFCECDCCCBCAC9C8C7C6C5C4C3C2C1C0BFBE
+BDBCBBBAB9B8B7B6B5B4B3B2B1B0AFAEADACABAAA9A8A7A6A5A4A3A2A1A09F9E9D9C9B9A99989796
+9594939291908F8E8D8C8B8A898887868584838281807F7E7D7C7B7A797877767574737271706F6E
+6D6C6B6A696867666564636261605F5E5D5C5B5A595857565554535251504F4E4D4C4B4A49484746
+4544434241403F3E3D3C3B3A393837363534333231302F2E2D2C2B2A292827262524232221201F1E
+1D1C1B1A191817161514131211100F0E0D0C0B0A09080706050403020100
+>
+<
+E5E6E6E6E6E6E6E6E6E7E7E7E7E7E7E7E7E7E8E8E8E8E8E8E8E8E8E9E9E9E9E9E9E9E9E9EAEAEAEA
+EAEAEAEAEAEBEBEBEBEBEBEBEBEBECECECECECECECECECEDEDEDEDEDEDEDEDEDEEEEEEEEEEEEEEEE
+EEEFEFEFEFEFEFEFEFEFF0F0F0F0F0F0F0F0F0F1F1F1F1F1F1F1F1F1F2F2F2F2F2F2F2F2F2F3F3F3
+F3F3F3F3F3F3F4F4F4F4F4F4F4F4F4F5F5F5F5F5F5F5F5F5F6F6F6F6F6F6F6F6F6F7F7F7F7F7F7F7
+F7F7F8F8F8F8F8F8F8F8F8F9F9F9F9F9F9F9F9F9FAFAFAFAFAFAFAFAFAFBFBFBFBFBFBFBFBFBFCFC
+FCFCFCFCFCFCFCFDFDFDFDFDFDFDFDFDFEFEFEFEFEFEFEFEFEFFFFFFFFFF
+>
+<
+00010203040405060708090A0B0C0C0D0E0F10111213141415161718191A1B1C1D1D1E1F20212223
+242525262728292A2B2C2D2D2E2F30313233343535363738393A3B3C3D3D3E3F4041424344454546
+4748494A4B4C4D4E4E4F50515253545556565758595A5B5C5D5E5E5F60616263646566666768696A
+6B6C6D6E6E6F70717273747576767778797A7B7C7D7E7F7F80818283848586878788898A8B8C8D8E
+8F8F90919293949596979798999A9B9C9D9E9F9FA0A1A2A3A4A5A6A7A7A8A9AAABACADAEAFAFB0B1
+B2B3B4B5B6B7B8B8B9BABBBCBDBEBFC0C0C1C2C3C4C5C6C7C8C8C9CACBCC
+>
+0
+1 %_Br
+[
+0 0.04 1 0 1 50 100 %_Bs
+0 1 0.8 0 1 50 50 %_Bs
+0.9 0.9 0 0 1 50 0 %_Bs
+BD
+%AI5_EndGradient
+%AI5_BeginGradient: (Rainbow)
+(Rainbow) 0 6 Bd
+[
+<
+FFFEFDFCFBFAF9F8F7F6F5F4F3F2F1F0EFEEEDECEBEAE9E8E7E6E5E4E3E2E1E0DFDEDDDCDBDAD9D8
+D7D6D5D4D3D2D1D0CFCECDCCCBCAC9C8C7C6C5C4C3C2C1C0BFBEBDBCBBBAB9B8B7B6B5B4B3B2B1B0
+AFAEADACABAAA9A8A7A6A5A4A3A2A1A09F9E9D9C9B9A999897969594939291908F8E8D8C8B8A8988
+87868584838281807F7E7D7C7B7A797877767574737271706F6E6D6C6B6A69686766656463626160
+5F5E5D5C5B5A595857565554535251504F4E4D4C4B4A494847464544434241403F3E3D3C3B3A3938
+37363534333231302F2E2D2C2B2A292827262524232221201F1E1D1C1B1A19181716151413121110
+0F0E0D0C0B0A09080706050403020100
+>
+1
+0
+0
+1 %_Br
+1
+<
+0708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E
+2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F50515253545556
+5758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E
+7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6
+A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7C8C9CACBCCCDCE
+CFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6
+F7F8F9FAFBFCFDFEFF
+>
+0
+0
+1 %_Br
+1
+<
+00000000000000000000000000000000000001010101010101010101010101010101010101010101
+01010101010101010101010101010202020202020202020202020202020202020202020202020202
+02020202020202020202030303030303030303030303030303030303030303030303030303030303
+03030303030304040404040404040404040404040404040404040404040404040404040404040404
+04040505050505050505050505050505050505050505050505050505050505050505050505050606
+06060606060606060606060606060606060606060606060606060606060606060606070707070707
+07070707070707070707070707070707
+>
+<
+FFFEFDFCFBFAF9F8F7F6F5F4F3F2F1F0EFEEEDECEBEAE9E8E7E6E5E4E3E2E1E0DFDEDDDCDBDAD9D8
+D7D6D5D4D3D2D1D0CFCECDCCCBCAC9C8C7C6C5C4C3C2C1C0BFBEBDBCBBBAB9B8B7B6B5B4B3B2B1B0
+AFAEADACABAAA9A8A7A6A5A4A3A2A1A09F9E9D9C9B9A999897969594939291908F8E8D8C8B8A8988
+87868584838281807F7E7D7C7B7A797877767574737271706F6E6D6C6B6A69686766656463626160
+5F5E5D5C5B5A595857565554535251504F4E4D4C4B4A494847464544434241403F3E3D3C3B3A3938
+37363534333231302F2E2D2C2B2A292827262524232221201F1E1D1C1B1A19181716151413121110
+0F0E0D0C0B0A09080706050403020100
+>
+0
+1 %_Br
+<
+000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627
+28292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F
+505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F7071727374757677
+78797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9F
+A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7
+C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEF
+F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF
+>
+0
+1
+0
+1 %_Br
+0
+<
+FFFEFDFCFBFAF9F8F7F6F5F4F3F2F1F0EFEEEDECEBEAE9E8E7E6E5E4E3E2E1E0DFDEDDDCDBDAD9D8
+D7D6D5D4D3D2D1D0CFCECDCCCBCAC9C8C7C6C5C4C3C2C1C0BFBEBDBCBBBAB9B8B7B6B5B4B3B2B1B0
+AFAEADACABAAA9A8A7A6A5A4A3A2A1A09F9E9D9C9B9A999897969594939291908F8E8D8C8B8A8988
+87868584838281807F7E7D7C7B7A797877767574737271706F6E6D6C6B6A69686766656463626160
+5F5E5D5C5B5A595857565554535251504F4E4D4C4B4A494847464544434241403F3E3D3C3B3A3938
+37363534333231302F2E2D2C2B2A292827262524232221201F1E1D1C1B1A19181716151413121110
+0F0E0D0C0B0A09080706050403020100
+>
+1
+0
+1 %_Br
+[
+0 1 0 0 1 50 100 %_Bs
+1 1 0 0 1 50 80 %_Bs
+1 0.0279 0 0 1 50 60 %_Bs
+1 0 1 0 1 50 40 %_Bs
+0 0 1 0 1 50 20 %_Bs
+0 1 1 0 1 50 0 %_Bs
+BD
+%AI5_EndGradient
+%AI5_BeginGradient: (Steel Bar)
+(Steel Bar) 0 3 Bd
+[
+<
+FFFEFDFCFBFAF9F8F7F6F5F4F3F2F1F0EFEEEDECEBEAE9E8E7E6E5E4E3E2E1E0DFDEDDDCDBDAD9D8
+D7D6D5D4D3D2D1D0CFCECDCCCBCAC9C8C7C6C5C4C3C2C1C0BFBEBDBCBBBAB9B8B7B6B5B4B3B2B1B0
+AFAEADACABAAA9A8A7A6A5A4A3A2A1A09F9E9D9C9B9A999897969594939291908F8E8D8C8B8A8988
+87868584838281807F7E7D7C7B7A797877767574737271706F6E6D6C6B6A69686766656463626160
+5F5E5D5C5B5A595857565554535251504F4E4D4C4B4A494847464544434241403F3E3D3C3B3A3938
+37363534333231302F2E2D2C2B2A292827262524232221201F1E1D1C1B1A19181716151413121110
+0F0E0D0C0B0A09080706050403020100
+>
+0 %_Br
+<
+000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627
+28292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F
+505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F7071727374757677
+78797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9F
+A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7
+C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEF
+F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF
+>
+0 %_Br
+[
+0 0 50 100 %_Bs
+1 0 50 70 %_Bs
+0 0 50 0 %_Bs
+BD
+%AI5_EndGradient
+%AI5_BeginGradient: (Yellow & Orange Radial)
+(Yellow & Orange Radial) 1 2 Bd
+[
+0
+<
+0001010203040506060708090A0B0C0C0D0E0F10111213131415161718191A1B1C1D1D1E1F202122
+232425262728292A2B2B2C2D2E2F303132333435363738393A3B3C3D3E3E3F404142434445464748
+494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F60606162636465666768696A6B6C6D6E6F
+707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C
+>
+<
+FFFFFFFFFEFEFEFEFEFEFEFDFDFDFDFDFDFCFCFCFCFCFCFBFBFBFBFBFBFAFAFAFAFAFAF9F9F9F9F9
+F9F8F8F8F8F8F8F7F7F7F7F7F7F6F6F6F6F6F6F5F5F5F5F5F5F4F4F4F4F4F3F3F3F3F3F3F2F2F2F2
+F2F2F1F1F1F1F1F0F0F0F0F0F0EFEFEFEFEFEFEEEEEEEEEEEDEDEDEDEDEDECECECECECEBEBEBEBEB
+EBEAEAEAEAEAE9E9E9E9E9E9E8E8E8E8E8E8E7E7E7E7E7E6E6E6E6E6E5
+>
+0
+1 %_Br
+[
+0 0 1 0 1 52 19 %_Bs
+0 0.55 0.9 0 1 50 100 %_Bs
+BD
+%AI5_EndGradient
+%AI5_BeginGradient: (Yellow & Purple Radial)
+(Yellow & Purple Radial) 1 2 Bd
+[
+<
+000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627
+28292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F
+505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F7071727374757677
+78797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9F
+A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7
+C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEF
+F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF
+>
+<
+1415161718191A1B1C1D1E1F1F202122232425262728292A2A2B2C2D2E2F30313233343536363738
+393A3B3C3D3E3F40414142434445464748494A4B4C4D4D4E4F50515253545556575858595A5B5C5D
+5E5F60616263646465666768696A6B6C6D6E6F6F707172737475767778797A7B7B7C7D7E7F808182
+83848586868788898A8B8C8D8E8F90919292939495969798999A9B9C9D9D9E9FA0A1A2A3A4A5A6A7
+A8A9A9AAABACADAEAFB0B1B2B3B4B4B5B6B7B8B9BABBBCBDBEBFC0C0C1C2C3C4C5C6C7C8C9CACBCB
+CCCDCECFD0D1D2D3D4D5D6D7D7D8D9DADBDCDDDEDFE0E1E2E2E3E4E5E6E7E8E9EAEBECEDEEEEEFF0
+F1F2F3F4F5F6F7F8F9F9FAFBFCFDFEFF
+>
+<
+ABAAAAA9A8A7A7A6A5A5A4A3A3A2A1A1A09F9F9E9D9D9C9B9B9A9999989797969595949393929191
+908F8F8E8D8D8C8B8B8A8989888787868585848383828181807F7F7E7D7D7C7B7B7A797978777776
+7575747373727171706F6F6E6D6D6C6B6B6A6969686767666565646362626160605F5E5E5D5C5C5B
+5A5A5958585756565554545352525150504F4E4E4D4C4C4B4A4A4948484746464544444342424140
+403F3E3E3D3C3C3B3A3A3938383736363534343332323130302F2E2E2D2C2C2B2A2A292828272626
+25242423222121201F1F1E1D1D1C1B1B1A1919181717161515141313121111100F0F0E0D0D0C0B0B
+0A090908070706050504030302010100
+>
+0
+1 %_Br
+[
+0 0.08 0.67 0 1 50 14 %_Bs
+1 1 0 0 1 50 100 %_Bs
+BD
+%AI5_EndGradient
+%AI5_End_NonPrinting--
+%AI5_BeginPalette
+0 2 Pb
+Pn
+Pc
+1 g
+Pc
+0 g
+Pc
+0 0 0 0 k
+Pc
+0.75 g
+Pc
+0.5 g
+Pc
+0.25 g
+Pc
+0 g
+Pc
+Bb
+2 (Black & White) -4014 4716 0 0 1 0 0 1 0 0 Bg
+0 BB
+Pc
+0.25 0 0 0 k
+Pc
+0.5 0 0 0 k
+Pc
+0.75 0 0 0 k
+Pc
+1 0 0 0 k
+Pc
+0.25 0.25 0 0 k
+Pc
+0.5 0.5 0 0 k
+Pc
+0.75 0.75 0 0 k
+Pc
+1 1 0 0 k
+Pc
+Bb
+2 (Pink, Yellow, Green) -4014 4716 0 0 1 0 0 1 0 0 Bg
+0 BB
+Pc
+0 0.25 0 0 k
+Pc
+0 0.5 0 0 k
+Pc
+0 0.75 0 0 k
+Pc
+0 1 0 0 k
+Pc
+0 0.25 0.25 0 k
+Pc
+0 0.5 0.5 0 k
+Pc
+0 0.75 0.75 0 k
+Pc
+0 1 1 0 k
+Pc
+Bb
+0 0 0 0 Bh
+2 (Yellow & Purple Radial) -4014 4716 0 0 1 0 0 1 0 0 Bg
+0 BB
+Pc
+0 0 0.25 0 k
+Pc
+0 0 0.5 0 k
+Pc
+0 0 0.75 0 k
+Pc
+0 0 1 0 k
+Pc
+0.25 0 0.25 0 k
+Pc
+0.5 0 0.5 0 k
+Pc
+0.75 0 0.75 0 k
+Pc
+1 0 1 0 k
+Pc
+Bb
+2 (Rainbow) -4014 4716 0 0 1 0 0 1 0 0 Bg
+0 BB
+Pc
+0.25 0.125 0 0 k
+Pc
+0.5 0.25 0 0 k
+Pc
+0.75 0.375 0 0 k
+Pc
+1 0.5 0 0 k
+Pc
+0.125 0.25 0 0 k
+Pc
+0.25 0.5 0 0 k
+Pc
+0.375 0.75 0 0 k
+Pc
+0.5 1 0 0 k
+Pc
+Bb
+2 (Steel Bar) -4014 4716 0 0 1 0 0 1 0 0 Bg
+0 BB
+Pc
+0 0.25 0.125 0 k
+Pc
+0 0.5 0.25 0 k
+Pc
+0 0.75 0.375 0 k
+Pc
+0 1 0.5 0 k
+Pc
+0 0.125 0.25 0 k
+Pc
+0 0.25 0.5 0 k
+Pc
+0 0.375 0.75 0 k
+Pc
+0 0.5 1 0 k
+Pc
+Bb
+2 (Purple, Red & Yellow) -4014 4716 0 0 1 0 0 1 0 0 Bg
+0 BB
+Pc
+0.125 0 0.25 0 k
+Pc
+0.25 0 0.5 0 k
+Pc
+0.375 0 0.75 0 k
+Pc
+0.5 0 1 0 k
+Pc
+0.25 0 0.125 0 k
+Pc
+0.5 0 0.25 0 k
+Pc
+0.75 0 0.375 0 k
+Pc
+1 0 0.5 0 k
+Pc
+Bb
+2 (Green & Blue) -4014 4716 0 0 1 0 0 1 0 0 Bg
+0 BB
+Pc
+0.25 0.125 0.125 0 k
+Pc
+0.5 0.25 0.25 0 k
+Pc
+0.75 0.375 0.375 0 k
+Pc
+1 0.5 0.5 0 k
+Pc
+0.25 0.25 0.125 0 k
+Pc
+0.5 0.5 0.25 0 k
+Pc
+0.75 0.75 0.375 0 k
+Pc
+1 1 0.5 0 k
+Pc
+Bb
+0 0 0 0 Bh
+2 (Yellow & Orange Radial) -4014 4716 0 0 1 0 0 1 0 0 Bg
+0 BB
+Pc
+0.125 0.25 0.125 0 k
+Pc
+0.25 0.5 0.25 0 k
+Pc
+0.375 0.75 0.375 0 k
+Pc
+0.5 1 0.5 0 k
+Pc
+0.125 0.25 0.25 0 k
+Pc
+0.25 0.5 0.5 0 k
+Pc
+0.375 0.75 0.75 0 k
+Pc
+0.5 1 1 0 k
+Pc
+0 0 0 0 k
+Pc
+0.125 0.125 0.25 0 k
+Pc
+0.25 0.25 0.5 0 k
+Pc
+0.375 0.375 0.75 0 k
+Pc
+0.5 0.5 1 0 k
+Pc
+0.25 0.125 0.25 0 k
+Pc
+0.5 0.25 0.5 0 k
+Pc
+0.75 0.375 0.75 0 k
+Pc
+1 0.5 1 0 k
+Pc
+PB
+%AI5_EndPalette
+%%EndSetup
+%AI5_BeginLayer
+1 1 1 1 0 0 0 79 128 255 Lb
+(Layer 1) Ln
+0 A
+800 Ar
+0 J 0 j 1 w 4 M []0 d
+%AI3_Note:
+0 D
+0 XR
+-4014 283.5 m
+4626 283.5 L
+(N) *
+453.5 4716 m
+453.5 -3924 L
+(N) *
+85 4716 m
+85 -3924 L
+(N) *
+-4014 765.5 m
+4626 765.5 L
+(N) *
+0 R
+0 G
+113 683.5 m
+439 683.5 l
+S
+113 663.5 m
+439 663.5 l
+S
+113 643.5 m
+439 643.5 l
+S
+113 686 m
+439 686 l
+S
+1 Ap
+439 624 m
+439 709 L
+113 709 L
+113 624 L
+439 624 L
+s
+0 Ap
+178.5 709 m
+178.5 624 l
+S
+243 709 m
+243 624 l
+S
+374 709 m
+374 624 l
+S
+308.5 709 m
+308.5 624 l
+S
+0 To
+1 0 0 1 146 692 0 Tp
+TP
+-12.2278 0 Td
+0 Tr
+0 O
+0 g
+/_Univers 10 Tf
+0 Ts
+100 Tz
+0 Tt
+1 TA
+%_ 0 XL
+36 0 Xb
+XB
+0 0 5 TC
+100 100 200 TW
+0 0 0 Ti
+1 Ta
+0 0 2 2 3 Th
+0 Tq
+0 0 Tl
+0 Tc
+0 Tw
+(key 1) Tx
+(\r) TX
+TO
+0 To
+1 0 0 1 213 692 0 Tp
+TP
+-12.2278 0 Td
+0 Tr
+(key 2) Tx
+(\r) TX
+TO
+0 To
+1 0 0 1 276 692 0 Tp
+TP
+-11.1121 0 Td
+0 Tr
+(col 3) Tx
+(\r) TX
+TO
+0 To
+1 0 0 1 225.5 747.5 0 Tp
+TP
+0 Tr
+(\r) Tx
+TO
+0 To
+1 0 0 1 336.5 693.5 0 Tp
+TP
+0 Tr
+(\r) Tx
+TO
+0 To
+1 0 0 1 341 692 0 Tp
+TP
+-11.1121 0 Td
+0 Tr
+(col 4) Tx
+(\r) TX
+TO
+0 To
+1 0 0 1 407.5 692 0 Tp
+TP
+-11.1121 0 Td
+0 Tr
+(col 5) Tx
+(\r) TX
+TO
+0 To
+1 0 0 1 185.5 736 0 Tp
+TP
+0 Tr
+(\r) Tx
+TO
+0 To
+1 0 0 1 145 669.5 0 Tp
+TP
+-2.7795 0 Td
+0 Tr
+(1) Tx
+(\r) TX
+TO
+0 To
+1 0 0 1 144.5 650.5 0 Tp
+TP
+-2.7795 0 Td
+0 Tr
+(1) Tx
+(\r) TX
+TO
+0 To
+1 0 0 1 145 630 0 Tp
+TP
+-2.7795 0 Td
+0 Tr
+(2) Tx
+(\r) TX
+TO
+0 To
+1 0 0 1 209.5 669 0 Tp
+TP
+-2.7795 0 Td
+0 Tr
+(1) Tx
+(\r) TX
+TO
+0 To
+1 0 0 1 209.5 649.5 0 Tp
+TP
+-2.7795 0 Td
+0 Tr
+(2) Tx
+(\r) TX
+TO
+0 To
+1 0 0 1 209.5 629.5 0 Tp
+TP
+-2.7795 0 Td
+0 Tr
+(1) Tx
+(\r) TX
+TO
+0 To
+1 0 0 1 274.5 669 0 Tp
+TP
+-2.7795 0 Td
+0 Tr
+(a) Tx
+(\r) TX
+TO
+0 To
+1 0 0 1 274.5 649.5 0 Tp
+TP
+-3.0542 0 Td
+0 Tr
+(d) Tx
+(\r) TX
+TO
+0 To
+1 0 0 1 274.5 629.5 0 Tp
+TP
+-3.0542 0 Td
+0 Tr
+(g) Tx
+(\r) TX
+TO
+0 To
+1 0 0 1 340 669 0 Tp
+TP
+-3.0542 0 Td
+0 Tr
+(b) Tx
+(\r) TX
+TO
+0 To
+1 0 0 1 340 649.5 0 Tp
+TP
+-2.7795 0 Td
+0 Tr
+(e) Tx
+(\r) TX
+TO
+0 To
+1 0 0 1 340 629.5 0 Tp
+TP
+-8.8879 0 Td
+0 Tr
+(N/A) Tx
+(\r) TX
+TO
+0 To
+1 0 0 1 405 669 0 Tp
+TP
+-2.5 0 Td
+0 Tr
+(c) Tx
+(\r) TX
+TO
+0 To
+1 0 0 1 405 649.5 0 Tp
+TP
+-1.6638 0 Td
+0 Tr
+(f) Tx
+(\r) TX
+TO
+0 To
+1 0 0 1 405 629.5 0 Tp
+TP
+-1.3892 0 Td
+0 Tr
+(i) Tx
+(\r) TX
+TO
+1 Ap
+0 R
+0 G
+274.4998 623.4963 m
+279.1963 623.4963 283.0037 627.3037 283.0037 632.0002 c
+283.0037 636.6968 279.1963 640.5042 274.4998 640.5042 c
+269.8032 640.5042 265.9958 636.6968 265.9958 632.0002 c
+265.9958 627.3037 269.8032 623.4963 274.4998 623.4963 c
+s
+[3 4 3 4 3 4 ]0 d
+339.9998 663.4963 m
+344.6963 663.4963 348.5037 667.3037 348.5037 672.0002 c
+348.5037 676.6968 344.6963 680.5042 339.9998 680.5042 c
+335.3032 680.5042 331.4958 676.6968 331.4958 672.0002 c
+331.4958 667.3037 335.3032 663.4963 339.9998 663.4963 c
+s
+u
+u
+u
+u
+u
+u
+u
+0 Ap
+[]0 d
+274.4998 623.4963 m
+277 615.5 297 615.5 v
+317 615.5 313.6364 635.614 316.5 648.5 c
+318.5 657.5 326 662 y
+S
+0 O
+0 g
+327.4981 664.0941 m
+325.8236 663.6715 324.6654 663.5131 323.254 663.2872 c
+325.8493 658.9617 l
+326.1406 659.3991 327.3976 661.0481 328.5586 662.3265 c
+329.8008 663.6954 330.9886 664.8344 331.8138 665.4817 c
+330.8543 665.0582 329.2904 664.5461 327.4981 664.0941 c
+f
+U
+U
+U
+U
+U
+U
+U
+1 Ap
+0 R
+0 G
+404.9998 624.4963 m
+409.6963 624.4963 413.5037 628.3037 413.5037 633.0002 c
+413.5037 637.6968 409.6963 641.5042 404.9998 641.5042 c
+400.3032 641.5042 396.4958 637.6968 396.4958 633.0002 c
+396.4958 628.3037 400.3032 624.4963 404.9998 624.4963 c
+s
+u
+0 Ap
+396.4958 633.0002 m
+384.5 634.5089 384.5 620.5 v
+383.5 603 l
+S
+0 O
+0 g
+384.3884 600.5834 m
+384.9812 602.2055 385.5017 603.2521 386.1089 604.5461 c
+381.0729 604.8338 l
+381.2706 604.347 381.9268 602.38 382.3305 600.701 c
+382.7634 598.904 383.0369 597.2812 383.1078 596.2348 c
+383.2974 597.2663 383.7539 598.8474 384.3884 600.5834 c
+f
+U
+0 To
+1 0 0 1 383 582 0 Tp
+TP
+-26.9788 0 Td
+0 Tr
+(endOfT) Tx 1 104 Tk
+(able) Tx
+(\r) TX
+TO
+LB
+%AI5_EndLayer--
+%%PageTrailer
+gsave annotatepage grestore showpage
+%%Trailer
+Adobe_Illustrator_AI5 /terminate get exec
+Adobe_ColorImage_AI6 /terminate get exec
+Adobe_typography_AI5 /terminate get exec
+Adobe_level2_AI5 /terminate get exec
+%%EOF
diff --git a/lib/snmp/doc/src/getnext4.gif b/lib/snmp/doc/src/getnext4.gif
new file mode 100644
index 0000000000..703afcc7c5
--- /dev/null
+++ b/lib/snmp/doc/src/getnext4.gif
Binary files differ
diff --git a/lib/snmp/doc/src/getnext4.ps b/lib/snmp/doc/src/getnext4.ps
new file mode 100644
index 0000000000..8ef3ccf709
--- /dev/null
+++ b/lib/snmp/doc/src/getnext4.ps
@@ -0,0 +1,3002 @@
+%!PS-Adobe-3.0 EPSF-3.0
+%%Creator: Adobe Illustrator(r) 6.0
+%%For: (Anna Fedoriw) (Ericsson Telecom)
+%%Title: (GetNext312.eps)
+%%CreationDate: (97-05-23) (14.04)
+%%BoundingBox: 112 605 440 757
+%%HiResBoundingBox: 112.5 605.1454 439.5 756.8677
+%%DocumentProcessColors: Black
+%%DocumentFonts: Univers
+%%DocumentSuppliedResources: procset Adobe_level2_AI5 1.0 0
+%%+ procset Adobe_typography_AI5 1.0 0
+%%+ procset Adobe_Illustrator_AI6_vars Adobe_Illustrator_AI6
+%%+ procset Adobe_Illustrator_AI5 1.0 0
+%AI5_FileFormat 2.0
+%AI3_ColorUsage: Black&White
+%%AI6_ColorSeparationSet: 1 1 (AI6 Default Color Separation Set)
+%%+ Options: 1 16 0 1 0 1 1 1 0 1 1 1 1 18 0 0 0 0 0 0 0 0 -1 -1
+%%+ PPD: 1 21 0 0 60 45 2 2 1 0 0 1 0 0 0 0 0 0 0 0 0 0 ()
+%AI3_TemplateBox: 306 396 306 396
+%AI3_TileBox: 21 -12 588 802
+%AI3_DocumentPreview: Macintosh_ColorPic
+%AI5_ArtSize: 595.2756 841.8898
+%AI5_RulerUnits: 1
+%AI5_ArtFlags: 0 0 0 1 0 0 1 1 0
+%AI5_TargetResolution: 800
+%AI5_NumLayers: 1
+%AI5_OpenToView: 54 804 2 1146 827 58 1 1 3 40
+%AI5_OpenViewLayers: 7
+%%EndComments
+%%BeginProlog
+%%BeginResource: procset Adobe_level2_AI5 1.2 0
+%%Title: (Adobe Illustrator (R) Version 5.0 Level 2 Emulation)
+%%Version: 1.2
+%%CreationDate: (04/10/93) ()
+%%Copyright: ((C) 1987-1993 Adobe Systems Incorporated All Rights Reserved)
+userdict /Adobe_level2_AI5 23 dict dup begin
+ put
+ /packedarray where not
+ {
+ userdict begin
+ /packedarray
+ {
+ array astore readonly
+ } bind def
+ /setpacking /pop load def
+ /currentpacking false def
+ end
+ 0
+ } if
+ pop
+ userdict /defaultpacking currentpacking put true setpacking
+ /initialize
+ {
+ Adobe_level2_AI5 begin
+ } bind def
+ /terminate
+ {
+ currentdict Adobe_level2_AI5 eq
+ {
+ end
+ } if
+ } bind def
+ mark
+ /setcustomcolor where not
+ {
+ /findcmykcustomcolor
+ {
+ 5 packedarray
+ } bind def
+ /setcustomcolor
+ {
+ exch aload pop pop
+ 4
+ {
+ 4 index mul 4 1 roll
+ } repeat
+ 5 -1 roll pop
+ setcmykcolor
+ }
+ def
+ } if
+
+ /gt38? mark {version cvr cvx exec} stopped {cleartomark true} {38 gt exch pop} ifelse def
+ userdict /deviceDPI 72 0 matrix defaultmatrix dtransform dup mul exch dup mul add sqrt put
+ userdict /level2?
+ systemdict /languagelevel known dup
+ {
+ pop systemdict /languagelevel get 2 ge
+ } if
+ put
+/level2ScreenFreq
+{
+ begin
+ 60
+ HalftoneType 1 eq
+ {
+ pop Frequency
+ } if
+ HalftoneType 2 eq
+ {
+ pop GrayFrequency
+ } if
+ HalftoneType 5 eq
+ {
+ pop Default level2ScreenFreq
+ } if
+ end
+} bind def
+userdict /currentScreenFreq
+ level2? {currenthalftone level2ScreenFreq} {currentscreen pop pop} ifelse put
+level2? not
+ {
+ /setcmykcolor where not
+ {
+ /setcmykcolor
+ {
+ exch .11 mul add exch .59 mul add exch .3 mul add
+ 1 exch sub setgray
+ } def
+ } if
+ /currentcmykcolor where not
+ {
+ /currentcmykcolor
+ {
+ 0 0 0 1 currentgray sub
+ } def
+ } if
+ /setoverprint where not
+ {
+ /setoverprint /pop load def
+ } if
+ /selectfont where not
+ {
+ /selectfont
+ {
+ exch findfont exch
+ dup type /arraytype eq
+ {
+ makefont
+ }
+ {
+ scalefont
+ } ifelse
+ setfont
+ } bind def
+ } if
+ /cshow where not
+ {
+ /cshow
+ {
+ [
+ 0 0 5 -1 roll aload pop
+ ] cvx bind forall
+ } bind def
+ } if
+ } if
+ cleartomark
+ /anyColor?
+ {
+ add add add 0 ne
+ } bind def
+ /testColor
+ {
+ gsave
+ setcmykcolor currentcmykcolor
+ grestore
+ } bind def
+ /testCMYKColorThrough
+ {
+ testColor anyColor?
+ } bind def
+ userdict /composite?
+ level2?
+ {
+ gsave 1 1 1 1 setcmykcolor currentcmykcolor grestore
+ add add add 4 eq
+ }
+ {
+ 1 0 0 0 testCMYKColorThrough
+ 0 1 0 0 testCMYKColorThrough
+ 0 0 1 0 testCMYKColorThrough
+ 0 0 0 1 testCMYKColorThrough
+ and and and
+ } ifelse
+ put
+ composite? not
+ {
+ userdict begin
+ gsave
+ /cyan? 1 0 0 0 testCMYKColorThrough def
+ /magenta? 0 1 0 0 testCMYKColorThrough def
+ /yellow? 0 0 1 0 testCMYKColorThrough def
+ /black? 0 0 0 1 testCMYKColorThrough def
+ grestore
+ /isCMYKSep? cyan? magenta? yellow? black? or or or def
+ /customColor? isCMYKSep? not def
+ end
+ } if
+ end defaultpacking setpacking
+%%EndResource
+%%BeginResource: procset Adobe_typography_AI5 1.0 1
+%%Title: (Typography Operators)
+%%Version: 1.0
+%%CreationDate:(03/26/93) ()
+%%Copyright: ((C) 1987-1993 Adobe Systems Incorporated All Rights Reserved)
+currentpacking true setpacking
+userdict /Adobe_typography_AI5 54 dict dup begin
+put
+/initialize
+{
+ begin
+ begin
+ Adobe_typography_AI5 begin
+ Adobe_typography_AI5
+ {
+ dup xcheck
+ {
+ bind
+ } if
+ pop pop
+ } forall
+ end
+ end
+ end
+ Adobe_typography_AI5 begin
+} def
+/terminate
+{
+ currentdict Adobe_typography_AI5 eq
+ {
+ end
+ } if
+} def
+/modifyEncoding
+{
+ /_tempEncode exch ddef
+ /_pntr 0 ddef
+ {
+ counttomark -1 roll
+ dup type dup /marktype eq
+ {
+ pop pop exit
+ }
+ {
+ /nametype eq
+ {
+ _tempEncode /_pntr dup load dup 3 1 roll 1 add ddef 3 -1 roll
+ put
+ }
+ {
+ /_pntr exch ddef
+ } ifelse
+ } ifelse
+ } loop
+ _tempEncode
+} def
+/TE
+{
+ StandardEncoding 256 array copy modifyEncoding
+ /_nativeEncoding exch def
+} def
+%
+/TZ
+{
+ dup type /arraytype eq
+ {
+ /_wv exch def
+ }
+ {
+ /_wv 0 def
+ } ifelse
+ /_useNativeEncoding exch def
+ pop pop
+ findfont _wv type /arraytype eq
+ {
+ _wv makeblendedfont
+ } if
+ dup length 2 add dict
+ begin
+ mark exch
+ {
+ 1 index /FID ne
+ {
+ def
+ } if
+ cleartomark mark
+ } forall
+ pop
+ /FontName exch def
+ counttomark 0 eq
+ {
+ 1 _useNativeEncoding eq
+ {
+ /Encoding _nativeEncoding def
+ } if
+ cleartomark
+ }
+ {
+ /Encoding load 256 array copy
+ modifyEncoding /Encoding exch def
+ } ifelse
+ FontName currentdict
+ end
+ definefont pop
+} def
+/tr
+{
+ _ax _ay 3 2 roll
+} def
+/trj
+{
+ _cx _cy _sp _ax _ay 6 5 roll
+} def
+/a0
+{
+ /Tx
+ {
+ dup
+ currentpoint 3 2 roll
+ tr _psf
+ newpath moveto
+ tr _ctm _pss
+ } ddef
+ /Tj
+ {
+ dup
+ currentpoint 3 2 roll
+ trj _pjsf
+ newpath moveto
+ trj _ctm _pjss
+ } ddef
+} def
+/a1
+{
+ /Tx
+ {
+ dup currentpoint 4 2 roll gsave
+ dup currentpoint 3 2 roll
+ tr _psf
+ newpath moveto
+ tr _ctm _pss
+ grestore 3 1 roll moveto tr sp
+ } ddef
+ /Tj
+ {
+ dup currentpoint 4 2 roll gsave
+ dup currentpoint 3 2 roll
+ trj _pjsf
+ newpath moveto
+ trj _ctm _pjss
+ grestore 3 1 roll moveto tr jsp
+ } ddef
+} def
+/e0
+{
+ /Tx
+ {
+ tr _psf
+ } ddef
+ /Tj
+ {
+ trj _pjsf
+ } ddef
+} def
+/e1
+{
+ /Tx
+ {
+ dup currentpoint 4 2 roll gsave
+ tr _psf
+ grestore 3 1 roll moveto tr sp
+ } ddef
+ /Tj
+ {
+ dup currentpoint 4 2 roll gsave
+ trj _pjsf
+ grestore 3 1 roll moveto tr jsp
+ } ddef
+} def
+/i0
+{
+ /Tx
+ {
+ tr sp
+ } ddef
+ /Tj
+ {
+ trj jsp
+ } ddef
+} def
+/i1
+{
+ W N
+} def
+/o0
+{
+ /Tx
+ {
+ tr sw rmoveto
+ } ddef
+ /Tj
+ {
+ trj swj rmoveto
+ } ddef
+} def
+/r0
+{
+ /Tx
+ {
+ tr _ctm _pss
+ } ddef
+ /Tj
+ {
+ trj _ctm _pjss
+ } ddef
+} def
+/r1
+{
+ /Tx
+ {
+ dup currentpoint 4 2 roll currentpoint gsave newpath moveto
+ tr _ctm _pss
+ grestore 3 1 roll moveto tr sp
+ } ddef
+ /Tj
+ {
+ dup currentpoint 4 2 roll currentpoint gsave newpath moveto
+ trj _ctm _pjss
+ grestore 3 1 roll moveto tr jsp
+ } ddef
+} def
+/To
+{
+ pop _ctm currentmatrix pop
+} def
+/TO
+{
+ iTe _ctm setmatrix newpath
+} def
+/Tp
+{
+ pop _tm astore pop _ctm setmatrix
+ _tDict begin
+ /W
+ {
+ } def
+ /h
+ {
+ } def
+} def
+/TP
+{
+ end
+ iTm 0 0 moveto
+} def
+/Tr
+{
+ _render 3 le
+ {
+ currentpoint newpath moveto
+ } if
+ dup 8 eq
+ {
+ pop 0
+ }
+ {
+ dup 9 eq
+ {
+ pop 1
+ } if
+ } ifelse
+ dup /_render exch ddef
+ _renderStart exch get load exec
+} def
+/iTm
+{
+ _ctm setmatrix _tm concat 0 _rise translate _hs 1 scale
+} def
+/Tm
+{
+ _tm astore pop iTm 0 0 moveto
+} def
+/Td
+{
+ _mtx translate _tm _tm concatmatrix pop iTm 0 0 moveto
+} def
+/iTe
+{
+ _render -1 eq
+ {
+ }
+ {
+ _renderEnd _render get dup null ne
+ {
+ load exec
+ }
+ {
+ pop
+ } ifelse
+ } ifelse
+ /_render -1 ddef
+} def
+/Ta
+{
+ pop
+} def
+/Tf
+{
+ dup 1000 div /_fScl exch ddef
+%
+ selectfont
+} def
+/Tl
+{
+ pop
+ 0 exch _leading astore pop
+} def
+/Tt
+{
+ pop
+} def
+/TW
+{
+ 3 npop
+} def
+/Tw
+{
+ /_cx exch ddef
+} def
+/TC
+{
+ 3 npop
+} def
+/Tc
+{
+ /_ax exch ddef
+} def
+/Ts
+{
+ /_rise exch ddef
+ currentpoint
+ iTm
+ moveto
+} def
+/Ti
+{
+ 3 npop
+} def
+/Tz
+{
+ 100 div /_hs exch ddef
+ iTm
+} def
+/TA
+{
+ pop
+} def
+/Tq
+{
+ pop
+} def
+/Th
+{
+ pop pop pop pop pop
+} def
+/TX
+{
+ pop
+} def
+/Tk
+{
+ exch pop _fScl mul neg 0 rmoveto
+} def
+/TK
+{
+ 2 npop
+} def
+/T*
+{
+ _leading aload pop neg Td
+} def
+/T*-
+{
+ _leading aload pop Td
+} def
+/T-
+{
+ _ax neg 0 rmoveto
+ _hyphen Tx
+} def
+/T+
+{
+} def
+/TR
+{
+ _ctm currentmatrix pop
+ _tm astore pop
+ iTm 0 0 moveto
+} def
+/TS
+{
+ currentfont 3 1 roll
+ /_Symbol_ _fScl 1000 mul selectfont
+
+ 0 eq
+ {
+ Tx
+ }
+ {
+ Tj
+ } ifelse
+ setfont
+} def
+/Xb
+{
+ pop pop
+} def
+/Tb /Xb load def
+/Xe
+{
+ pop pop pop pop
+} def
+/Te /Xe load def
+/XB
+{
+} def
+/TB /XB load def
+currentdict readonly pop
+end
+setpacking
+%%EndResource
+%%BeginProcSet: Adobe_ColorImage_AI6 1.0 0
+userdict /Adobe_ColorImage_AI6 known not
+{
+ userdict /Adobe_ColorImage_AI6 17 dict put
+} if
+userdict /Adobe_ColorImage_AI6 get begin
+
+ /initialize
+ {
+ Adobe_ColorImage_AI6 begin
+ Adobe_ColorImage_AI6
+ {
+ dup type /arraytype eq
+ {
+ dup xcheck
+ {
+ bind
+ } if
+ } if
+ pop pop
+ } forall
+ } def
+ /terminate { end } def
+
+ currentdict /Adobe_ColorImage_AI6_Vars known not
+ {
+ /Adobe_ColorImage_AI6_Vars 14 dict def
+ } if
+
+ Adobe_ColorImage_AI6_Vars begin
+ /channelcount 0 def
+ /sourcecount 0 def
+ /sourcearray 4 array def
+ /plateindex -1 def
+ /XIMask 0 def
+ /XIBinary 0 def
+ /XIChannelCount 0 def
+ /XIBitsPerPixel 0 def
+ /XIImageHeight 0 def
+ /XIImageWidth 0 def
+ /XIImageMatrix null def
+ /XIBuffer null def
+ /XIDataProc null def
+ end
+
+ /WalkRGBString null def
+ /WalkCMYKString null def
+
+ /StuffRGBIntoGrayString null def
+ /RGBToGrayImageProc null def
+ /StuffCMYKIntoGrayString null def
+ /CMYKToGrayImageProc null def
+ /ColorImageCompositeEmulator null def
+
+ /SeparateCMYKImageProc null def
+
+ /FourEqual null def
+ /TestPlateIndex null def
+
+ currentdict /_colorimage known not
+ {
+ /colorimage where
+ {
+ /colorimage get /_colorimage exch def
+ }
+ {
+ /_colorimage null def
+ } ifelse
+ } if
+
+ /_currenttransfer systemdict /currenttransfer get def
+
+ /colorimage null def
+ /XI null def
+
+
+ /WalkRGBString
+ {
+ 0 3 index
+
+ dup length 1 sub 0 3 3 -1 roll
+ {
+ 3 getinterval { } forall
+
+ 5 index exec
+
+ 3 index
+ } for
+
+ 5 { pop } repeat
+
+ } def
+
+
+ /WalkCMYKString
+ {
+ 0 3 index
+
+ dup length 1 sub 0 4 3 -1 roll
+ {
+ 4 getinterval { } forall
+
+ 6 index exec
+
+ 3 index
+
+ } for
+
+ 5 { pop } repeat
+
+ } def
+
+
+ /StuffRGBIntoGrayString
+ {
+ .11 mul exch
+
+ .59 mul add exch
+
+ .3 mul add
+
+ cvi 3 copy put
+
+ pop 1 add
+ } def
+
+
+ /RGBToGrayImageProc
+ {
+ Adobe_ColorImage_AI6_Vars begin
+ sourcearray 0 get exec
+ dup length 3 idiv string
+ dup 3 1 roll
+
+ /StuffRGBIntoGrayString load exch
+ WalkRGBString
+ end
+ } def
+
+
+ /StuffCMYKIntoGrayString
+ {
+ exch .11 mul add
+
+ exch .59 mul add
+
+ exch .3 mul add
+
+ dup 255 gt { pop 255 } if
+
+ 255 exch sub cvi 3 copy put
+
+ pop 1 add
+ } def
+
+
+ /CMYKToGrayImageProc
+ {
+ Adobe_ColorImage_AI6_Vars begin
+ sourcearray 0 get exec
+ dup length 4 idiv string
+ dup 3 1 roll
+
+ /StuffCMYKIntoGrayString load exch
+ WalkCMYKString
+ end
+ } def
+
+
+ /ColorImageCompositeEmulator
+ {
+ pop true eq
+ {
+ Adobe_ColorImage_AI6_Vars /sourcecount get 5 add { pop } repeat
+ }
+ {
+ Adobe_ColorImage_AI6_Vars /channelcount get 1 ne
+ {
+ Adobe_ColorImage_AI6_Vars begin
+ sourcearray 0 3 -1 roll put
+
+ channelcount 3 eq
+ {
+ /RGBToGrayImageProc
+ }
+ {
+ /CMYKToGrayImageProc
+ } ifelse
+ load
+ end
+ } if
+ image
+ } ifelse
+ } def
+
+
+ /SeparateCMYKImageProc
+ {
+ Adobe_ColorImage_AI6_Vars begin
+
+ sourcecount 0 ne
+ {
+ sourcearray plateindex get exec
+ }
+ {
+ sourcearray 0 get exec
+
+ dup length 4 idiv string
+
+ 0 2 index
+
+ plateindex 4 2 index length 1 sub
+ {
+ get 255 exch sub
+
+ 3 copy put pop 1 add
+
+ 2 index
+ } for
+
+ pop pop exch pop
+ } ifelse
+ end
+ } def
+
+
+ /FourEqual
+ {
+ 4 index ne
+ {
+ pop pop pop false
+ }
+ {
+ 4 index ne
+ {
+ pop pop false
+ }
+ {
+ 4 index ne
+ {
+ pop false
+ }
+ {
+ 4 index eq
+ } ifelse
+ } ifelse
+ } ifelse
+ } def
+
+
+ /TestPlateIndex
+ {
+ Adobe_ColorImage_AI6_Vars begin
+ /plateindex -1 def
+
+ /setcmykcolor where
+ {
+ pop
+ gsave
+ 1 0 0 0 setcmykcolor systemdict /currentgray get exec 1 exch sub
+ 0 1 0 0 setcmykcolor systemdict /currentgray get exec 1 exch sub
+ 0 0 1 0 setcmykcolor systemdict /currentgray get exec 1 exch sub
+ 0 0 0 1 setcmykcolor systemdict /currentgray get exec 1 exch sub
+ grestore
+
+ 1 0 0 0 FourEqual
+ {
+ /plateindex 0 def
+ }
+ {
+ 0 1 0 0 FourEqual
+ {
+ /plateindex 1 def
+ }
+ {
+ 0 0 1 0 FourEqual
+ {
+ /plateindex 2 def
+ }
+ {
+ 0 0 0 1 FourEqual
+ {
+ /plateindex 3 def
+ }
+ {
+ 0 0 0 0 FourEqual
+ {
+ /plateindex 5 def
+ } if
+ } ifelse
+ } ifelse
+ } ifelse
+ } ifelse
+ pop pop pop pop
+ } if
+ plateindex
+ end
+ } def
+
+
+ /colorimage
+ {
+ Adobe_ColorImage_AI6_Vars begin
+ /channelcount 1 index def
+ /sourcecount 2 index 1 eq { channelcount 1 sub } { 0 } ifelse def
+
+ 4 sourcecount add index dup
+ 8 eq exch 1 eq or not
+ end
+
+ {
+ /_colorimage load null ne
+ {
+ _colorimage
+ }
+ {
+ Adobe_ColorImage_AI6_Vars /sourcecount get
+ 7 add { pop } repeat
+ } ifelse
+ }
+ {
+ dup 3 eq
+ TestPlateIndex
+ dup -1 eq exch 5 eq or or
+ {
+ /_colorimage load null eq
+ {
+ ColorImageCompositeEmulator
+ }
+ {
+ dup 1 eq
+ {
+ pop pop image
+ }
+ {
+ Adobe_ColorImage_AI6_Vars /plateindex get 5 eq
+ {
+ gsave
+
+ 0 _currenttransfer exec
+ 1 _currenttransfer exec
+ eq
+ { 0 _currenttransfer exec 0.5 lt }
+ { 0 _currenttransfer exec 1 _currenttransfer exec gt } ifelse
+
+ { { pop 0 } } { { pop 1 } } ifelse
+ systemdict /settransfer get exec
+ } if
+
+ _colorimage
+
+ Adobe_ColorImage_AI6_Vars /plateindex get 5 eq
+ {
+ grestore
+ } if
+ } ifelse
+ } ifelse
+ }
+ {
+ dup 1 eq
+ {
+ pop pop
+ image
+ }
+ {
+ pop pop
+
+ Adobe_ColorImage_AI6_Vars begin
+ sourcecount -1 0
+ {
+ exch sourcearray 3 1 roll put
+ } for
+
+ /SeparateCMYKImageProc load
+ end
+
+ systemdict /image get exec
+ } ifelse
+ } ifelse
+ } ifelse
+ } def
+
+ /XI
+ {
+ Adobe_ColorImage_AI6_Vars begin
+ gsave
+ /XIMask exch 0 ne def
+ /XIBinary exch 0 ne def
+ pop
+ pop
+ /XIChannelCount exch def
+ /XIBitsPerPixel exch def
+ /XIImageHeight exch def
+ /XIImageWidth exch def
+ pop pop pop pop
+ /XIImageMatrix exch def
+
+ XIBitsPerPixel 1 eq
+ {
+ XIImageWidth 8 div ceiling cvi
+ }
+ {
+ XIImageWidth XIChannelCount mul
+ } ifelse
+ /XIBuffer exch string def
+
+ XIBinary
+ {
+ /XIDataProc { currentfile XIBuffer readstring pop } def
+ currentfile 128 string readline pop pop
+ }
+ {
+ /XIDataProc { currentfile XIBuffer readhexstring pop } def
+ } ifelse
+
+ 0 0 moveto
+ XIImageMatrix concat
+ XIImageWidth XIImageHeight scale
+
+ XIMask
+ {
+ XIImageWidth XIImageHeight
+ false
+ [ XIImageWidth 0 0 XIImageHeight neg 0 0 ]
+ /XIDataProc load
+
+ /_lp /null ddef
+ _fc
+ /_lp /imagemask ddef
+
+ imagemask
+ }
+ {
+ XIImageWidth XIImageHeight
+ XIBitsPerPixel
+ [ XIImageWidth 0 0 XIImageHeight neg 0 0 ]
+ /XIDataProc load
+
+ XIChannelCount 1 eq
+ {
+
+ gsave
+ 0 setgray
+
+ image
+
+ grestore
+ }
+ {
+ false
+ XIChannelCount
+ colorimage
+ } ifelse
+ } ifelse
+ grestore
+ end
+ } def
+
+end
+%%EndProcSet
+%%BeginResource: procset Adobe_Illustrator_AI5 1.1 0
+%%Title: (Adobe Illustrator (R) Version 5.0 Full Prolog)
+%%Version: 1.1
+%%CreationDate: (3/7/1994) ()
+%%Copyright: ((C) 1987-1994 Adobe Systems Incorporated All Rights Reserved)
+currentpacking true setpacking
+userdict /Adobe_Illustrator_AI5_vars 81 dict dup begin
+put
+/_eo false def
+/_lp /none def
+/_pf
+{
+} def
+/_ps
+{
+} def
+/_psf
+{
+} def
+/_pss
+{
+} def
+/_pjsf
+{
+} def
+/_pjss
+{
+} def
+/_pola 0 def
+/_doClip 0 def
+/cf currentflat def
+/_tm matrix def
+/_renderStart
+[
+/e0 /r0 /a0 /o0 /e1 /r1 /a1 /i0
+] def
+/_renderEnd
+[
+null null null null /i1 /i1 /i1 /i1
+] def
+/_render -1 def
+/_rise 0 def
+/_ax 0 def
+/_ay 0 def
+/_cx 0 def
+/_cy 0 def
+/_leading
+[
+0 0
+] def
+/_ctm matrix def
+/_mtx matrix def
+/_sp 16#020 def
+/_hyphen (-) def
+/_fScl 0 def
+/_cnt 0 def
+/_hs 1 def
+/_nativeEncoding 0 def
+/_useNativeEncoding 0 def
+/_tempEncode 0 def
+/_pntr 0 def
+/_tDict 2 dict def
+/_wv 0 def
+/Tx
+{
+} def
+/Tj
+{
+} def
+/CRender
+{
+} def
+/_AI3_savepage
+{
+} def
+/_gf null def
+/_cf 4 array def
+/_if null def
+/_of false def
+/_fc
+{
+} def
+/_gs null def
+/_cs 4 array def
+/_is null def
+/_os false def
+/_sc
+{
+} def
+/_pd 1 dict def
+/_ed 15 dict def
+/_pm matrix def
+/_fm null def
+/_fd null def
+/_fdd null def
+/_sm null def
+/_sd null def
+/_sdd null def
+/_i null def
+/discardSave null def
+/buffer 256 string def
+/beginString null def
+/endString null def
+/endStringLength null def
+/layerCnt 1 def
+/layerCount 1 def
+/perCent (%) 0 get def
+/perCentSeen? false def
+/newBuff null def
+/newBuffButFirst null def
+/newBuffLast null def
+/clipForward? false def
+end
+userdict /Adobe_Illustrator_AI5 known not {
+ userdict /Adobe_Illustrator_AI5 91 dict put
+} if
+userdict /Adobe_Illustrator_AI5 get begin
+/initialize
+{
+ Adobe_Illustrator_AI5 dup begin
+ Adobe_Illustrator_AI5_vars begin
+ discardDict
+ {
+ bind pop pop
+ } forall
+ dup /nc get begin
+ {
+ dup xcheck 1 index type /operatortype ne and
+ {
+ bind
+ } if
+ pop pop
+ } forall
+ end
+ newpath
+} def
+/terminate
+{
+ end
+ end
+} def
+/_
+null def
+/ddef
+{
+ Adobe_Illustrator_AI5_vars 3 1 roll put
+} def
+/xput
+{
+ dup load dup length exch maxlength eq
+ {
+ dup dup load dup
+ length 2 mul dict copy def
+ } if
+ load begin
+ def
+ end
+} def
+/npop
+{
+ {
+ pop
+ } repeat
+} def
+/sw
+{
+ dup length exch stringwidth
+ exch 5 -1 roll 3 index mul add
+ 4 1 roll 3 1 roll mul add
+} def
+/swj
+{
+ dup 4 1 roll
+ dup length exch stringwidth
+ exch 5 -1 roll 3 index mul add
+ 4 1 roll 3 1 roll mul add
+ 6 2 roll /_cnt 0 ddef
+ {
+ 1 index eq
+ {
+ /_cnt _cnt 1 add ddef
+ } if
+ } forall
+ pop
+ exch _cnt mul exch _cnt mul 2 index add 4 1 roll 2 index add 4 1 roll pop pop
+} def
+/ss
+{
+ 4 1 roll
+ {
+ 2 npop
+ (0) exch 2 copy 0 exch put pop
+ gsave
+ false charpath currentpoint
+ 4 index setmatrix
+ stroke
+ grestore
+ moveto
+ 2 copy rmoveto
+ } exch cshow
+ 3 npop
+} def
+/jss
+{
+ 4 1 roll
+ {
+ 2 npop
+ (0) exch 2 copy 0 exch put
+ gsave
+ _sp eq
+ {
+ exch 6 index 6 index 6 index 5 -1 roll widthshow
+ currentpoint
+ }
+ {
+ false charpath currentpoint
+ 4 index setmatrix stroke
+ } ifelse
+ grestore
+ moveto
+ 2 copy rmoveto
+ } exch cshow
+ 6 npop
+} def
+/sp
+{
+ {
+ 2 npop (0) exch
+ 2 copy 0 exch put pop
+ false charpath
+ 2 copy rmoveto
+ } exch cshow
+ 2 npop
+} def
+/jsp
+{
+ {
+ 2 npop
+ (0) exch 2 copy 0 exch put
+ _sp eq
+ {
+ exch 5 index 5 index 5 index 5 -1 roll widthshow
+ }
+ {
+ false charpath
+ } ifelse
+ 2 copy rmoveto
+ } exch cshow
+ 5 npop
+} def
+/pl
+{
+ transform
+ 0.25 sub round 0.25 add exch
+ 0.25 sub round 0.25 add exch
+ itransform
+} def
+/setstrokeadjust where
+{
+ pop true setstrokeadjust
+ /c
+ {
+ curveto
+ } def
+ /C
+ /c load def
+ /v
+ {
+ currentpoint 6 2 roll curveto
+ } def
+ /V
+ /v load def
+ /y
+ {
+ 2 copy curveto
+ } def
+ /Y
+ /y load def
+ /l
+ {
+ lineto
+ } def
+ /L
+ /l load def
+ /m
+ {
+ moveto
+ } def
+}
+{
+ /c
+ {
+ pl curveto
+ } def
+ /C
+ /c load def
+ /v
+ {
+ currentpoint 6 2 roll pl curveto
+ } def
+ /V
+ /v load def
+ /y
+ {
+ pl 2 copy curveto
+ } def
+ /Y
+ /y load def
+ /l
+ {
+ pl lineto
+ } def
+ /L
+ /l load def
+ /m
+ {
+ pl moveto
+ } def
+} ifelse
+/d
+{
+ setdash
+} def
+/cf
+{
+} def
+/i
+{
+ dup 0 eq
+ {
+ pop cf
+ } if
+ setflat
+} def
+/j
+{
+ setlinejoin
+} def
+/J
+{
+ setlinecap
+} def
+/M
+{
+ setmiterlimit
+} def
+/w
+{
+ setlinewidth
+} def
+/XR
+{
+ 0 ne
+ /_eo exch ddef
+} def
+/H
+{
+} def
+/h
+{
+ closepath
+} def
+/N
+{
+ _pola 0 eq
+ {
+ _doClip 1 eq
+ {
+ _eo {eoclip} {clip} ifelse /_doClip 0 ddef
+ } if
+ newpath
+ }
+ {
+ /CRender
+ {
+ N
+ } ddef
+ } ifelse
+} def
+/n
+{
+ N
+} def
+/F
+{
+ _pola 0 eq
+ {
+ _doClip 1 eq
+ {
+ gsave _pf grestore _eo {eoclip} {clip} ifelse newpath /_lp /none ddef _fc
+ /_doClip 0 ddef
+ }
+ {
+ _pf
+ } ifelse
+ }
+ {
+ /CRender
+ {
+ F
+ } ddef
+ } ifelse
+} def
+/f
+{
+ closepath
+ F
+} def
+/S
+{
+ _pola 0 eq
+ {
+ _doClip 1 eq
+ {
+ gsave _ps grestore _eo {eoclip} {clip} ifelse newpath /_lp /none ddef _sc
+ /_doClip 0 ddef
+ }
+ {
+ _ps
+ } ifelse
+ }
+ {
+ /CRender
+ {
+ S
+ } ddef
+ } ifelse
+} def
+/s
+{
+ closepath
+ S
+} def
+/B
+{
+ _pola 0 eq
+ {
+ _doClip 1 eq
+ gsave F grestore
+ {
+ gsave S grestore _eo {eoclip} {clip} ifelse newpath /_lp /none ddef _sc
+ /_doClip 0 ddef
+ }
+ {
+ S
+ } ifelse
+ }
+ {
+ /CRender
+ {
+ B
+ } ddef
+ } ifelse
+} def
+/b
+{
+ closepath
+ B
+} def
+/W
+{
+ /_doClip 1 ddef
+} def
+/*
+{
+ count 0 ne
+ {
+ dup type /stringtype eq
+ {
+ pop
+ } if
+ } if
+ newpath
+} def
+/u
+{
+} def
+/U
+{
+} def
+/q
+{
+ _pola 0 eq
+ {
+ gsave
+ } if
+} def
+/Q
+{
+ _pola 0 eq
+ {
+ grestore
+ } if
+} def
+/*u
+{
+ _pola 1 add /_pola exch ddef
+} def
+/*U
+{
+ _pola 1 sub /_pola exch ddef
+ _pola 0 eq
+ {
+ CRender
+ } if
+} def
+/D
+{
+ pop
+} def
+/*w
+{
+} def
+/*W
+{
+} def
+/`
+{
+ /_i save ddef
+ clipForward?
+ {
+ nulldevice
+ } if
+ 6 1 roll 4 npop
+ concat pop
+ userdict begin
+ /showpage
+ {
+ } def
+ 0 setgray
+ 0 setlinecap
+ 1 setlinewidth
+ 0 setlinejoin
+ 10 setmiterlimit
+ [] 0 setdash
+ /setstrokeadjust where {pop false setstrokeadjust} if
+ newpath
+ 0 setgray
+ false setoverprint
+} def
+/~
+{
+ end
+ _i restore
+} def
+/O
+{
+ 0 ne
+ /_of exch ddef
+ /_lp /none ddef
+} def
+/R
+{
+ 0 ne
+ /_os exch ddef
+ /_lp /none ddef
+} def
+/g
+{
+ /_gf exch ddef
+ /_fc
+ {
+ _lp /fill ne
+ {
+ _of setoverprint
+ _gf setgray
+ /_lp /fill ddef
+ } if
+ } ddef
+ /_pf
+ {
+ _fc
+ _eo {eofill} {fill} ifelse
+ } ddef
+ /_psf
+ {
+ _fc
+ ashow
+ } ddef
+ /_pjsf
+ {
+ _fc
+ awidthshow
+ } ddef
+ /_lp /none ddef
+} def
+/G
+{
+ /_gs exch ddef
+ /_sc
+ {
+ _lp /stroke ne
+ {
+ _os setoverprint
+ _gs setgray
+ /_lp /stroke ddef
+ } if
+ } ddef
+ /_ps
+ {
+ _sc
+ stroke
+ } ddef
+ /_pss
+ {
+ _sc
+ ss
+ } ddef
+ /_pjss
+ {
+ _sc
+ jss
+ } ddef
+ /_lp /none ddef
+} def
+/k
+{
+ _cf astore pop
+ /_fc
+ {
+ _lp /fill ne
+ {
+ _of setoverprint
+ _cf aload pop setcmykcolor
+ /_lp /fill ddef
+ } if
+ } ddef
+ /_pf
+ {
+ _fc
+ _eo {eofill} {fill} ifelse
+ } ddef
+ /_psf
+ {
+ _fc
+ ashow
+ } ddef
+ /_pjsf
+ {
+ _fc
+ awidthshow
+ } ddef
+ /_lp /none ddef
+} def
+/K
+{
+ _cs astore pop
+ /_sc
+ {
+ _lp /stroke ne
+ {
+ _os setoverprint
+ _cs aload pop setcmykcolor
+ /_lp /stroke ddef
+ } if
+ } ddef
+ /_ps
+ {
+ _sc
+ stroke
+ } ddef
+ /_pss
+ {
+ _sc
+ ss
+ } ddef
+ /_pjss
+ {
+ _sc
+ jss
+ } ddef
+ /_lp /none ddef
+} def
+/x
+{
+ /_gf exch ddef
+ findcmykcustomcolor
+ /_if exch ddef
+ /_fc
+ {
+ _lp /fill ne
+ {
+ _of setoverprint
+ _if _gf 1 exch sub setcustomcolor
+ /_lp /fill ddef
+ } if
+ } ddef
+ /_pf
+ {
+ _fc
+ _eo {eofill} {fill} ifelse
+ } ddef
+ /_psf
+ {
+ _fc
+ ashow
+ } ddef
+ /_pjsf
+ {
+ _fc
+ awidthshow
+ } ddef
+ /_lp /none ddef
+} def
+/X
+{
+ /_gs exch ddef
+ findcmykcustomcolor
+ /_is exch ddef
+ /_sc
+ {
+ _lp /stroke ne
+ {
+ _os setoverprint
+ _is _gs 1 exch sub setcustomcolor
+ /_lp /stroke ddef
+ } if
+ } ddef
+ /_ps
+ {
+ _sc
+ stroke
+ } ddef
+ /_pss
+ {
+ _sc
+ ss
+ } ddef
+ /_pjss
+ {
+ _sc
+ jss
+ } ddef
+ /_lp /none ddef
+} def
+/A
+{
+ pop
+} def
+/annotatepage
+{
+userdict /annotatepage 2 copy known {get exec} {pop pop} ifelse
+} def
+/XT {
+ pop pop
+} def
+/discard
+{
+ save /discardSave exch store
+ discardDict begin
+ /endString exch store
+ gt38?
+ {
+ 2 add
+ } if
+ load
+ stopped
+ pop
+ end
+ discardSave restore
+} bind def
+userdict /discardDict 7 dict dup begin
+put
+/pre38Initialize
+{
+ /endStringLength endString length store
+ /newBuff buffer 0 endStringLength getinterval store
+ /newBuffButFirst newBuff 1 endStringLength 1 sub getinterval store
+ /newBuffLast newBuff endStringLength 1 sub 1 getinterval store
+} def
+/shiftBuffer
+{
+ newBuff 0 newBuffButFirst putinterval
+ newBuffLast 0
+ currentfile read not
+ {
+ stop
+ } if
+ put
+} def
+0
+{
+ pre38Initialize
+ mark
+ currentfile newBuff readstring exch pop
+ {
+ {
+ newBuff endString eq
+ {
+ cleartomark stop
+ } if
+ shiftBuffer
+ } loop
+ }
+ {
+ stop
+ } ifelse
+} def
+1
+{
+ pre38Initialize
+ /beginString exch store
+ mark
+ currentfile newBuff readstring exch pop
+ {
+ {
+ newBuff beginString eq
+ {
+ /layerCount dup load 1 add store
+ }
+ {
+ newBuff endString eq
+ {
+ /layerCount dup load 1 sub store
+ layerCount 0 eq
+ {
+ cleartomark stop
+ } if
+ } if
+ } ifelse
+ shiftBuffer
+ } loop
+ } if
+} def
+2
+{
+ mark
+ {
+ currentfile buffer readline not
+ {
+ stop
+ } if
+ endString eq
+ {
+ cleartomark stop
+ } if
+ } loop
+} def
+3
+{
+ /beginString exch store
+ /layerCnt 1 store
+ mark
+ {
+ currentfile buffer readline not
+ {
+ stop
+ } if
+ dup beginString eq
+ {
+ pop /layerCnt dup load 1 add store
+ }
+ {
+ endString eq
+ {
+ layerCnt 1 eq
+ {
+ cleartomark stop
+ }
+ {
+ /layerCnt dup load 1 sub store
+ } ifelse
+ } if
+ } ifelse
+ } loop
+} def
+end
+userdict /clipRenderOff 15 dict dup begin
+put
+{
+ /n /N /s /S /f /F /b /B
+}
+{
+ {
+ _doClip 1 eq
+ {
+ /_doClip 0 ddef _eo {eoclip} {clip} ifelse
+ } if
+ newpath
+ } def
+} forall
+/Tr /pop load def
+/Bb {} def
+/BB /pop load def
+/Bg {12 npop} def
+/Bm {6 npop} def
+/Bc /Bm load def
+/Bh {4 npop} def
+end
+/Lb
+{
+ 4 npop
+ 6 1 roll
+ pop
+ 4 1 roll
+ pop pop pop
+ 0 eq
+ {
+ 0 eq
+ {
+ (%AI5_BeginLayer) 1 (%AI5_EndLayer--) discard
+ }
+ {
+
+ /clipForward? true def
+
+ /Tx /pop load def
+ /Tj /pop load def
+
+ currentdict end clipRenderOff begin begin
+ } ifelse
+ }
+ {
+ 0 eq
+ {
+ save /discardSave exch store
+ } if
+ } ifelse
+} bind def
+/LB
+{
+ discardSave dup null ne
+ {
+ restore
+ }
+ {
+ pop
+ clipForward?
+ {
+ currentdict
+ end
+ end
+ begin
+
+ /clipForward? false ddef
+ } if
+ } ifelse
+} bind def
+/Pb
+{
+ pop pop
+ 0 (%AI5_EndPalette) discard
+} bind def
+/Np
+{
+ 0 (%AI5_End_NonPrinting--) discard
+} bind def
+/Ln /pop load def
+/Ap
+/pop load def
+/Ar
+{
+ 72 exch div
+ 0 dtransform dup mul exch dup mul add sqrt
+ dup 1 lt
+ {
+ pop 1
+ } if
+ setflat
+} def
+/Mb
+{
+ q
+} def
+/Md
+{
+} def
+/MB
+{
+ Q
+} def
+/nc 3 dict def
+nc begin
+/setgray
+{
+ pop
+} bind def
+/setcmykcolor
+{
+ 4 npop
+} bind def
+/setcustomcolor
+{
+ 2 npop
+} bind def
+currentdict readonly pop
+end
+end
+setpacking
+%%EndResource
+%%EndProlog
+%%BeginSetup
+%%IncludeFont: Univers
+Adobe_level2_AI5 /initialize get exec
+Adobe_Illustrator_AI5_vars Adobe_Illustrator_AI5 Adobe_typography_AI5 /initialize get exec
+Adobe_ColorImage_AI6 /initialize get exec
+Adobe_Illustrator_AI5 /initialize get exec
+[
+39/quotesingle 96/grave 128/Adieresis/Aring/Ccedilla/Eacute/Ntilde/Odieresis
+/Udieresis/aacute/agrave/acircumflex/adieresis/atilde/aring/ccedilla/eacute
+/egrave/ecircumflex/edieresis/iacute/igrave/icircumflex/idieresis/ntilde
+/oacute/ograve/ocircumflex/odieresis/otilde/uacute/ugrave/ucircumflex
+/udieresis/dagger/degree/cent/sterling/section/bullet/paragraph/germandbls
+/registered/copyright/trademark/acute/dieresis/.notdef/AE/Oslash
+/.notdef/plusminus/.notdef/.notdef/yen/mu/.notdef/.notdef
+/.notdef/.notdef/.notdef/ordfeminine/ordmasculine/.notdef/ae/oslash
+/questiondown/exclamdown/logicalnot/.notdef/florin/.notdef/.notdef
+/guillemotleft/guillemotright/ellipsis/.notdef/Agrave/Atilde/Otilde/OE/oe
+/endash/emdash/quotedblleft/quotedblright/quoteleft/quoteright/divide
+/.notdef/ydieresis/Ydieresis/fraction/currency/guilsinglleft/guilsinglright
+/fi/fl/daggerdbl/periodcentered/quotesinglbase/quotedblbase/perthousand
+/Acircumflex/Ecircumflex/Aacute/Edieresis/Egrave/Iacute/Icircumflex
+/Idieresis/Igrave/Oacute/Ocircumflex/.notdef/Ograve/Uacute/Ucircumflex
+/Ugrave/dotlessi/circumflex/tilde/macron/breve/dotaccent/ring/cedilla
+/hungarumlaut/ogonek/caron
+TE
+%AI3_BeginEncoding: _Univers Univers
+[/_Univers/Univers 0 0 1 TZ
+%AI3_EndEncoding AdobeType
+%AI5_Begin_NonPrinting
+Np
+8 Bn
+%AI5_BeginGradient: (Black & White)
+(Black & White) 0 2 Bd
+[
+<
+FFFEFDFCFBFAF9F8F7F6F5F4F3F2F1F0EFEEEDECEBEAE9E8E7E6E5E4E3E2E1E0DFDEDDDCDBDAD9D8
+D7D6D5D4D3D2D1D0CFCECDCCCBCAC9C8C7C6C5C4C3C2C1C0BFBEBDBCBBBAB9B8B7B6B5B4B3B2B1B0
+AFAEADACABAAA9A8A7A6A5A4A3A2A1A09F9E9D9C9B9A999897969594939291908F8E8D8C8B8A8988
+87868584838281807F7E7D7C7B7A797877767574737271706F6E6D6C6B6A69686766656463626160
+5F5E5D5C5B5A595857565554535251504F4E4D4C4B4A494847464544434241403F3E3D3C3B3A3938
+37363534333231302F2E2D2C2B2A292827262524232221201F1E1D1C1B1A19181716151413121110
+0F0E0D0C0B0A09080706050403020100
+>
+0 %_Br
+[
+0 0 50 100 %_Bs
+1 0 50 0 %_Bs
+BD
+%AI5_EndGradient
+%AI5_BeginGradient: (Green & Blue)
+(Green & Blue) 0 2 Bd
+[
+<
+99999A9A9B9B9B9C9C9D9D9D9E9E9F9F9FA0A0A1A1A1A2A2A3A3A3A4A4A5A5A5A6A6A7A7A7A8A8A9
+A9A9AAAAABABABACACADADADAEAEAFAFAFB0B0B1B1B1B2B2B3B3B3B4B4B5B5B5B6B6B7B7B7B8B8B9
+B9B9BABABBBBBBBCBCBDBDBDBEBEBFBFBFC0C0C1C1C1C2C2C3C3C3C4C4C5C5C5C6C6C7C7C7C8C8C9
+C9C9CACACBCBCBCCCCCDCDCDCECECFCFCFD0D0D1D1D1D2D2D3D3D3D4D4D5D5D5D6D6D7D7D7D8D8D9
+D9D9DADADBDBDBDCDCDDDDDDDEDEDFDFDFE0E0E1E1E1E2E2E3E3E3E4E4E5E5E5E6E6E7E7E7E8E8E9
+E9E9EAEAEBEBEBECECEDEDEDEEEEEFEFEFF0F0F1F1F1F2F2F3F3F3F4F4F5F5F5F6F6F7F7F7F8F8F9
+F9F9FAFAFBFBFBFCFCFDFDFDFEFEFFFF
+>
+<
+000102020304050506070808090A0B0B0C0D0E0E0F101111121314141516171718191A1A1B1C1D1D
+1E1F20202122232324252626272829292A2B2C2C2D2E2F2F303132323334353536373838393A3B3B
+3C3D3E3E3F404141424344444546474748494A4A4B4C4D4D4E4F5050515253535455565657585959
+5A5B5C5C5D5E5F5F606162626364656566676868696A6B6B6C6D6E6E6F7071717273747475767777
+78797A7A7B7C7D7D7E7F80808182828384858586878888898A8B8B8C8D8E8E8F9091919293949495
+96979798999A9A9B9C9D9D9E9FA0A0A1A2A3A3A4A5A6A6A7A8A9A9AAABACACADAEAFAFB0B1B2B2B3
+B4B5B5B6B7B8B8B9BABBBBBCBDBEBEBF
+>
+<
+FFFEFDFCFBFAF9F8F7F6F5F4F3F2F1F0EFEEEDECEBEAE9E8E7E6E5E4E3E2E1E0DFDEDDDCDBDAD9D8
+D7D6D5D4D3D2D1D0CFCECDCCCBCAC9C8C7C6C5C4C3C2C1C0BFBEBDBCBBBAB9B8B7B6B5B4B3B2B1B0
+AFAEADACABAAA9A8A7A6A5A4A3A2A1A09F9E9D9C9B9A999897969594939291908F8E8D8C8B8A8988
+87868584838281807F7E7D7C7B7A797877767574737271706F6E6D6C6B6A69686766656463626160
+5F5E5D5C5B5A595857565554535251504F4E4D4C4B4A494847464544434241403F3E3D3C3B3A3938
+37363534333231302F2E2D2C2B2A292827262524232221201F1E1D1C1B1A19181716151413121110
+0F0E0D0C0B0A09080706050403020100
+>
+0
+1 %_Br
+[
+1 0.75 0 0 1 50 100 %_Bs
+0.6 0 1 0 1 50 0 %_Bs
+BD
+%AI5_EndGradient
+%AI5_BeginGradient: (Pink, Yellow, Green)
+(Pink, Yellow, Green) 0 3 Bd
+[
+<
+00000000000000000000000000000000000000010101010101010101010101010101010101010101
+01010101010202020202020202020202020202020202020202020203030303030303030303030303
+03030303030303030404040404040404040404040404040404040404050505050505050505050505
+05050505050505060606060606060606060606060606060606060707070707070707070707070707
+07070707080808080808080808080808080808080809090909090909090909090909090909090A0A
+0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0C0C0C0C0C0C0C0C0C
+0C0C0C0C0C0C0C0D0D0D0D0D
+>
+<
+050506060606070708080809090A0A0A0B0B0C0C0D0D0E0E0F0F1010111112121313141415151617
+17181819191A1A1B1C1C1D1D1E1F1F202021222223232425252626272828292A2A2B2C2C2D2D2E2F
+2F3031313233333435353637373839393A3B3B3C3D3E3E3F4040414242434445454647474849494A
+4B4C4C4D4E4F4F505151525354545556575758595A5A5B5C5C5D5E5F5F6061626363646566666768
+69696A6B6C6C6D6E6F707071727373747576777778797A7B7B7C7D7E7F7F80818283838485868787
+88898A8B8B8C8D8E8F8F9091929394949596979898999A9B9C9D9D9E9FA0A1A2A2A3A4A5A6A7A7A8
+A9AAABACADADAEAFB0B1B2B2
+>
+<
+CCCCCBCBCBCACACAC9C9C8C8C7C7C6C6C5C5C4C4C3C2C2C1C1C0C0BFBEBEBDBDBCBBBBBAB9B9B8B7
+B7B6B6B5B4B4B3B2B1B1B0AFAFAEADADACABAAAAA9A8A8A7A6A5A5A4A3A2A2A1A0A09F9E9D9C9C9B
+9A999998979696959493929291908F8E8E8D8C8B8A8A8988878686858483828181807F7E7D7C7C7B
+7A7978777776757473727171706F6E6D6C6B6A6A69686766656463636261605F5E5D5C5B5B5A5958
+5756555453525151504F4E4D4C4B4A49484746464544434241403F3E3D3C3B3A3938383736353433
+3231302F2E2D2C2B2A29282726252423222221201F1E1D1C1B1A191817161514131211100F0E0D0C
+0B0A09080706050403020100
+>
+0
+1 %_Br
+<
+737271706F6E6D6C6B6A696867666564636261605F5E5D5C5B5B5A59585756555453525150504F4E
+4D4C4B4A4949484746454443434241403F3E3E3D3C3B3A3A393837363635343333323130302F2E2D
+2D2C2B2A2A29282827262525242323222121201F1F1E1D1D1C1C1B1A1A1918181717161615141413
+1312121111100F0F0E0E0D0D0C0C0C0B0B0A0A090908080807070606060505050404040303030202
+020201010101010000000000
+>
+<
+00000000000000000000000001010101010101010101010101010101010101010101010102020202
+02020202020202020202020202020202020202020202030303030303030303030303030303030303
+03030303030303030303030303040404040404040404040404040404040404040404040404040404
+04040404040404040404050505050505050505050505050505050505050505050505050505050505
+050505050505050505050505
+>
+<
+BFBFBFC0C0C0C0C0C0C0C0C0C1C1C1C1C1C1C1C1C1C2C2C2C2C2C2C2C2C2C2C3C3C3C3C3C3C3C3C3
+C3C4C4C4C4C4C4C4C4C4C4C5C5C5C5C5C5C5C5C5C5C5C6C6C6C6C6C6C6C6C6C6C6C6C7C7C7C7C7C7
+C7C7C7C7C7C7C8C8C8C8C8C8C8C8C8C8C8C8C8C9C9C9C9C9C9C9C9C9C9C9C9C9C9C9CACACACACACA
+CACACACACACACACACACACBCBCBCBCBCBCBCBCBCBCBCBCBCBCBCBCBCBCBCBCBCBCCCCCCCCCCCCCCCC
+CCCCCCCCCCCCCCCCCCCCCCCC
+>
+0
+1 %_Br
+[
+0.05 0.7 0 0 1 50 100 %_Bs
+0 0.02 0.8 0 1 57 36 %_Bs
+0.45 0 0.75 0 1 37 0 %_Bs
+BD
+%AI5_EndGradient
+%AI5_BeginGradient: (Purple, Red & Yellow)
+(Purple, Red & Yellow) 0 3 Bd
+[
+0
+<
+FFFEFDFCFBFAF9F8F7F6F5F4F3F2F1F0EFEEEDECEBEAE9E8E7E6E5E4E3E2E1E0DFDEDDDCDBDAD9D8
+D7D6D5D4D3D2D1D0CFCECDCCCBCAC9C8C7C6C5C4C3C2C1C0BFBEBDBCBBBAB9B8B7B6B5B4B3B2B1B0
+AFAEADACABAAA9A8A7A6A5A4A3A2A1A09F9E9D9C9B9A999897969594939291908F8E8D8C8B8A8988
+87868584838281807F7E7D7C7B7A797877767574737271706F6E6D6C6B6A69686766656463626160
+5F5E5D5C5B5A595857565554535251504F4E4D4C4B4A494847464544434241403F3E3D3C3B3A3938
+37363534333231302F2E2D2C2B2A292827262524232221201F1E1D1C1B1A19181716151413121110
+0F0E0D0C0B0A
+>
+<
+CCCCCCCDCDCDCDCDCECECECECECFCFCFCFD0D0D0D0D0D1D1D1D1D1D2D2D2D2D2D3D3D3D3D3D4D4D4
+D4D5D5D5D5D5D6D6D6D6D6D7D7D7D7D7D8D8D8D8D8D9D9D9D9DADADADADADBDBDBDBDBDCDCDCDCDC
+DDDDDDDDDDDEDEDEDEDFDFDFDFDFE0E0E0E0E0E1E1E1E1E1E2E2E2E2E2E3E3E3E3E4E4E4E4E4E5E5
+E5E5E5E6E6E6E6E6E7E7E7E7E7E8E8E8E8E9E9E9E9E9EAEAEAEAEAEBEBEBEBEBECECECECECEDEDED
+EDEEEEEEEEEEEFEFEFEFEFF0F0F0F0F0F1F1F1F1F1F2F2F2F2F3F3F3F3F3F4F4F4F4F4F5F5F5F5F5
+F6F6F6F6F6F7F7F7F7F8F8F8F8F8F9F9F9F9F9FAFAFAFAFAFBFBFBFBFBFCFCFCFCFDFDFDFDFDFEFE
+FEFEFEFFFFFF
+>
+0
+1 %_Br
+<
+E5E4E3E2E1E0DFDEDDDCDBDAD9D8D7D6D5D4D3D2D1D0CFCECDCCCBCAC9C8C7C6C5C4C3C2C1C0BFBE
+BDBCBBBAB9B8B7B6B5B4B3B2B1B0AFAEADACABAAA9A8A7A6A5A4A3A2A1A09F9E9D9C9B9A99989796
+9594939291908F8E8D8C8B8A898887868584838281807F7E7D7C7B7A797877767574737271706F6E
+6D6C6B6A696867666564636261605F5E5D5C5B5A595857565554535251504F4E4D4C4B4A49484746
+4544434241403F3E3D3C3B3A393837363534333231302F2E2D2C2B2A292827262524232221201F1E
+1D1C1B1A191817161514131211100F0E0D0C0B0A09080706050403020100
+>
+<
+E5E6E6E6E6E6E6E6E6E7E7E7E7E7E7E7E7E7E8E8E8E8E8E8E8E8E8E9E9E9E9E9E9E9E9E9EAEAEAEA
+EAEAEAEAEAEBEBEBEBEBEBEBEBEBECECECECECECECECECEDEDEDEDEDEDEDEDEDEEEEEEEEEEEEEEEE
+EEEFEFEFEFEFEFEFEFEFF0F0F0F0F0F0F0F0F0F1F1F1F1F1F1F1F1F1F2F2F2F2F2F2F2F2F2F3F3F3
+F3F3F3F3F3F3F4F4F4F4F4F4F4F4F4F5F5F5F5F5F5F5F5F5F6F6F6F6F6F6F6F6F6F7F7F7F7F7F7F7
+F7F7F8F8F8F8F8F8F8F8F8F9F9F9F9F9F9F9F9F9FAFAFAFAFAFAFAFAFAFBFBFBFBFBFBFBFBFBFCFC
+FCFCFCFCFCFCFCFDFDFDFDFDFDFDFDFDFEFEFEFEFEFEFEFEFEFFFFFFFFFF
+>
+<
+00010203040405060708090A0B0C0C0D0E0F10111213141415161718191A1B1C1D1D1E1F20212223
+242525262728292A2B2C2D2D2E2F30313233343535363738393A3B3C3D3D3E3F4041424344454546
+4748494A4B4C4D4E4E4F50515253545556565758595A5B5C5D5E5E5F60616263646566666768696A
+6B6C6D6E6E6F70717273747576767778797A7B7C7D7E7F7F80818283848586878788898A8B8C8D8E
+8F8F90919293949596979798999A9B9C9D9E9F9FA0A1A2A3A4A5A6A7A7A8A9AAABACADAEAFAFB0B1
+B2B3B4B5B6B7B8B8B9BABBBCBDBEBFC0C0C1C2C3C4C5C6C7C8C8C9CACBCC
+>
+0
+1 %_Br
+[
+0 0.04 1 0 1 50 100 %_Bs
+0 1 0.8 0 1 50 50 %_Bs
+0.9 0.9 0 0 1 50 0 %_Bs
+BD
+%AI5_EndGradient
+%AI5_BeginGradient: (Rainbow)
+(Rainbow) 0 6 Bd
+[
+<
+FFFEFDFCFBFAF9F8F7F6F5F4F3F2F1F0EFEEEDECEBEAE9E8E7E6E5E4E3E2E1E0DFDEDDDCDBDAD9D8
+D7D6D5D4D3D2D1D0CFCECDCCCBCAC9C8C7C6C5C4C3C2C1C0BFBEBDBCBBBAB9B8B7B6B5B4B3B2B1B0
+AFAEADACABAAA9A8A7A6A5A4A3A2A1A09F9E9D9C9B9A999897969594939291908F8E8D8C8B8A8988
+87868584838281807F7E7D7C7B7A797877767574737271706F6E6D6C6B6A69686766656463626160
+5F5E5D5C5B5A595857565554535251504F4E4D4C4B4A494847464544434241403F3E3D3C3B3A3938
+37363534333231302F2E2D2C2B2A292827262524232221201F1E1D1C1B1A19181716151413121110
+0F0E0D0C0B0A09080706050403020100
+>
+1
+0
+0
+1 %_Br
+1
+<
+0708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E
+2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F50515253545556
+5758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E
+7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6
+A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7C8C9CACBCCCDCE
+CFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6
+F7F8F9FAFBFCFDFEFF
+>
+0
+0
+1 %_Br
+1
+<
+00000000000000000000000000000000000001010101010101010101010101010101010101010101
+01010101010101010101010101010202020202020202020202020202020202020202020202020202
+02020202020202020202030303030303030303030303030303030303030303030303030303030303
+03030303030304040404040404040404040404040404040404040404040404040404040404040404
+04040505050505050505050505050505050505050505050505050505050505050505050505050606
+06060606060606060606060606060606060606060606060606060606060606060606070707070707
+07070707070707070707070707070707
+>
+<
+FFFEFDFCFBFAF9F8F7F6F5F4F3F2F1F0EFEEEDECEBEAE9E8E7E6E5E4E3E2E1E0DFDEDDDCDBDAD9D8
+D7D6D5D4D3D2D1D0CFCECDCCCBCAC9C8C7C6C5C4C3C2C1C0BFBEBDBCBBBAB9B8B7B6B5B4B3B2B1B0
+AFAEADACABAAA9A8A7A6A5A4A3A2A1A09F9E9D9C9B9A999897969594939291908F8E8D8C8B8A8988
+87868584838281807F7E7D7C7B7A797877767574737271706F6E6D6C6B6A69686766656463626160
+5F5E5D5C5B5A595857565554535251504F4E4D4C4B4A494847464544434241403F3E3D3C3B3A3938
+37363534333231302F2E2D2C2B2A292827262524232221201F1E1D1C1B1A19181716151413121110
+0F0E0D0C0B0A09080706050403020100
+>
+0
+1 %_Br
+<
+000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627
+28292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F
+505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F7071727374757677
+78797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9F
+A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7
+C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEF
+F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF
+>
+0
+1
+0
+1 %_Br
+0
+<
+FFFEFDFCFBFAF9F8F7F6F5F4F3F2F1F0EFEEEDECEBEAE9E8E7E6E5E4E3E2E1E0DFDEDDDCDBDAD9D8
+D7D6D5D4D3D2D1D0CFCECDCCCBCAC9C8C7C6C5C4C3C2C1C0BFBEBDBCBBBAB9B8B7B6B5B4B3B2B1B0
+AFAEADACABAAA9A8A7A6A5A4A3A2A1A09F9E9D9C9B9A999897969594939291908F8E8D8C8B8A8988
+87868584838281807F7E7D7C7B7A797877767574737271706F6E6D6C6B6A69686766656463626160
+5F5E5D5C5B5A595857565554535251504F4E4D4C4B4A494847464544434241403F3E3D3C3B3A3938
+37363534333231302F2E2D2C2B2A292827262524232221201F1E1D1C1B1A19181716151413121110
+0F0E0D0C0B0A09080706050403020100
+>
+1
+0
+1 %_Br
+[
+0 1 0 0 1 50 100 %_Bs
+1 1 0 0 1 50 80 %_Bs
+1 0.0279 0 0 1 50 60 %_Bs
+1 0 1 0 1 50 40 %_Bs
+0 0 1 0 1 50 20 %_Bs
+0 1 1 0 1 50 0 %_Bs
+BD
+%AI5_EndGradient
+%AI5_BeginGradient: (Steel Bar)
+(Steel Bar) 0 3 Bd
+[
+<
+FFFEFDFCFBFAF9F8F7F6F5F4F3F2F1F0EFEEEDECEBEAE9E8E7E6E5E4E3E2E1E0DFDEDDDCDBDAD9D8
+D7D6D5D4D3D2D1D0CFCECDCCCBCAC9C8C7C6C5C4C3C2C1C0BFBEBDBCBBBAB9B8B7B6B5B4B3B2B1B0
+AFAEADACABAAA9A8A7A6A5A4A3A2A1A09F9E9D9C9B9A999897969594939291908F8E8D8C8B8A8988
+87868584838281807F7E7D7C7B7A797877767574737271706F6E6D6C6B6A69686766656463626160
+5F5E5D5C5B5A595857565554535251504F4E4D4C4B4A494847464544434241403F3E3D3C3B3A3938
+37363534333231302F2E2D2C2B2A292827262524232221201F1E1D1C1B1A19181716151413121110
+0F0E0D0C0B0A09080706050403020100
+>
+0 %_Br
+<
+000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627
+28292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F
+505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F7071727374757677
+78797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9F
+A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7
+C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEF
+F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF
+>
+0 %_Br
+[
+0 0 50 100 %_Bs
+1 0 50 70 %_Bs
+0 0 50 0 %_Bs
+BD
+%AI5_EndGradient
+%AI5_BeginGradient: (Yellow & Orange Radial)
+(Yellow & Orange Radial) 1 2 Bd
+[
+0
+<
+0001010203040506060708090A0B0C0C0D0E0F10111213131415161718191A1B1C1D1D1E1F202122
+232425262728292A2B2B2C2D2E2F303132333435363738393A3B3C3D3E3E3F404142434445464748
+494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F60606162636465666768696A6B6C6D6E6F
+707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C
+>
+<
+FFFFFFFFFEFEFEFEFEFEFEFDFDFDFDFDFDFCFCFCFCFCFCFBFBFBFBFBFBFAFAFAFAFAFAF9F9F9F9F9
+F9F8F8F8F8F8F8F7F7F7F7F7F7F6F6F6F6F6F6F5F5F5F5F5F5F4F4F4F4F4F3F3F3F3F3F3F2F2F2F2
+F2F2F1F1F1F1F1F0F0F0F0F0F0EFEFEFEFEFEFEEEEEEEEEEEDEDEDEDEDEDECECECECECEBEBEBEBEB
+EBEAEAEAEAEAE9E9E9E9E9E9E8E8E8E8E8E8E7E7E7E7E7E6E6E6E6E6E5
+>
+0
+1 %_Br
+[
+0 0 1 0 1 52 19 %_Bs
+0 0.55 0.9 0 1 50 100 %_Bs
+BD
+%AI5_EndGradient
+%AI5_BeginGradient: (Yellow & Purple Radial)
+(Yellow & Purple Radial) 1 2 Bd
+[
+<
+000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627
+28292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F
+505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F7071727374757677
+78797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9F
+A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7
+C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEF
+F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF
+>
+<
+1415161718191A1B1C1D1E1F1F202122232425262728292A2A2B2C2D2E2F30313233343536363738
+393A3B3C3D3E3F40414142434445464748494A4B4C4D4D4E4F50515253545556575858595A5B5C5D
+5E5F60616263646465666768696A6B6C6D6E6F6F707172737475767778797A7B7B7C7D7E7F808182
+83848586868788898A8B8C8D8E8F90919292939495969798999A9B9C9D9D9E9FA0A1A2A3A4A5A6A7
+A8A9A9AAABACADAEAFB0B1B2B3B4B4B5B6B7B8B9BABBBCBDBEBFC0C0C1C2C3C4C5C6C7C8C9CACBCB
+CCCDCECFD0D1D2D3D4D5D6D7D7D8D9DADBDCDDDEDFE0E1E2E2E3E4E5E6E7E8E9EAEBECEDEEEEEFF0
+F1F2F3F4F5F6F7F8F9F9FAFBFCFDFEFF
+>
+<
+ABAAAAA9A8A7A7A6A5A5A4A3A3A2A1A1A09F9F9E9D9D9C9B9B9A9999989797969595949393929191
+908F8F8E8D8D8C8B8B8A8989888787868585848383828181807F7F7E7D7D7C7B7B7A797978777776
+7575747373727171706F6F6E6D6D6C6B6B6A6969686767666565646362626160605F5E5E5D5C5C5B
+5A5A5958585756565554545352525150504F4E4E4D4C4C4B4A4A4948484746464544444342424140
+403F3E3E3D3C3C3B3A3A3938383736363534343332323130302F2E2E2D2C2C2B2A2A292828272626
+25242423222121201F1F1E1D1D1C1B1B1A1919181717161515141313121111100F0F0E0D0D0C0B0B
+0A090908070706050504030302010100
+>
+0
+1 %_Br
+[
+0 0.08 0.67 0 1 50 14 %_Bs
+1 1 0 0 1 50 100 %_Bs
+BD
+%AI5_EndGradient
+%AI5_End_NonPrinting--
+%AI5_BeginPalette
+0 2 Pb
+Pn
+Pc
+1 g
+Pc
+0 g
+Pc
+0 0 0 0 k
+Pc
+0.75 g
+Pc
+0.5 g
+Pc
+0.25 g
+Pc
+0 g
+Pc
+Bb
+2 (Black & White) -4014 4716 0 0 1 0 0 1 0 0 Bg
+0 BB
+Pc
+0.25 0 0 0 k
+Pc
+0.5 0 0 0 k
+Pc
+0.75 0 0 0 k
+Pc
+1 0 0 0 k
+Pc
+0.25 0.25 0 0 k
+Pc
+0.5 0.5 0 0 k
+Pc
+0.75 0.75 0 0 k
+Pc
+1 1 0 0 k
+Pc
+Bb
+2 (Pink, Yellow, Green) -4014 4716 0 0 1 0 0 1 0 0 Bg
+0 BB
+Pc
+0 0.25 0 0 k
+Pc
+0 0.5 0 0 k
+Pc
+0 0.75 0 0 k
+Pc
+0 1 0 0 k
+Pc
+0 0.25 0.25 0 k
+Pc
+0 0.5 0.5 0 k
+Pc
+0 0.75 0.75 0 k
+Pc
+0 1 1 0 k
+Pc
+Bb
+0 0 0 0 Bh
+2 (Yellow & Purple Radial) -4014 4716 0 0 1 0 0 1 0 0 Bg
+0 BB
+Pc
+0 0 0.25 0 k
+Pc
+0 0 0.5 0 k
+Pc
+0 0 0.75 0 k
+Pc
+0 0 1 0 k
+Pc
+0.25 0 0.25 0 k
+Pc
+0.5 0 0.5 0 k
+Pc
+0.75 0 0.75 0 k
+Pc
+1 0 1 0 k
+Pc
+Bb
+2 (Rainbow) -4014 4716 0 0 1 0 0 1 0 0 Bg
+0 BB
+Pc
+0.25 0.125 0 0 k
+Pc
+0.5 0.25 0 0 k
+Pc
+0.75 0.375 0 0 k
+Pc
+1 0.5 0 0 k
+Pc
+0.125 0.25 0 0 k
+Pc
+0.25 0.5 0 0 k
+Pc
+0.375 0.75 0 0 k
+Pc
+0.5 1 0 0 k
+Pc
+Bb
+2 (Steel Bar) -4014 4716 0 0 1 0 0 1 0 0 Bg
+0 BB
+Pc
+0 0.25 0.125 0 k
+Pc
+0 0.5 0.25 0 k
+Pc
+0 0.75 0.375 0 k
+Pc
+0 1 0.5 0 k
+Pc
+0 0.125 0.25 0 k
+Pc
+0 0.25 0.5 0 k
+Pc
+0 0.375 0.75 0 k
+Pc
+0 0.5 1 0 k
+Pc
+Bb
+2 (Purple, Red & Yellow) -4014 4716 0 0 1 0 0 1 0 0 Bg
+0 BB
+Pc
+0.125 0 0.25 0 k
+Pc
+0.25 0 0.5 0 k
+Pc
+0.375 0 0.75 0 k
+Pc
+0.5 0 1 0 k
+Pc
+0.25 0 0.125 0 k
+Pc
+0.5 0 0.25 0 k
+Pc
+0.75 0 0.375 0 k
+Pc
+1 0 0.5 0 k
+Pc
+Bb
+2 (Green & Blue) -4014 4716 0 0 1 0 0 1 0 0 Bg
+0 BB
+Pc
+0.25 0.125 0.125 0 k
+Pc
+0.5 0.25 0.25 0 k
+Pc
+0.75 0.375 0.375 0 k
+Pc
+1 0.5 0.5 0 k
+Pc
+0.25 0.25 0.125 0 k
+Pc
+0.5 0.5 0.25 0 k
+Pc
+0.75 0.75 0.375 0 k
+Pc
+1 1 0.5 0 k
+Pc
+Bb
+0 0 0 0 Bh
+2 (Yellow & Orange Radial) -4014 4716 0 0 1 0 0 1 0 0 Bg
+0 BB
+Pc
+0.125 0.25 0.125 0 k
+Pc
+0.25 0.5 0.25 0 k
+Pc
+0.375 0.75 0.375 0 k
+Pc
+0.5 1 0.5 0 k
+Pc
+0.125 0.25 0.25 0 k
+Pc
+0.25 0.5 0.5 0 k
+Pc
+0.375 0.75 0.75 0 k
+Pc
+0.5 1 1 0 k
+Pc
+0 0 0 0 k
+Pc
+0.125 0.125 0.25 0 k
+Pc
+0.25 0.25 0.5 0 k
+Pc
+0.375 0.375 0.75 0 k
+Pc
+0.5 0.5 1 0 k
+Pc
+0.25 0.125 0.25 0 k
+Pc
+0.5 0.25 0.5 0 k
+Pc
+0.75 0.375 0.75 0 k
+Pc
+1 0.5 1 0 k
+Pc
+PB
+%AI5_EndPalette
+%%EndSetup
+%AI5_BeginLayer
+1 1 1 1 0 0 0 79 128 255 Lb
+(Layer 1) Ln
+0 A
+800 Ar
+0 J 0 j 1 w 4 M []0 d
+%AI3_Note:
+0 D
+0 XR
+-4014 283.5 m
+4626 283.5 L
+(N) *
+453.5 4716 m
+453.5 -3924 L
+(N) *
+85 4716 m
+85 -3924 L
+(N) *
+-4014 765.5 m
+4626 765.5 L
+(N) *
+0 R
+0 G
+113 683.5 m
+439 683.5 l
+S
+113 663.5 m
+439 663.5 l
+S
+113 643.5 m
+439 643.5 l
+S
+113 686 m
+439 686 l
+S
+1 Ap
+439 624 m
+439 709 L
+113 709 L
+113 624 L
+439 624 L
+s
+0 Ap
+178.5 709 m
+178.5 624 l
+S
+243 709 m
+243 624 l
+S
+374 709 m
+374 624 l
+S
+308.5 709 m
+308.5 624 l
+S
+0 To
+1 0 0 1 146 692 0 Tp
+TP
+-12.2278 0 Td
+0 Tr
+0 O
+0 g
+/_Univers 10 Tf
+0 Ts
+100 Tz
+0 Tt
+1 TA
+%_ 0 XL
+36 0 Xb
+XB
+0 0 5 TC
+100 100 200 TW
+0 0 0 Ti
+1 Ta
+0 0 2 2 3 Th
+0 Tq
+0 0 Tl
+0 Tc
+0 Tw
+(key 1) Tx
+(\r) TX
+TO
+0 To
+1 0 0 1 213 692 0 Tp
+TP
+-12.2278 0 Td
+0 Tr
+(key 2) Tx
+(\r) TX
+TO
+0 To
+1 0 0 1 276 692 0 Tp
+TP
+-11.1121 0 Td
+0 Tr
+(col 3) Tx
+(\r) TX
+TO
+0 To
+1 0 0 1 225.5 747.5 0 Tp
+TP
+0 Tr
+(\r) Tx
+TO
+0 To
+1 0 0 1 336.5 693.5 0 Tp
+TP
+0 Tr
+(\r) Tx
+TO
+0 To
+1 0 0 1 341 692 0 Tp
+TP
+-11.1121 0 Td
+0 Tr
+(col 4) Tx
+(\r) TX
+TO
+0 To
+1 0 0 1 407.5 692 0 Tp
+TP
+-11.1121 0 Td
+0 Tr
+(col 5) Tx
+(\r) TX
+TO
+0 To
+1 0 0 1 185.5 736 0 Tp
+TP
+0 Tr
+(\r) Tx
+TO
+0 To
+1 0 0 1 145 669.5 0 Tp
+TP
+-2.7795 0 Td
+0 Tr
+(1) Tx
+(\r) TX
+TO
+0 To
+1 0 0 1 144.5 650.5 0 Tp
+TP
+-2.7795 0 Td
+0 Tr
+(1) Tx
+(\r) TX
+TO
+0 To
+1 0 0 1 145 630 0 Tp
+TP
+-2.7795 0 Td
+0 Tr
+(2) Tx
+(\r) TX
+TO
+0 To
+1 0 0 1 209.5 669 0 Tp
+TP
+-2.7795 0 Td
+0 Tr
+(1) Tx
+(\r) TX
+TO
+0 To
+1 0 0 1 209.5 649.5 0 Tp
+TP
+-2.7795 0 Td
+0 Tr
+(2) Tx
+(\r) TX
+TO
+0 To
+1 0 0 1 209.5 629.5 0 Tp
+TP
+-2.7795 0 Td
+0 Tr
+(1) Tx
+(\r) TX
+TO
+0 To
+1 0 0 1 274.5 669 0 Tp
+TP
+-2.7795 0 Td
+0 Tr
+(a) Tx
+(\r) TX
+TO
+0 To
+1 0 0 1 274.5 649.5 0 Tp
+TP
+-3.0542 0 Td
+0 Tr
+(d) Tx
+(\r) TX
+TO
+0 To
+1 0 0 1 274.5 629.5 0 Tp
+TP
+-3.0542 0 Td
+0 Tr
+(g) Tx
+(\r) TX
+TO
+0 To
+1 0 0 1 340 669 0 Tp
+TP
+-3.0542 0 Td
+0 Tr
+(b) Tx
+(\r) TX
+TO
+0 To
+1 0 0 1 340 649.5 0 Tp
+TP
+-2.7795 0 Td
+0 Tr
+(e) Tx
+(\r) TX
+TO
+0 To
+1 0 0 1 340 629.5 0 Tp
+TP
+-8.8879 0 Td
+0 Tr
+(N/A) Tx
+(\r) TX
+TO
+0 To
+1 0 0 1 405 669 0 Tp
+TP
+-2.5 0 Td
+0 Tr
+(c) Tx
+(\r) TX
+TO
+0 To
+1 0 0 1 405 649.5 0 Tp
+TP
+-1.6638 0 Td
+0 Tr
+(f) Tx
+(\r) TX
+TO
+0 To
+1 0 0 1 405 629.5 0 Tp
+TP
+-1.3892 0 Td
+0 Tr
+(i) Tx
+(\r) TX
+TO
+u
+1 Ap
+0 R
+0 G
+274.4998 643.4963 m
+279.1963 643.4963 283.0037 647.3037 283.0037 652.0002 c
+283.0037 656.6968 279.1963 660.5042 274.4998 660.5042 c
+269.8032 660.5042 265.9958 656.6968 265.9958 652.0002 c
+265.9958 647.3037 269.8032 643.4963 274.4998 643.4963 c
+s
+[3 4 3 4 3 4 ]0 d
+274.4998 623.9963 m
+279.1963 623.9963 283.0037 627.8037 283.0037 632.5002 c
+283.0037 637.1968 279.1963 641.0042 274.4998 641.0042 c
+269.8032 641.0042 265.9958 637.1968 265.9958 632.5002 c
+265.9958 627.8037 269.8032 623.9963 274.4998 623.9963 c
+s
+u
+u
+0 Ap
+[]0 d
+265.9958 652.0002 m
+251 652 250.5 642.5 v
+250.1312 635.4919 257.5 633.5 y
+S
+0 O
+0 g
+260.0476 633.873 m
+258.5818 634.7863 257.6645 635.5108 256.5229 636.3709 c
+255.2066 631.5014 l
+255.7237 631.5949 257.7835 631.833 259.5097 631.8831 c
+261.3573 631.9376 263.0016 631.8718 264.0403 631.7262 c
+263.0697 632.1237 261.6162 632.8953 260.0476 633.873 c
+f
+U
+U
+U
+1 Ap
+0 R
+0 G
+339.9998 643.4963 m
+344.6963 643.4963 348.5037 647.3037 348.5037 652.0002 c
+348.5037 656.6968 344.6963 660.5042 339.9998 660.5042 c
+335.3032 660.5042 331.4958 656.6968 331.4958 652.0002 c
+331.4958 647.3037 335.3032 643.4963 339.9998 643.4963 c
+s
+[3 4 3 4 3 4 ]0 d
+404.9998 663.4963 m
+409.6963 663.4963 413.5037 667.3037 413.5037 672.0002 c
+413.5037 676.6968 409.6963 680.5042 404.9998 680.5042 c
+400.3032 680.5042 396.4958 676.6968 396.4958 672.0002 c
+396.4958 667.3037 400.3032 663.4963 404.9998 663.4963 c
+s
+u
+u
+u
+u
+u
+0 Ap
+[]0 d
+331.4958 652.0002 m
+305.5 617.5 323 607.5 v
+338.4597 598.6658 363 623 377 643 c
+383.7965 652.7091 392.5 660 y
+S
+0 O
+0 g
+393.6525 662.3024 m
+392.0646 661.6234 390.9454 661.286 389.5867 660.8423 c
+392.8259 656.9755 l
+393.0452 657.453 394.0292 659.2782 394.9762 660.7223 c
+395.9892 662.2684 396.9844 663.579 397.6983 664.3473 c
+396.8168 663.779 395.3521 663.0289 393.6525 662.3024 c
+f
+U
+U
+U
+U
+U
+LB
+%AI5_EndLayer--
+%%PageTrailer
+gsave annotatepage grestore showpage
+%%Trailer
+Adobe_Illustrator_AI5 /terminate get exec
+Adobe_ColorImage_AI6 /terminate get exec
+Adobe_typography_AI5 /terminate get exec
+Adobe_level2_AI5 /terminate get exec
+%%EOF
diff --git a/lib/snmp/doc/src/index.html.src b/lib/snmp/doc/src/index.html.src
new file mode 100644
index 0000000000..7ad2140559
--- /dev/null
+++ b/lib/snmp/doc/src/index.html.src
@@ -0,0 +1,98 @@
+<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
+<!-- This file is obsolete -->
+<HTML>
+<!--
+ ``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 via the world wide web 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.
+
+ The Initial Developer of the Original Code is Ericsson Utvecklings AB.
+ Portions created by Ericsson are Copyright 1999, Ericsson Utvecklings
+ AB. All Rights Reserved.''
+
+ $Id$
+-->
+<HEAD>
+<TITLE>SNMP %VSN%</TITLE>
+</HEAD>
+
+<BODY BGCOLOR="#FFFFFF">
+
+<CENTER>
+<A HREF="http://www.erlang.se/"><IMG ALT="Erlang/OTP" BORDER=0 SRC="html/min_head.gif"></A><BR>
+
+<FONT SIZE="-1">
+[<A HREF="../../../doc/index.html">Up</A> |
+<A HREF="http://www.erlang.se/">Erlang/OTP</A>]
+</FONT><BR>
+
+<P><FONT SIZE="+3">
+SNMP
+</FONT><BR>
+Version %VSN%
+</CENTER>
+
+<P><TABLE>
+<TR>
+<TD>
+<IMG ALIGN=LEFT ALT="SNMP" SRC="html/snmp.gif">
+</TD>
+
+<TD>
+<P>A bilingual Simple Network Management Protocol application,
+ featuring an Extensible Agent, a simple manager, a MIB compiler
+ and facilities for implementing SNMP MIBs etc.
+</TD>
+</TR>
+</TABLE>
+
+<P><CENTER>
+<TABLE CELLPADDING=15>
+<TR>
+<TD ALIGN=CENTER>
+<A HREF="html/users_guide.html"><IMG ALT="User's Guide" BORDER=0 SRC="html/user_guide.gif"></A><BR>
+<FONT SIZE="-1">
+<A HREF="html/users_guide.html">User's Guide</A>
+</FONT>
+</TD>
+
+<TD ALIGN=CENTER>
+<A HREF="html/index.html"><IMG ALT="Reference Manual" BORDER=0 SRC="html/ref_man.gif"></A><BR>
+<FONT SIZE="-1">
+<A HREF="html/index.html">Reference Manual</A>
+</FONT>
+</TD>
+
+<TD ALIGN=CENTER>
+<A HREF="html/release_notes.html"><IMG ALT="Release Notes" BORDER=0 SRC="html/notes.gif"></A><BR>
+<FONT SIZE="-1">
+<A HREF="html/release_notes.html">Release Notes</A>
+</FONT>
+</TD>
+
+<TD ALIGN=CENTER>
+<A HREF="pdf/snmp-%VSN%.pdf"><IMG ALT="Off-Print" BORDER=0 SRC="html/book.gif"></A><BR>
+<FONT SIZE="-1">
+<A HREF="pdf/snmp-%VSN%.pdf">Off-Print</A>
+</FONT>
+</TD>
+</TR>
+</TABLE>
+</CENTER>
+
+<P><CENTER>
+<HR>
+<FONT SIZE="-1">
+Copyright &copy; 1991-2001
+<A HREF="http://www.erlang.se/">Ericsson Utvecklings AB</A>
+</FONT>
+</CENTER>
+</BODY>
+</HTML>
diff --git a/lib/snmp/doc/src/make.dep b/lib/snmp/doc/src/make.dep
new file mode 100644
index 0000000000..ccd01b9d3a
--- /dev/null
+++ b/lib/snmp/doc/src/make.dep
@@ -0,0 +1,77 @@
+#-*-makefile-*- ; force emacs to enter makefile-mode
+
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 1999-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%
+
+# ----------------------------------------------------
+# >>>> Do not edit this file <<<<
+# This file was automaticly generated by
+# /home/otp/bin/docdepend
+# ----------------------------------------------------
+
+
+# ----------------------------------------------------
+# TeX files that the DVI file depend on
+# ----------------------------------------------------
+
+book.dvi: book.tex part.tex ref_man.tex snmp.tex snmp_advanced_agent.tex \
+ snmp_agent_config_files.tex snmp_agent_funct_descr.tex \
+ snmp_agent_netif.tex snmp_app.tex snmp_app_a.tex \
+ snmp_app_b.tex snmp_audit_trail_log.tex \
+ snmp_community_mib.tex \
+ snmp_config.tex snmp_def_instr_functions.tex \
+ snmp_framework_mib.tex snmp_generic.tex \
+ snmp_impl_example_agent.tex \
+ snmp_impl_example_manager.tex snmp_index.tex \
+ snmp_instr_functions.tex snmp_intro.tex \
+ snmp_manager_config_files.tex \
+ snmp_manager_funct_descr.tex snmp_manager_netif.tex \
+ snmp_mib_compiler.tex snmp_notification_mib.tex \
+ snmp_pdus.tex snmp_standard_mib.tex snmp_target_mib.tex \
+ snmp_user_based_sm_mib.tex snmp_view_based_acm_mib.tex \
+ snmpa.tex snmpa_conf.tex snmpa_error.tex snmpa_error_io.tex \
+ snmpa_error_logger.tex snmpa_error_report.tex \
+ snmpa_local_db.tex snmpa_mpd.tex \
+ snmpa_discovery_handler.tex \
+ snmpa_network_interface.tex \
+ snmpa_network_interface_filter.tex \
+ snmpa_notification_delivery_info_receiver.tex \
+ snmpa_notification_filter.tex \
+ snmpa_supervisor.tex \
+ snmpc.tex snmpm.tex snmpm_conf.tex snmpm_mpd.tex \
+ snmpm_network_interface.tex snmpm_network_interface_filter.tex \
+ snmpm_user.tex
+
+# ----------------------------------------------------
+# Source inlined when transforming from source to LaTeX
+# ----------------------------------------------------
+
+book.tex: ref_man.xml
+
+# ----------------------------------------------------
+# Pictures that the DVI file depend on
+# ----------------------------------------------------
+
+book.dvi: MIB_mechanism.ps snmp-um-1-image-1.ps snmp-um-1-image-2.ps \
+ snmp-um-1-image-3.ps
+
+book.dvi: snmp_agent_netif_1.ps
+
+book.dvi: getnext1.ps getnext2.ps getnext3.ps getnext4.ps
+
+book.dvi: snmp_manager_netif_1.ps
+
diff --git a/lib/snmp/doc/src/min_head.gif b/lib/snmp/doc/src/min_head.gif
new file mode 100644
index 0000000000..67948a6378
--- /dev/null
+++ b/lib/snmp/doc/src/min_head.gif
Binary files differ
diff --git a/lib/snmp/doc/src/note.gif b/lib/snmp/doc/src/note.gif
new file mode 100644
index 0000000000..6fffe30419
--- /dev/null
+++ b/lib/snmp/doc/src/note.gif
Binary files differ
diff --git a/lib/snmp/doc/src/notes.gif b/lib/snmp/doc/src/notes.gif
new file mode 100644
index 0000000000..e000cca26a
--- /dev/null
+++ b/lib/snmp/doc/src/notes.gif
Binary files differ
diff --git a/lib/snmp/doc/src/notes.xml b/lib/snmp/doc/src/notes.xml
new file mode 100644
index 0000000000..96a444227d
--- /dev/null
+++ b/lib/snmp/doc/src/notes.xml
@@ -0,0 +1,1024 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE chapter SYSTEM "chapter.dtd">
+
+<chapter>
+ <header>
+ <copyright>
+ <year>1996</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ 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.
+
+ </legalnotice>
+
+ <title>SNMP Release Notes</title>
+ <prepared></prepared>
+ <responsible></responsible>
+ <docno></docno>
+ <approved></approved>
+ <checked></checked>
+ <date></date>
+ <rev></rev>
+ <file>notes.xml</file>
+ </header>
+
+ <section>
+ <title>SNMP Development Toolkit 4.15</title>
+
+ <p>Version 4.15 supports code replacement in runtime from/to
+ version 4.14 and 4.13.5.</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <!--
+ <p>-</p>
+ -->
+
+ <list type="bulleted">
+ <item>
+ <p>The documentation is now built with open source tools
+ (<em>xsltproc</em> and <em>fop</em>) that exists on most
+ platforms. One visible change is that the frames are removed.</p>
+ <p>Own Id: OTP-8249</p>
+ </item>
+
+ </list>
+
+ </section>
+
+ <section>
+ <title>Reported Fixed Bugs and Malfunctions</title>
+ <!--
+ <p>-</p>
+ -->
+ <list type="bulleted">
+ <item>
+ <p>[manager] When information from an unknown agent is received,
+ it was previously delivered to the default user via calls to all
+ the functions of the callback API depending on the info type
+ (<c>pdu</c>, <c>trap</c>, <c>report</c> or <c>inform</c>).
+ The problem was that the <c>TargetName</c> argument was useless
+ in this case (only an already known agent has a known/valid
+ <c>TargetName</c>, but the <c>TargetName</c> used in these calls
+ was generated "on the fly"). </p>
+ <p>This has now been changed so that when a message is received
+ from an unknown agent, then only
+ <seealso marker="snmpm_user#handle_agent">handle_agent</seealso>
+ (for the default user) is called, but now this call also has a
+ <c>Type</c> argument, which is
+ <c>pdu | trap | report | inform</c>, depending on what kind of
+ message was actually received, thus making it possible for the
+ user to properly analyze the data received. </p>
+ <p>To handle this, the
+ <seealso marker="snmpm_user">snmpm_user</seealso> behaviour has
+ been updated. </p>
+ <p>*** POTENTIAL INCOMPATIBILITY ***</p>
+ <p>Own Id: OTP-8229</p>
+ <!-- <p>Aux Id: Seq 11312</p> -->
+ </item>
+
+ </list>
+
+ </section>
+
+ </section> <!-- 4.15 -->
+
+
+ <section>
+ <title>SNMP Development Toolkit 4.14</title>
+
+ <p>Version 4.14 supports code replacement in runtime from/to
+ version 4.13.5, 4.13.4, 4.13.3, 4.13.2, 4.13.1 and 4.13.</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <!--
+ <p>-</p>
+ -->
+
+ <list type="bulleted">
+ <item>
+ <p>[compiler] Include object- and notification groups in the
+ compiled mib.
+ This will make it possible to import groups from other mibs. </p>
+ <p>Also the SNMPv2-MIB-file has been updated to a more
+ up-to-date version. </p>
+ <p>Own Id: OTP-8223</p>
+ <!-- <p>Aux Id: Seq 11383</p> -->
+ </item>
+
+ <item>
+ <p>[manager] Added support for message filtering in the
+ network interface module provided with the application.
+ The component that actually make the filter decisions
+ is the network interface filter module. This module
+ must implement the
+ <seealso marker="snmpm_network_interface_filter">network interface filter behaviour</seealso>
+ for message filtering.
+ See also the Configuring chapter of
+ the User's Guide to see how to configure this feature. </p>
+ <p>See the
+ <seealso marker="snmp_app#configuration_params">configuration</seealso>
+ chapter for more info about the filter options.</p>
+ <p>Own Id: OTP-8228</p>
+ <p>Aux Id: Seq 11411</p>
+ </item>
+
+ <item>
+ <p>The MIBs delivered as part of the application is now
+ also available as man pages, section 7. </p>
+ <p>Own Id: OTP-8237</p>
+ <!-- <p>Aux Id: Seq 11383</p> -->
+ </item>
+
+ </list>
+
+ </section>
+
+ <section>
+ <title>Reported Fixed Bugs and Malfunctions</title>
+ <p>-</p>
+
+ <!--
+ <list type="bulleted">
+ <item>
+ <p>[agent] The main agent type header file contained some miss-information
+ regarding the type of the entrytype field of the me-record, causing
+ unneccessary confusion.</p>
+ <p>Own Id: OTP-8116</p>
+ <p>Aux Id: Seq 11312</p>
+ </item>
+
+ </list>
+ -->
+
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+ </section> <!-- 4.14 -->
+
+
+ <section>
+ <title>SNMP Development Toolkit 4.13.5</title>
+
+ <p>Version 4.13.5 supports code replacement in runtime from/to
+ version 4.13.4, 4.13.3, 4.13.2, 4.13.1 and 4.13.</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <!--
+ <p>-</p>
+ -->
+
+ <list type="bulleted">
+ <item>
+ <p>[agent] Improved the cache handling of the mib server. </p>
+ <p>A number of new functions and config options for the mib server
+ cache has been added. </p>
+ <p>See
+ <seealso marker="snmpa#invalidate_mibs_cache">invalidate_mibs_cache/0,1</seealso>,
+ <seealso marker="snmpa#enable_mibs_cache">enable_mibs_cache/0,1</seealso>,
+ <seealso marker="snmpa#disable_mibs_cache">disable_mibs_cache/0,1</seealso>,
+ <seealso marker="snmpa#gc_mibs_cache">gc_mibs_cache/0,1,2,3</seealso>,
+ <seealso marker="snmpa#enable_mibs_cache_autogc">enable_mibs_cache_autogc/0,1</seealso>,
+ <seealso marker="snmpa#disable_mibs_cache_autogc">disable_mibs_cache_autogc/0,1</seealso>,
+ <seealso marker="snmpa#update_mibs_cache_age">update_mibs_cache_age/1,2</seealso> and
+ <seealso marker="snmpa#update_mibs_cache_gclimit">update_mibs_cache_gclimit/1,2</seealso> for more info. </p>
+ <p>See also the
+ <seealso marker="snmp_app#configuration_params">configuration</seealso>
+ chapter for more info about the mib server cache options.</p>
+ <p>Own Id: OTP-8182</p>
+ <p>Aux Id: Seq 11383</p>
+ </item>
+
+ <item>
+ <p>[agent] A manager could no longer use the SNMPv3 user "initial"
+ as this was interpretated as the first step of the discovery. </p>
+ <p>Introduced a new terminating option, <c>trigger_username</c> to
+ make it possible to configure the username the agent reacts to.
+ Default is <c>""</c>. </p>
+ <p>See the
+ <seealso marker="snmp_app#configuration_params">configuration</seealso>
+ chapter for more info about the discovery options.</p>
+ <p>Own Id: OTP-8120</p>
+ <p>Aux Id: Seq 11361</p>
+ </item>
+
+ </list>
+
+ </section>
+
+ <section>
+ <title>Reported Fixed Bugs and Malfunctions</title>
+ <!--
+ <p>-</p>
+ -->
+ <list type="bulleted">
+ <item>
+ <p>[agent] The main agent type header file contained some miss-information
+ regarding the type of the entrytype field of the me-record, causing
+ unneccessary confusion.</p>
+ <p>Own Id: OTP-8116</p>
+ <p>Aux Id: Seq 11312</p>
+ </item>
+
+ </list>
+
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+ </section> <!-- 4.13.5 -->
+
+
+ <section>
+ <title>SNMP Development Toolkit 4.13.4</title>
+
+ <p>Version 4.13.4 supports code replacement in runtime from/to
+ version 4.13.3, 4.13.2, 4.13.1 and 4.13.</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <p>-</p>
+
+ <!--
+ <list type="bulleted">
+ <item>
+ <p>[agent] Support for the discovery process. </p>
+ <p>The agent can both initiate discovery itself (see the
+ <seealso marker="snmp_agent_funct_descr#discovery">discovery</seealso> chapter
+ for more info) and respond to discovery initiated by a manager.</p>
+ <p>Own Id: OTP-7571</p>
+ <p>Aux Id: Seq 11053</p>
+ </item>
+
+ </list>
+ -->
+
+ </section>
+
+ <section>
+ <title>Reported Fixed Bugs and Malfunctions</title>
+ <!--
+ <p>-</p>
+ -->
+ <list type="bulleted">
+ <item>
+ <p>[agent] Originating discovery problems. </p>
+ <p>Invalid state variable update during second stage of
+ discovery causes master agent crash. </p>
+ <p>Also the net_if process failed to activate socket
+ ({active, once}) after first discovery response was sent. </p>
+ <p>Own Id: OTP-8044</p>
+ <p>Aux Id: Seq 11295</p>
+ </item>
+
+ <item>
+ <p>[agent] Terminating discovery problem. </p>
+ <p>The reply to the second stage request should include a
+ varbind with <c>usmStatsNotInTimeWindows</c>.</p>
+ <p>Own Id: OTP-8062</p>
+ <p>Aux Id: Seq 11318</p>
+ </item>
+
+ <item>
+ <p>[agent] Originating discovery improvement. </p>
+ <p>Added the ExtraInfo argument to the
+ <seealso marker="snmpa#discovery">discovery</seealso> function.
+ This argument will be passed on to the stage1_finish callback
+ function. Also, the
+ <seealso marker="snmpa#discovery">discovery</seealso> function
+ will now always return <c>{ok, ManagerEngineID}</c> on successful
+ discovery. </p>
+ <p>The <seealso marker="snmpa_discovery_handler">discovery handler</seealso>
+ behaviour updated accordingly. </p>
+ <p>Own Id: OTP-8098</p>
+ <p>Aux Id: Seq 11346</p>
+ </item>
+
+ </list>
+
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+ </section> <!-- 4.13.4 -->
+
+
+ <section>
+ <title>SNMP Development Toolkit 4.13.3</title>
+
+ <p>Version 4.13.3 supports code replacement in runtime from/to
+ version 4.13.2, 4.13.1 and 4.13.</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <p>-</p>
+
+ <!--
+ <list type="bulleted">
+ <item>
+ <p>[agent] Support for the discovery process. </p>
+ <p>The agent can both initiate discovery itself (see the
+ <seealso marker="snmp_agent_funct_descr#discovery">discovery</seealso> chapter
+ for more info) and respond to discovery initiated by a manager.</p>
+ <p>Own Id: OTP-7571</p>
+ <p>Aux Id: Seq 11053</p>
+ </item>
+
+ </list>
+ -->
+
+ </section>
+
+ <section>
+ <title>Reported Fixed Bugs and Malfunctions</title>
+ <!--
+ <p>-</p>
+ -->
+ <list type="bulleted">
+ <item>
+ <p>[manager] A request for an oid of type BITS was actually
+ returned as OCTET STRING. </p>
+ <p>Values of type BITS are encoded as OCTET STRING,
+ which makes it impossible for the decoder to know that
+ they should really be of type BITS.
+ Instead, this has to be done higher up in the stack, where
+ there is knowledge of the MIB (assuming that the mib has
+ been loaded, there is info about the type of the mibentry). </p>
+ <p>This problem has now been fixed, but requires that the MIB
+ defining this mib-entry is loaded! </p>
+ <p>The utility function
+ <seealso marker="snmpm#oid_to_type">oid_to_type</seealso>
+ has been added, for debug purpose. </p>
+ <p>The utility function(s)
+ <seealso marker="snmp#octet_string_to_bits">octet_string_to_bits</seealso>
+ and
+ <seealso marker="snmp#bits_to_octet_string">bits_to_octet_string</seealso>
+ has also been added. These can be used if the user prefers to
+ handle the conversion on their own. </p>
+ <p>Own Id: OTP-8015</p>
+ <p>Aux Id: Seq 11285</p>
+ </item>
+
+ <item>
+ <p>[agent] Fixed some issues with the discovery handling. </p>
+ <p>Changed the API of the
+ <seealso marker="snmpa#discovery">discovery</seealso>
+ function to solve some
+ of these problems. </p>
+ <p>Introduced various options for controlling the discovery
+ process. See the
+ <seealso marker="snmp_app#configuration_params">configuration</seealso>
+ chapter for more info about the discovery options.</p>
+ <p>Own Id: OTP-8020</p>
+ <p>Aux Id: Seq 11295</p>
+ </item>
+
+ </list>
+
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+ </section> <!-- 4.13.3 -->
+
+
+ <section>
+ <title>SNMP Development Toolkit 4.13.2</title>
+
+ <p>Version 4.13.2 supports code replacement in runtime from/to
+ version 4.13.1 and 4.13.</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <p>-</p>
+
+ <!--
+ <list type="bulleted">
+ <item>
+ <p>[agent] Support for the discovery process. </p>
+ <p>The agent can both initiate discovery itself (see the
+ <seealso marker="snmp_agent_funct_descr#discovery">discovery</seealso> chapter
+ for more info) and respond to discovery initiated by a manager.</p>
+ <p>Own Id: OTP-7571</p>
+ <p>Aux Id: Seq 11053</p>
+ </item>
+
+ </list>
+ -->
+
+ </section>
+
+ <section>
+ <title>Reported Fixed Bugs and Malfunctions</title>
+ <!--
+ <p>-</p>
+ -->
+ <list type="bulleted">
+ <item>
+ <p>[manager] Failure during downed user cleanup.
+ As part of the cleanup after a crashed user,
+ the manager attempts to unregister the agents
+ registered by this user. This however failed,
+ causing a server crash. </p>
+ <p>Own Id: OTP-7961</p>
+ <p>Aux Id: Seq 11275</p>
+ </item>
+
+ <item>
+ <p>[manager] Incorrectly documented value type for
+ IpAddress (ip). The value type for IpAddress is
+ documented as ip but is actually ia. The value type
+ ip has been added. The old (not documented) value
+ type ia still works. </p>
+ <p>Own Id: OTP-7977</p>
+ <p>Aux Id: Seq 11279</p>
+ </item>
+
+ <item>
+ <p>[manager] EngineId lookup fails when using version-3. </p>
+ <p>Own Id: OTP-7983</p>
+ <p>Aux Id: Seq 11275</p>
+ </item>
+
+ <item>
+ <p>[agent] As of version 4.13 the possible return values
+ of the function
+ <seealso marker="snmpa_mpd#process_packet">snmpa_mpd:process_packet/4</seealso>
+ changed, but this was not documented. </p>
+ <p>Own Id: OTP-7989</p>
+ <p>Aux Id: Seq 11275</p>
+ </item>
+
+ </list>
+
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+ </section> <!-- 4.13.2 -->
+
+ <section>
+ <title>SNMP Development Toolkit 4.13.1</title>
+
+ <p>Version 4.13.1 supports code replacement in runtime from/to
+ version 4.13.</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <p>-</p>
+
+ <!--
+ <list type="bulleted">
+ <item>
+ <p>[agent] Support for the discovery process. </p>
+ <p>The agent can both initiate discovery itself (see the
+ <seealso marker="snmp_agent_funct_descr#discovery">discovery</seealso> chapter
+ for more info) and respond to discovery initiated by a manager.</p>
+ <p>Own Id: OTP-7571</p>
+ <p>Aux Id: Seq 11053</p>
+ </item>
+
+ </list>
+ -->
+
+ </section>
+
+ <section>
+ <title>Reported Fixed Bugs and Malfunctions</title>
+ <!--
+ <p>-</p>
+ -->
+ <list type="bulleted">
+ <item>
+ <p>[manager] Registration of users had some issues. </p>
+ <p>Not all of the registration functions where actually exported
+ (<seealso marker="snmpm#register_user">register_user/4</seealso>
+ and
+ <seealso marker="snmpm#register_user_monitor">register_user_monitor/4</seealso>).
+ This has now been fixed. </p>
+ <p>Also, the registration did not succeed unless
+ user implemented the *new* behaviour. This has now
+ also been fixed (registration succeeds if the user
+ implements either the new (i.e. updated
+ <seealso marker="snmpm_user">snmpm_user</seealso>)
+ or the old user behaviour (<c>snmpm_user_old</c>)). </p>
+ <p>Own Id: OTP-7902</p>
+ <p>Aux Id: Seq 11240</p>
+ </item>
+
+ </list>
+
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+ </section> <!-- 4.13.1 -->
+
+ <section>
+ <title>SNMP Development Toolkit 4.13</title>
+<!--
+ <p>Version 4.13 supports code replacement in runtime from/to
+ version 4.12.1.</p>
+-->
+
+ <section>
+ <title>Improvements and new features</title>
+ <!--
+ <p>-</p>
+ -->
+ <list type="bulleted">
+ <item>
+ <p>[agent] Support for the discovery process. </p>
+ <p>The agent can both initiate discovery itself (see the
+ <seealso marker="snmp_agent_funct_descr#discovery">discovery</seealso> chapter
+ for more info) and respond to discovery initiated by a manager.</p>
+ <p>Own Id: OTP-7571</p>
+ <p>Aux Id: Seq 11053</p>
+ </item>
+
+ </list>
+
+ </section>
+
+ <section>
+ <title>Reported Fixed Bugs and Malfunctions</title>
+ <!--
+ <p>-</p>
+ -->
+ <list type="bulleted">
+ <item>
+ <p>[agent] Unnecessary use of math:pow/2 could cause problems
+ on systems without floating point support. </p>
+ <p>Per Hedeland</p>
+ <p>Own Id: OTP-7735</p>
+ <!-- <p>Aux Id: Seq 10966</p> -->
+ </item>
+
+ <item>
+ <p>[manager] A major flaw was discovered with the agent handling. </p>
+ <p>First, <c>TargetName</c> was never used as intended, as a unique
+ identifier for the target (agent in this case). </p>
+ <p>Second, <c>TargetName</c> had a <em>default value</em>, which meant
+ that several agents could have the same <c>TargetName</c>, causing
+ unpredictable behaviour in the manager. </p>
+ <p>Third, <c>EngineID</c> was not a mandatory config option and had
+ furthermore also a <em>default value</em>. </p>
+
+ <p>These problems has been solved in the following way: </p>
+ <p>First, a new set of api functions has been introduced (and documented):
+ <seealso marker="snmpm#register_user">register_user/4</seealso>,
+ <seealso marker="snmpm#register_user_monitor">register_user_monitor/4</seealso>,
+ <seealso marker="snmpm#register_agent">register_agent/3</seealso>,
+ <seealso marker="snmpm#unregister_agent">unregister_agent/2</seealso>,
+ <seealso marker="snmpm#agent_info">agent_info/2</seealso>,
+ <seealso marker="snmpm#update_agent_info">update_agent_info/4</seealso>,
+ <seealso marker="snmpm#sync_get">sync_get/3,4,5,6</seealso>,
+ <seealso marker="snmpm#async_get">async_get/3,4,5,6</seealso>,
+ <seealso marker="snmpm#sync_get_next">sync_get_next/3,4,5,6</seealso>,
+ <seealso marker="snmpm#async_get_next">async_get_next/3,4,5,6</seealso>,
+ <seealso marker="snmpm#sync_set">sync_set/3,4,5,6</seealso>,
+ <seealso marker="snmpm#async_set">async_set/3,4,5,6</seealso>,
+ <seealso marker="snmpm#sync_get_bulk">sync_get_bulk/5,6,7,8</seealso> and
+ <seealso marker="snmpm#async_get_bulk">async_get_bulk/5,6,7,8</seealso>
+ that all use <c>TargetName</c> (and not, as previously, <c>Addr</c>
+ and <c>Port</c>) to identify the agent (also the return value of
+ <seealso marker="snmpm#which_agents">which_agents</seealso> has
+ been changed). </p>
+ <p>Second, for backward compatibility, the old functions still
+ exist, but are no longer documented and are now wrappers for the
+ new functions, including erroneous default value for EngineID and
+ all. The TargetName is however generated from the provided
+ <c>Addr</c>, <c>Port</c> and <c>Version</c> config options. </p>
+ <p>Third, the behaviour of the
+ <seealso marker="snmpm_user">SNMP manager user</seealso> has
+ been changed to reflect this, i.e.
+ <seealso marker="snmpm_user#handle_pdu">handle_pdu/4</seealso>,
+ <seealso marker="snmpm_user#handle_trap">handle_trap/3</seealso>,
+ <seealso marker="snmpm_user#handle_inform">handle_inform/3</seealso>,
+ <seealso marker="snmpm_user#handle_report">handle_report/3</seealso>
+ and the return-value of
+ <seealso marker="snmpm_user#handle_agent">handle_agent/4</seealso>.
+ The old (non-documented) callback-functions (using Addr and Port)
+ will still be called if the agent was registered using the old
+ registration functions. </p>
+
+ <p>Own Id: OTP-7836</p>
+ <!-- <p>Aux Id: Seq 10966</p> -->
+ </item>
+
+ </list>
+
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+ </section> <!-- 4.13 -->
+
+ <section>
+ <title>SNMP Development Toolkit 4.12.2</title>
+ <p>Version 4.12.2 supports code replacement in runtime from/to
+ version 4.12.1, 4.12, 4.11.2, 4.11.1 and 4.11.</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <p>-</p>
+ <!--
+ <list type="bulleted">
+ <item>
+ <item>
+ <p>[agent] Improvement of the inform reporting.
+ It was previously not certain how many acks an
+ application received, 0, 1 or 2. This has now been
+ fixed, so that only 1 (one) ack is issued. </p>
+ <p>Per Hedeland</p>
+ <p>Own Id: OTP-7525</p>
+ </item>
+
+ </list>
+ -->
+
+ </section>
+
+ <section>
+ <title>Reported Fixed Bugs and Malfunctions</title>
+ <!--
+ <p>-</p>
+ -->
+ <list type="bulleted">
+ <item>
+ <p>[agent] Bad session cache (usm+camv-info) invalidation
+ could cause user crash, through call(s) to (a number of)
+ MIB API function(s) (undefined function). </p>
+ <p>Own Id: OTP-7868</p>
+ <!-- <p>Aux Id: Seq 11124</p> -->
+ </item>
+
+ </list>
+
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+ </section> <!-- 4.12.2 -->
+
+ <section>
+ <title>SNMP Development Toolkit 4.12.1</title>
+ <p>Version 4.12.1 supports code replacement in runtime from/to
+ version 4.12, 4.11.2, 4.11.1 and 4.11.</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <p>-</p>
+ <!--
+ <list type="bulleted">
+ <item>
+ <item>
+ <p>[agent] Improvement of the inform reporting.
+ It was previously not certain how many acks an
+ application received, 0, 1 or 2. This has now been
+ fixed, so that only 1 (one) ack is issued. </p>
+ <p>Per Hedeland</p>
+ <p>Own Id: OTP-7525</p>
+ </item>
+
+ </list>
+ -->
+
+ </section>
+
+ <section>
+ <title>Reported Fixed Bugs and Malfunctions</title>
+ <!--
+ <p>-</p>
+ -->
+ <list type="bulleted">
+ <item>
+ <p>Logging of messages with the GetBulk-request PDU
+ incorrectly produced an erroneous entry in the
+ log: "An error occurred". </p>
+ <p>The reason for this was that the PDU-fields
+ error_status and error_index is re-used for
+ Non-repeaters and Max-repetitions for
+ GetBulk-request PDUs, but this was not handled
+ by the logging code. </p>
+ <p>Own Id: OTP-7695</p>
+ <p>Aux Id: Seq 11124</p>
+ </item>
+
+ <item>
+ <p>[agent] An attempt to set the row status to active for an
+ notReady table row, could result in an "inconsistentValue"
+ error. </p>
+ <p>The same problem existed when attempting to set row status
+ to notInService for a row in notReady. </p>
+ <p>Serge Aleynikov</p>
+ <p>Own Id: OTP-7698</p>
+ <!-- <p>Aux Id: Seq 10966</p> -->
+ </item>
+
+ </list>
+
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+ </section> <!-- 4.12.1 -->
+
+ <section>
+ <title>SNMP Development Toolkit 4.12</title>
+ <p>Version 4.12 supports code replacement in runtime from/to
+ version 4.11.2, 4.11.1 and 4.11.</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <!--
+ <p>-</p>
+ -->
+ <list type="bulleted">
+ <item>
+ <p>[agent] A simple lookup cache has been added to improve
+ the mib server lookup performance. </p>
+ <p>This can be disabled with the mib_server
+ <seealso marker="snmp_app">cache</seealso> option. </p>
+ <p>Own Id: OTP-7346</p>
+ </item>
+
+ <item>
+ <p>[agent] Improvement of the inform reporting.
+ It was previously not certain how many acks an
+ application received, 0, 1 or 2. This has now been
+ fixed, so that only 1 (one) ack is issued. </p>
+ <p>Per Hedeland</p>
+ <p>Own Id: OTP-7525</p>
+ </item>
+
+ </list>
+
+ </section>
+
+ <section>
+ <title>Reported Fixed Bugs and Malfunctions</title>
+ <p>-</p>
+ <!--
+ <list type="bulleted">
+ <item>
+ <p>[manager] Encryption error when attempting to send
+ version 3 inform-requests. </p>
+ <p>Own Id: OTP-7432</p>
+ <p>Aux Id: Seq 10966</p>
+ </item>
+
+ </list>
+ -->
+
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+ </section> <!-- 4.12 -->
+
+ <section>
+ <title>SNMP Development Toolkit 4.11.2</title>
+ <p>Version 4.11.2 supports code replacement in runtime from/to
+ version 4.11.1 and 4.11. </p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <p>-</p>
+ <!--
+ <list type="bulleted">
+ <item>
+ <p>Added utility functions for transforming DateAndTime
+ as [int()] to strings;
+ <seealso marker="snmp#dat2s">date_and_time_to_string/2</seealso>
+ and
+ <seealso marker="snmp#dat2s2">date_and_time_to_string2/1</seealso>. </p>
+ <p>Also added new validation function
+ <seealso marker="snmp#vdat">validate_date_and_time/2</seealso>. </p>
+ <p>Own Id: OTP-7412</p>
+ <p>Aux Id: Seq 10987</p>
+ </item>
+ </list>
+ -->
+ </section>
+
+ <section>
+ <title>Reported Fixed Bugs and Malfunctions</title>
+ <!--
+ <p>-</p>
+ -->
+ <list type="bulleted">
+ <item>
+ <p>[manager] Erroneous engine-id check when receiving version 3
+ informs. </p>
+ <p>Own Id: OTP-7570</p>
+ <p>Aux Id: Seq 11060</p>
+ </item>
+
+ <item>
+ <p>Receiving an snmp message with a very large version
+ number could cause the erlang node to run out of
+ memory and consequently crash. </p>
+ <p>The standard specifies the snmp version as an
+ (unlimited) INTEGER, but today only
+ 0 (version 1), 1 (version 2) and 3 (version 3) is
+ actually used. So, when decoding a message, a limit
+ has been put on the snmp version integer in order
+ to not allow this kind of a problem. </p>
+ <p>Own Id: OTP-7575</p>
+ <p>Aux Id: Seq 11064</p>
+ </item>
+
+ </list>
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+ </section> <!-- 4.11.2 -->
+
+
+ <section>
+ <title>SNMP Development Toolkit 4.11.1</title>
+ <p>Version 4.11.1 supports code replacement in runtime from/to
+ version 4.11.</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <!--
+ <p>-</p>
+ -->
+ <list type="bulleted">
+ <item>
+ <p>[compiler] The MIB compiler did not retrieve the REFERENCE part
+ of a SNMP MIB definition. </p>
+ <p>This problem has been partly solved. For SNMP tables,
+ the assocList field of the tables mib-entry record now contains
+ this info (as <c>{reference, string()}</c>), <em>if</em> the
+ MIB was compiled with the compiler option <em>+reference</em>. </p>
+ <p>This solution is temporary, until such time as a permanent
+ solution (and probably not backward compatible) is devised, which
+ retrieves and stores all REFERENCE part(s) of a MIB. </p>
+ <p>See the
+ <seealso marker="snmpc#compiler_opts">compiler options</seealso>
+ for more info. </p>
+
+ <p>Serge Aleynikov</p>
+ <p>Own Id: OTP-7426</p>
+ </item>
+
+ <item>
+ <p>Added utility functions for transforming DateAndTime
+ as [int()] to strings;
+ <seealso marker="snmp#dat2s">date_and_time_to_string/2</seealso>
+ and
+ <seealso marker="snmp#dat2s2">date_and_time_to_string2/1</seealso>. </p>
+ <p>Also added new validation function
+ <seealso marker="snmp#vdat">validate_date_and_time/2</seealso>. </p>
+ <p>Own Id: OTP-7412</p>
+ <p>Aux Id: Seq 10987</p>
+ </item>
+
+ </list>
+
+ </section>
+
+ <section>
+ <title>Reported Fixed Bugs and Malfunctions</title>
+ <!--
+ <p>-</p>
+ -->
+ <list type="bulleted">
+ <item>
+ <p>[manager] Encryption error when attempting to send
+ version 3 inform-requests. </p>
+ <p>Own Id: OTP-7432</p>
+ <p>Aux Id: Seq 10966</p>
+ </item>
+
+ </list>
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+ </section> <!-- 4.11.1 -->
+
+ <section>
+ <title>SNMP Development Toolkit 4.11</title>
+ <p>Version 4.11 supports code replacement in runtime from/to
+ version 4.10.3, 4.10.2, 4.10.1 and 4.10.</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <!--
+ <p>-</p>
+ -->
+ <list type="bulleted">
+ <item>
+ <p>[agent] Performance improvements in the case when an SNMP
+ manager performs an snmpwalk. </p>
+ <p>Martin Bj&ouml;rklund</p>
+ <p>Own Id: OTP-7201</p>
+ </item>
+
+ <item>
+ <p>The API for sending inform(s) has been improved. Also
+ the documentation has been corrected and updated. See
+ <seealso marker="snmpa#send_notification">snmpa:send_notification</seealso> and
+ <seealso marker="snmpa_notification_delivery_info_receiver">snmpa_notification_delivery_info_receiver</seealso>
+ for more info.</p>
+ <p>Own Id: OTP-7287</p>
+ <p>Aux Id: Seq 10926</p>
+ </item>
+
+ <item>
+ <p>[agent] Performance of the internal database (local-db)
+ has been improved.</p>
+ <p>Own Id: OTP-7319</p>
+ <p>Aux Id: Seq 10942</p>
+ </item>
+
+ <item>
+ <p>[agent] Added utility functions,
+ <seealso marker="snmpa#restart_worker">snmpa:restart_worker/0,1</seealso> and
+ <seealso marker="snmpa#restart_set_worker">snmpa:restart_set_worker/0,1</seealso>,
+ for restarting the agent worker processes (in case the agent is
+ multi-threaded).</p>
+ <p>Own Id: OTP-7369</p>
+ </item>
+
+ <item>
+ <p>Add utility function to
+ <seealso marker="snmp#read_mib">read</seealso>
+ a compiled mib. </p>
+ <p>Own Id: OTP-7371</p>
+ </item>
+
+ </list>
+ </section>
+
+ <section>
+ <title>Reported Fixed Bugs and Malfunctions</title>
+ <!--
+ <p>-</p>
+ -->
+ <list type="bulleted">
+ <item>
+ <p>[manager] Encryption error when attempting to send
+ version 3 inform-requests. </p>
+ <p>Own Id: OTP-7377</p>
+ <p>Aux Id: Seq 10966</p>
+ </item>
+
+ </list>
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+ </section> <!-- 4.11 -->
+
+ <!-- section>
+ <title>Release notes history</title>
+ <p>For information about older versions see
+ <url href="part_notes_history_frame.html">release notes history</url>.</p>
+ </section -->
+</chapter>
+
diff --git a/lib/snmp/doc/src/notes_history.xml b/lib/snmp/doc/src/notes_history.xml
new file mode 100644
index 0000000000..8739400773
--- /dev/null
+++ b/lib/snmp/doc/src/notes_history.xml
@@ -0,0 +1,2151 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE chapter SYSTEM "chapter.dtd">
+
+<chapter>
+ <header>
+ <copyright>
+ <year>2004</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ 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.
+
+ </legalnotice>
+
+ <title>SNMP Release Notes history</title>
+ <prepared></prepared>
+ <responsible></responsible>
+ <docno></docno>
+ <approved></approved>
+ <checked></checked>
+ <date></date>
+ <rev></rev>
+ <file>notes_history.xml</file>
+ </header>
+
+ <section>
+ <title>SNMP Development Toolkit 4.10.3</title>
+ <p>Version 4.10.3 supports code replacement in runtime from/to
+ version 4.10.2, 4.10.1 and 4.10.</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <!--
+ <list type="bulleted">
+ <item>
+ <p>The snmp documentation source has been converted
+ from SGML to XML.</p>
+ <p>Own Id: OTP-6771</p>
+ </item>
+ </list>
+ -->
+ <p>-</p>
+ </section>
+
+ <section>
+ <title>Reported Fixed Bugs and Malfunctions</title>
+ <list type="bulleted">
+ <item>
+ <p>[manager] The configuration option
+ <seealso marker="snmp_app">inform_request_behaviour</seealso>
+ was not properly parsed, which caused the manager to revert
+ to the default value, <c>auto</c>. </p>
+ <p>Own Id: OTP-7219</p>
+ </item>
+
+ </list>
+ <!-- <p>-</p> -->
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+ </section> <!-- 4.10.3 -->
+
+
+ <section> <!-- 4.10.2 -->
+ <title>SNMP Development Toolkit 4.10.2</title>
+
+ <p>Version 4.10.2 supports code replacement in run-time from/to
+ version 4.10.1 and 4.10</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <!--
+ <p>-</p>
+ -->
+
+ <list type="bulleted">
+ <item>
+ <p>[compiler] The MIB-compiler did not recognize well-known-names
+ as top parents. The names 'ccitt' (0) , 'iso' (1) and
+ 'joint-iso-ccitt' (2) is now also recognized by the MIB
+ compiler. </p>
+ <p>Ola Samuelsson</p>
+ <p>Own Id: OTP-7160</p>
+ </item>
+
+ <item>
+ <p>[compiler] The MIB-compiler did not support a name assignment
+ which was sequence of numbers, only a parent object
+ name followed by a sequence of numbers. </p>
+ <p>Ola Samuelsson</p>
+ <p>Own Id: OTP-7158</p>
+ </item>
+
+ </list>
+ </section>
+
+ <section>
+ <title>Reported Fixed Bugs and Malfunctions</title>
+ <!--
+ <p>-</p>
+ -->
+ <list type="bulleted">
+ <item>
+ <p>[agent] Invalid variable value causes crashing agent worker
+ process when sending traps. </p>
+ <p>Own Id: OTP-7159</p>
+ </item>
+
+ <item>
+ <p>[agent] When sending a trap, the order of the variable
+ bindings not provided by the trap-sender, could be
+ mangled by the agent. </p>
+ <p>Ola Samuelsson</p>
+ <p>Own Id: OTP-7157</p>
+ </item>
+
+ <item>
+ <p>[agent] Uninstalling MEs when unloading mibs incorrect and
+ therefor never done. </p>
+ <p>Own Id: OTP-7153</p>
+ </item>
+
+ <item>
+ <p>[agent] snmp_generic:table_set_cols/3 did not handle unexpected
+ return values correctly when setting column values. </p>
+ <p>Serge Aleynikov</p>
+ <p>Own Id: OTP-7152</p>
+ </item>
+
+ </list>
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+ </section> <!-- 4.10.2 -->
+
+
+ <section> <!-- 4.10.1 -->
+ <title>SNMP Development Toolkit 4.10.1</title>
+
+ <p>Version 4.10.1 supports code replacement in run-time from/to
+ version 4.10</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <p>-</p>
+ <!--
+ <list type="bulleted">
+ <item>
+ <p>Added buffer sizes (both receive and send) of
+ the udp socket(s) info when calling the
+ <seealso marker="snmpa#info">agent info</seealso>
+ and
+ <seealso marker="snmpm#info">manager info</seealso>
+ function(s). </p>
+ <p>Own Id: OTP-6945</p>
+ </item>
+
+ </list>
+ -->
+ </section>
+
+ <section>
+ <title>Reported Fixed Bugs and Malfunctions</title>
+ <!--
+ <p>-</p>
+ -->
+ <list type="bulleted">
+ <item>
+ <p>[manager] Fixed usage of inet:gethostname/1. </p>
+ <p>Dialyzer</p>
+ <p>Own Id: OTP-7123</p>
+ </item>
+
+ <item>
+ <p>[agent] Remeoved invalid guard. There was an invalid
+ guard on the start function of the top agent
+ supervisor. </p>
+ <p>Dialyzer</p>
+ <p>Own Id: OTP-7121</p>
+ </item>
+
+ <item>
+ <p>[compiler] Old style fun cleanup in the MIB compiler. </p>
+ <p>Dialyzer</p>
+ <p>Own Id: OTP-7119</p>
+ </item>
+
+ <item>
+ <p>Corrected usage of function file:open/2 (the <c>Modes</c>
+ argument is a list). </p>
+ <p>Own Id: OTP-7110</p>
+ <!-- <p>Aux Id: Seq 10717</p> -->
+ </item>
+
+ <item>
+ <p>The SNMP application contains some (previously undocumented)
+ simple utility functions for function tracing (using dbg),
+ see
+ <seealso marker="snmp#enable_trace">enable_trace</seealso>,
+ <seealso marker="snmp#disable_trace">disable_trace</seealso>,
+ <seealso marker="snmp#set_trace1">set_trace/1</seealso>,
+ <seealso marker="snmp#reset_trace">reset_trace</seealso> and
+ <seealso marker="snmp#set_trace2">set_trace/2</seealso>
+ for more info.
+ These functions are intended to make it easy to enable tracing on
+ individual functions.
+ There where some minor errors, which has now been corrected. </p>
+ <p>Own Id: OTP-7109</p>
+ <!-- <p>Aux Id: Seq 10717</p> -->
+ </item>
+
+ <item>
+ <p>There is a bug in snmp_pdus:enc_oct_str_tag/1.
+ All the enc_* functions are supposed to return
+ a flat list, but the second clause of this function
+ does not. If it gets a binary it returns a deep list. </p>
+ <p>Martin Bj&ouml;rklund</p>
+ <p>Own Id: OTP-7083</p>
+ <!-- <p>Aux Id: Seq 10717</p> -->
+ </item>
+
+ </list>
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+ </section> <!-- 4.10.1 -->
+
+
+ <section> <!-- 4.10 -->
+ <title>SNMP Development Toolkit 4.10</title>
+ <!--
+ <p>Version 4.10 supports code replacement in run-time from/to
+ version 4.9.6</p>
+ -->
+
+ <section>
+ <title>Improvements and new features</title>
+ <list type="bulleted">
+ <item>
+ <p>Added buffer sizes (both receive and send) of
+ the udp socket(s) info when calling the
+ <seealso marker="snmpa#info">agent info</seealso>
+ and
+ <seealso marker="snmpm#info">manager info</seealso>
+ function(s). </p>
+ <p>Own Id: OTP-6945</p>
+ </item>
+
+ <item>
+ <p>[agent] Added the ability to change the request limit
+ in run-time, see
+ <seealso marker="snmpa#set_request_limit">set_request_limit</seealso>
+ for more info. </p>
+ <p>Own Id: OTP-6898</p>
+ </item>
+
+ <item>
+ <p>Added the ability to change the audit trail log type
+ in run-time (both agent and manager), see function(s)
+ <seealso marker="snmpm#set_log_type">[manager] set_log_type</seealso>
+ and
+ <seealso marker="snmpa#set_log_type">[agent] set_log_type</seealso>
+ for more info. </p>
+ <p>Own Id: OTP-6841</p>
+ </item>
+
+ <item>
+ <p>[agent] Added support for message filtering in the network
+ interface module provided with the application.
+ The component that actually make the filter decisions is the
+ network interface filter module. This module must implement the
+ <seealso marker="snmpa_network_interface_filter">network interface filter behaviour</seealso>.
+ See also the
+ <seealso marker="snmp_app#configuration_params">Configuring the application</seealso>
+ chapter of the User's Guide to see how to configure this
+ feature. </p>
+ <p>Own Id: OTP-6649</p>
+ </item>
+
+ </list>
+ <!--
+ <p>-</p>
+ -->
+ </section>
+
+ <section>
+ <title>Reported Fixed Bugs and Malfunctions</title>
+ <p>-</p>
+ <!--
+ <list type="bulleted">
+ <item>
+ <p>[agent] The order in which the processes in the snmp agent
+ where terminated was incorrect. This could, in some
+ case's, lead to incoming request(s) being processed
+ during the application termination phase. This, in
+ turn, could lead to various process crashes (when
+ expected resources where no longer available). </p>
+ <p>Own Id: OTP-6805</p>
+ <p>Aux Id: Seq 10717</p>
+ </item>
+
+ </list>
+ -->
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+ </section> <!-- 4.10 -->
+
+ <section>
+ <title>SNMP Development Toolkit 4.9.6</title>
+ <p>Version 4.9.6 supports code replacement in run-time from/to
+ version 4.9.5, 4.9.4, 4.9.3, 4.9.2, 4.9.1 and 4.9.</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <!--
+ <list type="bulleted">
+ <item>
+ <p>The snmp documentation source has been converted
+ from SGML to XML.</p>
+ <p>Own Id: OTP-6771</p>
+ </item>
+ </list>
+ -->
+ <p>-</p>
+ </section>
+
+ <section>
+ <title>Reported Fixed Bugs and Malfunctions</title>
+ <list type="bulleted">
+ <item>
+ <p>[compiler] The MIB compiler did not handle import
+ of the macro from the MIB RFC1155-SMI. </p>
+ <p>Own Id: OTP-6840</p>
+ <p>Aux Id: Seq 10726</p>
+ </item>
+
+ <item>
+ <p>Bad length check (i.e. none) when decoding
+ AuthenticationParameters. </p>
+ <p>Own Id: OTP-6843</p>
+ </item>
+
+ </list>
+ <!-- <p>-</p> -->
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+ </section> <!-- 4.9.6 -->
+
+ <section>
+ <title>SNMP Development Toolkit 4.9.5</title>
+ <p>Version 4.9.5 supports code replacement in run-time from/to
+ version 4.9.4, 4.9.3, 4.9.2, 4.9.1 and 4.9.</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <!--
+ <list type="bulleted">
+ <item>
+ <p>The snmp documentation source has been converted
+ from SGML to XML.</p>
+ <p>Own Id: OTP-6771</p>
+ </item>
+ </list>
+ -->
+ <p>-</p>
+ </section>
+
+ <section>
+ <title>Reported Fixed Bugs and Malfunctions</title>
+ <list type="bulleted">
+ <item>
+ <p>[agent] The order in which the processes in the snmp agent
+ where terminated was incorrect. This could, in some
+ case's, lead to incoming request(s) being processed
+ during the application termination phase. This, in
+ turn, could lead to various process crashes (when
+ expected resources where no longer available). </p>
+ <p>Own Id: OTP-6805</p>
+ <p>Aux Id: Seq 10717</p>
+ </item>
+
+ <item>
+ <p>[agent] In version 4.9.4 some requests could be
+ handled single threaded regardless of the value of
+ the multi_thread config option. </p>
+ <p>Own Id: OTP-6815</p>
+ <p>Aux Id: Seq 10724</p>
+ </item>
+ </list>
+ <!-- <p>-</p> -->
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+ </section>
+
+ <section>
+ <title>SNMP Development Toolkit 4.9.4</title>
+ <p>Version 4.9.4 supports code replacement in run-time from/to
+ version 4.9.3, 4.9.2, 4.9.1 and 4.9.</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <list type="bulleted">
+ <item>
+ <p>The snmp documentation source has been converted
+ from SGML to XML.</p>
+ <p>Own Id: OTP-6771</p>
+ </item>
+ </list>
+ <!-- <p>-</p> -->
+ </section>
+
+ <section>
+ <title>Reported Fixed Bugs and Malfunctions</title>
+ <list type="bulleted">
+ <item>
+ <p>[agent] Unexpected worker process termination.
+ When the agent is multi-threaded (multi_thread = true),
+ sending a request to the agent with an invalid context
+ could lead to an unexpected worker process termination.
+ This is a non-fatal problem since the master-agent
+ would simply create a new worker process. </p>
+ <p>Own Id: OTP-6784</p>
+ <p>Aux Id: Seq 10689</p>
+ </item>
+ </list>
+ <!-- <p>-</p> -->
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+ </section> <!-- 4.9.4 -->
+
+ <section>
+ <title>SNMP Development Toolkit 4.9.3</title>
+ <p>Version 4.9.3 supports code replacement in run-time from/to
+ version 4.9.2, 4.9.1 and 4.9.</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <p>-</p>
+ </section>
+
+ <section>
+ <title>Reported Fixed Bugs and Malfunctions</title>
+ <list type="bulleted">
+ <item>
+ <p>[agent] Changing own [usm] pass-phrase when agent is
+ multi-threaded did not work.</p>
+ <p>Scott Lystig Fritchie</p>
+ <p>Martin Bj&ouml;rklund</p>
+ <p>Own Id: OTP-6712</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+ </section>
+
+ <section>
+ <title>SNMP Development Toolkit 4.9.2</title>
+ <p>Version 4.9.2 supports code replacement in run-time from/to
+ version 4.9.1, 4.9 &amp; 4.8.4.</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <p>-</p>
+ </section>
+
+ <section>
+ <title>Reported Fixed Bugs and Malfunctions</title>
+ <list type="bulleted">
+ <item>
+ <p>[agent] Incorrect default verbosity (trace) for target cache.</p>
+ <p>Own Id: OTP-6571</p>
+ <p>Aux Id: Seq 10437</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+ </section>
+
+ <section>
+ <title>SNMP Development Toolkit 4.9.1</title>
+ <p>Version 4.9.1 supports code replacement in run-time from/to
+ version 4.9 &amp; 4.8.4.</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <p>-</p>
+ </section>
+
+ <section>
+ <title>Reported Fixed Bugs and Malfunctions</title>
+ <list type="bulleted">
+ <item>
+ <p>[agent] Used wrong DEFVAL for vacmAccessStorageType
+ (volatile instead of nonVolatile) in SNMP-VIEW-BASED-ACM-MIB. </p>
+ <p>Martin Bj&ouml;rklund</p>
+ <p>Own Id: OTP-6569</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+ </section>
+
+ <section>
+ <title>SNMP Development Toolkit 4.9</title>
+ <p>Version 4.9 supports code replacement in run-time from/to
+ version 4.8.4, 4.8.3, 4.8.2, 4.8.1 and 4.8.</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <list type="bulleted">
+ <item>
+ <p>Added documentation for
+ <seealso marker="snmp#passwd2localized_key">snmp:passwd2localized_key/3</seealso>. </p>
+ <p>Own Id: OTP-6540</p>
+ </item>
+ <item>
+ <p>The
+ <seealso marker="snmp#config">snmp:config/0</seealso>
+ utility function assumes by default
+ current working dir as the directory to write config
+ files. This is a problem since there are two files
+ that share the same name, usm.conf, one for the agent
+ and the other for the manager. Some extra checks has
+ been added to be able warn the user about this possible
+ conflict. </p>
+ <p>Own Id: OTP-6532</p>
+ </item>
+ <item>
+ <p>Minor documentation improvement for module snmp_generic. </p>
+ <p>Own Id: OTP-6518</p>
+ </item>
+ <item>
+ <p>[agent] Improve error handling of missing target params
+ config. </p>
+ <p>Own Id: OTP-6487</p>
+ </item>
+ <item>
+ <p>Minor improvement to the mnesia snmp indexing. </p>
+ <p>Own Id: OTP-6415</p>
+ </item>
+ <item>
+ <p>Include the INET-ADDRESS-MIB mib in the SNMP application. </p>
+ <p>Own Id: OTP-6383</p>
+ </item>
+ <item>
+ <p>Added utility modules to read, write and update the config
+ files of the
+ <seealso marker="snmpa_conf">agent</seealso> and
+ <seealso marker="snmpm_conf">manager</seealso>. </p>
+ <p>Own Id: OTP-6318</p>
+ </item>
+ <item>
+ <p>[agent] Improve behaviour during massive trap-
+ sending. This is done in two way's:</p>
+ <list type="bulleted">
+ <item>
+ <p>Improving performance of the target(s) cache
+ (which is used during trap/notification sending). </p>
+ </item>
+ <item>
+ <p>A slightly better flow control, making it more
+ difficult to actually overload the agent.</p>
+ </item>
+ </list>
+ <p>Own Id: OTP-6317</p>
+ <p>Aux Id: Seq 10437</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Reported Fixed Bugs and Malfunctions</title>
+ <list type="bulleted">
+ <item>
+ <p>Incorrect handling of decrypt failure resulting in
+ incorrect error reporting. Applies to both the
+ agent and the manager. Detected by dialyzer. </p>
+ <p>Own Id: OTP-6533</p>
+ </item>
+ <item>
+ <p>[manager] Invalid guard on function snmpm:agn/5
+ made it impossible to reach this particular clause.
+ Detected by dialyzer. </p>
+ <p>Own Id: OTP-6529</p>
+ </item>
+ <item>
+ <p>Miscellaneous minor corrections, such as
+ removing "dead code". Detected by dialyzer. </p>
+ <p>Own Id: OTP-6515</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+ </section>
+
+ <section>
+ <title>SNMP Development Toolkit 4.8.4</title>
+ <p>Version 4.8.4 supports code replacement in run-time from/to
+ version 4.8.3, 4.8.2, 4.8.1 and 4.8.</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <p>-</p>
+ </section>
+
+ <section>
+ <title>Reported Fixed Bugs and Malfunctions</title>
+ <list type="bulleted">
+ <item>
+ <p>[agent] An Audit Trail Log entry was sometimes done
+ using a list instead of the expected binary for the
+ snmp packet. This caused an error when converting the
+ log to a text-file. </p>
+ <p>Own Id: OTP-6408</p>
+ <p>Aux Id: Seq 10547</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+ </section>
+
+ <section>
+ <title>SNMP Development Toolkit 4.8.3</title>
+ <p>Version 4.8.3 supports code replacement in run-time from/to
+ version 4.8.2, 4.8.1 and 4.8.</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <p>-</p>
+ </section>
+
+ <section>
+ <title>Reported Fixed Bugs and Malfunctions</title>
+ <list type="bulleted">
+ <item>
+ <p>[agent] Verification of ViewTreeFamily
+ (SNMP-VIEW-BASED-ACM-MIB) incorrect.
+ No values other then <c>null</c> and <c>[]</c> where accepted. </p>
+ <p>Own Id: OTP-6337</p>
+ <p>Aux Id: Seq 10509</p>
+ </item>
+ <item>
+ <p>[agent] Start with type <c>takeover</c> did not work. </p>
+ <p>Own Id: OTP-6340</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+ </section>
+
+ <section>
+ <title>SNMP Development Toolkit 4.8.2</title>
+ <p>Version 4.8.2 supports code replacement in run-time from/to
+ version 4.8.1 and 4.8.</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <list type="bulleted">
+ <item>
+ <p>Add time-stamp to the verbosity printouts. </p>
+ <p>Own Id: OTP-6214</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Reported Fixed Bugs and Malfunctions</title>
+ <list type="bulleted">
+ <item>
+ <p>A badly formatted debug printout caused console printouts. </p>
+ <p>Own Id: OTP-6247</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+ </section>
+
+ <section>
+ <title>SNMP Development Toolkit 4.8.1</title>
+ <p>Version 4.8.1 supports code replacement in run-time from/to
+ version 4.8, 4.7.4 and 4.7.3.</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <p>-</p>
+ </section>
+
+ <section>
+ <title>Reported Fixed Bugs and Malfunctions</title>
+ <list type="bulleted">
+ <item>
+ <p>Removed an io:format in mini mib utility (used when
+ converting logs). </p>
+ <p>Own Id: OTP-6177</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+ </section>
+
+ <section>
+ <title>SNMP Development Toolkit 4.8</title>
+ <p>Version 4.8 supports code replacement in run-time from/to
+ version 4.7.4 and 4.7.3.</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <list type="bulleted">
+ <item>
+ <p>Added a config option, <c>sndbuf</c>, for the net_if-module(s).
+ See
+ <seealso marker="snmp_app">application configuration</seealso> or
+ <seealso marker="snmp_config">running the application</seealso>
+ for more info (look for manager_net_if_options and
+ agent_net_if_options). </p>
+ <p>Own Id: OTP-6137</p>
+ </item>
+ <item>
+ <p>Improve error handling of the log_to_txt function(s).
+ [snmpm|snmpa]:log_to_txt on a non-existing log-file
+ causes an obscure error reason.</p>
+ <p>Own Id: OTP-6149</p>
+ </item>
+ <item>
+ <p>Performance improvement when converting audit trail logs.</p>
+ <p>Own Id: OTP-6164</p>
+ <p>Aux Id: Seq 10362</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Reported Fixed Bugs and Malfunctions</title>
+ <list type="bulleted">
+ <item>
+ <p>[compiler] Allow empty definitions for SMI-II mibs,
+ i.e. mibs are allowed to only contain the
+ MODULE-IDENTITY construct. </p>
+ <p>Own Id: OTP-6150</p>
+ <p>Aux Id: Seq 10333</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+ </section>
+
+ <section>
+ <title>SNMP Development Toolkit 4.7.4</title>
+ <p>Version 4.7.4 supports code replacement in run-time from/to
+ version 4.7.3, 4.7.2, 4.7.1 and 4.7.</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <list type="bulleted">
+ <item>
+ <p>Add another example,
+ <seealso marker="snmp_impl_example_manager">ex2</seealso>.
+ This example is basically a simple manager module. </p>
+ <p>Own Id: OTP-6042</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Reported Fixed Bugs and Malfunctions</title>
+ <list type="bulleted">
+ <item>
+ <p>[agent] v1 trap sending minor problems. When sending a
+ v1 trap, the wrong record type (#pdu{}) was used to
+ access the type field (which does not exist in the
+ #tranpdu{} record). This value is used when logging.</p>
+ <p>Own Id: OTP-6077</p>
+ </item>
+ <item>
+ <p>[manager] Type guard error.</p>
+ <p>Kostis Sagonas.</p>
+ <p>Own Id: OTP-6074 (dialyzer)</p>
+ </item>
+ <item>
+ <p>Misc Dialyzer warnings.</p>
+ <p>Own Id: OTP-6068</p>
+ </item>
+ <item>
+ <p>[manager] Default value tags may conflict with actual
+ host name. When storing default values for agents, the
+ tag, default, was used for address (and port). This
+ could conflict with an actual host name.</p>
+ <p>Own Id: OTP-6062</p>
+ </item>
+ <item>
+ <p>Misc doc corrections.</p>
+ <p>Own Id: OTP-6044</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+ </section>
+
+ <section>
+ <title>SNMP Development Toolkit 4.7.3</title>
+ <p>Version 4.7.3 supports code replacement in run-time from/to
+ version 4.7.2, 4.7.1 and 4.7.</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <p>-</p>
+ </section>
+
+ <section>
+ <title>Reported Fixed Bugs and Malfunctions</title>
+ <list type="bulleted">
+ <item>
+ <p>Misc compiler warning cleanup.</p>
+ <p>Own Id: OTP-6031</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+ </section>
+
+ <section>
+ <title>SNMP Development Toolkit 4.7.2</title>
+ <p>Version 4.7.2 supports code replacement in run-time from/to
+ version 4.7.1 and 4.7.</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <list type="bulleted">
+ <item>
+ <p>[manager] Improve handling of empty messages. Today
+ when receiving an empty (size = 0) udp message, this
+ will result in a decode failure (a catched function
+ clause), which in turn will be passed on to the user,
+ via a call to the
+ <seealso marker="snmpm_user#handle_error">handle_error</seealso>
+ callback function, in the <c>Reason</c> argument.
+ This has now been changed so that instead, the
+ <c>Reason</c> argument will get a <c>empty message</c>
+ value.</p>
+ <p>See
+ <seealso marker="snmpm_user#handle_error">handle_error</seealso>
+ for more details. </p>
+ <p>Own Id: OTP-6024</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Reported Fixed Bugs and Malfunctions</title>
+ <list type="bulleted">
+ <item>
+ <p>[manager] Some error cases are reported to the 'user'
+ with the ReqId and Reason swapped in the call to the
+ <seealso marker="snmpm_user#handle_error">handle_error</seealso>
+ callback function.</p>
+ <p>Own Id: OTP-5992</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+ </section>
+
+ <section>
+ <title>SNMP Development Toolkit 4.7.1</title>
+ <p>Version 4.7.1 supports code replacement in run-time from/to
+ version 4.7, 4.6.1 and 4.6.</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <list type="bulleted">
+ <item>
+ <p>Added new version info print functions,
+ <seealso marker="snmp#print_version_info">print_version_info</seealso>.</p>
+ <p>Own Id: OTP-5968</p>
+ </item>
+ <item>
+ <p>Updated the documentation for the
+ <seealso marker="snmpa#log_to_txt">agent</seealso> and
+ <seealso marker="snmpm#log_to_txt">manager</seealso>
+ log_to_txt functions.</p>
+ <p>Own Id: OTP-5969</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Reported Fixed Bugs and Malfunctions</title>
+ <list type="bulleted">
+ <item>
+ <p>[manager] The supervision structure contained several
+ errors which unnecessarily caused a complete restart of
+ the manager.</p>
+ <p>Own Id: OTP-5963</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+ </section>
+
+ <section>
+ <title>SNMP Development Toolkit 4.7</title>
+ <p>Version 4.7 supports code replacement in run-time from/to
+ version 4.6.1 and 4.6.</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <list type="bulleted">
+ <item>
+ <p>Add simple backup mechanism,
+ see <seealso marker="snmpa#backup">agent backup</seealso>
+ and <seealso marker="snmpm#backup">manager backup</seealso>.</p>
+ <p>Own Id: OTP-5870</p>
+ </item>
+ <item>
+ <p>Improve handling of faulty data base files.</p>
+ <p>Added new agent and manager config option,
+ <c>db_init_error</c>, see
+ <seealso marker="snmp_config">config</seealso> for more
+ info.</p>
+ <p>Own Id: OTP-5934</p>
+ <p>Aux Id: Seq 10202</p>
+ </item>
+ <item>
+ <p>Added possibility to configure restart type for each of
+ the components (default is permanent for the agent and
+ transient for the manager).
+ See <seealso marker="snmp_config">config</seealso> for more
+ info.</p>
+ <p>Own Id: OTP-5935</p>
+ </item>
+ <item>
+ <p>[compiler] Improve error printouts.</p>
+ <p>Own Id: OTP-5937</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Reported Fixed Bugs and Malfunctions</title>
+ <p>-</p>
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+ </section>
+
+ <section>
+ <title>SNMP Development Toolkit 4.6.1</title>
+ <p>Version 4.6.1 supports code replacement in run-time from/to
+ version 4.6.</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <p>-</p>
+ </section>
+
+ <section>
+ <title>Reported Fixed Bugs and Malfunctions</title>
+ <list type="bulleted">
+ <item>
+ <p>[agent] SNMP sha/aes decryption did not work. </p>
+ <p>Magnus Fr&ouml;berg</p>
+ <p>Own Id: OTP-5834</p>
+ </item>
+ <item>
+ <p>[agent] The SNMP agent internal data base (local db)
+ uses dets, and does not properly handle error's from
+ e.g. lookup.</p>
+ <p>Own Id: OTP-5838</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+ </section>
+
+ <section>
+ <title>SNMP Development Toolkit 4.6</title>
+ <p>Version 4.6 supports code replacement in run-time from/to
+ version 4.5.</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <list type="bulleted">
+ <item>
+ <p>Improved application start flexibility. It is now
+ possible to start snmp application components (agent
+ or manager) after the application has been started.
+ It is even possible to start an "empty" snmp
+ application and start the agent and/or manager
+ afterwords. See
+ <seealso marker="snmp#start_agent">start_agent</seealso> and
+ <seealso marker="snmp#start_manager">start_manager</seealso>.</p>
+ <p>Own Id: OTP-5797</p>
+ <p>Aux Id: Seq 10128</p>
+ </item>
+ <item>
+ <p>[agent] Adding utility function to convert old
+ application config to current agent config.
+ See the <seealso marker="snmpa#convert_config">convert_config</seealso>
+ for more info.</p>
+ <p>Own Id: OTP-5787</p>
+ </item>
+ <item>
+ <p>Improved handling of audit trail logs.
+ See the <seealso marker="snmp_app">atl_repair</seealso>
+ config for more info.</p>
+ <p>Own Id: OTP-5771</p>
+ </item>
+ <item>
+ <p>[manager] Introduced the
+ <seealso marker="snmpm#notify_started">notify_started</seealso>
+ function used by a <em>client</em> to get a notification
+ when the manager is started.</p>
+ <p>Own Id: OTP-5763</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Reported Fixed Bugs and Malfunctions</title>
+ <list type="bulleted">
+ <item>
+ <p>Misc documentation corrections.</p>
+ <p>Own Id: OTP-5829</p>
+ <p>Aux Id: Seq 10152</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+ </section>
+
+ <section>
+ <title>SNMP Development Toolkit 4.5</title>
+ <p>Version 4.5 supports code replacement in run-time from/to
+ version 4.4.1 and 4.4.</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <list type="bulleted">
+ <item>
+ <p>[manager] Introduced the
+ <seealso marker="snmp_app">inform request behaviour</seealso>
+ configuration option to allow the user to specify
+ how/when the manager shall acknowledge inform-request's.</p>
+ <p>Own Id: OTP-5733</p>
+ </item>
+ <item>
+ <p>[manager] In order to improve application behaviour,
+ all callback function (see the
+ <seealso marker="snmpm_user">snmpm_user behaviour</seealso>)
+ calls
+ are now done by spawned processes (and not as previously
+ by the SNMP manager server process).</p>
+ <p>Own Id: OTP-5726</p>
+ </item>
+ <item>
+ <p>[manager] In order to present the various error
+ reason's returned by the manager, a
+ <seealso marker="snmpm#format_reason">format_reason</seealso>
+ function has been added.
+ The error reasons this function handles are those
+ returned by the (sync and async) get, get-next,
+ get-bulk and set-functions
+ (see the <seealso marker="snmpm">snmpm</seealso> module)
+ as well as the
+ <c>Reason</c> argument of the
+ <seealso marker="snmpm_user#handle_error">handle_error</seealso>
+ function of the
+ <seealso marker="snmpm_user">user callback module</seealso>.</p>
+ <p>Own Id: OTP-5581</p>
+ <p>Aux Id: Seq 9870</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Reported Fixed Bugs and Malfunctions</title>
+ <list type="bulleted">
+ <item>
+ <p>[manager] The (error) report according to RFC 2572, chapter
+ 7.2 point 6) was never sent.</p>
+ <p>Own Id: OTP-5742</p>
+ </item>
+ <item>
+ <p>[agent] Check of notification name collision
+ could fail due to incorrect record name (assumed to
+ be <c>#trap</c>, but could also be <c>#notification</c>).
+ This only cases a problem when the application is
+ compiled with the strict_record_tests option.</p>
+ <p>Own Id: OTP-5740</p>
+ </item>
+ <item>
+ <p>[agent] Table get-request failure in some cases.</p>
+ <p>Own Id: OTP-5732</p>
+ <p>Aux Id: Seq 10087</p>
+ </item>
+ <item>
+ <p>Explicitly sync all audit trail log's upon termination.</p>
+ <p>Own Id: OTP-5727</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <list type="bulleted">
+ <item>
+ <p>[manager] The
+ <seealso marker="snmpm_network_interface">snmpm_network_interface</seealso>
+ behaviour has been updated (see
+ <seealso marker="snmpm_network_interface#inform_response">inform_response</seealso> and
+ <seealso marker="snmp_manager_netif">definition of the manager net if</seealso>).</p>
+ <p>Own Id: OTP-5733</p>
+ </item>
+ </list>
+ </section>
+ </section>
+
+ <section>
+ <title>SNMP Development Toolkit 4.4.1</title>
+ <p>Version 4.4.1 supports code replacement in run-time from/to
+ version 4.4.</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <list type="bulleted">
+ <item>
+ <p>[manager] Add monitoring of the SNMP manager.
+ The SNMP application consists of two different
+ run-time parts, the agent and the manager. They are
+ independent of each other. The agent is "permanent"
+ and the manager "transient". In order to handle
+ manager crashes a simple
+ <seealso marker="snmpm#monitor">monitor</seealso>
+ (and <seealso marker="snmpm#demonitor">demonitor</seealso>)
+ function has been added.</p>
+ <p>Own Id: OTP-5720</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Reported Fixed Bugs and Malfunctions</title>
+ <list type="bulleted">
+ <item>
+ <p>[manager] If sending a set-request containing an
+ 'OCTET STRING' with an invalid integer (valid integer
+ are 0-255), the encoding will fail and cause the
+ net_if process to crash.</p>
+ <p>Own Id: OTP-5719</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+ </section>
+
+ <section>
+ <title>SNMP Development Toolkit 4.4</title>
+ <p>Version 4.4 supports code replacement in run-time from/to
+ version 4.3.</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <list type="bulleted">
+ <item>
+ <p>Updated and extended the
+ <seealso marker="snmpa#info">agent</seealso>
+ info retrieval function. Also added an info retrieval
+ function for the
+ <seealso marker="snmpm#info">manager</seealso>.</p>
+ <p>Own Id: OTP-5666</p>
+ </item>
+ <item>
+ <p>[manager] Added get-bulk functionality, see (sync) get-bulk
+ and (async) get-bulk for more info.</p>
+ <p>Own Id: OTP-5669</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Reported Fixed Bugs and Malfunctions</title>
+ <list type="bulleted">
+ <item>
+ <p>[manager] Mini-MIB not properly initiated which could
+ cause a server crash if the name_to_oid or oid_to_name
+ functions where called (if no mib's where loaded).</p>
+ <p>Own Id: OTP-5675</p>
+ </item>
+ <item>
+ <p>[manager] The out packet counter was not incremented for
+ sent v1/v2 messages.</p>
+ <p>Own Id: OTP-5676</p>
+ </item>
+ <item>
+ <p>[manager] The request GC process was started with the
+ wrong default value (idle) which could (unlikely but
+ still) cause problems after a code-change.</p>
+ <p>Own Id: OTP-5678</p>
+ </item>
+ <item>
+ <p>Bad handling of error cases (corrupt log file) when
+ converting log files (i.e. when calling the function
+ log_to_txt).</p>
+ <p>Own Id: OTP-5703</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <list type="bulleted">
+ <item>
+ <p>[agent] The format of the info returned by the agent
+ info retrieval function has been changed. The info
+ can be converted to the old format by calling the
+ <seealso marker="snmpa#old_info_format">old_info_format</seealso>).</p>
+ <p>function. </p>
+ <p>Own Id: OTP-5666</p>
+ </item>
+ </list>
+ </section>
+ </section>
+
+ <section>
+ <title>SNMP Development Toolkit 4.3</title>
+ <p>Version 4.3 supports code replacement in run-time from/to
+ version 4.2.</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <list type="bulleted">
+ <item>
+ <p>[manager] Improved async error reporting.</p>
+ <p>Own Id: OTP-5637</p>
+ <p>Aux Id: Seq 9970</p>
+ </item>
+ <item>
+ <p>Added support for The Advanced Encryption Standard (AES)
+ Cipher Algorithm in the SNMP User-based Security Model
+ (RFC 3826). Both agent and manager. </p>
+ <p>Martin Bj&ouml;rklund</p>
+ <p>Own Id: OTP-5490</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Reported Fixed Bugs and Malfunctions</title>
+ <list type="bulleted">
+ <item>
+ <p>[manager] Reset of USM-cache when unregister agent.</p>
+ <p>Own Id: OTP-5636</p>
+ <p>Aux Id: Seq 9970</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+ </section>
+
+ <section>
+ <title>SNMP Development Toolkit 4.2</title>
+ <p>Version 4.2 supports code replacement in run-time from/to
+ version 4.1.5.</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <list type="bulleted">
+ <item>
+ <p>[manager] Added another get, get-next and set function
+ with another argument, <c>ExtraInfo</c> (see
+ synchronous get (g), asynchronous get (ag),
+ synchronous set (s), asynchronous set (as),
+ synchronous get-next (gn), and asynchronous get-next (agn)).
+ This argument is passed on to the net-if process. The net-if
+ process included in this application makes no use of this
+ info, but other implementations might.</p>
+ <p>Own Id: OTP-5574</p>
+ <p>Aux Id: Seq 9850</p>
+ </item>
+ <item>
+ <p>[manager] <c>report</c> message with incorrect security info
+ (e.g. securtyModel and/or securityLevel) was ignored (dropped,
+ except for incrementing the proper error counter) even if all
+ other info was correct. This has been changed so that in this
+ situation, the user will be informed, either via the
+ return value from a synchronous call (see synchronous get (g),
+ synchronous set (s) and synchronous get-next (gn))
+ or via a call to the handle_error callback function.</p>
+ <p>Own Id: OTP-5578</p>
+ <p>Aux Id: Seq 9850</p>
+ </item>
+ <item>
+ <p>[manager] Added a
+ <seealso marker="snmpm#unregister_usm_user">unregister_usm_user</seealso> function.</p>
+ <p>Own Id: OTP-5580</p>
+ <p>Aux Id: Seq 9850</p>
+ </item>
+ <item>
+ <p>[agent] Added new functions to get lists of all tables,
+ <seealso marker="snmpa#which_tables">which_tables</seealso>,
+ and variables,
+ <seealso marker="snmpa#which_variables">which_variables</seealso>,
+ known to the agent.</p>
+ <p>Own Id: OTP-5590</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Reported Fixed Bugs and Malfunctions</title>
+ <list type="bulleted">
+ <item>
+ <p>[manager] Incorrect SHA-key length check when
+ updating usm-user info (should have been 20 but
+ was 16).</p>
+ <p>Own Id: OTP-5579</p>
+ <p>Aux Id: Seq 9850</p>
+ </item>
+ <item>
+ <p>[compiler] Incorrect error report when the name of the
+ field and object is the same. </p>
+ <p>Kostis Sagonas</p>
+ <p>Own Id: OTP-5591 (dialyzer)</p>
+ </item>
+ <item>
+ <p>[manager] Arguments Port (third argument) and CtxName
+ (fourth argument) where swapped in snmpm:g/5
+ when forwarding call. </p>
+ <p>Kostis Sagonas</p>
+ <p>Own Id: OTP-5592 (dialyzer)</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <list type="bulleted">
+ <item>
+ <p>[manager] The <c>snmpm_network_interface</c> behaviour has changed.
+ One more argument (ExtraInfo) was added to the
+ function send_pdu (see
+ <seealso marker="snmpm_network_interface#send_pdu">send_pdu</seealso>).</p>
+ <p>Own Id: OTP-5574</p>
+ <p>Aux Id: Seq 9850</p>
+ </item>
+ </list>
+ </section>
+ </section>
+
+ <section>
+ <title>SNMP Development Toolkit 4.1.5</title>
+ <p>Version 4.1.5 supports code replacement in run-time from/to
+ version 4.1.4, 4.1.3, 4.1.2, 4.1.1 and 4.1.</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <list type="bulleted">
+ <item>
+ <p>[agent] Add mapping of notification oid to alias-name. </p>
+ <p>Martin Bj&ouml;rklund</p>
+ <p>Own Id: OTP-5562</p>
+ </item>
+ <item>
+ <p>[manager] Late (async) reply incorrectly delivered to
+ user via handle_pdu instead of handle_error.</p>
+ <p>Own Id: OTP-5506</p>
+ <p>Aux Id: Seq 9804</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Reported Fixed Bugs and Malfunctions</title>
+ <list type="bulleted">
+ <item>
+ <p>[manager] Security level handled incorrectly.</p>
+ <p>Own Id: OTP-5564</p>
+ <p>Aux Id: Seq 9850</p>
+ </item>
+ <item>
+ <p>[manager] (v3) Encryption/decryption failure.</p>
+ <p>Own Id: OTP-5560</p>
+ <p>Aux Id: Seq 9850</p>
+ </item>
+ <item>
+ <p>[manager] Cannot handle version-1 traps.</p>
+ <p>Own Id: OTP-5557</p>
+ <p>Aux Id: Seq 9850</p>
+ </item>
+ <item>
+ <p>[manager] Set-request without specifying the variable
+ type failed. The type of the oid had to be found in the
+ loaded MIB. This look-up was erroneous.</p>
+ <p>Own Id: OTP-5556</p>
+ <p>Aux Id: Seq 9850</p>
+ </item>
+ <item>
+ <p>[agent] Error's reported by the SecModule (v3) when
+ generating outgoing message was not handled correctly
+ in message processing dispatcher module.</p>
+ <p>Own Id: OTP-5550</p>
+ </item>
+ <item>
+ <p>[manager] Error's reported by the SecModule (v3) when
+ generating outgoing message was not handled correctly
+ in message processing dispatcher module. And also when
+ encryption failed, the real error was masked into another
+ error.</p>
+ <p>Own Id: OTP-5548</p>
+ <p>Aux Id: Seq 9804</p>
+ </item>
+ <item>
+ <p>[agent] Failure to stop the snmp application when
+ started with the old config type.</p>
+ <p>Own Id: OTP-5547</p>
+ <p>Aux Id: Seq 9842</p>
+ </item>
+ <item>
+ <p>[manager] User unregistration after reboot causes process crash
+ (snmpm_server).</p>
+ <p>Own Id: OTP-5539</p>
+ </item>
+ <item>
+ <p>[manager] Security engine id look-up errors.</p>
+ <p>Own Id: OTP-5508</p>
+ <p>Aux Id: Seq 9804</p>
+ </item>
+ <item>
+ <p>[manager] Registering of USM users erroneous.</p>
+ <p>Own Id: OTP-5505</p>
+ <p>Aux Id: Seq 9804</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+ </section>
+
+ <section>
+ <title>SNMP Development Toolkit 4.1.4</title>
+ <p>Version 4.1.4 supports code replacement in run-time from/to
+ version 4.1.3, 4.1.2, 4.1.1 and 4.1.</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <p>-</p>
+ </section>
+
+ <section>
+ <title>Reported Fixed Bugs and Malfunctions</title>
+ <list type="bulleted">
+ <item>
+ <p>Fixed a perl related problem in the mibs Makefile. </p>
+ <p>Geoff White</p>
+ <p>Own Id: OTP-5491</p>
+ </item>
+ <item>
+ <p>[manager] Failed to register usm users. Both using the
+ usm config file
+ (<seealso marker="snmp_manager_config_files#usm_user">usm.conf</seealso>)
+ and the API functions
+ <seealso marker="snmpm#register_usm_user">register_usm_user</seealso></p>
+ <p>Own Id: OTP-5499</p>
+ <p>Aux Id: Seq 9804</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+ </section>
+
+ <section>
+ <title>SNMP Development Toolkit 4.1.3</title>
+ <p>Version 4.1.3 supports code replacement in run-time from/to
+ version 4.1.2, 4.1.1 and 4.1.</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <list type="bulleted">
+ <item>
+ <p>Added utility functions to update agent and manager
+ config files.</p>
+ <p>Own Id: OTP-5468</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Reported Fixed Bugs and Malfunctions</title>
+ <list type="bulleted">
+ <item>
+ <p>[agent] Error replies was composed with invalid OIDs for the
+ following error counters:
+ <em>usmStatsWrongDigests</em> (RFC 2574, chap 3.2, point 6),
+ <em>usmStatsUnsupportedSecLevels</em> (point 5) and
+ <em>usmStatsDecryptionErrors</em> (point 8a).</p>
+ <p>Own Id: OTP-5464</p>
+ <p>Aux Id: Seq 9791</p>
+ </item>
+ <item>
+ <p>[agent] Malformed Oid returned from a get_next operation as
+ part of a get-bulk-request causes the agent to crash.</p>
+ <p>Own Id: OTP-5465</p>
+ <p>Aux Id: Seq 9783, Seq 9793</p>
+ </item>
+ <item>
+ <p>[agent] Missing catch on decode function call.</p>
+ <p>Kostis Sagonas (Dialyzer)</p>
+ <p>Own Id: OTP-5479</p>
+ </item>
+ <item>
+ <p>[manager] Invalid check for illegal options.</p>
+ <p>Kostis Sagonas (Dialyzer</p>
+ <p>Own Id: OTP-5480</p>
+ </item>
+ <item>
+ <p>Faulty utility function for generation of agent
+ config file target_addr.conf.</p>
+ <p>Own Id: OTP-5482</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+ </section>
+
+ <section>
+ <title>SNMP Development Toolkit 4.1.2</title>
+ <p>Version 4.1.2 supports code replacement in run-time from/to
+ version 4.1.1 and 4.1.</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <list type="bulleted">
+ <item>
+ <p>Export utility functions to create agent and manager
+ config files.</p>
+ <p>Own Id: OTP-5390</p>
+ </item>
+ <item>
+ <p>[agent] Documented instrumentation utility functions
+ (e.g. <seealso marker="snmpa#current_request_id">current_request_id</seealso>).</p>
+ <p>Own Id: OTP-5423</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Reported Fixed Bugs and Malfunctions</title>
+ <list type="bulleted">
+ <item>
+ <p>[manager] If the client crashes after having issued
+ an async request, the server will crash when trying to
+ perform cleanup. Supervision of the calling process issuing an
+ async request has been removed. </p>
+ <p>Own Id: OTP-5370</p>
+ </item>
+ <item>
+ <p>Failure to convert an audit-trail-log to text-file when
+ using the default log name. This applies to both the manager
+ and the agent. </p>
+ <p>Own Id: OTP-5394</p>
+ </item>
+ <item>
+ <p>[manager] Corrected the discovery handling of the manager.</p>
+ <p>Own Id: OTP-5414</p>
+ </item>
+ <item>
+ <p>[manager] Statistic counter creation correction.</p>
+ <p>Own Id: OTP-5415</p>
+ </item>
+ <item>
+ <p>[agent] When using the old style agent configuration (pre 4.0),
+ it was not possible to specify a different error report
+ module (the agent always choose snmpa_error_logger).
+ A similar problem existed for the config option
+ force_config_load, which always reverted to false.</p>
+ <p>Own Id: OTP-5424</p>
+ </item>
+ <item>
+ <p>[manager] The manager net_if process failed to properly handle
+ the case bind_to option value true.</p>
+ <p>Own Id: OTP-5431</p>
+ </item>
+ <item>
+ <p>[agent] Various minor mnesia-related fixes.</p>
+ <p>Martin Bj&ouml;rklund</p>
+ <p>Own Id: OTP-5433</p>
+ </item>
+ <item>
+ <p>[manager] Missing interface functions for loading and
+ unloading mibs into/from the manager:
+ <seealso marker="snmpm#load_mib">load_mib</seealso>,
+ <seealso marker="snmpm#unload_mib">unload_mib</seealso>,
+ <seealso marker="snmpm#which_mibs">which_mibs</seealso>,
+ <seealso marker="snmpm#name_to_oid">name_to_oid</seealso> and
+ <seealso marker="snmpm#oid_to_name">oid_to_name</seealso>.</p>
+ <p>Own Id: OTP-5441</p>
+ </item>
+ <item>
+ <p>Added utility functions to retrieve some system and application
+ info, see <seealso marker="snmp#versions1">versions1</seealso> and
+ <seealso marker="snmp#versions2">versions2</seealso>.</p>
+ <p>Own Id: OTP-5445</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+ </section>
+
+ <section>
+ <title>SNMP Development Toolkit v4.1.1</title>
+ <p>Version 4.1.1 supports code replacement in run-time from/to
+ version 4.1. </p>
+ <p>When performing a downgrade, make sure the verbosity of the
+ manager server process is silence, or else the process will crash
+ (due to a bug in version 4.0.4) and be restarted by it's
+ supervisor.</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <p>-</p>
+ </section>
+
+ <section>
+ <title>Reported Fixed Bugs and Malfunctions</title>
+ <list type="bulleted">
+ <item>
+ <p>[manager] Manager synchronous get-function with timeout erroneous.
+ Results in a function clause.</p>
+ <p>Own Id: OTP-5364</p>
+ </item>
+ <item>
+ <p>Replace in decoder fun's of the "old style" fun format,
+ {atom(), atom()}, with a proper fun, e.g. "fun the_function/1".</p>
+ <p>Own Id: OTP-5365</p>
+ </item>
+ <item>
+ <p>[manager] Register agent using the config file
+ agents.conf failed due to incorrect function guard.</p>
+ <p>Own Id: OTP-5367</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+ </section>
+
+ <section>
+ <title>SNMP Development Toolkit v4.1.0</title>
+ <p>Version 4.1.0 supports code replacement in run-time from/to
+ version 4.0.4. </p>
+ <p>When performing a downgrade, make sure the verbosity of the
+ manager server process is silence, or else the process will crash
+ (due to a bug in version 4.0.4) and be restarted by it's
+ supervisor.</p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <list type="bulleted">
+ <item>
+ <p>[manager] Added possibility to monitor a registered user.
+ See <seealso marker="snmpm#register_user_monitor">snmpm:register_user_monitor</seealso>.</p>
+ <p>Own Id: OTP-5286</p>
+ </item>
+ <item>
+ <p>[agent] Improved symbolic store. Alias and Oids where stored
+ with similar key's (separated by types: atom() and
+ lists() respectively). Also added new function:
+ <seealso marker="snmpa#which_aliasnames">snmpa:which_aliasnames</seealso>.</p>
+ <p>Own Id: OTP-5298</p>
+ </item>
+ <item>
+ <p>[agent] The agent local_db volatile storage method uses
+ an ets-table which is private. This table has been made
+ protected in order to make it easier to debug and test the
+ snmp agent.</p>
+ <p>Own Id: OTP-5308</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Reported Fixed Bugs and Malfunctions</title>
+ <list type="bulleted">
+ <item>
+ <p>Misspelled deprecated function. Non-existent function
+ snmp:is_constistent/1 was marked as deprecated. Should
+ have been snmp:is_consistent/1).</p>
+ <p>Own Id: OTP-5273</p>
+ </item>
+ <item>
+ <p>[agent] Unclear documentation for function
+ <seealso marker="snmpa#send_notification">snmpa:send_notification</seealso>. The Recv argument
+ (specifically the {M,F,A} variant).</p>
+ <p>Own Id: OTP-5281</p>
+ </item>
+ <item>
+ <p>[manager] It was never documented how the default
+ <seealso marker="snmpm_user">user behaviour</seealso>
+ could be overridden (default user is the module
+ <c>snmpm_user_default</c>).
+ See <seealso marker="snmp_app">application configuration</seealso> or
+ <seealso marker="snmp_config#configuration_params">configuration params</seealso>.</p>
+ <p>Own Id: OTP-5299</p>
+ </item>
+ <item>
+ <p>[manager] The server process contained a bug that caused it
+ to crash, if it received an exit message from it's gct (GC timer)
+ process and it's verbosity was <em>log</em> or higher. </p>
+ <p>This also effects the application downgrade. </p>
+ <p>Own Id: OTP-5306</p>
+ </item>
+ <item>
+ <p>[agent] The agent config file, target_addr.conf, was
+ incorrectly described in the
+ <seealso marker="snmp_agent_config_files#target_addr">Target Address Definitions</seealso> chapter of the
+ User's Guide. The EngineId option was left out.</p>
+ <p>Own Id: OTP-5307</p>
+ <p>Aux Id: Seq 9689</p>
+ </item>
+ <item>
+ <p>[manager] When a InformRequest is received, the manager sends
+ a response message. This did not include the varbinds
+ of the original message. See RFC 3416, chapter 4.2.7.</p>
+ <p>Own Id: OTP-5314</p>
+ </item>
+ <item>
+ <p>[manager] Erroneous function guards made it possible to update
+ some agent info (that should be "static").</p>
+ <p>Own Id: OTP-5315</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+ </section>
+
+ <section>
+ <title>SNMP Development Toolkit v4.0.4</title>
+ <p>Version 4.0.4 supports code replacement in run-time from/to
+ version 4.0.3, 4.0.2, 4.0.1 and 4.0.
+ </p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <p>-</p>
+ </section>
+
+ <section>
+ <title>Reported Fixed Bugs and Malfunctions</title>
+ <list type="bulleted">
+ <item>
+ <p>[manager] The timeout calculation for the request
+ gc timer incorrect.</p>
+ <p>Own Id: OTP-5267</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+ </section>
+
+ <section>
+ <title>SNMP Development Toolkit v4.0.3</title>
+ <p>Version 4.0.3 supports code replacement in run-time from/to
+ version 4.0.2, 4.0.1 and 4.0. </p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <p>-</p>
+ </section>
+
+ <section>
+ <title>Reported Fixed Bugs and Malfunctions</title>
+ <list type="bulleted">
+ <item>
+ <p>[manager] Some basic SNMP types where not handled when
+ performing set-requests snmpm:s and snmpm:as):
+ 'BITS' (b), 'IpAddress' (ip), 'Opaque' (op),
+ 'Counter32' (c32), 'Counter64' (c64) and 'TimeTicks' (tt).</p>
+ <p>Own Id: OTP-5256</p>
+ </item>
+ <item>
+ <p>[manager] Unnecessary error message when receiving trap from
+ unregistered agent or agent using other port then the
+ request port for trap-sending.</p>
+ <p>Own Id: OTP-5258</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+ </section>
+
+ <section>
+ <title>SNMP Development Toolkit v4.0.2</title>
+ <p>Version 4.0.2 supports code replacement in run-time from/to
+ version 4.0.1 and 4.0.
+ </p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <list type="bulleted">
+ <item>
+ <p>[manager] When the net_if process failed to send a message, for
+ whatever reason, this is just dropped. And the user is
+ "left hanging". Now, if the request is synchronous,
+ it will return with a proper reason (snmpm:g, snmpm:gn and
+ snmpm:s), and if the request
+ was asynchronous, the new callback function,
+ handle_error
+ (see <seealso marker="snmpm_user">snmpm_user</seealso>) is
+ called. </p>
+ <p>Own Id: OTP-5242</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Reported Fixed Bugs and Malfunctions</title>
+ <list type="bulleted">
+ <item>
+ <p>[manager] The arguments CtxName and Port was swapped in the
+ function snmpm:g/6.</p>
+ <p>Own Id: OTP-5225</p>
+ </item>
+ <item>
+ <p>[manager] TRAP receive fails for unknown agent due to
+ failing message size calculation.</p>
+ <p>Own Id: OTP-5241</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <list type="bulleted">
+ <item>
+ <p>[manager] Introduced a new callback function in the behaviour
+ <seealso marker="snmpm_user">snmpm_user</seealso>.</p>
+ <p>Own Id: OTP-5242</p>
+ </item>
+ </list>
+ </section>
+ </section>
+
+ <section>
+ <title>SNMP Development Toolkit v4.0.1</title>
+ <p>Version 4.0.1 supports code replacement in run-time from/to version 4.0.
+ </p>
+
+ <section>
+ <title>Improvements and new features</title>
+ <list type="bulleted">
+ <item>
+ <p>[agent] Added functions to get a list of all mibs loaded into
+ an agent
+ (see <seealso marker="snmpa#which_mibs">snmpa:which_mibs</seealso>)
+ and to get the (full path) file name of a loaded mib (see
+ <seealso marker="snmpa#whereis_mib">snmpa:whereis_mib</seealso>).</p>
+ <p>Own Id: OTP-5187</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Reported Fixed Bugs and Malfunctions</title>
+ <list type="bulleted">
+ <item>
+ <p>[manager] The wrong default value (1024) was used for the
+ net-if option recbuf. If no value is specified, then the OS
+ default shall be used.</p>
+ <p>Own Id: OTP-5196</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <p>-</p>
+ </section>
+ </section>
+
+ <section>
+ <title>SNMP Development Toolkit v4.0</title>
+
+ <section>
+ <title>Improvements and new features</title>
+ <list type="bulleted">
+ <item>
+ <p>[manager] Added a proper snmp manager.</p>
+ <p>Major restructure of the application in order to
+ incorporate the new manager.</p>
+ </item>
+ <item>
+ <p>[agent] Add a <c>snmpa:get/3</c> with an extra <c>Context</c>
+ argument. Also added similar <c>snmpa:get_next/2,3</c> functions.
+ See <seealso marker="snmpa#get">snmpa:get</seealso> and
+ <seealso marker="snmpa#get_next">snmpa:get_next</seealso>. </p>
+ <p>Martin Bj&ouml;rklund</p>
+ <p>Own Id: OTP-5054</p>
+ </item>
+ <item>
+ <p>[agent] Add <em>notification filters</em>. See
+ <seealso marker="snmpa_notification_filter">snmpa_notification_filter</seealso>,
+ <seealso marker="snmpa#register_notification_filter">register_notification_filter</seealso>,
+ <seealso marker="snmpa#unregister_notification_filter">unregister_notification_filter</seealso> and
+ <seealso marker="snmpa#which_notification_filter">which_notification_filter</seealso>.</p>
+ <p>Own Id: OTP-5055</p>
+ </item>
+ <item>
+ <p>[agent] Added two mib look-up functions,
+ <seealso marker="snmpa#me_of">me_of</seealso> and
+ <seealso marker="snmpa#mib_of">mib_of</seealso>.</p>
+ <p>Own Id: OTP-5082</p>
+ <p>Aux Id: Seq 8848</p>
+ </item>
+ <item>
+ <p>[compiler] The MIB compiler is now (source code) independent
+ of the rest of the application (and vice versa).</p>
+ </item>
+ <item>
+ <p>[compiler] DISPLAY-HINT and UNITS included in the
+ compiled mib.</p>
+ <p>Own Id: OTP-5053</p>
+ </item>
+ <item>
+ <p>[compiler] Added compiler options <c>imports</c> and
+ <c>module_identity</c> to include the imports list and
+ module identity (only SMIv2) info in the compiled mib,
+ see <seealso marker="snmpc">snmpc</seealso>.</p>
+ </item>
+ <item>
+ <p>[compiler] Added the MIB compiler option
+ <c>+no_defs</c>, see <seealso marker="snmpc">snmpc</seealso>.</p>
+ <p>Martin Bj&ouml;rklund</p>
+ </item>
+ <item>
+ <p>[compiler] Added the MIB compiler option
+ <c>+'{module, atom()}'</c>,
+ see <seealso marker="snmpc">snmpc</seealso>. </p>
+ <p>Martin Bj&ouml;rklund</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Reported Fixed Bugs and Malfunctions</title>
+ <list type="bulleted">
+ <item>
+ <p>[agent] Failing MIB configure/reconfigure was difficult
+ to diagnose. Added better error handling and verbosity.</p>
+ </item>
+ <item>
+ <p>[compiler] Added "default value" for INTEGER with enumeration
+ without a DEFVAL clause.
+ The lowest valid integer value is chosen for the
+ variable_info defval.</p>
+ <p>Own Id: OTP-5124</p>
+ <p>Aux Id: Seq 8738</p>
+ </item>
+ <item>
+ <p>[compiler] Unnecessarily reserved words in the mib compiler
+ can cause some enumeration definitions to fail.</p>
+ <p>Martin Bj&ouml;rklund</p>
+ <p>Own Id: OTP-5066</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Incompatibilities</title>
+ <list type="bulleted">
+ <item>
+ <p>New sys configuration format.
+ Although the old configuration format still
+ works (if only the agent is used), it is no
+ longer documented and will eventually be
+ eliminated.
+ See <seealso marker="snmp_app">application configuration</seealso> or
+ <seealso marker="snmp_config#configuration_params">configuration params</seealso> for more info.</p>
+ </item>
+ <item>
+ <p>Three new interface modules have been introduced. One
+ for each of the individual parts of the application:</p>
+ <list type="bulleted">
+ <item>
+ <p>[agent] <c>snmpa</c></p>
+ </item>
+ <item>
+ <p>[manager] <c>snmpm</c></p>
+ </item>
+ <item>
+ <p>[compiler] <c>snmpc</c></p>
+ </item>
+ </list>
+ <p>The primary interface module, <c>snmp</c>, still exist.
+ It contains the application generic functions. The
+ agent specific stuff still exist (for backward
+ compatibility reasons), but has been deprecated and will
+ eventually be removed.</p>
+ <p>Some previously already deprecated functions has been
+ removed (since they in turn was dependent on deprecated
+ functions, see calendar).</p>
+ </item>
+ <item>
+ <p>[agent] The agent network interface API has changed.
+ See <seealso marker="snmp_agent_netif">snmp agent net if</seealso>,</p>
+ </item>
+ <item>
+ <p>[agent] The default agent audit trail log name has changed.</p>
+ </item>
+ <item>
+ <p>[compiler] Mib format has changed (see OTP-5053 above).</p>
+ </item>
+ </list>
+ </section>
+ </section>
+</chapter>
+
diff --git a/lib/snmp/doc/src/part.xml b/lib/snmp/doc/src/part.xml
new file mode 100644
index 0000000000..603ddc7a62
--- /dev/null
+++ b/lib/snmp/doc/src/part.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE part SYSTEM "part.dtd">
+
+<part xmlns:xi="http://www.w3.org/2001/XInclude">
+ <header>
+ <copyright>
+ <year>1996</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ 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.
+
+ </legalnotice>
+
+ <title>SNMP User's Guide</title>
+ <prepared></prepared>
+ <docno></docno>
+ <date></date>
+ <rev></rev>
+ <file>part.xml</file>
+ </header>
+ <description>
+ <p>A multilingual Simple Network Management Protocol application,
+ featuring an Extensible Agent, a simple manager and a MIB
+ compiler and facilities for implementing SNMP MIBs etc.</p>
+ </description>
+ <xi:include href="snmp_intro.xml"/>
+ <xi:include href="snmp_agent_funct_descr.xml"/>
+ <xi:include href="snmp_manager_funct_descr.xml"/>
+ <xi:include href="snmp_mib_compiler.xml"/>
+ <xi:include href="snmp_config.xml"/>
+ <xi:include href="snmp_agent_config_files.xml"/>
+ <xi:include href="snmp_manager_config_files.xml"/>
+ <xi:include href="snmp_impl_example_agent.xml"/>
+ <xi:include href="snmp_impl_example_manager.xml"/>
+ <xi:include href="snmp_instr_functions.xml"/>
+ <xi:include href="snmp_def_instr_functions.xml"/>
+ <xi:include href="snmp_agent_netif.xml"/>
+ <xi:include href="snmp_manager_netif.xml"/>
+ <xi:include href="snmp_audit_trail_log.xml"/>
+ <xi:include href="snmp_advanced_agent.xml"/>
+ <xi:include href="snmp_app_a.xml"/>
+ <xi:include href="snmp_app_b.xml"/>
+</part>
+
diff --git a/lib/snmp/doc/src/part_notes.xml b/lib/snmp/doc/src/part_notes.xml
new file mode 100644
index 0000000000..6d00e5b7e3
--- /dev/null
+++ b/lib/snmp/doc/src/part_notes.xml
@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE part SYSTEM "part.dtd">
+
+<part xmlns:xi="http://www.w3.org/2001/XInclude">
+ <header>
+ <copyright>
+ <year>1997</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ 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.
+
+ </legalnotice>
+
+ <title>SNMP Release Notes</title>
+ <prepared></prepared>
+ <docno></docno>
+ <date></date>
+ <rev></rev>
+ <file>part_notes.xml</file>
+ </header>
+ <description>
+ <p>A multilingual Simple Network Management Protocol application,
+ featuring an Extensible Agent, a simple manager and a MIB
+ compiler and facilities for implementing SNMP MIBs etc.</p>
+ <p>For information about older versions see
+ <url href="part_notes_history_frame.html">release notes history</url>.</p>
+ </description>
+ <xi:include href="notes.xml"/>
+</part>
+
diff --git a/lib/snmp/doc/src/part_notes_history.xml b/lib/snmp/doc/src/part_notes_history.xml
new file mode 100644
index 0000000000..bebd33e81b
--- /dev/null
+++ b/lib/snmp/doc/src/part_notes_history.xml
@@ -0,0 +1,41 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE part SYSTEM "part.dtd">
+
+<part>
+ <header>
+ <copyright>
+ <year>2004</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ 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.
+
+ </legalnotice>
+
+ <title>SNMP Release Notes History</title>
+ <prepared></prepared>
+ <responsible></responsible>
+ <docno></docno>
+ <approved></approved>
+ <checked></checked>
+ <date></date>
+ <rev></rev>
+ <file>part_notes_history.xml</file>
+ </header>
+ <description>
+ <p>A multilingual Simple Network Management Protocol application,
+ featuring an Extensible Agent, a simple manager and a MIB
+ compiler and facilities for implementing SNMP MIBs etc.</p>
+ </description>
+ <include file="notes_history"></include>
+</part>
+
diff --git a/lib/snmp/doc/src/ref_man.gif b/lib/snmp/doc/src/ref_man.gif
new file mode 100644
index 0000000000..b13c4efd53
--- /dev/null
+++ b/lib/snmp/doc/src/ref_man.gif
Binary files differ
diff --git a/lib/snmp/doc/src/ref_man.xml b/lib/snmp/doc/src/ref_man.xml
new file mode 100644
index 0000000000..1ae5a8205b
--- /dev/null
+++ b/lib/snmp/doc/src/ref_man.xml
@@ -0,0 +1,71 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE application SYSTEM "application.dtd">
+
+<application xmlns:xi="http://www.w3.org/2001/XInclude">
+ <header>
+ <copyright>
+ <year>1996</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ 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.
+
+ </legalnotice>
+
+ <title>SNMP Reference Manual</title>
+ <prepared></prepared>
+ <docno></docno>
+ <date></date>
+ <rev></rev>
+ <file>ref_man.xml</file>
+ </header>
+ <description>
+ <p>A multilingual Simple Network Management Protocol
+ application featuring an Extensible Agent, simple manager,
+ a MIB compiler and facilities for implementing SNMP MIBs etc.
+ </p>
+ </description>
+ <xi:include href="snmp.xml"/>
+ <xi:include href="snmp_app.xml"/>
+ <xi:include href="snmpa.xml"/>
+ <xi:include href="snmpa_conf.xml"/>
+ <xi:include href="snmpa_discovery_handler.xml"/>
+ <xi:include href="snmpa_error_report.xml"/>
+ <xi:include href="snmpa_error.xml"/>
+ <xi:include href="snmpa_error_io.xml"/>
+ <xi:include href="snmpa_error_logger.xml"/>
+ <xi:include href="snmpa_local_db.xml"/>
+ <xi:include href="snmpa_mpd.xml"/>
+ <xi:include href="snmpa_network_interface.xml"/>
+ <xi:include href="snmpa_network_interface_filter.xml"/>
+ <xi:include href="snmpa_notification_delivery_info_receiver.xml"/>
+ <xi:include href="snmpa_notification_filter.xml"/>
+ <xi:include href="snmpa_supervisor.xml"/>
+ <xi:include href="snmp_community_mib.xml"/>
+ <xi:include href="snmp_framework_mib.xml"/>
+ <xi:include href="snmp_generic.xml"/>
+ <xi:include href="snmp_index.xml"/>
+ <xi:include href="snmp_notification_mib.xml"/>
+ <xi:include href="snmp_pdus.xml"/>
+ <xi:include href="snmp_standard_mib.xml"/>
+ <xi:include href="snmp_target_mib.xml"/>
+ <xi:include href="snmp_user_based_sm_mib.xml"/>
+ <xi:include href="snmp_view_based_acm_mib.xml"/>
+ <xi:include href="snmpc.xml"/>
+ <xi:include href="snmpm.xml"/>
+ <xi:include href="snmpm_conf.xml"/>
+ <xi:include href="snmpm_mpd.xml"/>
+ <xi:include href="snmpm_network_interface.xml"/>
+ <xi:include href="snmpm_user.xml"/>
+ <xi:include href="snmpm_network_interface_filter.xml"/>
+</application>
+
diff --git a/lib/snmp/doc/src/snmp-um-1-image-1.gif b/lib/snmp/doc/src/snmp-um-1-image-1.gif
new file mode 100644
index 0000000000..a633391c9a
--- /dev/null
+++ b/lib/snmp/doc/src/snmp-um-1-image-1.gif
Binary files differ
diff --git a/lib/snmp/doc/src/snmp-um-1-image-1.ps b/lib/snmp/doc/src/snmp-um-1-image-1.ps
new file mode 100644
index 0000000000..13562a8366
--- /dev/null
+++ b/lib/snmp/doc/src/snmp-um-1-image-1.ps
@@ -0,0 +1,2912 @@
+%!PS-Adobe-3.0 EPSF-3.0
+%%Creator: Adobe Illustrator(r) 6.0
+%%For: (Anna Fedoriw) (Ericsson Telecom)
+%%Title: (MIBcompilerPrinciples.eps)
+%%CreationDate: (97-05-23) (14.05)
+%%BoundingBox: 86 487 456 695
+%%HiResBoundingBox: 86.1667 487.1601 455.3333 694.8333
+%%DocumentProcessColors: Black
+%%DocumentFonts: Univers
+%%DocumentSuppliedResources: procset Adobe_level2_AI5 1.0 0
+%%+ procset Adobe_typography_AI5 1.0 0
+%%+ procset Adobe_Illustrator_AI6_vars Adobe_Illustrator_AI6
+%%+ procset Adobe_Illustrator_AI5 1.0 0
+%AI5_FileFormat 2.0
+%AI3_ColorUsage: Black&White
+%%AI6_ColorSeparationSet: 1 1 (AI6 Default Color Separation Set)
+%%+ Options: 1 16 0 1 0 1 1 1 0 1 1 1 1 18 0 0 0 0 0 0 0 0 -1 -1
+%%+ PPD: 1 21 0 0 60 45 2 2 1 0 0 1 0 0 0 0 0 0 0 0 0 0 ()
+%AI3_TemplateBox: 306 396 306 396
+%AI3_TileBox: 21 -12 588 802
+%AI3_DocumentPreview: Macintosh_ColorPic
+%AI5_ArtSize: 595.2756 841.8898
+%AI5_RulerUnits: 1
+%AI5_ArtFlags: 0 0 0 1 0 0 1 1 0
+%AI5_TargetResolution: 800
+%AI5_NumLayers: 1
+%AI5_OpenToView: 2 796 1.5 1146 827 58 1 1 3 40
+%AI5_OpenViewLayers: 7
+%%EndComments
+%%BeginProlog
+%%BeginResource: procset Adobe_level2_AI5 1.2 0
+%%Title: (Adobe Illustrator (R) Version 5.0 Level 2 Emulation)
+%%Version: 1.2
+%%CreationDate: (04/10/93) ()
+%%Copyright: ((C) 1987-1993 Adobe Systems Incorporated All Rights Reserved)
+userdict /Adobe_level2_AI5 23 dict dup begin
+ put
+ /packedarray where not
+ {
+ userdict begin
+ /packedarray
+ {
+ array astore readonly
+ } bind def
+ /setpacking /pop load def
+ /currentpacking false def
+ end
+ 0
+ } if
+ pop
+ userdict /defaultpacking currentpacking put true setpacking
+ /initialize
+ {
+ Adobe_level2_AI5 begin
+ } bind def
+ /terminate
+ {
+ currentdict Adobe_level2_AI5 eq
+ {
+ end
+ } if
+ } bind def
+ mark
+ /setcustomcolor where not
+ {
+ /findcmykcustomcolor
+ {
+ 5 packedarray
+ } bind def
+ /setcustomcolor
+ {
+ exch aload pop pop
+ 4
+ {
+ 4 index mul 4 1 roll
+ } repeat
+ 5 -1 roll pop
+ setcmykcolor
+ }
+ def
+ } if
+
+ /gt38? mark {version cvr cvx exec} stopped {cleartomark true} {38 gt exch pop} ifelse def
+ userdict /deviceDPI 72 0 matrix defaultmatrix dtransform dup mul exch dup mul add sqrt put
+ userdict /level2?
+ systemdict /languagelevel known dup
+ {
+ pop systemdict /languagelevel get 2 ge
+ } if
+ put
+/level2ScreenFreq
+{
+ begin
+ 60
+ HalftoneType 1 eq
+ {
+ pop Frequency
+ } if
+ HalftoneType 2 eq
+ {
+ pop GrayFrequency
+ } if
+ HalftoneType 5 eq
+ {
+ pop Default level2ScreenFreq
+ } if
+ end
+} bind def
+userdict /currentScreenFreq
+ level2? {currenthalftone level2ScreenFreq} {currentscreen pop pop} ifelse put
+level2? not
+ {
+ /setcmykcolor where not
+ {
+ /setcmykcolor
+ {
+ exch .11 mul add exch .59 mul add exch .3 mul add
+ 1 exch sub setgray
+ } def
+ } if
+ /currentcmykcolor where not
+ {
+ /currentcmykcolor
+ {
+ 0 0 0 1 currentgray sub
+ } def
+ } if
+ /setoverprint where not
+ {
+ /setoverprint /pop load def
+ } if
+ /selectfont where not
+ {
+ /selectfont
+ {
+ exch findfont exch
+ dup type /arraytype eq
+ {
+ makefont
+ }
+ {
+ scalefont
+ } ifelse
+ setfont
+ } bind def
+ } if
+ /cshow where not
+ {
+ /cshow
+ {
+ [
+ 0 0 5 -1 roll aload pop
+ ] cvx bind forall
+ } bind def
+ } if
+ } if
+ cleartomark
+ /anyColor?
+ {
+ add add add 0 ne
+ } bind def
+ /testColor
+ {
+ gsave
+ setcmykcolor currentcmykcolor
+ grestore
+ } bind def
+ /testCMYKColorThrough
+ {
+ testColor anyColor?
+ } bind def
+ userdict /composite?
+ level2?
+ {
+ gsave 1 1 1 1 setcmykcolor currentcmykcolor grestore
+ add add add 4 eq
+ }
+ {
+ 1 0 0 0 testCMYKColorThrough
+ 0 1 0 0 testCMYKColorThrough
+ 0 0 1 0 testCMYKColorThrough
+ 0 0 0 1 testCMYKColorThrough
+ and and and
+ } ifelse
+ put
+ composite? not
+ {
+ userdict begin
+ gsave
+ /cyan? 1 0 0 0 testCMYKColorThrough def
+ /magenta? 0 1 0 0 testCMYKColorThrough def
+ /yellow? 0 0 1 0 testCMYKColorThrough def
+ /black? 0 0 0 1 testCMYKColorThrough def
+ grestore
+ /isCMYKSep? cyan? magenta? yellow? black? or or or def
+ /customColor? isCMYKSep? not def
+ end
+ } if
+ end defaultpacking setpacking
+%%EndResource
+%%BeginResource: procset Adobe_typography_AI5 1.0 1
+%%Title: (Typography Operators)
+%%Version: 1.0
+%%CreationDate:(03/26/93) ()
+%%Copyright: ((C) 1987-1993 Adobe Systems Incorporated All Rights Reserved)
+currentpacking true setpacking
+userdict /Adobe_typography_AI5 54 dict dup begin
+put
+/initialize
+{
+ begin
+ begin
+ Adobe_typography_AI5 begin
+ Adobe_typography_AI5
+ {
+ dup xcheck
+ {
+ bind
+ } if
+ pop pop
+ } forall
+ end
+ end
+ end
+ Adobe_typography_AI5 begin
+} def
+/terminate
+{
+ currentdict Adobe_typography_AI5 eq
+ {
+ end
+ } if
+} def
+/modifyEncoding
+{
+ /_tempEncode exch ddef
+ /_pntr 0 ddef
+ {
+ counttomark -1 roll
+ dup type dup /marktype eq
+ {
+ pop pop exit
+ }
+ {
+ /nametype eq
+ {
+ _tempEncode /_pntr dup load dup 3 1 roll 1 add ddef 3 -1 roll
+ put
+ }
+ {
+ /_pntr exch ddef
+ } ifelse
+ } ifelse
+ } loop
+ _tempEncode
+} def
+/TE
+{
+ StandardEncoding 256 array copy modifyEncoding
+ /_nativeEncoding exch def
+} def
+%
+/TZ
+{
+ dup type /arraytype eq
+ {
+ /_wv exch def
+ }
+ {
+ /_wv 0 def
+ } ifelse
+ /_useNativeEncoding exch def
+ pop pop
+ findfont _wv type /arraytype eq
+ {
+ _wv makeblendedfont
+ } if
+ dup length 2 add dict
+ begin
+ mark exch
+ {
+ 1 index /FID ne
+ {
+ def
+ } if
+ cleartomark mark
+ } forall
+ pop
+ /FontName exch def
+ counttomark 0 eq
+ {
+ 1 _useNativeEncoding eq
+ {
+ /Encoding _nativeEncoding def
+ } if
+ cleartomark
+ }
+ {
+ /Encoding load 256 array copy
+ modifyEncoding /Encoding exch def
+ } ifelse
+ FontName currentdict
+ end
+ definefont pop
+} def
+/tr
+{
+ _ax _ay 3 2 roll
+} def
+/trj
+{
+ _cx _cy _sp _ax _ay 6 5 roll
+} def
+/a0
+{
+ /Tx
+ {
+ dup
+ currentpoint 3 2 roll
+ tr _psf
+ newpath moveto
+ tr _ctm _pss
+ } ddef
+ /Tj
+ {
+ dup
+ currentpoint 3 2 roll
+ trj _pjsf
+ newpath moveto
+ trj _ctm _pjss
+ } ddef
+} def
+/a1
+{
+ /Tx
+ {
+ dup currentpoint 4 2 roll gsave
+ dup currentpoint 3 2 roll
+ tr _psf
+ newpath moveto
+ tr _ctm _pss
+ grestore 3 1 roll moveto tr sp
+ } ddef
+ /Tj
+ {
+ dup currentpoint 4 2 roll gsave
+ dup currentpoint 3 2 roll
+ trj _pjsf
+ newpath moveto
+ trj _ctm _pjss
+ grestore 3 1 roll moveto tr jsp
+ } ddef
+} def
+/e0
+{
+ /Tx
+ {
+ tr _psf
+ } ddef
+ /Tj
+ {
+ trj _pjsf
+ } ddef
+} def
+/e1
+{
+ /Tx
+ {
+ dup currentpoint 4 2 roll gsave
+ tr _psf
+ grestore 3 1 roll moveto tr sp
+ } ddef
+ /Tj
+ {
+ dup currentpoint 4 2 roll gsave
+ trj _pjsf
+ grestore 3 1 roll moveto tr jsp
+ } ddef
+} def
+/i0
+{
+ /Tx
+ {
+ tr sp
+ } ddef
+ /Tj
+ {
+ trj jsp
+ } ddef
+} def
+/i1
+{
+ W N
+} def
+/o0
+{
+ /Tx
+ {
+ tr sw rmoveto
+ } ddef
+ /Tj
+ {
+ trj swj rmoveto
+ } ddef
+} def
+/r0
+{
+ /Tx
+ {
+ tr _ctm _pss
+ } ddef
+ /Tj
+ {
+ trj _ctm _pjss
+ } ddef
+} def
+/r1
+{
+ /Tx
+ {
+ dup currentpoint 4 2 roll currentpoint gsave newpath moveto
+ tr _ctm _pss
+ grestore 3 1 roll moveto tr sp
+ } ddef
+ /Tj
+ {
+ dup currentpoint 4 2 roll currentpoint gsave newpath moveto
+ trj _ctm _pjss
+ grestore 3 1 roll moveto tr jsp
+ } ddef
+} def
+/To
+{
+ pop _ctm currentmatrix pop
+} def
+/TO
+{
+ iTe _ctm setmatrix newpath
+} def
+/Tp
+{
+ pop _tm astore pop _ctm setmatrix
+ _tDict begin
+ /W
+ {
+ } def
+ /h
+ {
+ } def
+} def
+/TP
+{
+ end
+ iTm 0 0 moveto
+} def
+/Tr
+{
+ _render 3 le
+ {
+ currentpoint newpath moveto
+ } if
+ dup 8 eq
+ {
+ pop 0
+ }
+ {
+ dup 9 eq
+ {
+ pop 1
+ } if
+ } ifelse
+ dup /_render exch ddef
+ _renderStart exch get load exec
+} def
+/iTm
+{
+ _ctm setmatrix _tm concat 0 _rise translate _hs 1 scale
+} def
+/Tm
+{
+ _tm astore pop iTm 0 0 moveto
+} def
+/Td
+{
+ _mtx translate _tm _tm concatmatrix pop iTm 0 0 moveto
+} def
+/iTe
+{
+ _render -1 eq
+ {
+ }
+ {
+ _renderEnd _render get dup null ne
+ {
+ load exec
+ }
+ {
+ pop
+ } ifelse
+ } ifelse
+ /_render -1 ddef
+} def
+/Ta
+{
+ pop
+} def
+/Tf
+{
+ dup 1000 div /_fScl exch ddef
+%
+ selectfont
+} def
+/Tl
+{
+ pop
+ 0 exch _leading astore pop
+} def
+/Tt
+{
+ pop
+} def
+/TW
+{
+ 3 npop
+} def
+/Tw
+{
+ /_cx exch ddef
+} def
+/TC
+{
+ 3 npop
+} def
+/Tc
+{
+ /_ax exch ddef
+} def
+/Ts
+{
+ /_rise exch ddef
+ currentpoint
+ iTm
+ moveto
+} def
+/Ti
+{
+ 3 npop
+} def
+/Tz
+{
+ 100 div /_hs exch ddef
+ iTm
+} def
+/TA
+{
+ pop
+} def
+/Tq
+{
+ pop
+} def
+/Th
+{
+ pop pop pop pop pop
+} def
+/TX
+{
+ pop
+} def
+/Tk
+{
+ exch pop _fScl mul neg 0 rmoveto
+} def
+/TK
+{
+ 2 npop
+} def
+/T*
+{
+ _leading aload pop neg Td
+} def
+/T*-
+{
+ _leading aload pop Td
+} def
+/T-
+{
+ _ax neg 0 rmoveto
+ _hyphen Tx
+} def
+/T+
+{
+} def
+/TR
+{
+ _ctm currentmatrix pop
+ _tm astore pop
+ iTm 0 0 moveto
+} def
+/TS
+{
+ currentfont 3 1 roll
+ /_Symbol_ _fScl 1000 mul selectfont
+
+ 0 eq
+ {
+ Tx
+ }
+ {
+ Tj
+ } ifelse
+ setfont
+} def
+/Xb
+{
+ pop pop
+} def
+/Tb /Xb load def
+/Xe
+{
+ pop pop pop pop
+} def
+/Te /Xe load def
+/XB
+{
+} def
+/TB /XB load def
+currentdict readonly pop
+end
+setpacking
+%%EndResource
+%%BeginProcSet: Adobe_ColorImage_AI6 1.0 0
+userdict /Adobe_ColorImage_AI6 known not
+{
+ userdict /Adobe_ColorImage_AI6 17 dict put
+} if
+userdict /Adobe_ColorImage_AI6 get begin
+
+ /initialize
+ {
+ Adobe_ColorImage_AI6 begin
+ Adobe_ColorImage_AI6
+ {
+ dup type /arraytype eq
+ {
+ dup xcheck
+ {
+ bind
+ } if
+ } if
+ pop pop
+ } forall
+ } def
+ /terminate { end } def
+
+ currentdict /Adobe_ColorImage_AI6_Vars known not
+ {
+ /Adobe_ColorImage_AI6_Vars 14 dict def
+ } if
+
+ Adobe_ColorImage_AI6_Vars begin
+ /channelcount 0 def
+ /sourcecount 0 def
+ /sourcearray 4 array def
+ /plateindex -1 def
+ /XIMask 0 def
+ /XIBinary 0 def
+ /XIChannelCount 0 def
+ /XIBitsPerPixel 0 def
+ /XIImageHeight 0 def
+ /XIImageWidth 0 def
+ /XIImageMatrix null def
+ /XIBuffer null def
+ /XIDataProc null def
+ end
+
+ /WalkRGBString null def
+ /WalkCMYKString null def
+
+ /StuffRGBIntoGrayString null def
+ /RGBToGrayImageProc null def
+ /StuffCMYKIntoGrayString null def
+ /CMYKToGrayImageProc null def
+ /ColorImageCompositeEmulator null def
+
+ /SeparateCMYKImageProc null def
+
+ /FourEqual null def
+ /TestPlateIndex null def
+
+ currentdict /_colorimage known not
+ {
+ /colorimage where
+ {
+ /colorimage get /_colorimage exch def
+ }
+ {
+ /_colorimage null def
+ } ifelse
+ } if
+
+ /_currenttransfer systemdict /currenttransfer get def
+
+ /colorimage null def
+ /XI null def
+
+
+ /WalkRGBString
+ {
+ 0 3 index
+
+ dup length 1 sub 0 3 3 -1 roll
+ {
+ 3 getinterval { } forall
+
+ 5 index exec
+
+ 3 index
+ } for
+
+ 5 { pop } repeat
+
+ } def
+
+
+ /WalkCMYKString
+ {
+ 0 3 index
+
+ dup length 1 sub 0 4 3 -1 roll
+ {
+ 4 getinterval { } forall
+
+ 6 index exec
+
+ 3 index
+
+ } for
+
+ 5 { pop } repeat
+
+ } def
+
+
+ /StuffRGBIntoGrayString
+ {
+ .11 mul exch
+
+ .59 mul add exch
+
+ .3 mul add
+
+ cvi 3 copy put
+
+ pop 1 add
+ } def
+
+
+ /RGBToGrayImageProc
+ {
+ Adobe_ColorImage_AI6_Vars begin
+ sourcearray 0 get exec
+ dup length 3 idiv string
+ dup 3 1 roll
+
+ /StuffRGBIntoGrayString load exch
+ WalkRGBString
+ end
+ } def
+
+
+ /StuffCMYKIntoGrayString
+ {
+ exch .11 mul add
+
+ exch .59 mul add
+
+ exch .3 mul add
+
+ dup 255 gt { pop 255 } if
+
+ 255 exch sub cvi 3 copy put
+
+ pop 1 add
+ } def
+
+
+ /CMYKToGrayImageProc
+ {
+ Adobe_ColorImage_AI6_Vars begin
+ sourcearray 0 get exec
+ dup length 4 idiv string
+ dup 3 1 roll
+
+ /StuffCMYKIntoGrayString load exch
+ WalkCMYKString
+ end
+ } def
+
+
+ /ColorImageCompositeEmulator
+ {
+ pop true eq
+ {
+ Adobe_ColorImage_AI6_Vars /sourcecount get 5 add { pop } repeat
+ }
+ {
+ Adobe_ColorImage_AI6_Vars /channelcount get 1 ne
+ {
+ Adobe_ColorImage_AI6_Vars begin
+ sourcearray 0 3 -1 roll put
+
+ channelcount 3 eq
+ {
+ /RGBToGrayImageProc
+ }
+ {
+ /CMYKToGrayImageProc
+ } ifelse
+ load
+ end
+ } if
+ image
+ } ifelse
+ } def
+
+
+ /SeparateCMYKImageProc
+ {
+ Adobe_ColorImage_AI6_Vars begin
+
+ sourcecount 0 ne
+ {
+ sourcearray plateindex get exec
+ }
+ {
+ sourcearray 0 get exec
+
+ dup length 4 idiv string
+
+ 0 2 index
+
+ plateindex 4 2 index length 1 sub
+ {
+ get 255 exch sub
+
+ 3 copy put pop 1 add
+
+ 2 index
+ } for
+
+ pop pop exch pop
+ } ifelse
+ end
+ } def
+
+
+ /FourEqual
+ {
+ 4 index ne
+ {
+ pop pop pop false
+ }
+ {
+ 4 index ne
+ {
+ pop pop false
+ }
+ {
+ 4 index ne
+ {
+ pop false
+ }
+ {
+ 4 index eq
+ } ifelse
+ } ifelse
+ } ifelse
+ } def
+
+
+ /TestPlateIndex
+ {
+ Adobe_ColorImage_AI6_Vars begin
+ /plateindex -1 def
+
+ /setcmykcolor where
+ {
+ pop
+ gsave
+ 1 0 0 0 setcmykcolor systemdict /currentgray get exec 1 exch sub
+ 0 1 0 0 setcmykcolor systemdict /currentgray get exec 1 exch sub
+ 0 0 1 0 setcmykcolor systemdict /currentgray get exec 1 exch sub
+ 0 0 0 1 setcmykcolor systemdict /currentgray get exec 1 exch sub
+ grestore
+
+ 1 0 0 0 FourEqual
+ {
+ /plateindex 0 def
+ }
+ {
+ 0 1 0 0 FourEqual
+ {
+ /plateindex 1 def
+ }
+ {
+ 0 0 1 0 FourEqual
+ {
+ /plateindex 2 def
+ }
+ {
+ 0 0 0 1 FourEqual
+ {
+ /plateindex 3 def
+ }
+ {
+ 0 0 0 0 FourEqual
+ {
+ /plateindex 5 def
+ } if
+ } ifelse
+ } ifelse
+ } ifelse
+ } ifelse
+ pop pop pop pop
+ } if
+ plateindex
+ end
+ } def
+
+
+ /colorimage
+ {
+ Adobe_ColorImage_AI6_Vars begin
+ /channelcount 1 index def
+ /sourcecount 2 index 1 eq { channelcount 1 sub } { 0 } ifelse def
+
+ 4 sourcecount add index dup
+ 8 eq exch 1 eq or not
+ end
+
+ {
+ /_colorimage load null ne
+ {
+ _colorimage
+ }
+ {
+ Adobe_ColorImage_AI6_Vars /sourcecount get
+ 7 add { pop } repeat
+ } ifelse
+ }
+ {
+ dup 3 eq
+ TestPlateIndex
+ dup -1 eq exch 5 eq or or
+ {
+ /_colorimage load null eq
+ {
+ ColorImageCompositeEmulator
+ }
+ {
+ dup 1 eq
+ {
+ pop pop image
+ }
+ {
+ Adobe_ColorImage_AI6_Vars /plateindex get 5 eq
+ {
+ gsave
+
+ 0 _currenttransfer exec
+ 1 _currenttransfer exec
+ eq
+ { 0 _currenttransfer exec 0.5 lt }
+ { 0 _currenttransfer exec 1 _currenttransfer exec gt } ifelse
+
+ { { pop 0 } } { { pop 1 } } ifelse
+ systemdict /settransfer get exec
+ } if
+
+ _colorimage
+
+ Adobe_ColorImage_AI6_Vars /plateindex get 5 eq
+ {
+ grestore
+ } if
+ } ifelse
+ } ifelse
+ }
+ {
+ dup 1 eq
+ {
+ pop pop
+ image
+ }
+ {
+ pop pop
+
+ Adobe_ColorImage_AI6_Vars begin
+ sourcecount -1 0
+ {
+ exch sourcearray 3 1 roll put
+ } for
+
+ /SeparateCMYKImageProc load
+ end
+
+ systemdict /image get exec
+ } ifelse
+ } ifelse
+ } ifelse
+ } def
+
+ /XI
+ {
+ Adobe_ColorImage_AI6_Vars begin
+ gsave
+ /XIMask exch 0 ne def
+ /XIBinary exch 0 ne def
+ pop
+ pop
+ /XIChannelCount exch def
+ /XIBitsPerPixel exch def
+ /XIImageHeight exch def
+ /XIImageWidth exch def
+ pop pop pop pop
+ /XIImageMatrix exch def
+
+ XIBitsPerPixel 1 eq
+ {
+ XIImageWidth 8 div ceiling cvi
+ }
+ {
+ XIImageWidth XIChannelCount mul
+ } ifelse
+ /XIBuffer exch string def
+
+ XIBinary
+ {
+ /XIDataProc { currentfile XIBuffer readstring pop } def
+ currentfile 128 string readline pop pop
+ }
+ {
+ /XIDataProc { currentfile XIBuffer readhexstring pop } def
+ } ifelse
+
+ 0 0 moveto
+ XIImageMatrix concat
+ XIImageWidth XIImageHeight scale
+
+ XIMask
+ {
+ XIImageWidth XIImageHeight
+ false
+ [ XIImageWidth 0 0 XIImageHeight neg 0 0 ]
+ /XIDataProc load
+
+ /_lp /null ddef
+ _fc
+ /_lp /imagemask ddef
+
+ imagemask
+ }
+ {
+ XIImageWidth XIImageHeight
+ XIBitsPerPixel
+ [ XIImageWidth 0 0 XIImageHeight neg 0 0 ]
+ /XIDataProc load
+
+ XIChannelCount 1 eq
+ {
+
+ gsave
+ 0 setgray
+
+ image
+
+ grestore
+ }
+ {
+ false
+ XIChannelCount
+ colorimage
+ } ifelse
+ } ifelse
+ grestore
+ end
+ } def
+
+end
+%%EndProcSet
+%%BeginResource: procset Adobe_Illustrator_AI5 1.1 0
+%%Title: (Adobe Illustrator (R) Version 5.0 Full Prolog)
+%%Version: 1.1
+%%CreationDate: (3/7/1994) ()
+%%Copyright: ((C) 1987-1994 Adobe Systems Incorporated All Rights Reserved)
+currentpacking true setpacking
+userdict /Adobe_Illustrator_AI5_vars 81 dict dup begin
+put
+/_eo false def
+/_lp /none def
+/_pf
+{
+} def
+/_ps
+{
+} def
+/_psf
+{
+} def
+/_pss
+{
+} def
+/_pjsf
+{
+} def
+/_pjss
+{
+} def
+/_pola 0 def
+/_doClip 0 def
+/cf currentflat def
+/_tm matrix def
+/_renderStart
+[
+/e0 /r0 /a0 /o0 /e1 /r1 /a1 /i0
+] def
+/_renderEnd
+[
+null null null null /i1 /i1 /i1 /i1
+] def
+/_render -1 def
+/_rise 0 def
+/_ax 0 def
+/_ay 0 def
+/_cx 0 def
+/_cy 0 def
+/_leading
+[
+0 0
+] def
+/_ctm matrix def
+/_mtx matrix def
+/_sp 16#020 def
+/_hyphen (-) def
+/_fScl 0 def
+/_cnt 0 def
+/_hs 1 def
+/_nativeEncoding 0 def
+/_useNativeEncoding 0 def
+/_tempEncode 0 def
+/_pntr 0 def
+/_tDict 2 dict def
+/_wv 0 def
+/Tx
+{
+} def
+/Tj
+{
+} def
+/CRender
+{
+} def
+/_AI3_savepage
+{
+} def
+/_gf null def
+/_cf 4 array def
+/_if null def
+/_of false def
+/_fc
+{
+} def
+/_gs null def
+/_cs 4 array def
+/_is null def
+/_os false def
+/_sc
+{
+} def
+/_pd 1 dict def
+/_ed 15 dict def
+/_pm matrix def
+/_fm null def
+/_fd null def
+/_fdd null def
+/_sm null def
+/_sd null def
+/_sdd null def
+/_i null def
+/discardSave null def
+/buffer 256 string def
+/beginString null def
+/endString null def
+/endStringLength null def
+/layerCnt 1 def
+/layerCount 1 def
+/perCent (%) 0 get def
+/perCentSeen? false def
+/newBuff null def
+/newBuffButFirst null def
+/newBuffLast null def
+/clipForward? false def
+end
+userdict /Adobe_Illustrator_AI5 known not {
+ userdict /Adobe_Illustrator_AI5 91 dict put
+} if
+userdict /Adobe_Illustrator_AI5 get begin
+/initialize
+{
+ Adobe_Illustrator_AI5 dup begin
+ Adobe_Illustrator_AI5_vars begin
+ discardDict
+ {
+ bind pop pop
+ } forall
+ dup /nc get begin
+ {
+ dup xcheck 1 index type /operatortype ne and
+ {
+ bind
+ } if
+ pop pop
+ } forall
+ end
+ newpath
+} def
+/terminate
+{
+ end
+ end
+} def
+/_
+null def
+/ddef
+{
+ Adobe_Illustrator_AI5_vars 3 1 roll put
+} def
+/xput
+{
+ dup load dup length exch maxlength eq
+ {
+ dup dup load dup
+ length 2 mul dict copy def
+ } if
+ load begin
+ def
+ end
+} def
+/npop
+{
+ {
+ pop
+ } repeat
+} def
+/sw
+{
+ dup length exch stringwidth
+ exch 5 -1 roll 3 index mul add
+ 4 1 roll 3 1 roll mul add
+} def
+/swj
+{
+ dup 4 1 roll
+ dup length exch stringwidth
+ exch 5 -1 roll 3 index mul add
+ 4 1 roll 3 1 roll mul add
+ 6 2 roll /_cnt 0 ddef
+ {
+ 1 index eq
+ {
+ /_cnt _cnt 1 add ddef
+ } if
+ } forall
+ pop
+ exch _cnt mul exch _cnt mul 2 index add 4 1 roll 2 index add 4 1 roll pop pop
+} def
+/ss
+{
+ 4 1 roll
+ {
+ 2 npop
+ (0) exch 2 copy 0 exch put pop
+ gsave
+ false charpath currentpoint
+ 4 index setmatrix
+ stroke
+ grestore
+ moveto
+ 2 copy rmoveto
+ } exch cshow
+ 3 npop
+} def
+/jss
+{
+ 4 1 roll
+ {
+ 2 npop
+ (0) exch 2 copy 0 exch put
+ gsave
+ _sp eq
+ {
+ exch 6 index 6 index 6 index 5 -1 roll widthshow
+ currentpoint
+ }
+ {
+ false charpath currentpoint
+ 4 index setmatrix stroke
+ } ifelse
+ grestore
+ moveto
+ 2 copy rmoveto
+ } exch cshow
+ 6 npop
+} def
+/sp
+{
+ {
+ 2 npop (0) exch
+ 2 copy 0 exch put pop
+ false charpath
+ 2 copy rmoveto
+ } exch cshow
+ 2 npop
+} def
+/jsp
+{
+ {
+ 2 npop
+ (0) exch 2 copy 0 exch put
+ _sp eq
+ {
+ exch 5 index 5 index 5 index 5 -1 roll widthshow
+ }
+ {
+ false charpath
+ } ifelse
+ 2 copy rmoveto
+ } exch cshow
+ 5 npop
+} def
+/pl
+{
+ transform
+ 0.25 sub round 0.25 add exch
+ 0.25 sub round 0.25 add exch
+ itransform
+} def
+/setstrokeadjust where
+{
+ pop true setstrokeadjust
+ /c
+ {
+ curveto
+ } def
+ /C
+ /c load def
+ /v
+ {
+ currentpoint 6 2 roll curveto
+ } def
+ /V
+ /v load def
+ /y
+ {
+ 2 copy curveto
+ } def
+ /Y
+ /y load def
+ /l
+ {
+ lineto
+ } def
+ /L
+ /l load def
+ /m
+ {
+ moveto
+ } def
+}
+{
+ /c
+ {
+ pl curveto
+ } def
+ /C
+ /c load def
+ /v
+ {
+ currentpoint 6 2 roll pl curveto
+ } def
+ /V
+ /v load def
+ /y
+ {
+ pl 2 copy curveto
+ } def
+ /Y
+ /y load def
+ /l
+ {
+ pl lineto
+ } def
+ /L
+ /l load def
+ /m
+ {
+ pl moveto
+ } def
+} ifelse
+/d
+{
+ setdash
+} def
+/cf
+{
+} def
+/i
+{
+ dup 0 eq
+ {
+ pop cf
+ } if
+ setflat
+} def
+/j
+{
+ setlinejoin
+} def
+/J
+{
+ setlinecap
+} def
+/M
+{
+ setmiterlimit
+} def
+/w
+{
+ setlinewidth
+} def
+/XR
+{
+ 0 ne
+ /_eo exch ddef
+} def
+/H
+{
+} def
+/h
+{
+ closepath
+} def
+/N
+{
+ _pola 0 eq
+ {
+ _doClip 1 eq
+ {
+ _eo {eoclip} {clip} ifelse /_doClip 0 ddef
+ } if
+ newpath
+ }
+ {
+ /CRender
+ {
+ N
+ } ddef
+ } ifelse
+} def
+/n
+{
+ N
+} def
+/F
+{
+ _pola 0 eq
+ {
+ _doClip 1 eq
+ {
+ gsave _pf grestore _eo {eoclip} {clip} ifelse newpath /_lp /none ddef _fc
+ /_doClip 0 ddef
+ }
+ {
+ _pf
+ } ifelse
+ }
+ {
+ /CRender
+ {
+ F
+ } ddef
+ } ifelse
+} def
+/f
+{
+ closepath
+ F
+} def
+/S
+{
+ _pola 0 eq
+ {
+ _doClip 1 eq
+ {
+ gsave _ps grestore _eo {eoclip} {clip} ifelse newpath /_lp /none ddef _sc
+ /_doClip 0 ddef
+ }
+ {
+ _ps
+ } ifelse
+ }
+ {
+ /CRender
+ {
+ S
+ } ddef
+ } ifelse
+} def
+/s
+{
+ closepath
+ S
+} def
+/B
+{
+ _pola 0 eq
+ {
+ _doClip 1 eq
+ gsave F grestore
+ {
+ gsave S grestore _eo {eoclip} {clip} ifelse newpath /_lp /none ddef _sc
+ /_doClip 0 ddef
+ }
+ {
+ S
+ } ifelse
+ }
+ {
+ /CRender
+ {
+ B
+ } ddef
+ } ifelse
+} def
+/b
+{
+ closepath
+ B
+} def
+/W
+{
+ /_doClip 1 ddef
+} def
+/*
+{
+ count 0 ne
+ {
+ dup type /stringtype eq
+ {
+ pop
+ } if
+ } if
+ newpath
+} def
+/u
+{
+} def
+/U
+{
+} def
+/q
+{
+ _pola 0 eq
+ {
+ gsave
+ } if
+} def
+/Q
+{
+ _pola 0 eq
+ {
+ grestore
+ } if
+} def
+/*u
+{
+ _pola 1 add /_pola exch ddef
+} def
+/*U
+{
+ _pola 1 sub /_pola exch ddef
+ _pola 0 eq
+ {
+ CRender
+ } if
+} def
+/D
+{
+ pop
+} def
+/*w
+{
+} def
+/*W
+{
+} def
+/`
+{
+ /_i save ddef
+ clipForward?
+ {
+ nulldevice
+ } if
+ 6 1 roll 4 npop
+ concat pop
+ userdict begin
+ /showpage
+ {
+ } def
+ 0 setgray
+ 0 setlinecap
+ 1 setlinewidth
+ 0 setlinejoin
+ 10 setmiterlimit
+ [] 0 setdash
+ /setstrokeadjust where {pop false setstrokeadjust} if
+ newpath
+ 0 setgray
+ false setoverprint
+} def
+/~
+{
+ end
+ _i restore
+} def
+/O
+{
+ 0 ne
+ /_of exch ddef
+ /_lp /none ddef
+} def
+/R
+{
+ 0 ne
+ /_os exch ddef
+ /_lp /none ddef
+} def
+/g
+{
+ /_gf exch ddef
+ /_fc
+ {
+ _lp /fill ne
+ {
+ _of setoverprint
+ _gf setgray
+ /_lp /fill ddef
+ } if
+ } ddef
+ /_pf
+ {
+ _fc
+ _eo {eofill} {fill} ifelse
+ } ddef
+ /_psf
+ {
+ _fc
+ ashow
+ } ddef
+ /_pjsf
+ {
+ _fc
+ awidthshow
+ } ddef
+ /_lp /none ddef
+} def
+/G
+{
+ /_gs exch ddef
+ /_sc
+ {
+ _lp /stroke ne
+ {
+ _os setoverprint
+ _gs setgray
+ /_lp /stroke ddef
+ } if
+ } ddef
+ /_ps
+ {
+ _sc
+ stroke
+ } ddef
+ /_pss
+ {
+ _sc
+ ss
+ } ddef
+ /_pjss
+ {
+ _sc
+ jss
+ } ddef
+ /_lp /none ddef
+} def
+/k
+{
+ _cf astore pop
+ /_fc
+ {
+ _lp /fill ne
+ {
+ _of setoverprint
+ _cf aload pop setcmykcolor
+ /_lp /fill ddef
+ } if
+ } ddef
+ /_pf
+ {
+ _fc
+ _eo {eofill} {fill} ifelse
+ } ddef
+ /_psf
+ {
+ _fc
+ ashow
+ } ddef
+ /_pjsf
+ {
+ _fc
+ awidthshow
+ } ddef
+ /_lp /none ddef
+} def
+/K
+{
+ _cs astore pop
+ /_sc
+ {
+ _lp /stroke ne
+ {
+ _os setoverprint
+ _cs aload pop setcmykcolor
+ /_lp /stroke ddef
+ } if
+ } ddef
+ /_ps
+ {
+ _sc
+ stroke
+ } ddef
+ /_pss
+ {
+ _sc
+ ss
+ } ddef
+ /_pjss
+ {
+ _sc
+ jss
+ } ddef
+ /_lp /none ddef
+} def
+/x
+{
+ /_gf exch ddef
+ findcmykcustomcolor
+ /_if exch ddef
+ /_fc
+ {
+ _lp /fill ne
+ {
+ _of setoverprint
+ _if _gf 1 exch sub setcustomcolor
+ /_lp /fill ddef
+ } if
+ } ddef
+ /_pf
+ {
+ _fc
+ _eo {eofill} {fill} ifelse
+ } ddef
+ /_psf
+ {
+ _fc
+ ashow
+ } ddef
+ /_pjsf
+ {
+ _fc
+ awidthshow
+ } ddef
+ /_lp /none ddef
+} def
+/X
+{
+ /_gs exch ddef
+ findcmykcustomcolor
+ /_is exch ddef
+ /_sc
+ {
+ _lp /stroke ne
+ {
+ _os setoverprint
+ _is _gs 1 exch sub setcustomcolor
+ /_lp /stroke ddef
+ } if
+ } ddef
+ /_ps
+ {
+ _sc
+ stroke
+ } ddef
+ /_pss
+ {
+ _sc
+ ss
+ } ddef
+ /_pjss
+ {
+ _sc
+ jss
+ } ddef
+ /_lp /none ddef
+} def
+/A
+{
+ pop
+} def
+/annotatepage
+{
+userdict /annotatepage 2 copy known {get exec} {pop pop} ifelse
+} def
+/XT {
+ pop pop
+} def
+/discard
+{
+ save /discardSave exch store
+ discardDict begin
+ /endString exch store
+ gt38?
+ {
+ 2 add
+ } if
+ load
+ stopped
+ pop
+ end
+ discardSave restore
+} bind def
+userdict /discardDict 7 dict dup begin
+put
+/pre38Initialize
+{
+ /endStringLength endString length store
+ /newBuff buffer 0 endStringLength getinterval store
+ /newBuffButFirst newBuff 1 endStringLength 1 sub getinterval store
+ /newBuffLast newBuff endStringLength 1 sub 1 getinterval store
+} def
+/shiftBuffer
+{
+ newBuff 0 newBuffButFirst putinterval
+ newBuffLast 0
+ currentfile read not
+ {
+ stop
+ } if
+ put
+} def
+0
+{
+ pre38Initialize
+ mark
+ currentfile newBuff readstring exch pop
+ {
+ {
+ newBuff endString eq
+ {
+ cleartomark stop
+ } if
+ shiftBuffer
+ } loop
+ }
+ {
+ stop
+ } ifelse
+} def
+1
+{
+ pre38Initialize
+ /beginString exch store
+ mark
+ currentfile newBuff readstring exch pop
+ {
+ {
+ newBuff beginString eq
+ {
+ /layerCount dup load 1 add store
+ }
+ {
+ newBuff endString eq
+ {
+ /layerCount dup load 1 sub store
+ layerCount 0 eq
+ {
+ cleartomark stop
+ } if
+ } if
+ } ifelse
+ shiftBuffer
+ } loop
+ } if
+} def
+2
+{
+ mark
+ {
+ currentfile buffer readline not
+ {
+ stop
+ } if
+ endString eq
+ {
+ cleartomark stop
+ } if
+ } loop
+} def
+3
+{
+ /beginString exch store
+ /layerCnt 1 store
+ mark
+ {
+ currentfile buffer readline not
+ {
+ stop
+ } if
+ dup beginString eq
+ {
+ pop /layerCnt dup load 1 add store
+ }
+ {
+ endString eq
+ {
+ layerCnt 1 eq
+ {
+ cleartomark stop
+ }
+ {
+ /layerCnt dup load 1 sub store
+ } ifelse
+ } if
+ } ifelse
+ } loop
+} def
+end
+userdict /clipRenderOff 15 dict dup begin
+put
+{
+ /n /N /s /S /f /F /b /B
+}
+{
+ {
+ _doClip 1 eq
+ {
+ /_doClip 0 ddef _eo {eoclip} {clip} ifelse
+ } if
+ newpath
+ } def
+} forall
+/Tr /pop load def
+/Bb {} def
+/BB /pop load def
+/Bg {12 npop} def
+/Bm {6 npop} def
+/Bc /Bm load def
+/Bh {4 npop} def
+end
+/Lb
+{
+ 4 npop
+ 6 1 roll
+ pop
+ 4 1 roll
+ pop pop pop
+ 0 eq
+ {
+ 0 eq
+ {
+ (%AI5_BeginLayer) 1 (%AI5_EndLayer--) discard
+ }
+ {
+
+ /clipForward? true def
+
+ /Tx /pop load def
+ /Tj /pop load def
+
+ currentdict end clipRenderOff begin begin
+ } ifelse
+ }
+ {
+ 0 eq
+ {
+ save /discardSave exch store
+ } if
+ } ifelse
+} bind def
+/LB
+{
+ discardSave dup null ne
+ {
+ restore
+ }
+ {
+ pop
+ clipForward?
+ {
+ currentdict
+ end
+ end
+ begin
+
+ /clipForward? false ddef
+ } if
+ } ifelse
+} bind def
+/Pb
+{
+ pop pop
+ 0 (%AI5_EndPalette) discard
+} bind def
+/Np
+{
+ 0 (%AI5_End_NonPrinting--) discard
+} bind def
+/Ln /pop load def
+/Ap
+/pop load def
+/Ar
+{
+ 72 exch div
+ 0 dtransform dup mul exch dup mul add sqrt
+ dup 1 lt
+ {
+ pop 1
+ } if
+ setflat
+} def
+/Mb
+{
+ q
+} def
+/Md
+{
+} def
+/MB
+{
+ Q
+} def
+/nc 3 dict def
+nc begin
+/setgray
+{
+ pop
+} bind def
+/setcmykcolor
+{
+ 4 npop
+} bind def
+/setcustomcolor
+{
+ 2 npop
+} bind def
+currentdict readonly pop
+end
+end
+setpacking
+%%EndResource
+%%EndProlog
+%%BeginSetup
+%%IncludeFont: Univers
+Adobe_level2_AI5 /initialize get exec
+Adobe_Illustrator_AI5_vars Adobe_Illustrator_AI5 Adobe_typography_AI5 /initialize get exec
+Adobe_ColorImage_AI6 /initialize get exec
+Adobe_Illustrator_AI5 /initialize get exec
+[
+39/quotesingle 96/grave 128/Adieresis/Aring/Ccedilla/Eacute/Ntilde/Odieresis
+/Udieresis/aacute/agrave/acircumflex/adieresis/atilde/aring/ccedilla/eacute
+/egrave/ecircumflex/edieresis/iacute/igrave/icircumflex/idieresis/ntilde
+/oacute/ograve/ocircumflex/odieresis/otilde/uacute/ugrave/ucircumflex
+/udieresis/dagger/degree/cent/sterling/section/bullet/paragraph/germandbls
+/registered/copyright/trademark/acute/dieresis/.notdef/AE/Oslash
+/.notdef/plusminus/.notdef/.notdef/yen/mu/.notdef/.notdef
+/.notdef/.notdef/.notdef/ordfeminine/ordmasculine/.notdef/ae/oslash
+/questiondown/exclamdown/logicalnot/.notdef/florin/.notdef/.notdef
+/guillemotleft/guillemotright/ellipsis/.notdef/Agrave/Atilde/Otilde/OE/oe
+/endash/emdash/quotedblleft/quotedblright/quoteleft/quoteright/divide
+/.notdef/ydieresis/Ydieresis/fraction/currency/guilsinglleft/guilsinglright
+/fi/fl/daggerdbl/periodcentered/quotesinglbase/quotedblbase/perthousand
+/Acircumflex/Ecircumflex/Aacute/Edieresis/Egrave/Iacute/Icircumflex
+/Idieresis/Igrave/Oacute/Ocircumflex/.notdef/Ograve/Uacute/Ucircumflex
+/Ugrave/dotlessi/circumflex/tilde/macron/breve/dotaccent/ring/cedilla
+/hungarumlaut/ogonek/caron
+TE
+%AI3_BeginEncoding: _Univers Univers
+[/_Univers/Univers 0 0 1 TZ
+%AI3_EndEncoding AdobeType
+%AI5_Begin_NonPrinting
+Np
+8 Bn
+%AI5_BeginGradient: (Black & White)
+(Black & White) 0 2 Bd
+[
+<
+FFFEFDFCFBFAF9F8F7F6F5F4F3F2F1F0EFEEEDECEBEAE9E8E7E6E5E4E3E2E1E0DFDEDDDCDBDAD9D8
+D7D6D5D4D3D2D1D0CFCECDCCCBCAC9C8C7C6C5C4C3C2C1C0BFBEBDBCBBBAB9B8B7B6B5B4B3B2B1B0
+AFAEADACABAAA9A8A7A6A5A4A3A2A1A09F9E9D9C9B9A999897969594939291908F8E8D8C8B8A8988
+87868584838281807F7E7D7C7B7A797877767574737271706F6E6D6C6B6A69686766656463626160
+5F5E5D5C5B5A595857565554535251504F4E4D4C4B4A494847464544434241403F3E3D3C3B3A3938
+37363534333231302F2E2D2C2B2A292827262524232221201F1E1D1C1B1A19181716151413121110
+0F0E0D0C0B0A09080706050403020100
+>
+0 %_Br
+[
+0 0 50 100 %_Bs
+1 0 50 0 %_Bs
+BD
+%AI5_EndGradient
+%AI5_BeginGradient: (Green & Blue)
+(Green & Blue) 0 2 Bd
+[
+<
+99999A9A9B9B9B9C9C9D9D9D9E9E9F9F9FA0A0A1A1A1A2A2A3A3A3A4A4A5A5A5A6A6A7A7A7A8A8A9
+A9A9AAAAABABABACACADADADAEAEAFAFAFB0B0B1B1B1B2B2B3B3B3B4B4B5B5B5B6B6B7B7B7B8B8B9
+B9B9BABABBBBBBBCBCBDBDBDBEBEBFBFBFC0C0C1C1C1C2C2C3C3C3C4C4C5C5C5C6C6C7C7C7C8C8C9
+C9C9CACACBCBCBCCCCCDCDCDCECECFCFCFD0D0D1D1D1D2D2D3D3D3D4D4D5D5D5D6D6D7D7D7D8D8D9
+D9D9DADADBDBDBDCDCDDDDDDDEDEDFDFDFE0E0E1E1E1E2E2E3E3E3E4E4E5E5E5E6E6E7E7E7E8E8E9
+E9E9EAEAEBEBEBECECEDEDEDEEEEEFEFEFF0F0F1F1F1F2F2F3F3F3F4F4F5F5F5F6F6F7F7F7F8F8F9
+F9F9FAFAFBFBFBFCFCFDFDFDFEFEFFFF
+>
+<
+000102020304050506070808090A0B0B0C0D0E0E0F101111121314141516171718191A1A1B1C1D1D
+1E1F20202122232324252626272829292A2B2C2C2D2E2F2F303132323334353536373838393A3B3B
+3C3D3E3E3F404141424344444546474748494A4A4B4C4D4D4E4F5050515253535455565657585959
+5A5B5C5C5D5E5F5F606162626364656566676868696A6B6B6C6D6E6E6F7071717273747475767777
+78797A7A7B7C7D7D7E7F80808182828384858586878888898A8B8B8C8D8E8E8F9091919293949495
+96979798999A9A9B9C9D9D9E9FA0A0A1A2A3A3A4A5A6A6A7A8A9A9AAABACACADAEAFAFB0B1B2B2B3
+B4B5B5B6B7B8B8B9BABBBBBCBDBEBEBF
+>
+<
+FFFEFDFCFBFAF9F8F7F6F5F4F3F2F1F0EFEEEDECEBEAE9E8E7E6E5E4E3E2E1E0DFDEDDDCDBDAD9D8
+D7D6D5D4D3D2D1D0CFCECDCCCBCAC9C8C7C6C5C4C3C2C1C0BFBEBDBCBBBAB9B8B7B6B5B4B3B2B1B0
+AFAEADACABAAA9A8A7A6A5A4A3A2A1A09F9E9D9C9B9A999897969594939291908F8E8D8C8B8A8988
+87868584838281807F7E7D7C7B7A797877767574737271706F6E6D6C6B6A69686766656463626160
+5F5E5D5C5B5A595857565554535251504F4E4D4C4B4A494847464544434241403F3E3D3C3B3A3938
+37363534333231302F2E2D2C2B2A292827262524232221201F1E1D1C1B1A19181716151413121110
+0F0E0D0C0B0A09080706050403020100
+>
+0
+1 %_Br
+[
+1 0.75 0 0 1 50 100 %_Bs
+0.6 0 1 0 1 50 0 %_Bs
+BD
+%AI5_EndGradient
+%AI5_BeginGradient: (Pink, Yellow, Green)
+(Pink, Yellow, Green) 0 3 Bd
+[
+<
+00000000000000000000000000000000000000010101010101010101010101010101010101010101
+01010101010202020202020202020202020202020202020202020203030303030303030303030303
+03030303030303030404040404040404040404040404040404040404050505050505050505050505
+05050505050505060606060606060606060606060606060606060707070707070707070707070707
+07070707080808080808080808080808080808080809090909090909090909090909090909090A0A
+0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0C0C0C0C0C0C0C0C0C
+0C0C0C0C0C0C0C0D0D0D0D0D
+>
+<
+050506060606070708080809090A0A0A0B0B0C0C0D0D0E0E0F0F1010111112121313141415151617
+17181819191A1A1B1C1C1D1D1E1F1F202021222223232425252626272828292A2A2B2C2C2D2D2E2F
+2F3031313233333435353637373839393A3B3B3C3D3E3E3F4040414242434445454647474849494A
+4B4C4C4D4E4F4F505151525354545556575758595A5A5B5C5C5D5E5F5F6061626363646566666768
+69696A6B6C6C6D6E6F707071727373747576777778797A7B7B7C7D7E7F7F80818283838485868787
+88898A8B8B8C8D8E8F8F9091929394949596979898999A9B9C9D9D9E9FA0A1A2A2A3A4A5A6A7A7A8
+A9AAABACADADAEAFB0B1B2B2
+>
+<
+CCCCCBCBCBCACACAC9C9C8C8C7C7C6C6C5C5C4C4C3C2C2C1C1C0C0BFBEBEBDBDBCBBBBBAB9B9B8B7
+B7B6B6B5B4B4B3B2B1B1B0AFAFAEADADACABAAAAA9A8A8A7A6A5A5A4A3A2A2A1A0A09F9E9D9C9C9B
+9A999998979696959493929291908F8E8E8D8C8B8A8A8988878686858483828181807F7E7D7C7C7B
+7A7978777776757473727171706F6E6D6C6B6A6A69686766656463636261605F5E5D5C5B5B5A5958
+5756555453525151504F4E4D4C4B4A49484746464544434241403F3E3D3C3B3A3938383736353433
+3231302F2E2D2C2B2A29282726252423222221201F1E1D1C1B1A191817161514131211100F0E0D0C
+0B0A09080706050403020100
+>
+0
+1 %_Br
+<
+737271706F6E6D6C6B6A696867666564636261605F5E5D5C5B5B5A59585756555453525150504F4E
+4D4C4B4A4949484746454443434241403F3E3E3D3C3B3A3A393837363635343333323130302F2E2D
+2D2C2B2A2A29282827262525242323222121201F1F1E1D1D1C1C1B1A1A1918181717161615141413
+1312121111100F0F0E0E0D0D0C0C0C0B0B0A0A090908080807070606060505050404040303030202
+020201010101010000000000
+>
+<
+00000000000000000000000001010101010101010101010101010101010101010101010102020202
+02020202020202020202020202020202020202020202030303030303030303030303030303030303
+03030303030303030303030303040404040404040404040404040404040404040404040404040404
+04040404040404040404050505050505050505050505050505050505050505050505050505050505
+050505050505050505050505
+>
+<
+BFBFBFC0C0C0C0C0C0C0C0C0C1C1C1C1C1C1C1C1C1C2C2C2C2C2C2C2C2C2C2C3C3C3C3C3C3C3C3C3
+C3C4C4C4C4C4C4C4C4C4C4C5C5C5C5C5C5C5C5C5C5C5C6C6C6C6C6C6C6C6C6C6C6C6C7C7C7C7C7C7
+C7C7C7C7C7C7C8C8C8C8C8C8C8C8C8C8C8C8C8C9C9C9C9C9C9C9C9C9C9C9C9C9C9C9CACACACACACA
+CACACACACACACACACACACBCBCBCBCBCBCBCBCBCBCBCBCBCBCBCBCBCBCBCBCBCBCCCCCCCCCCCCCCCC
+CCCCCCCCCCCCCCCCCCCCCCCC
+>
+0
+1 %_Br
+[
+0.05 0.7 0 0 1 50 100 %_Bs
+0 0.02 0.8 0 1 57 36 %_Bs
+0.45 0 0.75 0 1 37 0 %_Bs
+BD
+%AI5_EndGradient
+%AI5_BeginGradient: (Purple, Red & Yellow)
+(Purple, Red & Yellow) 0 3 Bd
+[
+0
+<
+FFFEFDFCFBFAF9F8F7F6F5F4F3F2F1F0EFEEEDECEBEAE9E8E7E6E5E4E3E2E1E0DFDEDDDCDBDAD9D8
+D7D6D5D4D3D2D1D0CFCECDCCCBCAC9C8C7C6C5C4C3C2C1C0BFBEBDBCBBBAB9B8B7B6B5B4B3B2B1B0
+AFAEADACABAAA9A8A7A6A5A4A3A2A1A09F9E9D9C9B9A999897969594939291908F8E8D8C8B8A8988
+87868584838281807F7E7D7C7B7A797877767574737271706F6E6D6C6B6A69686766656463626160
+5F5E5D5C5B5A595857565554535251504F4E4D4C4B4A494847464544434241403F3E3D3C3B3A3938
+37363534333231302F2E2D2C2B2A292827262524232221201F1E1D1C1B1A19181716151413121110
+0F0E0D0C0B0A
+>
+<
+CCCCCCCDCDCDCDCDCECECECECECFCFCFCFD0D0D0D0D0D1D1D1D1D1D2D2D2D2D2D3D3D3D3D3D4D4D4
+D4D5D5D5D5D5D6D6D6D6D6D7D7D7D7D7D8D8D8D8D8D9D9D9D9DADADADADADBDBDBDBDBDCDCDCDCDC
+DDDDDDDDDDDEDEDEDEDFDFDFDFDFE0E0E0E0E0E1E1E1E1E1E2E2E2E2E2E3E3E3E3E4E4E4E4E4E5E5
+E5E5E5E6E6E6E6E6E7E7E7E7E7E8E8E8E8E9E9E9E9E9EAEAEAEAEAEBEBEBEBEBECECECECECEDEDED
+EDEEEEEEEEEEEFEFEFEFEFF0F0F0F0F0F1F1F1F1F1F2F2F2F2F3F3F3F3F3F4F4F4F4F4F5F5F5F5F5
+F6F6F6F6F6F7F7F7F7F8F8F8F8F8F9F9F9F9F9FAFAFAFAFAFBFBFBFBFBFCFCFCFCFDFDFDFDFDFEFE
+FEFEFEFFFFFF
+>
+0
+1 %_Br
+<
+E5E4E3E2E1E0DFDEDDDCDBDAD9D8D7D6D5D4D3D2D1D0CFCECDCCCBCAC9C8C7C6C5C4C3C2C1C0BFBE
+BDBCBBBAB9B8B7B6B5B4B3B2B1B0AFAEADACABAAA9A8A7A6A5A4A3A2A1A09F9E9D9C9B9A99989796
+9594939291908F8E8D8C8B8A898887868584838281807F7E7D7C7B7A797877767574737271706F6E
+6D6C6B6A696867666564636261605F5E5D5C5B5A595857565554535251504F4E4D4C4B4A49484746
+4544434241403F3E3D3C3B3A393837363534333231302F2E2D2C2B2A292827262524232221201F1E
+1D1C1B1A191817161514131211100F0E0D0C0B0A09080706050403020100
+>
+<
+E5E6E6E6E6E6E6E6E6E7E7E7E7E7E7E7E7E7E8E8E8E8E8E8E8E8E8E9E9E9E9E9E9E9E9E9EAEAEAEA
+EAEAEAEAEAEBEBEBEBEBEBEBEBEBECECECECECECECECECEDEDEDEDEDEDEDEDEDEEEEEEEEEEEEEEEE
+EEEFEFEFEFEFEFEFEFEFF0F0F0F0F0F0F0F0F0F1F1F1F1F1F1F1F1F1F2F2F2F2F2F2F2F2F2F3F3F3
+F3F3F3F3F3F3F4F4F4F4F4F4F4F4F4F5F5F5F5F5F5F5F5F5F6F6F6F6F6F6F6F6F6F7F7F7F7F7F7F7
+F7F7F8F8F8F8F8F8F8F8F8F9F9F9F9F9F9F9F9F9FAFAFAFAFAFAFAFAFAFBFBFBFBFBFBFBFBFBFCFC
+FCFCFCFCFCFCFCFDFDFDFDFDFDFDFDFDFEFEFEFEFEFEFEFEFEFFFFFFFFFF
+>
+<
+00010203040405060708090A0B0C0C0D0E0F10111213141415161718191A1B1C1D1D1E1F20212223
+242525262728292A2B2C2D2D2E2F30313233343535363738393A3B3C3D3D3E3F4041424344454546
+4748494A4B4C4D4E4E4F50515253545556565758595A5B5C5D5E5E5F60616263646566666768696A
+6B6C6D6E6E6F70717273747576767778797A7B7C7D7E7F7F80818283848586878788898A8B8C8D8E
+8F8F90919293949596979798999A9B9C9D9E9F9FA0A1A2A3A4A5A6A7A7A8A9AAABACADAEAFAFB0B1
+B2B3B4B5B6B7B8B8B9BABBBCBDBEBFC0C0C1C2C3C4C5C6C7C8C8C9CACBCC
+>
+0
+1 %_Br
+[
+0 0.04 1 0 1 50 100 %_Bs
+0 1 0.8 0 1 50 50 %_Bs
+0.9 0.9 0 0 1 50 0 %_Bs
+BD
+%AI5_EndGradient
+%AI5_BeginGradient: (Rainbow)
+(Rainbow) 0 6 Bd
+[
+<
+FFFEFDFCFBFAF9F8F7F6F5F4F3F2F1F0EFEEEDECEBEAE9E8E7E6E5E4E3E2E1E0DFDEDDDCDBDAD9D8
+D7D6D5D4D3D2D1D0CFCECDCCCBCAC9C8C7C6C5C4C3C2C1C0BFBEBDBCBBBAB9B8B7B6B5B4B3B2B1B0
+AFAEADACABAAA9A8A7A6A5A4A3A2A1A09F9E9D9C9B9A999897969594939291908F8E8D8C8B8A8988
+87868584838281807F7E7D7C7B7A797877767574737271706F6E6D6C6B6A69686766656463626160
+5F5E5D5C5B5A595857565554535251504F4E4D4C4B4A494847464544434241403F3E3D3C3B3A3938
+37363534333231302F2E2D2C2B2A292827262524232221201F1E1D1C1B1A19181716151413121110
+0F0E0D0C0B0A09080706050403020100
+>
+1
+0
+0
+1 %_Br
+1
+<
+0708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E
+2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F50515253545556
+5758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E
+7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6
+A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7C8C9CACBCCCDCE
+CFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6
+F7F8F9FAFBFCFDFEFF
+>
+0
+0
+1 %_Br
+1
+<
+00000000000000000000000000000000000001010101010101010101010101010101010101010101
+01010101010101010101010101010202020202020202020202020202020202020202020202020202
+02020202020202020202030303030303030303030303030303030303030303030303030303030303
+03030303030304040404040404040404040404040404040404040404040404040404040404040404
+04040505050505050505050505050505050505050505050505050505050505050505050505050606
+06060606060606060606060606060606060606060606060606060606060606060606070707070707
+07070707070707070707070707070707
+>
+<
+FFFEFDFCFBFAF9F8F7F6F5F4F3F2F1F0EFEEEDECEBEAE9E8E7E6E5E4E3E2E1E0DFDEDDDCDBDAD9D8
+D7D6D5D4D3D2D1D0CFCECDCCCBCAC9C8C7C6C5C4C3C2C1C0BFBEBDBCBBBAB9B8B7B6B5B4B3B2B1B0
+AFAEADACABAAA9A8A7A6A5A4A3A2A1A09F9E9D9C9B9A999897969594939291908F8E8D8C8B8A8988
+87868584838281807F7E7D7C7B7A797877767574737271706F6E6D6C6B6A69686766656463626160
+5F5E5D5C5B5A595857565554535251504F4E4D4C4B4A494847464544434241403F3E3D3C3B3A3938
+37363534333231302F2E2D2C2B2A292827262524232221201F1E1D1C1B1A19181716151413121110
+0F0E0D0C0B0A09080706050403020100
+>
+0
+1 %_Br
+<
+000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627
+28292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F
+505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F7071727374757677
+78797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9F
+A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7
+C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEF
+F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF
+>
+0
+1
+0
+1 %_Br
+0
+<
+FFFEFDFCFBFAF9F8F7F6F5F4F3F2F1F0EFEEEDECEBEAE9E8E7E6E5E4E3E2E1E0DFDEDDDCDBDAD9D8
+D7D6D5D4D3D2D1D0CFCECDCCCBCAC9C8C7C6C5C4C3C2C1C0BFBEBDBCBBBAB9B8B7B6B5B4B3B2B1B0
+AFAEADACABAAA9A8A7A6A5A4A3A2A1A09F9E9D9C9B9A999897969594939291908F8E8D8C8B8A8988
+87868584838281807F7E7D7C7B7A797877767574737271706F6E6D6C6B6A69686766656463626160
+5F5E5D5C5B5A595857565554535251504F4E4D4C4B4A494847464544434241403F3E3D3C3B3A3938
+37363534333231302F2E2D2C2B2A292827262524232221201F1E1D1C1B1A19181716151413121110
+0F0E0D0C0B0A09080706050403020100
+>
+1
+0
+1 %_Br
+[
+0 1 0 0 1 50 100 %_Bs
+1 1 0 0 1 50 80 %_Bs
+1 0.0279 0 0 1 50 60 %_Bs
+1 0 1 0 1 50 40 %_Bs
+0 0 1 0 1 50 20 %_Bs
+0 1 1 0 1 50 0 %_Bs
+BD
+%AI5_EndGradient
+%AI5_BeginGradient: (Steel Bar)
+(Steel Bar) 0 3 Bd
+[
+<
+FFFEFDFCFBFAF9F8F7F6F5F4F3F2F1F0EFEEEDECEBEAE9E8E7E6E5E4E3E2E1E0DFDEDDDCDBDAD9D8
+D7D6D5D4D3D2D1D0CFCECDCCCBCAC9C8C7C6C5C4C3C2C1C0BFBEBDBCBBBAB9B8B7B6B5B4B3B2B1B0
+AFAEADACABAAA9A8A7A6A5A4A3A2A1A09F9E9D9C9B9A999897969594939291908F8E8D8C8B8A8988
+87868584838281807F7E7D7C7B7A797877767574737271706F6E6D6C6B6A69686766656463626160
+5F5E5D5C5B5A595857565554535251504F4E4D4C4B4A494847464544434241403F3E3D3C3B3A3938
+37363534333231302F2E2D2C2B2A292827262524232221201F1E1D1C1B1A19181716151413121110
+0F0E0D0C0B0A09080706050403020100
+>
+0 %_Br
+<
+000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627
+28292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F
+505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F7071727374757677
+78797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9F
+A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7
+C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEF
+F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF
+>
+0 %_Br
+[
+0 0 50 100 %_Bs
+1 0 50 70 %_Bs
+0 0 50 0 %_Bs
+BD
+%AI5_EndGradient
+%AI5_BeginGradient: (Yellow & Orange Radial)
+(Yellow & Orange Radial) 1 2 Bd
+[
+0
+<
+0001010203040506060708090A0B0C0C0D0E0F10111213131415161718191A1B1C1D1D1E1F202122
+232425262728292A2B2B2C2D2E2F303132333435363738393A3B3C3D3E3E3F404142434445464748
+494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F60606162636465666768696A6B6C6D6E6F
+707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C
+>
+<
+FFFFFFFFFEFEFEFEFEFEFEFDFDFDFDFDFDFCFCFCFCFCFCFBFBFBFBFBFBFAFAFAFAFAFAF9F9F9F9F9
+F9F8F8F8F8F8F8F7F7F7F7F7F7F6F6F6F6F6F6F5F5F5F5F5F5F4F4F4F4F4F3F3F3F3F3F3F2F2F2F2
+F2F2F1F1F1F1F1F0F0F0F0F0F0EFEFEFEFEFEFEEEEEEEEEEEDEDEDEDEDEDECECECECECEBEBEBEBEB
+EBEAEAEAEAEAE9E9E9E9E9E9E8E8E8E8E8E8E7E7E7E7E7E6E6E6E6E6E5
+>
+0
+1 %_Br
+[
+0 0 1 0 1 52 19 %_Bs
+0 0.55 0.9 0 1 50 100 %_Bs
+BD
+%AI5_EndGradient
+%AI5_BeginGradient: (Yellow & Purple Radial)
+(Yellow & Purple Radial) 1 2 Bd
+[
+<
+000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627
+28292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F
+505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F7071727374757677
+78797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9F
+A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7
+C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEF
+F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF
+>
+<
+1415161718191A1B1C1D1E1F1F202122232425262728292A2A2B2C2D2E2F30313233343536363738
+393A3B3C3D3E3F40414142434445464748494A4B4C4D4D4E4F50515253545556575858595A5B5C5D
+5E5F60616263646465666768696A6B6C6D6E6F6F707172737475767778797A7B7B7C7D7E7F808182
+83848586868788898A8B8C8D8E8F90919292939495969798999A9B9C9D9D9E9FA0A1A2A3A4A5A6A7
+A8A9A9AAABACADAEAFB0B1B2B3B4B4B5B6B7B8B9BABBBCBDBEBFC0C0C1C2C3C4C5C6C7C8C9CACBCB
+CCCDCECFD0D1D2D3D4D5D6D7D7D8D9DADBDCDDDEDFE0E1E2E2E3E4E5E6E7E8E9EAEBECEDEEEEEFF0
+F1F2F3F4F5F6F7F8F9F9FAFBFCFDFEFF
+>
+<
+ABAAAAA9A8A7A7A6A5A5A4A3A3A2A1A1A09F9F9E9D9D9C9B9B9A9999989797969595949393929191
+908F8F8E8D8D8C8B8B8A8989888787868585848383828181807F7F7E7D7D7C7B7B7A797978777776
+7575747373727171706F6F6E6D6D6C6B6B6A6969686767666565646362626160605F5E5E5D5C5C5B
+5A5A5958585756565554545352525150504F4E4E4D4C4C4B4A4A4948484746464544444342424140
+403F3E3E3D3C3C3B3A3A3938383736363534343332323130302F2E2E2D2C2C2B2A2A292828272626
+25242423222121201F1F1E1D1D1C1B1B1A1919181717161515141313121111100F0F0E0D0D0C0B0B
+0A090908070706050504030302010100
+>
+0
+1 %_Br
+[
+0 0.08 0.67 0 1 50 14 %_Bs
+1 1 0 0 1 50 100 %_Bs
+BD
+%AI5_EndGradient
+%AI5_End_NonPrinting--
+%AI5_BeginPalette
+0 2 Pb
+Pn
+Pc
+1 g
+Pc
+0 g
+Pc
+0 0 0 0 k
+Pc
+0.75 g
+Pc
+0.5 g
+Pc
+0.25 g
+Pc
+0 g
+Pc
+Bb
+2 (Black & White) -4014 4716 0 0 1 0 0 1 0 0 Bg
+0 BB
+Pc
+0.25 0 0 0 k
+Pc
+0.5 0 0 0 k
+Pc
+0.75 0 0 0 k
+Pc
+1 0 0 0 k
+Pc
+0.25 0.25 0 0 k
+Pc
+0.5 0.5 0 0 k
+Pc
+0.75 0.75 0 0 k
+Pc
+1 1 0 0 k
+Pc
+Bb
+2 (Pink, Yellow, Green) -4014 4716 0 0 1 0 0 1 0 0 Bg
+0 BB
+Pc
+0 0.25 0 0 k
+Pc
+0 0.5 0 0 k
+Pc
+0 0.75 0 0 k
+Pc
+0 1 0 0 k
+Pc
+0 0.25 0.25 0 k
+Pc
+0 0.5 0.5 0 k
+Pc
+0 0.75 0.75 0 k
+Pc
+0 1 1 0 k
+Pc
+Bb
+0 0 0 0 Bh
+2 (Yellow & Purple Radial) -4014 4716 0 0 1 0 0 1 0 0 Bg
+0 BB
+Pc
+0 0 0.25 0 k
+Pc
+0 0 0.5 0 k
+Pc
+0 0 0.75 0 k
+Pc
+0 0 1 0 k
+Pc
+0.25 0 0.25 0 k
+Pc
+0.5 0 0.5 0 k
+Pc
+0.75 0 0.75 0 k
+Pc
+1 0 1 0 k
+Pc
+Bb
+2 (Rainbow) -4014 4716 0 0 1 0 0 1 0 0 Bg
+0 BB
+Pc
+0.25 0.125 0 0 k
+Pc
+0.5 0.25 0 0 k
+Pc
+0.75 0.375 0 0 k
+Pc
+1 0.5 0 0 k
+Pc
+0.125 0.25 0 0 k
+Pc
+0.25 0.5 0 0 k
+Pc
+0.375 0.75 0 0 k
+Pc
+0.5 1 0 0 k
+Pc
+Bb
+2 (Steel Bar) -4014 4716 0 0 1 0 0 1 0 0 Bg
+0 BB
+Pc
+0 0.25 0.125 0 k
+Pc
+0 0.5 0.25 0 k
+Pc
+0 0.75 0.375 0 k
+Pc
+0 1 0.5 0 k
+Pc
+0 0.125 0.25 0 k
+Pc
+0 0.25 0.5 0 k
+Pc
+0 0.375 0.75 0 k
+Pc
+0 0.5 1 0 k
+Pc
+Bb
+2 (Purple, Red & Yellow) -4014 4716 0 0 1 0 0 1 0 0 Bg
+0 BB
+Pc
+0.125 0 0.25 0 k
+Pc
+0.25 0 0.5 0 k
+Pc
+0.375 0 0.75 0 k
+Pc
+0.5 0 1 0 k
+Pc
+0.25 0 0.125 0 k
+Pc
+0.5 0 0.25 0 k
+Pc
+0.75 0 0.375 0 k
+Pc
+1 0 0.5 0 k
+Pc
+Bb
+2 (Green & Blue) -4014 4716 0 0 1 0 0 1 0 0 Bg
+0 BB
+Pc
+0.25 0.125 0.125 0 k
+Pc
+0.5 0.25 0.25 0 k
+Pc
+0.75 0.375 0.375 0 k
+Pc
+1 0.5 0.5 0 k
+Pc
+0.25 0.25 0.125 0 k
+Pc
+0.5 0.5 0.25 0 k
+Pc
+0.75 0.75 0.375 0 k
+Pc
+1 1 0.5 0 k
+Pc
+Bb
+0 0 0 0 Bh
+2 (Yellow & Orange Radial) -4014 4716 0 0 1 0 0 1 0 0 Bg
+0 BB
+Pc
+0.125 0.25 0.125 0 k
+Pc
+0.25 0.5 0.25 0 k
+Pc
+0.375 0.75 0.375 0 k
+Pc
+0.5 1 0.5 0 k
+Pc
+0.125 0.25 0.25 0 k
+Pc
+0.25 0.5 0.5 0 k
+Pc
+0.375 0.75 0.75 0 k
+Pc
+0.5 1 1 0 k
+Pc
+0 0 0 0 k
+Pc
+0.125 0.125 0.25 0 k
+Pc
+0.25 0.25 0.5 0 k
+Pc
+0.375 0.375 0.75 0 k
+Pc
+0.5 0.5 1 0 k
+Pc
+0.25 0.125 0.25 0 k
+Pc
+0.5 0.25 0.5 0 k
+Pc
+0.75 0.375 0.75 0 k
+Pc
+1 0.5 1 0 k
+Pc
+PB
+%AI5_EndPalette
+%%EndSetup
+%AI5_BeginLayer
+1 1 1 1 0 0 0 79 128 255 Lb
+(Layer 1) Ln
+0 A
+800 Ar
+0 J 0 j 1 w 4 M []0 d
+%AI3_Note:
+0 D
+0 XR
+-4014 283.5 m
+4626 283.5 L
+(N) *
+453.5 4716 m
+453.5 -3924 L
+(N) *
+85 4716 m
+85 -3924 L
+(N) *
+-4014 765.5 m
+4626 765.5 L
+(N) *
+1 Ap
+0 O
+1 g
+0 R
+0 G
+228.6667 637.3333 m
+228.6667 694.3333 L
+86.6667 694.3333 L
+86.6667 637.3333 L
+228.6667 637.3333 L
+b
+454.8333 643.8333 m
+454.8333 679.8333 L
+255.8333 679.8333 L
+255.8333 643.8333 L
+454.8333 643.8333 L
+b
+0 Ap
+214.1667 671.3333 m
+B
+87.1667 671.3333 m
+228.6667 671.3333 l
+B
+1 Ap
+286.105 487.6601 m
+286.105 516.0065 L
+192.5617 516.0065 L
+192.5617 487.6601 L
+286.105 487.6601 L
+b
+u
+u
+u
+0 Ap
+151.7708 636.6458 m
+223.2708 605.1458 l
+B
+0 g
+225.8455 605.1261 m
+224.5361 606.2522 223.74 607.1081 222.7428 608.1322 c
+220.6995 603.5202 l
+221.2248 603.5338 223.2969 603.455 225.0105 603.2414 c
+226.8449 603.0136 228.46 602.6979 229.4643 602.3956 c
+228.5657 602.9365 227.2467 603.9206 225.8455 605.1261 c
+f
+U
+U
+U
+u
+u
+0 R
+0 G
+355.3333 643.2083 m
+254.3333 604.7083 l
+S
+0 O
+0 g
+252.4878 602.9128 m
+254.2108 603.032 255.3786 602.9827 256.8077 602.9549 c
+255.02 607.6718 l
+254.6558 607.293 253.1265 605.8928 251.7573 604.8403 c
+250.2923 603.7133 248.9215 602.8028 247.9946 602.3119 c
+249.014 602.5587 250.6439 602.7856 252.4878 602.9128 c
+f
+U
+U
+u
+u
+0 R
+0 G
+239.3333 558.8333 m
+239.4177 522.6094 l
+S
+0 O
+0 g
+240.4481 520.2498 m
+240.9434 521.9043 241.4009 522.9799 241.9302 524.3077 c
+236.8859 524.2959 l
+237.1123 523.8216 237.884 521.8971 238.3868 520.245 c
+238.9256 518.4768 239.295 516.8732 239.4279 515.8328 c
+239.556 516.8738 239.9177 518.4791 240.4481 520.2498 c
+f
+U
+U
+0 To
+1 0 0 1 91.6667 676.8333 0 Tp
+TP
+0 Tr
+/_Univers 10 Tf
+0 Ts
+100 Tz
+0 Tt
+1 TA
+%_ 0 XL
+36 0 Xb
+XB
+0 0 5 TC
+100 100 200 TW
+0 0 0 Ti
+0 Ta
+0 0 2 2 3 Th
+0 Tq
+0 0 Tl
+0 Tc
+0 Tw
+(MIB in ASN.1) Tx
+(\r) TX
+TO
+0 To
+1 0 0 1 173.6667 676.8333 0 Tp
+TP
+0 Tr
+(file.mib) Tx
+(\r) TX
+TO
+0 To
+1 0 0 1 92.6667 660.8333 0 Tp
+TP
+0 Tr
+/_Univers 9 Tf
+(sysContact OBJECT) Tx 1 92 Tk
+(-TYPE\r) Tx
+0 -11 Td
+( SYNT) Tx 1 74 Tk
+(AX DisplayString\r) Tx
+0 -11 Td
+( ...) Tx
+(\r) TX
+TO
+163.1667 670.8333 m
+F
+163.6667 693.8333 m
+F
+0 R
+0 G
+163.6667 694.2083 m
+163.6667 671.4583 l
+S
+0 To
+1 0 0 1 264.8333 665.8333 0 Tp
+TP
+0 Tr
+0 O
+0 g
+/_Univers 10 Tf
+(Association file) Tx
+(\r) TX
+TO
+0 To
+1 0 0 1 264.8333 648.8333 0 Tp
+TP
+0 Tr
+({sysContact, {mymod, sysCFunc, []}}.) Tx
+(\r) TX
+TO
+0 R
+0 G
+228.3333 516.3333 m
+228.3333 501.8333 l
+285.8333 501.8333 l
+S
+0 To
+1 0 0 1 195.3333 503.8333 0 Tp
+TP
+0 Tr
+0 O
+0 g
+(Binary\r) Tx
+0 -12 Td
+(Representation) Tx
+(\r) TX
+TO
+0 To
+1 0 0 1 234.3333 504.3333 0 Tp
+TP
+0 Tr
+(file.bin) Tx
+(\r) TX
+TO
+0 R
+0 G
+255.8333 661.3333 m
+454.8333 661.3333 l
+S
+352.8333 679.8333 m
+352.8333 661.3333 l
+S
+0 To
+1 0 0 1 363.3333 665.8333 0 Tp
+TP
+0 Tr
+0 O
+0 g
+(file.funcs) Tx
+(\r) TX
+TO
+u
+1 Ap
+0 R
+0 G
+239.3333 559.0734 m
+258.9022 559.0734 274.7664 568.5919 274.7664 580.3332 c
+274.7664 592.0746 258.9022 601.5931 239.3333 601.5931 c
+219.7644 601.5931 203.9002 592.0746 203.9002 580.3332 c
+203.9002 568.5919 219.7644 559.0734 239.3333 559.0734 c
+s
+0 To
+1 0 0 1 239.3333 582.8994 0 Tp
+TP
+-9.4434 0 Td
+0 Tr
+0 O
+0 g
+1 Ta
+(MIB\r) Tx
+-12.2217 -12 Td
+(Compiler) Tx
+(\r) TX
+TO
+U
+LB
+%AI5_EndLayer--
+%%PageTrailer
+gsave annotatepage grestore showpage
+%%Trailer
+Adobe_Illustrator_AI5 /terminate get exec
+Adobe_ColorImage_AI6 /terminate get exec
+Adobe_typography_AI5 /terminate get exec
+Adobe_level2_AI5 /terminate get exec
+%%EOF
diff --git a/lib/snmp/doc/src/snmp-um-1-image-2.gif b/lib/snmp/doc/src/snmp-um-1-image-2.gif
new file mode 100644
index 0000000000..3c976e4355
--- /dev/null
+++ b/lib/snmp/doc/src/snmp-um-1-image-2.gif
Binary files differ
diff --git a/lib/snmp/doc/src/snmp-um-1-image-2.ps b/lib/snmp/doc/src/snmp-um-1-image-2.ps
new file mode 100644
index 0000000000..38d875eff1
--- /dev/null
+++ b/lib/snmp/doc/src/snmp-um-1-image-2.ps
@@ -0,0 +1,2866 @@
+%!PS-Adobe-3.0 EPSF-3.0
+%%Creator: Adobe Illustrator(r) 6.0
+%%For: (Anna Fedoriw) (Ericsson Telecom)
+%%Title: (StartingTheAgent.eps)
+%%CreationDate: (97-05-23) (14.06)
+%%BoundingBox: 126 592 437 744
+%%HiResBoundingBox: 126.8422 592.4803 436.5 743.6667
+%%DocumentProcessColors: Black
+%%DocumentFonts: Courier
+%%+ Univers
+%%DocumentSuppliedResources: procset Adobe_level2_AI5 1.0 0
+%%+ procset Adobe_typography_AI5 1.0 0
+%%+ procset Adobe_Illustrator_AI6_vars Adobe_Illustrator_AI6
+%%+ procset Adobe_Illustrator_AI5 1.0 0
+%AI5_FileFormat 2.0
+%AI3_ColorUsage: Black&White
+%%AI6_ColorSeparationSet: 1 1 (AI6 Default Color Separation Set)
+%%+ Options: 1 16 0 1 0 1 1 1 0 1 1 1 1 18 0 0 0 0 0 0 0 0 -1 -1
+%%+ PPD: 1 21 0 0 60 45 2 2 1 0 0 1 0 0 0 0 0 0 0 0 0 0 ()
+%AI3_TemplateBox: 306 396 306 396
+%AI3_TileBox: 21 -12 588 802
+%AI3_DocumentPreview: Macintosh_ColorPic
+%AI5_ArtSize: 595.2756 841.8898
+%AI5_RulerUnits: 1
+%AI5_ArtFlags: 0 0 0 1 0 0 1 1 0
+%AI5_TargetResolution: 800
+%AI5_NumLayers: 1
+%AI5_OpenToView: 78 768 2 1146 827 58 1 1 3 40
+%AI5_OpenViewLayers: 7
+%%EndComments
+%%BeginProlog
+%%BeginResource: procset Adobe_level2_AI5 1.2 0
+%%Title: (Adobe Illustrator (R) Version 5.0 Level 2 Emulation)
+%%Version: 1.2
+%%CreationDate: (04/10/93) ()
+%%Copyright: ((C) 1987-1993 Adobe Systems Incorporated All Rights Reserved)
+userdict /Adobe_level2_AI5 23 dict dup begin
+ put
+ /packedarray where not
+ {
+ userdict begin
+ /packedarray
+ {
+ array astore readonly
+ } bind def
+ /setpacking /pop load def
+ /currentpacking false def
+ end
+ 0
+ } if
+ pop
+ userdict /defaultpacking currentpacking put true setpacking
+ /initialize
+ {
+ Adobe_level2_AI5 begin
+ } bind def
+ /terminate
+ {
+ currentdict Adobe_level2_AI5 eq
+ {
+ end
+ } if
+ } bind def
+ mark
+ /setcustomcolor where not
+ {
+ /findcmykcustomcolor
+ {
+ 5 packedarray
+ } bind def
+ /setcustomcolor
+ {
+ exch aload pop pop
+ 4
+ {
+ 4 index mul 4 1 roll
+ } repeat
+ 5 -1 roll pop
+ setcmykcolor
+ }
+ def
+ } if
+
+ /gt38? mark {version cvr cvx exec} stopped {cleartomark true} {38 gt exch pop} ifelse def
+ userdict /deviceDPI 72 0 matrix defaultmatrix dtransform dup mul exch dup mul add sqrt put
+ userdict /level2?
+ systemdict /languagelevel known dup
+ {
+ pop systemdict /languagelevel get 2 ge
+ } if
+ put
+/level2ScreenFreq
+{
+ begin
+ 60
+ HalftoneType 1 eq
+ {
+ pop Frequency
+ } if
+ HalftoneType 2 eq
+ {
+ pop GrayFrequency
+ } if
+ HalftoneType 5 eq
+ {
+ pop Default level2ScreenFreq
+ } if
+ end
+} bind def
+userdict /currentScreenFreq
+ level2? {currenthalftone level2ScreenFreq} {currentscreen pop pop} ifelse put
+level2? not
+ {
+ /setcmykcolor where not
+ {
+ /setcmykcolor
+ {
+ exch .11 mul add exch .59 mul add exch .3 mul add
+ 1 exch sub setgray
+ } def
+ } if
+ /currentcmykcolor where not
+ {
+ /currentcmykcolor
+ {
+ 0 0 0 1 currentgray sub
+ } def
+ } if
+ /setoverprint where not
+ {
+ /setoverprint /pop load def
+ } if
+ /selectfont where not
+ {
+ /selectfont
+ {
+ exch findfont exch
+ dup type /arraytype eq
+ {
+ makefont
+ }
+ {
+ scalefont
+ } ifelse
+ setfont
+ } bind def
+ } if
+ /cshow where not
+ {
+ /cshow
+ {
+ [
+ 0 0 5 -1 roll aload pop
+ ] cvx bind forall
+ } bind def
+ } if
+ } if
+ cleartomark
+ /anyColor?
+ {
+ add add add 0 ne
+ } bind def
+ /testColor
+ {
+ gsave
+ setcmykcolor currentcmykcolor
+ grestore
+ } bind def
+ /testCMYKColorThrough
+ {
+ testColor anyColor?
+ } bind def
+ userdict /composite?
+ level2?
+ {
+ gsave 1 1 1 1 setcmykcolor currentcmykcolor grestore
+ add add add 4 eq
+ }
+ {
+ 1 0 0 0 testCMYKColorThrough
+ 0 1 0 0 testCMYKColorThrough
+ 0 0 1 0 testCMYKColorThrough
+ 0 0 0 1 testCMYKColorThrough
+ and and and
+ } ifelse
+ put
+ composite? not
+ {
+ userdict begin
+ gsave
+ /cyan? 1 0 0 0 testCMYKColorThrough def
+ /magenta? 0 1 0 0 testCMYKColorThrough def
+ /yellow? 0 0 1 0 testCMYKColorThrough def
+ /black? 0 0 0 1 testCMYKColorThrough def
+ grestore
+ /isCMYKSep? cyan? magenta? yellow? black? or or or def
+ /customColor? isCMYKSep? not def
+ end
+ } if
+ end defaultpacking setpacking
+%%EndResource
+%%BeginResource: procset Adobe_typography_AI5 1.0 1
+%%Title: (Typography Operators)
+%%Version: 1.0
+%%CreationDate:(03/26/93) ()
+%%Copyright: ((C) 1987-1993 Adobe Systems Incorporated All Rights Reserved)
+currentpacking true setpacking
+userdict /Adobe_typography_AI5 54 dict dup begin
+put
+/initialize
+{
+ begin
+ begin
+ Adobe_typography_AI5 begin
+ Adobe_typography_AI5
+ {
+ dup xcheck
+ {
+ bind
+ } if
+ pop pop
+ } forall
+ end
+ end
+ end
+ Adobe_typography_AI5 begin
+} def
+/terminate
+{
+ currentdict Adobe_typography_AI5 eq
+ {
+ end
+ } if
+} def
+/modifyEncoding
+{
+ /_tempEncode exch ddef
+ /_pntr 0 ddef
+ {
+ counttomark -1 roll
+ dup type dup /marktype eq
+ {
+ pop pop exit
+ }
+ {
+ /nametype eq
+ {
+ _tempEncode /_pntr dup load dup 3 1 roll 1 add ddef 3 -1 roll
+ put
+ }
+ {
+ /_pntr exch ddef
+ } ifelse
+ } ifelse
+ } loop
+ _tempEncode
+} def
+/TE
+{
+ StandardEncoding 256 array copy modifyEncoding
+ /_nativeEncoding exch def
+} def
+%
+/TZ
+{
+ dup type /arraytype eq
+ {
+ /_wv exch def
+ }
+ {
+ /_wv 0 def
+ } ifelse
+ /_useNativeEncoding exch def
+ pop pop
+ findfont _wv type /arraytype eq
+ {
+ _wv makeblendedfont
+ } if
+ dup length 2 add dict
+ begin
+ mark exch
+ {
+ 1 index /FID ne
+ {
+ def
+ } if
+ cleartomark mark
+ } forall
+ pop
+ /FontName exch def
+ counttomark 0 eq
+ {
+ 1 _useNativeEncoding eq
+ {
+ /Encoding _nativeEncoding def
+ } if
+ cleartomark
+ }
+ {
+ /Encoding load 256 array copy
+ modifyEncoding /Encoding exch def
+ } ifelse
+ FontName currentdict
+ end
+ definefont pop
+} def
+/tr
+{
+ _ax _ay 3 2 roll
+} def
+/trj
+{
+ _cx _cy _sp _ax _ay 6 5 roll
+} def
+/a0
+{
+ /Tx
+ {
+ dup
+ currentpoint 3 2 roll
+ tr _psf
+ newpath moveto
+ tr _ctm _pss
+ } ddef
+ /Tj
+ {
+ dup
+ currentpoint 3 2 roll
+ trj _pjsf
+ newpath moveto
+ trj _ctm _pjss
+ } ddef
+} def
+/a1
+{
+ /Tx
+ {
+ dup currentpoint 4 2 roll gsave
+ dup currentpoint 3 2 roll
+ tr _psf
+ newpath moveto
+ tr _ctm _pss
+ grestore 3 1 roll moveto tr sp
+ } ddef
+ /Tj
+ {
+ dup currentpoint 4 2 roll gsave
+ dup currentpoint 3 2 roll
+ trj _pjsf
+ newpath moveto
+ trj _ctm _pjss
+ grestore 3 1 roll moveto tr jsp
+ } ddef
+} def
+/e0
+{
+ /Tx
+ {
+ tr _psf
+ } ddef
+ /Tj
+ {
+ trj _pjsf
+ } ddef
+} def
+/e1
+{
+ /Tx
+ {
+ dup currentpoint 4 2 roll gsave
+ tr _psf
+ grestore 3 1 roll moveto tr sp
+ } ddef
+ /Tj
+ {
+ dup currentpoint 4 2 roll gsave
+ trj _pjsf
+ grestore 3 1 roll moveto tr jsp
+ } ddef
+} def
+/i0
+{
+ /Tx
+ {
+ tr sp
+ } ddef
+ /Tj
+ {
+ trj jsp
+ } ddef
+} def
+/i1
+{
+ W N
+} def
+/o0
+{
+ /Tx
+ {
+ tr sw rmoveto
+ } ddef
+ /Tj
+ {
+ trj swj rmoveto
+ } ddef
+} def
+/r0
+{
+ /Tx
+ {
+ tr _ctm _pss
+ } ddef
+ /Tj
+ {
+ trj _ctm _pjss
+ } ddef
+} def
+/r1
+{
+ /Tx
+ {
+ dup currentpoint 4 2 roll currentpoint gsave newpath moveto
+ tr _ctm _pss
+ grestore 3 1 roll moveto tr sp
+ } ddef
+ /Tj
+ {
+ dup currentpoint 4 2 roll currentpoint gsave newpath moveto
+ trj _ctm _pjss
+ grestore 3 1 roll moveto tr jsp
+ } ddef
+} def
+/To
+{
+ pop _ctm currentmatrix pop
+} def
+/TO
+{
+ iTe _ctm setmatrix newpath
+} def
+/Tp
+{
+ pop _tm astore pop _ctm setmatrix
+ _tDict begin
+ /W
+ {
+ } def
+ /h
+ {
+ } def
+} def
+/TP
+{
+ end
+ iTm 0 0 moveto
+} def
+/Tr
+{
+ _render 3 le
+ {
+ currentpoint newpath moveto
+ } if
+ dup 8 eq
+ {
+ pop 0
+ }
+ {
+ dup 9 eq
+ {
+ pop 1
+ } if
+ } ifelse
+ dup /_render exch ddef
+ _renderStart exch get load exec
+} def
+/iTm
+{
+ _ctm setmatrix _tm concat 0 _rise translate _hs 1 scale
+} def
+/Tm
+{
+ _tm astore pop iTm 0 0 moveto
+} def
+/Td
+{
+ _mtx translate _tm _tm concatmatrix pop iTm 0 0 moveto
+} def
+/iTe
+{
+ _render -1 eq
+ {
+ }
+ {
+ _renderEnd _render get dup null ne
+ {
+ load exec
+ }
+ {
+ pop
+ } ifelse
+ } ifelse
+ /_render -1 ddef
+} def
+/Ta
+{
+ pop
+} def
+/Tf
+{
+ dup 1000 div /_fScl exch ddef
+%
+ selectfont
+} def
+/Tl
+{
+ pop
+ 0 exch _leading astore pop
+} def
+/Tt
+{
+ pop
+} def
+/TW
+{
+ 3 npop
+} def
+/Tw
+{
+ /_cx exch ddef
+} def
+/TC
+{
+ 3 npop
+} def
+/Tc
+{
+ /_ax exch ddef
+} def
+/Ts
+{
+ /_rise exch ddef
+ currentpoint
+ iTm
+ moveto
+} def
+/Ti
+{
+ 3 npop
+} def
+/Tz
+{
+ 100 div /_hs exch ddef
+ iTm
+} def
+/TA
+{
+ pop
+} def
+/Tq
+{
+ pop
+} def
+/Th
+{
+ pop pop pop pop pop
+} def
+/TX
+{
+ pop
+} def
+/Tk
+{
+ exch pop _fScl mul neg 0 rmoveto
+} def
+/TK
+{
+ 2 npop
+} def
+/T*
+{
+ _leading aload pop neg Td
+} def
+/T*-
+{
+ _leading aload pop Td
+} def
+/T-
+{
+ _ax neg 0 rmoveto
+ _hyphen Tx
+} def
+/T+
+{
+} def
+/TR
+{
+ _ctm currentmatrix pop
+ _tm astore pop
+ iTm 0 0 moveto
+} def
+/TS
+{
+ currentfont 3 1 roll
+ /_Symbol_ _fScl 1000 mul selectfont
+
+ 0 eq
+ {
+ Tx
+ }
+ {
+ Tj
+ } ifelse
+ setfont
+} def
+/Xb
+{
+ pop pop
+} def
+/Tb /Xb load def
+/Xe
+{
+ pop pop pop pop
+} def
+/Te /Xe load def
+/XB
+{
+} def
+/TB /XB load def
+currentdict readonly pop
+end
+setpacking
+%%EndResource
+%%BeginProcSet: Adobe_ColorImage_AI6 1.0 0
+userdict /Adobe_ColorImage_AI6 known not
+{
+ userdict /Adobe_ColorImage_AI6 17 dict put
+} if
+userdict /Adobe_ColorImage_AI6 get begin
+
+ /initialize
+ {
+ Adobe_ColorImage_AI6 begin
+ Adobe_ColorImage_AI6
+ {
+ dup type /arraytype eq
+ {
+ dup xcheck
+ {
+ bind
+ } if
+ } if
+ pop pop
+ } forall
+ } def
+ /terminate { end } def
+
+ currentdict /Adobe_ColorImage_AI6_Vars known not
+ {
+ /Adobe_ColorImage_AI6_Vars 14 dict def
+ } if
+
+ Adobe_ColorImage_AI6_Vars begin
+ /channelcount 0 def
+ /sourcecount 0 def
+ /sourcearray 4 array def
+ /plateindex -1 def
+ /XIMask 0 def
+ /XIBinary 0 def
+ /XIChannelCount 0 def
+ /XIBitsPerPixel 0 def
+ /XIImageHeight 0 def
+ /XIImageWidth 0 def
+ /XIImageMatrix null def
+ /XIBuffer null def
+ /XIDataProc null def
+ end
+
+ /WalkRGBString null def
+ /WalkCMYKString null def
+
+ /StuffRGBIntoGrayString null def
+ /RGBToGrayImageProc null def
+ /StuffCMYKIntoGrayString null def
+ /CMYKToGrayImageProc null def
+ /ColorImageCompositeEmulator null def
+
+ /SeparateCMYKImageProc null def
+
+ /FourEqual null def
+ /TestPlateIndex null def
+
+ currentdict /_colorimage known not
+ {
+ /colorimage where
+ {
+ /colorimage get /_colorimage exch def
+ }
+ {
+ /_colorimage null def
+ } ifelse
+ } if
+
+ /_currenttransfer systemdict /currenttransfer get def
+
+ /colorimage null def
+ /XI null def
+
+
+ /WalkRGBString
+ {
+ 0 3 index
+
+ dup length 1 sub 0 3 3 -1 roll
+ {
+ 3 getinterval { } forall
+
+ 5 index exec
+
+ 3 index
+ } for
+
+ 5 { pop } repeat
+
+ } def
+
+
+ /WalkCMYKString
+ {
+ 0 3 index
+
+ dup length 1 sub 0 4 3 -1 roll
+ {
+ 4 getinterval { } forall
+
+ 6 index exec
+
+ 3 index
+
+ } for
+
+ 5 { pop } repeat
+
+ } def
+
+
+ /StuffRGBIntoGrayString
+ {
+ .11 mul exch
+
+ .59 mul add exch
+
+ .3 mul add
+
+ cvi 3 copy put
+
+ pop 1 add
+ } def
+
+
+ /RGBToGrayImageProc
+ {
+ Adobe_ColorImage_AI6_Vars begin
+ sourcearray 0 get exec
+ dup length 3 idiv string
+ dup 3 1 roll
+
+ /StuffRGBIntoGrayString load exch
+ WalkRGBString
+ end
+ } def
+
+
+ /StuffCMYKIntoGrayString
+ {
+ exch .11 mul add
+
+ exch .59 mul add
+
+ exch .3 mul add
+
+ dup 255 gt { pop 255 } if
+
+ 255 exch sub cvi 3 copy put
+
+ pop 1 add
+ } def
+
+
+ /CMYKToGrayImageProc
+ {
+ Adobe_ColorImage_AI6_Vars begin
+ sourcearray 0 get exec
+ dup length 4 idiv string
+ dup 3 1 roll
+
+ /StuffCMYKIntoGrayString load exch
+ WalkCMYKString
+ end
+ } def
+
+
+ /ColorImageCompositeEmulator
+ {
+ pop true eq
+ {
+ Adobe_ColorImage_AI6_Vars /sourcecount get 5 add { pop } repeat
+ }
+ {
+ Adobe_ColorImage_AI6_Vars /channelcount get 1 ne
+ {
+ Adobe_ColorImage_AI6_Vars begin
+ sourcearray 0 3 -1 roll put
+
+ channelcount 3 eq
+ {
+ /RGBToGrayImageProc
+ }
+ {
+ /CMYKToGrayImageProc
+ } ifelse
+ load
+ end
+ } if
+ image
+ } ifelse
+ } def
+
+
+ /SeparateCMYKImageProc
+ {
+ Adobe_ColorImage_AI6_Vars begin
+
+ sourcecount 0 ne
+ {
+ sourcearray plateindex get exec
+ }
+ {
+ sourcearray 0 get exec
+
+ dup length 4 idiv string
+
+ 0 2 index
+
+ plateindex 4 2 index length 1 sub
+ {
+ get 255 exch sub
+
+ 3 copy put pop 1 add
+
+ 2 index
+ } for
+
+ pop pop exch pop
+ } ifelse
+ end
+ } def
+
+
+ /FourEqual
+ {
+ 4 index ne
+ {
+ pop pop pop false
+ }
+ {
+ 4 index ne
+ {
+ pop pop false
+ }
+ {
+ 4 index ne
+ {
+ pop false
+ }
+ {
+ 4 index eq
+ } ifelse
+ } ifelse
+ } ifelse
+ } def
+
+
+ /TestPlateIndex
+ {
+ Adobe_ColorImage_AI6_Vars begin
+ /plateindex -1 def
+
+ /setcmykcolor where
+ {
+ pop
+ gsave
+ 1 0 0 0 setcmykcolor systemdict /currentgray get exec 1 exch sub
+ 0 1 0 0 setcmykcolor systemdict /currentgray get exec 1 exch sub
+ 0 0 1 0 setcmykcolor systemdict /currentgray get exec 1 exch sub
+ 0 0 0 1 setcmykcolor systemdict /currentgray get exec 1 exch sub
+ grestore
+
+ 1 0 0 0 FourEqual
+ {
+ /plateindex 0 def
+ }
+ {
+ 0 1 0 0 FourEqual
+ {
+ /plateindex 1 def
+ }
+ {
+ 0 0 1 0 FourEqual
+ {
+ /plateindex 2 def
+ }
+ {
+ 0 0 0 1 FourEqual
+ {
+ /plateindex 3 def
+ }
+ {
+ 0 0 0 0 FourEqual
+ {
+ /plateindex 5 def
+ } if
+ } ifelse
+ } ifelse
+ } ifelse
+ } ifelse
+ pop pop pop pop
+ } if
+ plateindex
+ end
+ } def
+
+
+ /colorimage
+ {
+ Adobe_ColorImage_AI6_Vars begin
+ /channelcount 1 index def
+ /sourcecount 2 index 1 eq { channelcount 1 sub } { 0 } ifelse def
+
+ 4 sourcecount add index dup
+ 8 eq exch 1 eq or not
+ end
+
+ {
+ /_colorimage load null ne
+ {
+ _colorimage
+ }
+ {
+ Adobe_ColorImage_AI6_Vars /sourcecount get
+ 7 add { pop } repeat
+ } ifelse
+ }
+ {
+ dup 3 eq
+ TestPlateIndex
+ dup -1 eq exch 5 eq or or
+ {
+ /_colorimage load null eq
+ {
+ ColorImageCompositeEmulator
+ }
+ {
+ dup 1 eq
+ {
+ pop pop image
+ }
+ {
+ Adobe_ColorImage_AI6_Vars /plateindex get 5 eq
+ {
+ gsave
+
+ 0 _currenttransfer exec
+ 1 _currenttransfer exec
+ eq
+ { 0 _currenttransfer exec 0.5 lt }
+ { 0 _currenttransfer exec 1 _currenttransfer exec gt } ifelse
+
+ { { pop 0 } } { { pop 1 } } ifelse
+ systemdict /settransfer get exec
+ } if
+
+ _colorimage
+
+ Adobe_ColorImage_AI6_Vars /plateindex get 5 eq
+ {
+ grestore
+ } if
+ } ifelse
+ } ifelse
+ }
+ {
+ dup 1 eq
+ {
+ pop pop
+ image
+ }
+ {
+ pop pop
+
+ Adobe_ColorImage_AI6_Vars begin
+ sourcecount -1 0
+ {
+ exch sourcearray 3 1 roll put
+ } for
+
+ /SeparateCMYKImageProc load
+ end
+
+ systemdict /image get exec
+ } ifelse
+ } ifelse
+ } ifelse
+ } def
+
+ /XI
+ {
+ Adobe_ColorImage_AI6_Vars begin
+ gsave
+ /XIMask exch 0 ne def
+ /XIBinary exch 0 ne def
+ pop
+ pop
+ /XIChannelCount exch def
+ /XIBitsPerPixel exch def
+ /XIImageHeight exch def
+ /XIImageWidth exch def
+ pop pop pop pop
+ /XIImageMatrix exch def
+
+ XIBitsPerPixel 1 eq
+ {
+ XIImageWidth 8 div ceiling cvi
+ }
+ {
+ XIImageWidth XIChannelCount mul
+ } ifelse
+ /XIBuffer exch string def
+
+ XIBinary
+ {
+ /XIDataProc { currentfile XIBuffer readstring pop } def
+ currentfile 128 string readline pop pop
+ }
+ {
+ /XIDataProc { currentfile XIBuffer readhexstring pop } def
+ } ifelse
+
+ 0 0 moveto
+ XIImageMatrix concat
+ XIImageWidth XIImageHeight scale
+
+ XIMask
+ {
+ XIImageWidth XIImageHeight
+ false
+ [ XIImageWidth 0 0 XIImageHeight neg 0 0 ]
+ /XIDataProc load
+
+ /_lp /null ddef
+ _fc
+ /_lp /imagemask ddef
+
+ imagemask
+ }
+ {
+ XIImageWidth XIImageHeight
+ XIBitsPerPixel
+ [ XIImageWidth 0 0 XIImageHeight neg 0 0 ]
+ /XIDataProc load
+
+ XIChannelCount 1 eq
+ {
+
+ gsave
+ 0 setgray
+
+ image
+
+ grestore
+ }
+ {
+ false
+ XIChannelCount
+ colorimage
+ } ifelse
+ } ifelse
+ grestore
+ end
+ } def
+
+end
+%%EndProcSet
+%%BeginResource: procset Adobe_Illustrator_AI5 1.1 0
+%%Title: (Adobe Illustrator (R) Version 5.0 Full Prolog)
+%%Version: 1.1
+%%CreationDate: (3/7/1994) ()
+%%Copyright: ((C) 1987-1994 Adobe Systems Incorporated All Rights Reserved)
+currentpacking true setpacking
+userdict /Adobe_Illustrator_AI5_vars 81 dict dup begin
+put
+/_eo false def
+/_lp /none def
+/_pf
+{
+} def
+/_ps
+{
+} def
+/_psf
+{
+} def
+/_pss
+{
+} def
+/_pjsf
+{
+} def
+/_pjss
+{
+} def
+/_pola 0 def
+/_doClip 0 def
+/cf currentflat def
+/_tm matrix def
+/_renderStart
+[
+/e0 /r0 /a0 /o0 /e1 /r1 /a1 /i0
+] def
+/_renderEnd
+[
+null null null null /i1 /i1 /i1 /i1
+] def
+/_render -1 def
+/_rise 0 def
+/_ax 0 def
+/_ay 0 def
+/_cx 0 def
+/_cy 0 def
+/_leading
+[
+0 0
+] def
+/_ctm matrix def
+/_mtx matrix def
+/_sp 16#020 def
+/_hyphen (-) def
+/_fScl 0 def
+/_cnt 0 def
+/_hs 1 def
+/_nativeEncoding 0 def
+/_useNativeEncoding 0 def
+/_tempEncode 0 def
+/_pntr 0 def
+/_tDict 2 dict def
+/_wv 0 def
+/Tx
+{
+} def
+/Tj
+{
+} def
+/CRender
+{
+} def
+/_AI3_savepage
+{
+} def
+/_gf null def
+/_cf 4 array def
+/_if null def
+/_of false def
+/_fc
+{
+} def
+/_gs null def
+/_cs 4 array def
+/_is null def
+/_os false def
+/_sc
+{
+} def
+/_pd 1 dict def
+/_ed 15 dict def
+/_pm matrix def
+/_fm null def
+/_fd null def
+/_fdd null def
+/_sm null def
+/_sd null def
+/_sdd null def
+/_i null def
+/discardSave null def
+/buffer 256 string def
+/beginString null def
+/endString null def
+/endStringLength null def
+/layerCnt 1 def
+/layerCount 1 def
+/perCent (%) 0 get def
+/perCentSeen? false def
+/newBuff null def
+/newBuffButFirst null def
+/newBuffLast null def
+/clipForward? false def
+end
+userdict /Adobe_Illustrator_AI5 known not {
+ userdict /Adobe_Illustrator_AI5 91 dict put
+} if
+userdict /Adobe_Illustrator_AI5 get begin
+/initialize
+{
+ Adobe_Illustrator_AI5 dup begin
+ Adobe_Illustrator_AI5_vars begin
+ discardDict
+ {
+ bind pop pop
+ } forall
+ dup /nc get begin
+ {
+ dup xcheck 1 index type /operatortype ne and
+ {
+ bind
+ } if
+ pop pop
+ } forall
+ end
+ newpath
+} def
+/terminate
+{
+ end
+ end
+} def
+/_
+null def
+/ddef
+{
+ Adobe_Illustrator_AI5_vars 3 1 roll put
+} def
+/xput
+{
+ dup load dup length exch maxlength eq
+ {
+ dup dup load dup
+ length 2 mul dict copy def
+ } if
+ load begin
+ def
+ end
+} def
+/npop
+{
+ {
+ pop
+ } repeat
+} def
+/sw
+{
+ dup length exch stringwidth
+ exch 5 -1 roll 3 index mul add
+ 4 1 roll 3 1 roll mul add
+} def
+/swj
+{
+ dup 4 1 roll
+ dup length exch stringwidth
+ exch 5 -1 roll 3 index mul add
+ 4 1 roll 3 1 roll mul add
+ 6 2 roll /_cnt 0 ddef
+ {
+ 1 index eq
+ {
+ /_cnt _cnt 1 add ddef
+ } if
+ } forall
+ pop
+ exch _cnt mul exch _cnt mul 2 index add 4 1 roll 2 index add 4 1 roll pop pop
+} def
+/ss
+{
+ 4 1 roll
+ {
+ 2 npop
+ (0) exch 2 copy 0 exch put pop
+ gsave
+ false charpath currentpoint
+ 4 index setmatrix
+ stroke
+ grestore
+ moveto
+ 2 copy rmoveto
+ } exch cshow
+ 3 npop
+} def
+/jss
+{
+ 4 1 roll
+ {
+ 2 npop
+ (0) exch 2 copy 0 exch put
+ gsave
+ _sp eq
+ {
+ exch 6 index 6 index 6 index 5 -1 roll widthshow
+ currentpoint
+ }
+ {
+ false charpath currentpoint
+ 4 index setmatrix stroke
+ } ifelse
+ grestore
+ moveto
+ 2 copy rmoveto
+ } exch cshow
+ 6 npop
+} def
+/sp
+{
+ {
+ 2 npop (0) exch
+ 2 copy 0 exch put pop
+ false charpath
+ 2 copy rmoveto
+ } exch cshow
+ 2 npop
+} def
+/jsp
+{
+ {
+ 2 npop
+ (0) exch 2 copy 0 exch put
+ _sp eq
+ {
+ exch 5 index 5 index 5 index 5 -1 roll widthshow
+ }
+ {
+ false charpath
+ } ifelse
+ 2 copy rmoveto
+ } exch cshow
+ 5 npop
+} def
+/pl
+{
+ transform
+ 0.25 sub round 0.25 add exch
+ 0.25 sub round 0.25 add exch
+ itransform
+} def
+/setstrokeadjust where
+{
+ pop true setstrokeadjust
+ /c
+ {
+ curveto
+ } def
+ /C
+ /c load def
+ /v
+ {
+ currentpoint 6 2 roll curveto
+ } def
+ /V
+ /v load def
+ /y
+ {
+ 2 copy curveto
+ } def
+ /Y
+ /y load def
+ /l
+ {
+ lineto
+ } def
+ /L
+ /l load def
+ /m
+ {
+ moveto
+ } def
+}
+{
+ /c
+ {
+ pl curveto
+ } def
+ /C
+ /c load def
+ /v
+ {
+ currentpoint 6 2 roll pl curveto
+ } def
+ /V
+ /v load def
+ /y
+ {
+ pl 2 copy curveto
+ } def
+ /Y
+ /y load def
+ /l
+ {
+ pl lineto
+ } def
+ /L
+ /l load def
+ /m
+ {
+ pl moveto
+ } def
+} ifelse
+/d
+{
+ setdash
+} def
+/cf
+{
+} def
+/i
+{
+ dup 0 eq
+ {
+ pop cf
+ } if
+ setflat
+} def
+/j
+{
+ setlinejoin
+} def
+/J
+{
+ setlinecap
+} def
+/M
+{
+ setmiterlimit
+} def
+/w
+{
+ setlinewidth
+} def
+/XR
+{
+ 0 ne
+ /_eo exch ddef
+} def
+/H
+{
+} def
+/h
+{
+ closepath
+} def
+/N
+{
+ _pola 0 eq
+ {
+ _doClip 1 eq
+ {
+ _eo {eoclip} {clip} ifelse /_doClip 0 ddef
+ } if
+ newpath
+ }
+ {
+ /CRender
+ {
+ N
+ } ddef
+ } ifelse
+} def
+/n
+{
+ N
+} def
+/F
+{
+ _pola 0 eq
+ {
+ _doClip 1 eq
+ {
+ gsave _pf grestore _eo {eoclip} {clip} ifelse newpath /_lp /none ddef _fc
+ /_doClip 0 ddef
+ }
+ {
+ _pf
+ } ifelse
+ }
+ {
+ /CRender
+ {
+ F
+ } ddef
+ } ifelse
+} def
+/f
+{
+ closepath
+ F
+} def
+/S
+{
+ _pola 0 eq
+ {
+ _doClip 1 eq
+ {
+ gsave _ps grestore _eo {eoclip} {clip} ifelse newpath /_lp /none ddef _sc
+ /_doClip 0 ddef
+ }
+ {
+ _ps
+ } ifelse
+ }
+ {
+ /CRender
+ {
+ S
+ } ddef
+ } ifelse
+} def
+/s
+{
+ closepath
+ S
+} def
+/B
+{
+ _pola 0 eq
+ {
+ _doClip 1 eq
+ gsave F grestore
+ {
+ gsave S grestore _eo {eoclip} {clip} ifelse newpath /_lp /none ddef _sc
+ /_doClip 0 ddef
+ }
+ {
+ S
+ } ifelse
+ }
+ {
+ /CRender
+ {
+ B
+ } ddef
+ } ifelse
+} def
+/b
+{
+ closepath
+ B
+} def
+/W
+{
+ /_doClip 1 ddef
+} def
+/*
+{
+ count 0 ne
+ {
+ dup type /stringtype eq
+ {
+ pop
+ } if
+ } if
+ newpath
+} def
+/u
+{
+} def
+/U
+{
+} def
+/q
+{
+ _pola 0 eq
+ {
+ gsave
+ } if
+} def
+/Q
+{
+ _pola 0 eq
+ {
+ grestore
+ } if
+} def
+/*u
+{
+ _pola 1 add /_pola exch ddef
+} def
+/*U
+{
+ _pola 1 sub /_pola exch ddef
+ _pola 0 eq
+ {
+ CRender
+ } if
+} def
+/D
+{
+ pop
+} def
+/*w
+{
+} def
+/*W
+{
+} def
+/`
+{
+ /_i save ddef
+ clipForward?
+ {
+ nulldevice
+ } if
+ 6 1 roll 4 npop
+ concat pop
+ userdict begin
+ /showpage
+ {
+ } def
+ 0 setgray
+ 0 setlinecap
+ 1 setlinewidth
+ 0 setlinejoin
+ 10 setmiterlimit
+ [] 0 setdash
+ /setstrokeadjust where {pop false setstrokeadjust} if
+ newpath
+ 0 setgray
+ false setoverprint
+} def
+/~
+{
+ end
+ _i restore
+} def
+/O
+{
+ 0 ne
+ /_of exch ddef
+ /_lp /none ddef
+} def
+/R
+{
+ 0 ne
+ /_os exch ddef
+ /_lp /none ddef
+} def
+/g
+{
+ /_gf exch ddef
+ /_fc
+ {
+ _lp /fill ne
+ {
+ _of setoverprint
+ _gf setgray
+ /_lp /fill ddef
+ } if
+ } ddef
+ /_pf
+ {
+ _fc
+ _eo {eofill} {fill} ifelse
+ } ddef
+ /_psf
+ {
+ _fc
+ ashow
+ } ddef
+ /_pjsf
+ {
+ _fc
+ awidthshow
+ } ddef
+ /_lp /none ddef
+} def
+/G
+{
+ /_gs exch ddef
+ /_sc
+ {
+ _lp /stroke ne
+ {
+ _os setoverprint
+ _gs setgray
+ /_lp /stroke ddef
+ } if
+ } ddef
+ /_ps
+ {
+ _sc
+ stroke
+ } ddef
+ /_pss
+ {
+ _sc
+ ss
+ } ddef
+ /_pjss
+ {
+ _sc
+ jss
+ } ddef
+ /_lp /none ddef
+} def
+/k
+{
+ _cf astore pop
+ /_fc
+ {
+ _lp /fill ne
+ {
+ _of setoverprint
+ _cf aload pop setcmykcolor
+ /_lp /fill ddef
+ } if
+ } ddef
+ /_pf
+ {
+ _fc
+ _eo {eofill} {fill} ifelse
+ } ddef
+ /_psf
+ {
+ _fc
+ ashow
+ } ddef
+ /_pjsf
+ {
+ _fc
+ awidthshow
+ } ddef
+ /_lp /none ddef
+} def
+/K
+{
+ _cs astore pop
+ /_sc
+ {
+ _lp /stroke ne
+ {
+ _os setoverprint
+ _cs aload pop setcmykcolor
+ /_lp /stroke ddef
+ } if
+ } ddef
+ /_ps
+ {
+ _sc
+ stroke
+ } ddef
+ /_pss
+ {
+ _sc
+ ss
+ } ddef
+ /_pjss
+ {
+ _sc
+ jss
+ } ddef
+ /_lp /none ddef
+} def
+/x
+{
+ /_gf exch ddef
+ findcmykcustomcolor
+ /_if exch ddef
+ /_fc
+ {
+ _lp /fill ne
+ {
+ _of setoverprint
+ _if _gf 1 exch sub setcustomcolor
+ /_lp /fill ddef
+ } if
+ } ddef
+ /_pf
+ {
+ _fc
+ _eo {eofill} {fill} ifelse
+ } ddef
+ /_psf
+ {
+ _fc
+ ashow
+ } ddef
+ /_pjsf
+ {
+ _fc
+ awidthshow
+ } ddef
+ /_lp /none ddef
+} def
+/X
+{
+ /_gs exch ddef
+ findcmykcustomcolor
+ /_is exch ddef
+ /_sc
+ {
+ _lp /stroke ne
+ {
+ _os setoverprint
+ _is _gs 1 exch sub setcustomcolor
+ /_lp /stroke ddef
+ } if
+ } ddef
+ /_ps
+ {
+ _sc
+ stroke
+ } ddef
+ /_pss
+ {
+ _sc
+ ss
+ } ddef
+ /_pjss
+ {
+ _sc
+ jss
+ } ddef
+ /_lp /none ddef
+} def
+/A
+{
+ pop
+} def
+/annotatepage
+{
+userdict /annotatepage 2 copy known {get exec} {pop pop} ifelse
+} def
+/XT {
+ pop pop
+} def
+/discard
+{
+ save /discardSave exch store
+ discardDict begin
+ /endString exch store
+ gt38?
+ {
+ 2 add
+ } if
+ load
+ stopped
+ pop
+ end
+ discardSave restore
+} bind def
+userdict /discardDict 7 dict dup begin
+put
+/pre38Initialize
+{
+ /endStringLength endString length store
+ /newBuff buffer 0 endStringLength getinterval store
+ /newBuffButFirst newBuff 1 endStringLength 1 sub getinterval store
+ /newBuffLast newBuff endStringLength 1 sub 1 getinterval store
+} def
+/shiftBuffer
+{
+ newBuff 0 newBuffButFirst putinterval
+ newBuffLast 0
+ currentfile read not
+ {
+ stop
+ } if
+ put
+} def
+0
+{
+ pre38Initialize
+ mark
+ currentfile newBuff readstring exch pop
+ {
+ {
+ newBuff endString eq
+ {
+ cleartomark stop
+ } if
+ shiftBuffer
+ } loop
+ }
+ {
+ stop
+ } ifelse
+} def
+1
+{
+ pre38Initialize
+ /beginString exch store
+ mark
+ currentfile newBuff readstring exch pop
+ {
+ {
+ newBuff beginString eq
+ {
+ /layerCount dup load 1 add store
+ }
+ {
+ newBuff endString eq
+ {
+ /layerCount dup load 1 sub store
+ layerCount 0 eq
+ {
+ cleartomark stop
+ } if
+ } if
+ } ifelse
+ shiftBuffer
+ } loop
+ } if
+} def
+2
+{
+ mark
+ {
+ currentfile buffer readline not
+ {
+ stop
+ } if
+ endString eq
+ {
+ cleartomark stop
+ } if
+ } loop
+} def
+3
+{
+ /beginString exch store
+ /layerCnt 1 store
+ mark
+ {
+ currentfile buffer readline not
+ {
+ stop
+ } if
+ dup beginString eq
+ {
+ pop /layerCnt dup load 1 add store
+ }
+ {
+ endString eq
+ {
+ layerCnt 1 eq
+ {
+ cleartomark stop
+ }
+ {
+ /layerCnt dup load 1 sub store
+ } ifelse
+ } if
+ } ifelse
+ } loop
+} def
+end
+userdict /clipRenderOff 15 dict dup begin
+put
+{
+ /n /N /s /S /f /F /b /B
+}
+{
+ {
+ _doClip 1 eq
+ {
+ /_doClip 0 ddef _eo {eoclip} {clip} ifelse
+ } if
+ newpath
+ } def
+} forall
+/Tr /pop load def
+/Bb {} def
+/BB /pop load def
+/Bg {12 npop} def
+/Bm {6 npop} def
+/Bc /Bm load def
+/Bh {4 npop} def
+end
+/Lb
+{
+ 4 npop
+ 6 1 roll
+ pop
+ 4 1 roll
+ pop pop pop
+ 0 eq
+ {
+ 0 eq
+ {
+ (%AI5_BeginLayer) 1 (%AI5_EndLayer--) discard
+ }
+ {
+
+ /clipForward? true def
+
+ /Tx /pop load def
+ /Tj /pop load def
+
+ currentdict end clipRenderOff begin begin
+ } ifelse
+ }
+ {
+ 0 eq
+ {
+ save /discardSave exch store
+ } if
+ } ifelse
+} bind def
+/LB
+{
+ discardSave dup null ne
+ {
+ restore
+ }
+ {
+ pop
+ clipForward?
+ {
+ currentdict
+ end
+ end
+ begin
+
+ /clipForward? false ddef
+ } if
+ } ifelse
+} bind def
+/Pb
+{
+ pop pop
+ 0 (%AI5_EndPalette) discard
+} bind def
+/Np
+{
+ 0 (%AI5_End_NonPrinting--) discard
+} bind def
+/Ln /pop load def
+/Ap
+/pop load def
+/Ar
+{
+ 72 exch div
+ 0 dtransform dup mul exch dup mul add sqrt
+ dup 1 lt
+ {
+ pop 1
+ } if
+ setflat
+} def
+/Mb
+{
+ q
+} def
+/Md
+{
+} def
+/MB
+{
+ Q
+} def
+/nc 3 dict def
+nc begin
+/setgray
+{
+ pop
+} bind def
+/setcmykcolor
+{
+ 4 npop
+} bind def
+/setcustomcolor
+{
+ 2 npop
+} bind def
+currentdict readonly pop
+end
+end
+setpacking
+%%EndResource
+%%EndProlog
+%%BeginSetup
+%%IncludeFont: Courier
+%%IncludeFont: Univers
+Adobe_level2_AI5 /initialize get exec
+Adobe_Illustrator_AI5_vars Adobe_Illustrator_AI5 Adobe_typography_AI5 /initialize get exec
+Adobe_ColorImage_AI6 /initialize get exec
+Adobe_Illustrator_AI5 /initialize get exec
+[
+39/quotesingle 96/grave 128/Adieresis/Aring/Ccedilla/Eacute/Ntilde/Odieresis
+/Udieresis/aacute/agrave/acircumflex/adieresis/atilde/aring/ccedilla/eacute
+/egrave/ecircumflex/edieresis/iacute/igrave/icircumflex/idieresis/ntilde
+/oacute/ograve/ocircumflex/odieresis/otilde/uacute/ugrave/ucircumflex
+/udieresis/dagger/degree/cent/sterling/section/bullet/paragraph/germandbls
+/registered/copyright/trademark/acute/dieresis/.notdef/AE/Oslash
+/.notdef/plusminus/.notdef/.notdef/yen/mu/.notdef/.notdef
+/.notdef/.notdef/.notdef/ordfeminine/ordmasculine/.notdef/ae/oslash
+/questiondown/exclamdown/logicalnot/.notdef/florin/.notdef/.notdef
+/guillemotleft/guillemotright/ellipsis/.notdef/Agrave/Atilde/Otilde/OE/oe
+/endash/emdash/quotedblleft/quotedblright/quoteleft/quoteright/divide
+/.notdef/ydieresis/Ydieresis/fraction/currency/guilsinglleft/guilsinglright
+/fi/fl/daggerdbl/periodcentered/quotesinglbase/quotedblbase/perthousand
+/Acircumflex/Ecircumflex/Aacute/Edieresis/Egrave/Iacute/Icircumflex
+/Idieresis/Igrave/Oacute/Ocircumflex/.notdef/Ograve/Uacute/Ucircumflex
+/Ugrave/dotlessi/circumflex/tilde/macron/breve/dotaccent/ring/cedilla
+/hungarumlaut/ogonek/caron
+TE
+%AI3_BeginEncoding: _Courier Courier
+[/_Courier/Courier 0 0 1 TZ
+%AI3_EndEncoding TrueType
+%AI3_BeginEncoding: _Univers Univers
+[/_Univers/Univers 0 0 1 TZ
+%AI3_EndEncoding AdobeType
+%AI5_Begin_NonPrinting
+Np
+8 Bn
+%AI5_BeginGradient: (Black & White)
+(Black & White) 0 2 Bd
+[
+<
+FFFEFDFCFBFAF9F8F7F6F5F4F3F2F1F0EFEEEDECEBEAE9E8E7E6E5E4E3E2E1E0DFDEDDDCDBDAD9D8
+D7D6D5D4D3D2D1D0CFCECDCCCBCAC9C8C7C6C5C4C3C2C1C0BFBEBDBCBBBAB9B8B7B6B5B4B3B2B1B0
+AFAEADACABAAA9A8A7A6A5A4A3A2A1A09F9E9D9C9B9A999897969594939291908F8E8D8C8B8A8988
+87868584838281807F7E7D7C7B7A797877767574737271706F6E6D6C6B6A69686766656463626160
+5F5E5D5C5B5A595857565554535251504F4E4D4C4B4A494847464544434241403F3E3D3C3B3A3938
+37363534333231302F2E2D2C2B2A292827262524232221201F1E1D1C1B1A19181716151413121110
+0F0E0D0C0B0A09080706050403020100
+>
+0 %_Br
+[
+0 0 50 100 %_Bs
+1 0 50 0 %_Bs
+BD
+%AI5_EndGradient
+%AI5_BeginGradient: (Green & Blue)
+(Green & Blue) 0 2 Bd
+[
+<
+99999A9A9B9B9B9C9C9D9D9D9E9E9F9F9FA0A0A1A1A1A2A2A3A3A3A4A4A5A5A5A6A6A7A7A7A8A8A9
+A9A9AAAAABABABACACADADADAEAEAFAFAFB0B0B1B1B1B2B2B3B3B3B4B4B5B5B5B6B6B7B7B7B8B8B9
+B9B9BABABBBBBBBCBCBDBDBDBEBEBFBFBFC0C0C1C1C1C2C2C3C3C3C4C4C5C5C5C6C6C7C7C7C8C8C9
+C9C9CACACBCBCBCCCCCDCDCDCECECFCFCFD0D0D1D1D1D2D2D3D3D3D4D4D5D5D5D6D6D7D7D7D8D8D9
+D9D9DADADBDBDBDCDCDDDDDDDEDEDFDFDFE0E0E1E1E1E2E2E3E3E3E4E4E5E5E5E6E6E7E7E7E8E8E9
+E9E9EAEAEBEBEBECECEDEDEDEEEEEFEFEFF0F0F1F1F1F2F2F3F3F3F4F4F5F5F5F6F6F7F7F7F8F8F9
+F9F9FAFAFBFBFBFCFCFDFDFDFEFEFFFF
+>
+<
+000102020304050506070808090A0B0B0C0D0E0E0F101111121314141516171718191A1A1B1C1D1D
+1E1F20202122232324252626272829292A2B2C2C2D2E2F2F303132323334353536373838393A3B3B
+3C3D3E3E3F404141424344444546474748494A4A4B4C4D4D4E4F5050515253535455565657585959
+5A5B5C5C5D5E5F5F606162626364656566676868696A6B6B6C6D6E6E6F7071717273747475767777
+78797A7A7B7C7D7D7E7F80808182828384858586878888898A8B8B8C8D8E8E8F9091919293949495
+96979798999A9A9B9C9D9D9E9FA0A0A1A2A3A3A4A5A6A6A7A8A9A9AAABACACADAEAFAFB0B1B2B2B3
+B4B5B5B6B7B8B8B9BABBBBBCBDBEBEBF
+>
+<
+FFFEFDFCFBFAF9F8F7F6F5F4F3F2F1F0EFEEEDECEBEAE9E8E7E6E5E4E3E2E1E0DFDEDDDCDBDAD9D8
+D7D6D5D4D3D2D1D0CFCECDCCCBCAC9C8C7C6C5C4C3C2C1C0BFBEBDBCBBBAB9B8B7B6B5B4B3B2B1B0
+AFAEADACABAAA9A8A7A6A5A4A3A2A1A09F9E9D9C9B9A999897969594939291908F8E8D8C8B8A8988
+87868584838281807F7E7D7C7B7A797877767574737271706F6E6D6C6B6A69686766656463626160
+5F5E5D5C5B5A595857565554535251504F4E4D4C4B4A494847464544434241403F3E3D3C3B3A3938
+37363534333231302F2E2D2C2B2A292827262524232221201F1E1D1C1B1A19181716151413121110
+0F0E0D0C0B0A09080706050403020100
+>
+0
+1 %_Br
+[
+1 0.75 0 0 1 50 100 %_Bs
+0.6 0 1 0 1 50 0 %_Bs
+BD
+%AI5_EndGradient
+%AI5_BeginGradient: (Pink, Yellow, Green)
+(Pink, Yellow, Green) 0 3 Bd
+[
+<
+00000000000000000000000000000000000000010101010101010101010101010101010101010101
+01010101010202020202020202020202020202020202020202020203030303030303030303030303
+03030303030303030404040404040404040404040404040404040404050505050505050505050505
+05050505050505060606060606060606060606060606060606060707070707070707070707070707
+07070707080808080808080808080808080808080809090909090909090909090909090909090A0A
+0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0C0C0C0C0C0C0C0C0C
+0C0C0C0C0C0C0C0D0D0D0D0D
+>
+<
+050506060606070708080809090A0A0A0B0B0C0C0D0D0E0E0F0F1010111112121313141415151617
+17181819191A1A1B1C1C1D1D1E1F1F202021222223232425252626272828292A2A2B2C2C2D2D2E2F
+2F3031313233333435353637373839393A3B3B3C3D3E3E3F4040414242434445454647474849494A
+4B4C4C4D4E4F4F505151525354545556575758595A5A5B5C5C5D5E5F5F6061626363646566666768
+69696A6B6C6C6D6E6F707071727373747576777778797A7B7B7C7D7E7F7F80818283838485868787
+88898A8B8B8C8D8E8F8F9091929394949596979898999A9B9C9D9D9E9FA0A1A2A2A3A4A5A6A7A7A8
+A9AAABACADADAEAFB0B1B2B2
+>
+<
+CCCCCBCBCBCACACAC9C9C8C8C7C7C6C6C5C5C4C4C3C2C2C1C1C0C0BFBEBEBDBDBCBBBBBAB9B9B8B7
+B7B6B6B5B4B4B3B2B1B1B0AFAFAEADADACABAAAAA9A8A8A7A6A5A5A4A3A2A2A1A0A09F9E9D9C9C9B
+9A999998979696959493929291908F8E8E8D8C8B8A8A8988878686858483828181807F7E7D7C7C7B
+7A7978777776757473727171706F6E6D6C6B6A6A69686766656463636261605F5E5D5C5B5B5A5958
+5756555453525151504F4E4D4C4B4A49484746464544434241403F3E3D3C3B3A3938383736353433
+3231302F2E2D2C2B2A29282726252423222221201F1E1D1C1B1A191817161514131211100F0E0D0C
+0B0A09080706050403020100
+>
+0
+1 %_Br
+<
+737271706F6E6D6C6B6A696867666564636261605F5E5D5C5B5B5A59585756555453525150504F4E
+4D4C4B4A4949484746454443434241403F3E3E3D3C3B3A3A393837363635343333323130302F2E2D
+2D2C2B2A2A29282827262525242323222121201F1F1E1D1D1C1C1B1A1A1918181717161615141413
+1312121111100F0F0E0E0D0D0C0C0C0B0B0A0A090908080807070606060505050404040303030202
+020201010101010000000000
+>
+<
+00000000000000000000000001010101010101010101010101010101010101010101010102020202
+02020202020202020202020202020202020202020202030303030303030303030303030303030303
+03030303030303030303030303040404040404040404040404040404040404040404040404040404
+04040404040404040404050505050505050505050505050505050505050505050505050505050505
+050505050505050505050505
+>
+<
+BFBFBFC0C0C0C0C0C0C0C0C0C1C1C1C1C1C1C1C1C1C2C2C2C2C2C2C2C2C2C2C3C3C3C3C3C3C3C3C3
+C3C4C4C4C4C4C4C4C4C4C4C5C5C5C5C5C5C5C5C5C5C5C6C6C6C6C6C6C6C6C6C6C6C6C7C7C7C7C7C7
+C7C7C7C7C7C7C8C8C8C8C8C8C8C8C8C8C8C8C8C9C9C9C9C9C9C9C9C9C9C9C9C9C9C9CACACACACACA
+CACACACACACACACACACACBCBCBCBCBCBCBCBCBCBCBCBCBCBCBCBCBCBCBCBCBCBCCCCCCCCCCCCCCCC
+CCCCCCCCCCCCCCCCCCCCCCCC
+>
+0
+1 %_Br
+[
+0.05 0.7 0 0 1 50 100 %_Bs
+0 0.02 0.8 0 1 57 36 %_Bs
+0.45 0 0.75 0 1 37 0 %_Bs
+BD
+%AI5_EndGradient
+%AI5_BeginGradient: (Purple, Red & Yellow)
+(Purple, Red & Yellow) 0 3 Bd
+[
+0
+<
+FFFEFDFCFBFAF9F8F7F6F5F4F3F2F1F0EFEEEDECEBEAE9E8E7E6E5E4E3E2E1E0DFDEDDDCDBDAD9D8
+D7D6D5D4D3D2D1D0CFCECDCCCBCAC9C8C7C6C5C4C3C2C1C0BFBEBDBCBBBAB9B8B7B6B5B4B3B2B1B0
+AFAEADACABAAA9A8A7A6A5A4A3A2A1A09F9E9D9C9B9A999897969594939291908F8E8D8C8B8A8988
+87868584838281807F7E7D7C7B7A797877767574737271706F6E6D6C6B6A69686766656463626160
+5F5E5D5C5B5A595857565554535251504F4E4D4C4B4A494847464544434241403F3E3D3C3B3A3938
+37363534333231302F2E2D2C2B2A292827262524232221201F1E1D1C1B1A19181716151413121110
+0F0E0D0C0B0A
+>
+<
+CCCCCCCDCDCDCDCDCECECECECECFCFCFCFD0D0D0D0D0D1D1D1D1D1D2D2D2D2D2D3D3D3D3D3D4D4D4
+D4D5D5D5D5D5D6D6D6D6D6D7D7D7D7D7D8D8D8D8D8D9D9D9D9DADADADADADBDBDBDBDBDCDCDCDCDC
+DDDDDDDDDDDEDEDEDEDFDFDFDFDFE0E0E0E0E0E1E1E1E1E1E2E2E2E2E2E3E3E3E3E4E4E4E4E4E5E5
+E5E5E5E6E6E6E6E6E7E7E7E7E7E8E8E8E8E9E9E9E9E9EAEAEAEAEAEBEBEBEBEBECECECECECEDEDED
+EDEEEEEEEEEEEFEFEFEFEFF0F0F0F0F0F1F1F1F1F1F2F2F2F2F3F3F3F3F3F4F4F4F4F4F5F5F5F5F5
+F6F6F6F6F6F7F7F7F7F8F8F8F8F8F9F9F9F9F9FAFAFAFAFAFBFBFBFBFBFCFCFCFCFDFDFDFDFDFEFE
+FEFEFEFFFFFF
+>
+0
+1 %_Br
+<
+E5E4E3E2E1E0DFDEDDDCDBDAD9D8D7D6D5D4D3D2D1D0CFCECDCCCBCAC9C8C7C6C5C4C3C2C1C0BFBE
+BDBCBBBAB9B8B7B6B5B4B3B2B1B0AFAEADACABAAA9A8A7A6A5A4A3A2A1A09F9E9D9C9B9A99989796
+9594939291908F8E8D8C8B8A898887868584838281807F7E7D7C7B7A797877767574737271706F6E
+6D6C6B6A696867666564636261605F5E5D5C5B5A595857565554535251504F4E4D4C4B4A49484746
+4544434241403F3E3D3C3B3A393837363534333231302F2E2D2C2B2A292827262524232221201F1E
+1D1C1B1A191817161514131211100F0E0D0C0B0A09080706050403020100
+>
+<
+E5E6E6E6E6E6E6E6E6E7E7E7E7E7E7E7E7E7E8E8E8E8E8E8E8E8E8E9E9E9E9E9E9E9E9E9EAEAEAEA
+EAEAEAEAEAEBEBEBEBEBEBEBEBEBECECECECECECECECECEDEDEDEDEDEDEDEDEDEEEEEEEEEEEEEEEE
+EEEFEFEFEFEFEFEFEFEFF0F0F0F0F0F0F0F0F0F1F1F1F1F1F1F1F1F1F2F2F2F2F2F2F2F2F2F3F3F3
+F3F3F3F3F3F3F4F4F4F4F4F4F4F4F4F5F5F5F5F5F5F5F5F5F6F6F6F6F6F6F6F6F6F7F7F7F7F7F7F7
+F7F7F8F8F8F8F8F8F8F8F8F9F9F9F9F9F9F9F9F9FAFAFAFAFAFAFAFAFAFBFBFBFBFBFBFBFBFBFCFC
+FCFCFCFCFCFCFCFDFDFDFDFDFDFDFDFDFEFEFEFEFEFEFEFEFEFFFFFFFFFF
+>
+<
+00010203040405060708090A0B0C0C0D0E0F10111213141415161718191A1B1C1D1D1E1F20212223
+242525262728292A2B2C2D2D2E2F30313233343535363738393A3B3C3D3D3E3F4041424344454546
+4748494A4B4C4D4E4E4F50515253545556565758595A5B5C5D5E5E5F60616263646566666768696A
+6B6C6D6E6E6F70717273747576767778797A7B7C7D7E7F7F80818283848586878788898A8B8C8D8E
+8F8F90919293949596979798999A9B9C9D9E9F9FA0A1A2A3A4A5A6A7A7A8A9AAABACADAEAFAFB0B1
+B2B3B4B5B6B7B8B8B9BABBBCBDBEBFC0C0C1C2C3C4C5C6C7C8C8C9CACBCC
+>
+0
+1 %_Br
+[
+0 0.04 1 0 1 50 100 %_Bs
+0 1 0.8 0 1 50 50 %_Bs
+0.9 0.9 0 0 1 50 0 %_Bs
+BD
+%AI5_EndGradient
+%AI5_BeginGradient: (Rainbow)
+(Rainbow) 0 6 Bd
+[
+<
+FFFEFDFCFBFAF9F8F7F6F5F4F3F2F1F0EFEEEDECEBEAE9E8E7E6E5E4E3E2E1E0DFDEDDDCDBDAD9D8
+D7D6D5D4D3D2D1D0CFCECDCCCBCAC9C8C7C6C5C4C3C2C1C0BFBEBDBCBBBAB9B8B7B6B5B4B3B2B1B0
+AFAEADACABAAA9A8A7A6A5A4A3A2A1A09F9E9D9C9B9A999897969594939291908F8E8D8C8B8A8988
+87868584838281807F7E7D7C7B7A797877767574737271706F6E6D6C6B6A69686766656463626160
+5F5E5D5C5B5A595857565554535251504F4E4D4C4B4A494847464544434241403F3E3D3C3B3A3938
+37363534333231302F2E2D2C2B2A292827262524232221201F1E1D1C1B1A19181716151413121110
+0F0E0D0C0B0A09080706050403020100
+>
+1
+0
+0
+1 %_Br
+1
+<
+0708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E
+2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F50515253545556
+5758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E
+7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6
+A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7C8C9CACBCCCDCE
+CFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6
+F7F8F9FAFBFCFDFEFF
+>
+0
+0
+1 %_Br
+1
+<
+00000000000000000000000000000000000001010101010101010101010101010101010101010101
+01010101010101010101010101010202020202020202020202020202020202020202020202020202
+02020202020202020202030303030303030303030303030303030303030303030303030303030303
+03030303030304040404040404040404040404040404040404040404040404040404040404040404
+04040505050505050505050505050505050505050505050505050505050505050505050505050606
+06060606060606060606060606060606060606060606060606060606060606060606070707070707
+07070707070707070707070707070707
+>
+<
+FFFEFDFCFBFAF9F8F7F6F5F4F3F2F1F0EFEEEDECEBEAE9E8E7E6E5E4E3E2E1E0DFDEDDDCDBDAD9D8
+D7D6D5D4D3D2D1D0CFCECDCCCBCAC9C8C7C6C5C4C3C2C1C0BFBEBDBCBBBAB9B8B7B6B5B4B3B2B1B0
+AFAEADACABAAA9A8A7A6A5A4A3A2A1A09F9E9D9C9B9A999897969594939291908F8E8D8C8B8A8988
+87868584838281807F7E7D7C7B7A797877767574737271706F6E6D6C6B6A69686766656463626160
+5F5E5D5C5B5A595857565554535251504F4E4D4C4B4A494847464544434241403F3E3D3C3B3A3938
+37363534333231302F2E2D2C2B2A292827262524232221201F1E1D1C1B1A19181716151413121110
+0F0E0D0C0B0A09080706050403020100
+>
+0
+1 %_Br
+<
+000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627
+28292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F
+505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F7071727374757677
+78797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9F
+A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7
+C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEF
+F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF
+>
+0
+1
+0
+1 %_Br
+0
+<
+FFFEFDFCFBFAF9F8F7F6F5F4F3F2F1F0EFEEEDECEBEAE9E8E7E6E5E4E3E2E1E0DFDEDDDCDBDAD9D8
+D7D6D5D4D3D2D1D0CFCECDCCCBCAC9C8C7C6C5C4C3C2C1C0BFBEBDBCBBBAB9B8B7B6B5B4B3B2B1B0
+AFAEADACABAAA9A8A7A6A5A4A3A2A1A09F9E9D9C9B9A999897969594939291908F8E8D8C8B8A8988
+87868584838281807F7E7D7C7B7A797877767574737271706F6E6D6C6B6A69686766656463626160
+5F5E5D5C5B5A595857565554535251504F4E4D4C4B4A494847464544434241403F3E3D3C3B3A3938
+37363534333231302F2E2D2C2B2A292827262524232221201F1E1D1C1B1A19181716151413121110
+0F0E0D0C0B0A09080706050403020100
+>
+1
+0
+1 %_Br
+[
+0 1 0 0 1 50 100 %_Bs
+1 1 0 0 1 50 80 %_Bs
+1 0.0279 0 0 1 50 60 %_Bs
+1 0 1 0 1 50 40 %_Bs
+0 0 1 0 1 50 20 %_Bs
+0 1 1 0 1 50 0 %_Bs
+BD
+%AI5_EndGradient
+%AI5_BeginGradient: (Steel Bar)
+(Steel Bar) 0 3 Bd
+[
+<
+FFFEFDFCFBFAF9F8F7F6F5F4F3F2F1F0EFEEEDECEBEAE9E8E7E6E5E4E3E2E1E0DFDEDDDCDBDAD9D8
+D7D6D5D4D3D2D1D0CFCECDCCCBCAC9C8C7C6C5C4C3C2C1C0BFBEBDBCBBBAB9B8B7B6B5B4B3B2B1B0
+AFAEADACABAAA9A8A7A6A5A4A3A2A1A09F9E9D9C9B9A999897969594939291908F8E8D8C8B8A8988
+87868584838281807F7E7D7C7B7A797877767574737271706F6E6D6C6B6A69686766656463626160
+5F5E5D5C5B5A595857565554535251504F4E4D4C4B4A494847464544434241403F3E3D3C3B3A3938
+37363534333231302F2E2D2C2B2A292827262524232221201F1E1D1C1B1A19181716151413121110
+0F0E0D0C0B0A09080706050403020100
+>
+0 %_Br
+<
+000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627
+28292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F
+505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F7071727374757677
+78797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9F
+A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7
+C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEF
+F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF
+>
+0 %_Br
+[
+0 0 50 100 %_Bs
+1 0 50 70 %_Bs
+0 0 50 0 %_Bs
+BD
+%AI5_EndGradient
+%AI5_BeginGradient: (Yellow & Orange Radial)
+(Yellow & Orange Radial) 1 2 Bd
+[
+0
+<
+0001010203040506060708090A0B0C0C0D0E0F10111213131415161718191A1B1C1D1D1E1F202122
+232425262728292A2B2B2C2D2E2F303132333435363738393A3B3C3D3E3E3F404142434445464748
+494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F60606162636465666768696A6B6C6D6E6F
+707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C
+>
+<
+FFFFFFFFFEFEFEFEFEFEFEFDFDFDFDFDFDFCFCFCFCFCFCFBFBFBFBFBFBFAFAFAFAFAFAF9F9F9F9F9
+F9F8F8F8F8F8F8F7F7F7F7F7F7F6F6F6F6F6F6F5F5F5F5F5F5F4F4F4F4F4F3F3F3F3F3F3F2F2F2F2
+F2F2F1F1F1F1F1F0F0F0F0F0F0EFEFEFEFEFEFEEEEEEEEEEEDEDEDEDEDEDECECECECECEBEBEBEBEB
+EBEAEAEAEAEAE9E9E9E9E9E9E8E8E8E8E8E8E7E7E7E7E7E6E6E6E6E6E5
+>
+0
+1 %_Br
+[
+0 0 1 0 1 52 19 %_Bs
+0 0.55 0.9 0 1 50 100 %_Bs
+BD
+%AI5_EndGradient
+%AI5_BeginGradient: (Yellow & Purple Radial)
+(Yellow & Purple Radial) 1 2 Bd
+[
+<
+000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627
+28292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F
+505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F7071727374757677
+78797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9F
+A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7
+C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEF
+F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF
+>
+<
+1415161718191A1B1C1D1E1F1F202122232425262728292A2A2B2C2D2E2F30313233343536363738
+393A3B3C3D3E3F40414142434445464748494A4B4C4D4D4E4F50515253545556575858595A5B5C5D
+5E5F60616263646465666768696A6B6C6D6E6F6F707172737475767778797A7B7B7C7D7E7F808182
+83848586868788898A8B8C8D8E8F90919292939495969798999A9B9C9D9D9E9FA0A1A2A3A4A5A6A7
+A8A9A9AAABACADAEAFB0B1B2B3B4B4B5B6B7B8B9BABBBCBDBEBFC0C0C1C2C3C4C5C6C7C8C9CACBCB
+CCCDCECFD0D1D2D3D4D5D6D7D7D8D9DADBDCDDDEDFE0E1E2E2E3E4E5E6E7E8E9EAEBECEDEEEEEFF0
+F1F2F3F4F5F6F7F8F9F9FAFBFCFDFEFF
+>
+<
+ABAAAAA9A8A7A7A6A5A5A4A3A3A2A1A1A09F9F9E9D9D9C9B9B9A9999989797969595949393929191
+908F8F8E8D8D8C8B8B8A8989888787868585848383828181807F7F7E7D7D7C7B7B7A797978777776
+7575747373727171706F6F6E6D6D6C6B6B6A6969686767666565646362626160605F5E5E5D5C5C5B
+5A5A5958585756565554545352525150504F4E4E4D4C4C4B4A4A4948484746464544444342424140
+403F3E3E3D3C3C3B3A3A3938383736363534343332323130302F2E2E2D2C2C2B2A2A292828272626
+25242423222121201F1F1E1D1D1C1B1B1A1919181717161515141313121111100F0F0E0D0D0C0B0B
+0A090908070706050504030302010100
+>
+0
+1 %_Br
+[
+0 0.08 0.67 0 1 50 14 %_Bs
+1 1 0 0 1 50 100 %_Bs
+BD
+%AI5_EndGradient
+%AI5_End_NonPrinting--
+%AI5_BeginPalette
+0 0 Pb
+Pn
+Pc
+1 g
+Pc
+0 g
+Pc
+0 0 0 0 k
+Pc
+0.75 g
+Pc
+0.5 g
+Pc
+0.25 g
+Pc
+0 g
+Pc
+Bb
+2 (Black & White) -4014 4716 0 0 1 0 0 1 0 0 Bg
+0 BB
+Pc
+0.25 0 0 0 k
+Pc
+0.5 0 0 0 k
+Pc
+0.75 0 0 0 k
+Pc
+1 0 0 0 k
+Pc
+0.25 0.25 0 0 k
+Pc
+0.5 0.5 0 0 k
+Pc
+0.75 0.75 0 0 k
+Pc
+1 1 0 0 k
+Pc
+Bb
+2 (Pink, Yellow, Green) -4014 4716 0 0 1 0 0 1 0 0 Bg
+0 BB
+Pc
+0 0.25 0 0 k
+Pc
+0 0.5 0 0 k
+Pc
+0 0.75 0 0 k
+Pc
+0 1 0 0 k
+Pc
+0 0.25 0.25 0 k
+Pc
+0 0.5 0.5 0 k
+Pc
+0 0.75 0.75 0 k
+Pc
+0 1 1 0 k
+Pc
+Bb
+0 0 0 0 Bh
+2 (Yellow & Purple Radial) -4014 4716 0 0 1 0 0 1 0 0 Bg
+0 BB
+Pc
+0 0 0.25 0 k
+Pc
+0 0 0.5 0 k
+Pc
+0 0 0.75 0 k
+Pc
+0 0 1 0 k
+Pc
+0.25 0 0.25 0 k
+Pc
+0.5 0 0.5 0 k
+Pc
+0.75 0 0.75 0 k
+Pc
+1 0 1 0 k
+Pc
+Bb
+2 (Rainbow) -4014 4716 0 0 1 0 0 1 0 0 Bg
+0 BB
+Pc
+0.25 0.125 0 0 k
+Pc
+0.5 0.25 0 0 k
+Pc
+0.75 0.375 0 0 k
+Pc
+1 0.5 0 0 k
+Pc
+0.125 0.25 0 0 k
+Pc
+0.25 0.5 0 0 k
+Pc
+0.375 0.75 0 0 k
+Pc
+0.5 1 0 0 k
+Pc
+Bb
+2 (Steel Bar) -4014 4716 0 0 1 0 0 1 0 0 Bg
+0 BB
+Pc
+0 0.25 0.125 0 k
+Pc
+0 0.5 0.25 0 k
+Pc
+0 0.75 0.375 0 k
+Pc
+0 1 0.5 0 k
+Pc
+0 0.125 0.25 0 k
+Pc
+0 0.25 0.5 0 k
+Pc
+0 0.375 0.75 0 k
+Pc
+0 0.5 1 0 k
+Pc
+Bb
+2 (Purple, Red & Yellow) -4014 4716 0 0 1 0 0 1 0 0 Bg
+0 BB
+Pc
+0.125 0 0.25 0 k
+Pc
+0.25 0 0.5 0 k
+Pc
+0.375 0 0.75 0 k
+Pc
+0.5 0 1 0 k
+Pc
+0.25 0 0.125 0 k
+Pc
+0.5 0 0.25 0 k
+Pc
+0.75 0 0.375 0 k
+Pc
+1 0 0.5 0 k
+Pc
+Bb
+2 (Green & Blue) -4014 4716 0 0 1 0 0 1 0 0 Bg
+0 BB
+Pc
+0.25 0.125 0.125 0 k
+Pc
+0.5 0.25 0.25 0 k
+Pc
+0.75 0.375 0.375 0 k
+Pc
+1 0.5 0.5 0 k
+Pc
+0.25 0.25 0.125 0 k
+Pc
+0.5 0.5 0.25 0 k
+Pc
+0.75 0.75 0.375 0 k
+Pc
+1 1 0.5 0 k
+Pc
+Bb
+0 0 0 0 Bh
+2 (Yellow & Orange Radial) -4014 4716 0 0 1 0 0 1 0 0 Bg
+0 BB
+Pc
+0.125 0.25 0.125 0 k
+Pc
+0.25 0.5 0.25 0 k
+Pc
+0.375 0.75 0.375 0 k
+Pc
+0.5 1 0.5 0 k
+Pc
+0.125 0.25 0.25 0 k
+Pc
+0.25 0.5 0.5 0 k
+Pc
+0.375 0.75 0.75 0 k
+Pc
+0.5 1 1 0 k
+Pc
+0 0 0 0 k
+Pc
+0.125 0.125 0.25 0 k
+Pc
+0.25 0.25 0.5 0 k
+Pc
+0.375 0.375 0.75 0 k
+Pc
+0.5 0.5 1 0 k
+Pc
+0.25 0.125 0.25 0 k
+Pc
+0.5 0.25 0.5 0 k
+Pc
+0.75 0.375 0.75 0 k
+Pc
+1 0.5 1 0 k
+Pc
+PB
+%AI5_EndPalette
+%%EndSetup
+%AI5_BeginLayer
+1 1 1 1 0 0 0 79 128 255 Lb
+(Layer 1) Ln
+0 A
+800 Ar
+0 J 0 j 1 w 4 M []0 d
+%AI3_Note:
+0 D
+0 XR
+-4014 283.5 m
+4626 283.5 L
+(N) *
+453.5 4716 m
+453.5 -3924 L
+(N) *
+85 4716 m
+85 -3924 L
+(N) *
+-4014 765.5 m
+4626 765.5 L
+(N) *
+1 Ap
+0 O
+1 g
+0 R
+0 G
+220.8907 672 m
+220.8907 703 L
+127.6667 703 L
+127.3474 672 L
+220.8907 672 L
+b
+0 Ap
+163.119 702.4773 m
+163.119 687.9773 l
+220.619 687.9773 l
+S
+0 To
+1 0 0 1 130.119 689.9773 0 Tp
+TP
+0 Tr
+0 O
+0 g
+/_Univers 10 Tf
+0 Ts
+100 Tz
+0 Tt
+1 TA
+%_ 0 XL
+36 0 Xb
+XB
+0 0 5 TC
+100 100 200 TW
+0 0 0 Ti
+0 Ta
+0 0 2 2 3 Th
+0 Tq
+0 0 Tl
+0 Tc
+0 Tw
+(Binary\r) Tx
+0 -12 Td
+(Representation) Tx
+(\r) TX
+TO
+0 To
+1 0 0 1 169.119 690.4773 0 Tp
+TP
+0 Tr
+(file.bin) Tx
+(\r) TX
+TO
+1 Ap
+1 g
+0 R
+0 G
+436 672 m
+436 743.1667 L
+237 743.1667 L
+237 672 L
+436 672 L
+b
+0 To
+1 0 0 1 246 730.5 0 Tp
+TP
+0 Tr
+0 g
+(Instrumentation) Tx
+(\r) TX
+TO
+0 To
+1 0 0 1 246 713.5 0 Tp
+TP
+0 Tr
+/_Courier 10 Tf
+(sysCFunc\(get, ...\) ->) Tx
+(\r) TX
+0 -12 Td
+( <code>;) Tx
+(\r) TX
+0 -12 Td
+(sysCFunc\(set, ...\) ->) Tx
+(\r) TX
+0 -12 Td
+( <code>.) Tx
+(\r) TX
+TO
+0 Ap
+0 R
+0 G
+237 726 m
+436 726 l
+S
+334 743 m
+334 726 l
+S
+0 To
+1 0 0 1 344.5 730.5 0 Tp
+TP
+0 Tr
+0 O
+0 g
+/_Univers 10 Tf
+(mymod.beam) Tx
+(\r) TX
+TO
+u
+u
+u
+u
+1 g
+0 R
+0 G
+170 672 m
+248.8065 637.7501 l
+B
+0 g
+251.3813 637.7486 m
+250.0639 638.8655 249.2617 639.7157 248.2574 640.7327 c
+246.2468 636.1064 l
+246.772 636.1237 248.8445 636.0596 250.5596 635.8582 c
+252.3955 635.6433 254.0128 635.339 255.0193 635.0439 c
+254.1168 635.5784 252.791 636.5532 251.3813 637.7486 c
+f
+U
+U
+U
+U
+u
+u
+u
+0 R
+0 G
+368.3333 672 m
+289.672 637.3964 l
+S
+0 O
+0 g
+287.9227 635.5072 m
+289.637 635.716 290.8059 635.7276 292.2345 635.7744 c
+290.2033 640.3917 l
+289.8594 639.9944 288.4051 638.5164 287.0927 637.394 c
+285.6884 636.192 284.3669 635.2113 283.4669 634.6728 c
+284.472 634.9724 286.0879 635.2839 287.9227 635.5072 c
+f
+U
+U
+U
+u
+1 Ap
+0 R
+0 G
+268 592.9803 m
+287.5689 592.9803 303.4331 602.4988 303.4331 614.2401 c
+303.4331 625.9815 287.5689 635.5 268 635.5 c
+248.4311 635.5 232.5669 625.9815 232.5669 614.2401 c
+232.5669 602.4988 248.4311 592.9803 268 592.9803 c
+s
+0 To
+1 0 0 1 268 610.8063 0 Tp
+TP
+-14.1614 0 Td
+0 Tr
+0 O
+0 g
+1 Ta
+(Agent) Tx
+(\r) TX
+TO
+U
+LB
+%AI5_EndLayer--
+%%PageTrailer
+gsave annotatepage grestore showpage
+%%Trailer
+Adobe_Illustrator_AI5 /terminate get exec
+Adobe_ColorImage_AI6 /terminate get exec
+Adobe_typography_AI5 /terminate get exec
+Adobe_level2_AI5 /terminate get exec
+%%EOF
diff --git a/lib/snmp/doc/src/snmp-um-1-image-3.gif b/lib/snmp/doc/src/snmp-um-1-image-3.gif
new file mode 100644
index 0000000000..47f94bcf06
--- /dev/null
+++ b/lib/snmp/doc/src/snmp-um-1-image-3.gif
Binary files differ
diff --git a/lib/snmp/doc/src/snmp-um-1-image-3.ps b/lib/snmp/doc/src/snmp-um-1-image-3.ps
new file mode 100644
index 0000000000..6c63c88f87
--- /dev/null
+++ b/lib/snmp/doc/src/snmp-um-1-image-3.ps
@@ -0,0 +1,3400 @@
+%!PS-Adobe-3.0 EPSF-3.0
+%%Creator: Adobe Illustrator(r) 6.0
+%%For: (Anna Fedoriw) (Ericsson Telecom)
+%%Title: (Architecture.eps)
+%%CreationDate: (97-05-23) (14.03)
+%%BoundingBox: 93 465 440 765
+%%HiResBoundingBox: 93.3333 465.1667 439.8333 764.3677
+%%DocumentProcessColors: Black
+%%DocumentFonts: Univers
+%%DocumentSuppliedResources: procset Adobe_level2_AI5 1.0 0
+%%+ procset Adobe_typography_AI5 1.0 0
+%%+ procset Adobe_Illustrator_AI6_vars Adobe_Illustrator_AI6
+%%+ procset Adobe_Illustrator_AI5 1.0 0
+%AI5_FileFormat 2.0
+%AI3_ColorUsage: Black&White
+%%AI6_ColorSeparationSet: 1 1 (AI6 Default Color Separation Set)
+%%+ Options: 1 16 0 1 0 1 1 1 0 1 1 1 1 18 0 0 0 0 0 0 0 0 -1 -1
+%%+ PPD: 1 21 0 0 60 45 2 2 1 0 0 1 0 0 0 0 0 0 0 0 0 0 ()
+%AI3_TemplateBox: 306 396 306 396
+%AI3_TileBox: 21 -12 588 802
+%AI3_DocumentPreview: Macintosh_ColorPic
+%AI5_ArtSize: 595.2756 841.8898
+%AI5_RulerUnits: 1
+%AI5_ArtFlags: 0 0 0 1 0 0 1 1 0
+%AI5_TargetResolution: 800
+%AI5_NumLayers: 1
+%AI5_OpenToView: 194 764 3 1146 827 58 1 1 3 40
+%AI5_OpenViewLayers: 7
+%%EndComments
+%%BeginProlog
+%%BeginResource: procset Adobe_level2_AI5 1.2 0
+%%Title: (Adobe Illustrator (R) Version 5.0 Level 2 Emulation)
+%%Version: 1.2
+%%CreationDate: (04/10/93) ()
+%%Copyright: ((C) 1987-1993 Adobe Systems Incorporated All Rights Reserved)
+userdict /Adobe_level2_AI5 23 dict dup begin
+ put
+ /packedarray where not
+ {
+ userdict begin
+ /packedarray
+ {
+ array astore readonly
+ } bind def
+ /setpacking /pop load def
+ /currentpacking false def
+ end
+ 0
+ } if
+ pop
+ userdict /defaultpacking currentpacking put true setpacking
+ /initialize
+ {
+ Adobe_level2_AI5 begin
+ } bind def
+ /terminate
+ {
+ currentdict Adobe_level2_AI5 eq
+ {
+ end
+ } if
+ } bind def
+ mark
+ /setcustomcolor where not
+ {
+ /findcmykcustomcolor
+ {
+ 5 packedarray
+ } bind def
+ /setcustomcolor
+ {
+ exch aload pop pop
+ 4
+ {
+ 4 index mul 4 1 roll
+ } repeat
+ 5 -1 roll pop
+ setcmykcolor
+ }
+ def
+ } if
+
+ /gt38? mark {version cvr cvx exec} stopped {cleartomark true} {38 gt exch pop} ifelse def
+ userdict /deviceDPI 72 0 matrix defaultmatrix dtransform dup mul exch dup mul add sqrt put
+ userdict /level2?
+ systemdict /languagelevel known dup
+ {
+ pop systemdict /languagelevel get 2 ge
+ } if
+ put
+/level2ScreenFreq
+{
+ begin
+ 60
+ HalftoneType 1 eq
+ {
+ pop Frequency
+ } if
+ HalftoneType 2 eq
+ {
+ pop GrayFrequency
+ } if
+ HalftoneType 5 eq
+ {
+ pop Default level2ScreenFreq
+ } if
+ end
+} bind def
+userdict /currentScreenFreq
+ level2? {currenthalftone level2ScreenFreq} {currentscreen pop pop} ifelse put
+level2? not
+ {
+ /setcmykcolor where not
+ {
+ /setcmykcolor
+ {
+ exch .11 mul add exch .59 mul add exch .3 mul add
+ 1 exch sub setgray
+ } def
+ } if
+ /currentcmykcolor where not
+ {
+ /currentcmykcolor
+ {
+ 0 0 0 1 currentgray sub
+ } def
+ } if
+ /setoverprint where not
+ {
+ /setoverprint /pop load def
+ } if
+ /selectfont where not
+ {
+ /selectfont
+ {
+ exch findfont exch
+ dup type /arraytype eq
+ {
+ makefont
+ }
+ {
+ scalefont
+ } ifelse
+ setfont
+ } bind def
+ } if
+ /cshow where not
+ {
+ /cshow
+ {
+ [
+ 0 0 5 -1 roll aload pop
+ ] cvx bind forall
+ } bind def
+ } if
+ } if
+ cleartomark
+ /anyColor?
+ {
+ add add add 0 ne
+ } bind def
+ /testColor
+ {
+ gsave
+ setcmykcolor currentcmykcolor
+ grestore
+ } bind def
+ /testCMYKColorThrough
+ {
+ testColor anyColor?
+ } bind def
+ userdict /composite?
+ level2?
+ {
+ gsave 1 1 1 1 setcmykcolor currentcmykcolor grestore
+ add add add 4 eq
+ }
+ {
+ 1 0 0 0 testCMYKColorThrough
+ 0 1 0 0 testCMYKColorThrough
+ 0 0 1 0 testCMYKColorThrough
+ 0 0 0 1 testCMYKColorThrough
+ and and and
+ } ifelse
+ put
+ composite? not
+ {
+ userdict begin
+ gsave
+ /cyan? 1 0 0 0 testCMYKColorThrough def
+ /magenta? 0 1 0 0 testCMYKColorThrough def
+ /yellow? 0 0 1 0 testCMYKColorThrough def
+ /black? 0 0 0 1 testCMYKColorThrough def
+ grestore
+ /isCMYKSep? cyan? magenta? yellow? black? or or or def
+ /customColor? isCMYKSep? not def
+ end
+ } if
+ end defaultpacking setpacking
+%%EndResource
+%%BeginResource: procset Adobe_typography_AI5 1.0 1
+%%Title: (Typography Operators)
+%%Version: 1.0
+%%CreationDate:(03/26/93) ()
+%%Copyright: ((C) 1987-1993 Adobe Systems Incorporated All Rights Reserved)
+currentpacking true setpacking
+userdict /Adobe_typography_AI5 54 dict dup begin
+put
+/initialize
+{
+ begin
+ begin
+ Adobe_typography_AI5 begin
+ Adobe_typography_AI5
+ {
+ dup xcheck
+ {
+ bind
+ } if
+ pop pop
+ } forall
+ end
+ end
+ end
+ Adobe_typography_AI5 begin
+} def
+/terminate
+{
+ currentdict Adobe_typography_AI5 eq
+ {
+ end
+ } if
+} def
+/modifyEncoding
+{
+ /_tempEncode exch ddef
+ /_pntr 0 ddef
+ {
+ counttomark -1 roll
+ dup type dup /marktype eq
+ {
+ pop pop exit
+ }
+ {
+ /nametype eq
+ {
+ _tempEncode /_pntr dup load dup 3 1 roll 1 add ddef 3 -1 roll
+ put
+ }
+ {
+ /_pntr exch ddef
+ } ifelse
+ } ifelse
+ } loop
+ _tempEncode
+} def
+/TE
+{
+ StandardEncoding 256 array copy modifyEncoding
+ /_nativeEncoding exch def
+} def
+%
+/TZ
+{
+ dup type /arraytype eq
+ {
+ /_wv exch def
+ }
+ {
+ /_wv 0 def
+ } ifelse
+ /_useNativeEncoding exch def
+ pop pop
+ findfont _wv type /arraytype eq
+ {
+ _wv makeblendedfont
+ } if
+ dup length 2 add dict
+ begin
+ mark exch
+ {
+ 1 index /FID ne
+ {
+ def
+ } if
+ cleartomark mark
+ } forall
+ pop
+ /FontName exch def
+ counttomark 0 eq
+ {
+ 1 _useNativeEncoding eq
+ {
+ /Encoding _nativeEncoding def
+ } if
+ cleartomark
+ }
+ {
+ /Encoding load 256 array copy
+ modifyEncoding /Encoding exch def
+ } ifelse
+ FontName currentdict
+ end
+ definefont pop
+} def
+/tr
+{
+ _ax _ay 3 2 roll
+} def
+/trj
+{
+ _cx _cy _sp _ax _ay 6 5 roll
+} def
+/a0
+{
+ /Tx
+ {
+ dup
+ currentpoint 3 2 roll
+ tr _psf
+ newpath moveto
+ tr _ctm _pss
+ } ddef
+ /Tj
+ {
+ dup
+ currentpoint 3 2 roll
+ trj _pjsf
+ newpath moveto
+ trj _ctm _pjss
+ } ddef
+} def
+/a1
+{
+ /Tx
+ {
+ dup currentpoint 4 2 roll gsave
+ dup currentpoint 3 2 roll
+ tr _psf
+ newpath moveto
+ tr _ctm _pss
+ grestore 3 1 roll moveto tr sp
+ } ddef
+ /Tj
+ {
+ dup currentpoint 4 2 roll gsave
+ dup currentpoint 3 2 roll
+ trj _pjsf
+ newpath moveto
+ trj _ctm _pjss
+ grestore 3 1 roll moveto tr jsp
+ } ddef
+} def
+/e0
+{
+ /Tx
+ {
+ tr _psf
+ } ddef
+ /Tj
+ {
+ trj _pjsf
+ } ddef
+} def
+/e1
+{
+ /Tx
+ {
+ dup currentpoint 4 2 roll gsave
+ tr _psf
+ grestore 3 1 roll moveto tr sp
+ } ddef
+ /Tj
+ {
+ dup currentpoint 4 2 roll gsave
+ trj _pjsf
+ grestore 3 1 roll moveto tr jsp
+ } ddef
+} def
+/i0
+{
+ /Tx
+ {
+ tr sp
+ } ddef
+ /Tj
+ {
+ trj jsp
+ } ddef
+} def
+/i1
+{
+ W N
+} def
+/o0
+{
+ /Tx
+ {
+ tr sw rmoveto
+ } ddef
+ /Tj
+ {
+ trj swj rmoveto
+ } ddef
+} def
+/r0
+{
+ /Tx
+ {
+ tr _ctm _pss
+ } ddef
+ /Tj
+ {
+ trj _ctm _pjss
+ } ddef
+} def
+/r1
+{
+ /Tx
+ {
+ dup currentpoint 4 2 roll currentpoint gsave newpath moveto
+ tr _ctm _pss
+ grestore 3 1 roll moveto tr sp
+ } ddef
+ /Tj
+ {
+ dup currentpoint 4 2 roll currentpoint gsave newpath moveto
+ trj _ctm _pjss
+ grestore 3 1 roll moveto tr jsp
+ } ddef
+} def
+/To
+{
+ pop _ctm currentmatrix pop
+} def
+/TO
+{
+ iTe _ctm setmatrix newpath
+} def
+/Tp
+{
+ pop _tm astore pop _ctm setmatrix
+ _tDict begin
+ /W
+ {
+ } def
+ /h
+ {
+ } def
+} def
+/TP
+{
+ end
+ iTm 0 0 moveto
+} def
+/Tr
+{
+ _render 3 le
+ {
+ currentpoint newpath moveto
+ } if
+ dup 8 eq
+ {
+ pop 0
+ }
+ {
+ dup 9 eq
+ {
+ pop 1
+ } if
+ } ifelse
+ dup /_render exch ddef
+ _renderStart exch get load exec
+} def
+/iTm
+{
+ _ctm setmatrix _tm concat 0 _rise translate _hs 1 scale
+} def
+/Tm
+{
+ _tm astore pop iTm 0 0 moveto
+} def
+/Td
+{
+ _mtx translate _tm _tm concatmatrix pop iTm 0 0 moveto
+} def
+/iTe
+{
+ _render -1 eq
+ {
+ }
+ {
+ _renderEnd _render get dup null ne
+ {
+ load exec
+ }
+ {
+ pop
+ } ifelse
+ } ifelse
+ /_render -1 ddef
+} def
+/Ta
+{
+ pop
+} def
+/Tf
+{
+ dup 1000 div /_fScl exch ddef
+%
+ selectfont
+} def
+/Tl
+{
+ pop
+ 0 exch _leading astore pop
+} def
+/Tt
+{
+ pop
+} def
+/TW
+{
+ 3 npop
+} def
+/Tw
+{
+ /_cx exch ddef
+} def
+/TC
+{
+ 3 npop
+} def
+/Tc
+{
+ /_ax exch ddef
+} def
+/Ts
+{
+ /_rise exch ddef
+ currentpoint
+ iTm
+ moveto
+} def
+/Ti
+{
+ 3 npop
+} def
+/Tz
+{
+ 100 div /_hs exch ddef
+ iTm
+} def
+/TA
+{
+ pop
+} def
+/Tq
+{
+ pop
+} def
+/Th
+{
+ pop pop pop pop pop
+} def
+/TX
+{
+ pop
+} def
+/Tk
+{
+ exch pop _fScl mul neg 0 rmoveto
+} def
+/TK
+{
+ 2 npop
+} def
+/T*
+{
+ _leading aload pop neg Td
+} def
+/T*-
+{
+ _leading aload pop Td
+} def
+/T-
+{
+ _ax neg 0 rmoveto
+ _hyphen Tx
+} def
+/T+
+{
+} def
+/TR
+{
+ _ctm currentmatrix pop
+ _tm astore pop
+ iTm 0 0 moveto
+} def
+/TS
+{
+ currentfont 3 1 roll
+ /_Symbol_ _fScl 1000 mul selectfont
+
+ 0 eq
+ {
+ Tx
+ }
+ {
+ Tj
+ } ifelse
+ setfont
+} def
+/Xb
+{
+ pop pop
+} def
+/Tb /Xb load def
+/Xe
+{
+ pop pop pop pop
+} def
+/Te /Xe load def
+/XB
+{
+} def
+/TB /XB load def
+currentdict readonly pop
+end
+setpacking
+%%EndResource
+%%BeginProcSet: Adobe_ColorImage_AI6 1.0 0
+userdict /Adobe_ColorImage_AI6 known not
+{
+ userdict /Adobe_ColorImage_AI6 17 dict put
+} if
+userdict /Adobe_ColorImage_AI6 get begin
+
+ /initialize
+ {
+ Adobe_ColorImage_AI6 begin
+ Adobe_ColorImage_AI6
+ {
+ dup type /arraytype eq
+ {
+ dup xcheck
+ {
+ bind
+ } if
+ } if
+ pop pop
+ } forall
+ } def
+ /terminate { end } def
+
+ currentdict /Adobe_ColorImage_AI6_Vars known not
+ {
+ /Adobe_ColorImage_AI6_Vars 14 dict def
+ } if
+
+ Adobe_ColorImage_AI6_Vars begin
+ /channelcount 0 def
+ /sourcecount 0 def
+ /sourcearray 4 array def
+ /plateindex -1 def
+ /XIMask 0 def
+ /XIBinary 0 def
+ /XIChannelCount 0 def
+ /XIBitsPerPixel 0 def
+ /XIImageHeight 0 def
+ /XIImageWidth 0 def
+ /XIImageMatrix null def
+ /XIBuffer null def
+ /XIDataProc null def
+ end
+
+ /WalkRGBString null def
+ /WalkCMYKString null def
+
+ /StuffRGBIntoGrayString null def
+ /RGBToGrayImageProc null def
+ /StuffCMYKIntoGrayString null def
+ /CMYKToGrayImageProc null def
+ /ColorImageCompositeEmulator null def
+
+ /SeparateCMYKImageProc null def
+
+ /FourEqual null def
+ /TestPlateIndex null def
+
+ currentdict /_colorimage known not
+ {
+ /colorimage where
+ {
+ /colorimage get /_colorimage exch def
+ }
+ {
+ /_colorimage null def
+ } ifelse
+ } if
+
+ /_currenttransfer systemdict /currenttransfer get def
+
+ /colorimage null def
+ /XI null def
+
+
+ /WalkRGBString
+ {
+ 0 3 index
+
+ dup length 1 sub 0 3 3 -1 roll
+ {
+ 3 getinterval { } forall
+
+ 5 index exec
+
+ 3 index
+ } for
+
+ 5 { pop } repeat
+
+ } def
+
+
+ /WalkCMYKString
+ {
+ 0 3 index
+
+ dup length 1 sub 0 4 3 -1 roll
+ {
+ 4 getinterval { } forall
+
+ 6 index exec
+
+ 3 index
+
+ } for
+
+ 5 { pop } repeat
+
+ } def
+
+
+ /StuffRGBIntoGrayString
+ {
+ .11 mul exch
+
+ .59 mul add exch
+
+ .3 mul add
+
+ cvi 3 copy put
+
+ pop 1 add
+ } def
+
+
+ /RGBToGrayImageProc
+ {
+ Adobe_ColorImage_AI6_Vars begin
+ sourcearray 0 get exec
+ dup length 3 idiv string
+ dup 3 1 roll
+
+ /StuffRGBIntoGrayString load exch
+ WalkRGBString
+ end
+ } def
+
+
+ /StuffCMYKIntoGrayString
+ {
+ exch .11 mul add
+
+ exch .59 mul add
+
+ exch .3 mul add
+
+ dup 255 gt { pop 255 } if
+
+ 255 exch sub cvi 3 copy put
+
+ pop 1 add
+ } def
+
+
+ /CMYKToGrayImageProc
+ {
+ Adobe_ColorImage_AI6_Vars begin
+ sourcearray 0 get exec
+ dup length 4 idiv string
+ dup 3 1 roll
+
+ /StuffCMYKIntoGrayString load exch
+ WalkCMYKString
+ end
+ } def
+
+
+ /ColorImageCompositeEmulator
+ {
+ pop true eq
+ {
+ Adobe_ColorImage_AI6_Vars /sourcecount get 5 add { pop } repeat
+ }
+ {
+ Adobe_ColorImage_AI6_Vars /channelcount get 1 ne
+ {
+ Adobe_ColorImage_AI6_Vars begin
+ sourcearray 0 3 -1 roll put
+
+ channelcount 3 eq
+ {
+ /RGBToGrayImageProc
+ }
+ {
+ /CMYKToGrayImageProc
+ } ifelse
+ load
+ end
+ } if
+ image
+ } ifelse
+ } def
+
+
+ /SeparateCMYKImageProc
+ {
+ Adobe_ColorImage_AI6_Vars begin
+
+ sourcecount 0 ne
+ {
+ sourcearray plateindex get exec
+ }
+ {
+ sourcearray 0 get exec
+
+ dup length 4 idiv string
+
+ 0 2 index
+
+ plateindex 4 2 index length 1 sub
+ {
+ get 255 exch sub
+
+ 3 copy put pop 1 add
+
+ 2 index
+ } for
+
+ pop pop exch pop
+ } ifelse
+ end
+ } def
+
+
+ /FourEqual
+ {
+ 4 index ne
+ {
+ pop pop pop false
+ }
+ {
+ 4 index ne
+ {
+ pop pop false
+ }
+ {
+ 4 index ne
+ {
+ pop false
+ }
+ {
+ 4 index eq
+ } ifelse
+ } ifelse
+ } ifelse
+ } def
+
+
+ /TestPlateIndex
+ {
+ Adobe_ColorImage_AI6_Vars begin
+ /plateindex -1 def
+
+ /setcmykcolor where
+ {
+ pop
+ gsave
+ 1 0 0 0 setcmykcolor systemdict /currentgray get exec 1 exch sub
+ 0 1 0 0 setcmykcolor systemdict /currentgray get exec 1 exch sub
+ 0 0 1 0 setcmykcolor systemdict /currentgray get exec 1 exch sub
+ 0 0 0 1 setcmykcolor systemdict /currentgray get exec 1 exch sub
+ grestore
+
+ 1 0 0 0 FourEqual
+ {
+ /plateindex 0 def
+ }
+ {
+ 0 1 0 0 FourEqual
+ {
+ /plateindex 1 def
+ }
+ {
+ 0 0 1 0 FourEqual
+ {
+ /plateindex 2 def
+ }
+ {
+ 0 0 0 1 FourEqual
+ {
+ /plateindex 3 def
+ }
+ {
+ 0 0 0 0 FourEqual
+ {
+ /plateindex 5 def
+ } if
+ } ifelse
+ } ifelse
+ } ifelse
+ } ifelse
+ pop pop pop pop
+ } if
+ plateindex
+ end
+ } def
+
+
+ /colorimage
+ {
+ Adobe_ColorImage_AI6_Vars begin
+ /channelcount 1 index def
+ /sourcecount 2 index 1 eq { channelcount 1 sub } { 0 } ifelse def
+
+ 4 sourcecount add index dup
+ 8 eq exch 1 eq or not
+ end
+
+ {
+ /_colorimage load null ne
+ {
+ _colorimage
+ }
+ {
+ Adobe_ColorImage_AI6_Vars /sourcecount get
+ 7 add { pop } repeat
+ } ifelse
+ }
+ {
+ dup 3 eq
+ TestPlateIndex
+ dup -1 eq exch 5 eq or or
+ {
+ /_colorimage load null eq
+ {
+ ColorImageCompositeEmulator
+ }
+ {
+ dup 1 eq
+ {
+ pop pop image
+ }
+ {
+ Adobe_ColorImage_AI6_Vars /plateindex get 5 eq
+ {
+ gsave
+
+ 0 _currenttransfer exec
+ 1 _currenttransfer exec
+ eq
+ { 0 _currenttransfer exec 0.5 lt }
+ { 0 _currenttransfer exec 1 _currenttransfer exec gt } ifelse
+
+ { { pop 0 } } { { pop 1 } } ifelse
+ systemdict /settransfer get exec
+ } if
+
+ _colorimage
+
+ Adobe_ColorImage_AI6_Vars /plateindex get 5 eq
+ {
+ grestore
+ } if
+ } ifelse
+ } ifelse
+ }
+ {
+ dup 1 eq
+ {
+ pop pop
+ image
+ }
+ {
+ pop pop
+
+ Adobe_ColorImage_AI6_Vars begin
+ sourcecount -1 0
+ {
+ exch sourcearray 3 1 roll put
+ } for
+
+ /SeparateCMYKImageProc load
+ end
+
+ systemdict /image get exec
+ } ifelse
+ } ifelse
+ } ifelse
+ } def
+
+ /XI
+ {
+ Adobe_ColorImage_AI6_Vars begin
+ gsave
+ /XIMask exch 0 ne def
+ /XIBinary exch 0 ne def
+ pop
+ pop
+ /XIChannelCount exch def
+ /XIBitsPerPixel exch def
+ /XIImageHeight exch def
+ /XIImageWidth exch def
+ pop pop pop pop
+ /XIImageMatrix exch def
+
+ XIBitsPerPixel 1 eq
+ {
+ XIImageWidth 8 div ceiling cvi
+ }
+ {
+ XIImageWidth XIChannelCount mul
+ } ifelse
+ /XIBuffer exch string def
+
+ XIBinary
+ {
+ /XIDataProc { currentfile XIBuffer readstring pop } def
+ currentfile 128 string readline pop pop
+ }
+ {
+ /XIDataProc { currentfile XIBuffer readhexstring pop } def
+ } ifelse
+
+ 0 0 moveto
+ XIImageMatrix concat
+ XIImageWidth XIImageHeight scale
+
+ XIMask
+ {
+ XIImageWidth XIImageHeight
+ false
+ [ XIImageWidth 0 0 XIImageHeight neg 0 0 ]
+ /XIDataProc load
+
+ /_lp /null ddef
+ _fc
+ /_lp /imagemask ddef
+
+ imagemask
+ }
+ {
+ XIImageWidth XIImageHeight
+ XIBitsPerPixel
+ [ XIImageWidth 0 0 XIImageHeight neg 0 0 ]
+ /XIDataProc load
+
+ XIChannelCount 1 eq
+ {
+
+ gsave
+ 0 setgray
+
+ image
+
+ grestore
+ }
+ {
+ false
+ XIChannelCount
+ colorimage
+ } ifelse
+ } ifelse
+ grestore
+ end
+ } def
+
+end
+%%EndProcSet
+%%BeginResource: procset Adobe_Illustrator_AI5 1.1 0
+%%Title: (Adobe Illustrator (R) Version 5.0 Full Prolog)
+%%Version: 1.1
+%%CreationDate: (3/7/1994) ()
+%%Copyright: ((C) 1987-1994 Adobe Systems Incorporated All Rights Reserved)
+currentpacking true setpacking
+userdict /Adobe_Illustrator_AI5_vars 81 dict dup begin
+put
+/_eo false def
+/_lp /none def
+/_pf
+{
+} def
+/_ps
+{
+} def
+/_psf
+{
+} def
+/_pss
+{
+} def
+/_pjsf
+{
+} def
+/_pjss
+{
+} def
+/_pola 0 def
+/_doClip 0 def
+/cf currentflat def
+/_tm matrix def
+/_renderStart
+[
+/e0 /r0 /a0 /o0 /e1 /r1 /a1 /i0
+] def
+/_renderEnd
+[
+null null null null /i1 /i1 /i1 /i1
+] def
+/_render -1 def
+/_rise 0 def
+/_ax 0 def
+/_ay 0 def
+/_cx 0 def
+/_cy 0 def
+/_leading
+[
+0 0
+] def
+/_ctm matrix def
+/_mtx matrix def
+/_sp 16#020 def
+/_hyphen (-) def
+/_fScl 0 def
+/_cnt 0 def
+/_hs 1 def
+/_nativeEncoding 0 def
+/_useNativeEncoding 0 def
+/_tempEncode 0 def
+/_pntr 0 def
+/_tDict 2 dict def
+/_wv 0 def
+/Tx
+{
+} def
+/Tj
+{
+} def
+/CRender
+{
+} def
+/_AI3_savepage
+{
+} def
+/_gf null def
+/_cf 4 array def
+/_if null def
+/_of false def
+/_fc
+{
+} def
+/_gs null def
+/_cs 4 array def
+/_is null def
+/_os false def
+/_sc
+{
+} def
+/_pd 1 dict def
+/_ed 15 dict def
+/_pm matrix def
+/_fm null def
+/_fd null def
+/_fdd null def
+/_sm null def
+/_sd null def
+/_sdd null def
+/_i null def
+/discardSave null def
+/buffer 256 string def
+/beginString null def
+/endString null def
+/endStringLength null def
+/layerCnt 1 def
+/layerCount 1 def
+/perCent (%) 0 get def
+/perCentSeen? false def
+/newBuff null def
+/newBuffButFirst null def
+/newBuffLast null def
+/clipForward? false def
+end
+userdict /Adobe_Illustrator_AI5 known not {
+ userdict /Adobe_Illustrator_AI5 91 dict put
+} if
+userdict /Adobe_Illustrator_AI5 get begin
+/initialize
+{
+ Adobe_Illustrator_AI5 dup begin
+ Adobe_Illustrator_AI5_vars begin
+ discardDict
+ {
+ bind pop pop
+ } forall
+ dup /nc get begin
+ {
+ dup xcheck 1 index type /operatortype ne and
+ {
+ bind
+ } if
+ pop pop
+ } forall
+ end
+ newpath
+} def
+/terminate
+{
+ end
+ end
+} def
+/_
+null def
+/ddef
+{
+ Adobe_Illustrator_AI5_vars 3 1 roll put
+} def
+/xput
+{
+ dup load dup length exch maxlength eq
+ {
+ dup dup load dup
+ length 2 mul dict copy def
+ } if
+ load begin
+ def
+ end
+} def
+/npop
+{
+ {
+ pop
+ } repeat
+} def
+/sw
+{
+ dup length exch stringwidth
+ exch 5 -1 roll 3 index mul add
+ 4 1 roll 3 1 roll mul add
+} def
+/swj
+{
+ dup 4 1 roll
+ dup length exch stringwidth
+ exch 5 -1 roll 3 index mul add
+ 4 1 roll 3 1 roll mul add
+ 6 2 roll /_cnt 0 ddef
+ {
+ 1 index eq
+ {
+ /_cnt _cnt 1 add ddef
+ } if
+ } forall
+ pop
+ exch _cnt mul exch _cnt mul 2 index add 4 1 roll 2 index add 4 1 roll pop pop
+} def
+/ss
+{
+ 4 1 roll
+ {
+ 2 npop
+ (0) exch 2 copy 0 exch put pop
+ gsave
+ false charpath currentpoint
+ 4 index setmatrix
+ stroke
+ grestore
+ moveto
+ 2 copy rmoveto
+ } exch cshow
+ 3 npop
+} def
+/jss
+{
+ 4 1 roll
+ {
+ 2 npop
+ (0) exch 2 copy 0 exch put
+ gsave
+ _sp eq
+ {
+ exch 6 index 6 index 6 index 5 -1 roll widthshow
+ currentpoint
+ }
+ {
+ false charpath currentpoint
+ 4 index setmatrix stroke
+ } ifelse
+ grestore
+ moveto
+ 2 copy rmoveto
+ } exch cshow
+ 6 npop
+} def
+/sp
+{
+ {
+ 2 npop (0) exch
+ 2 copy 0 exch put pop
+ false charpath
+ 2 copy rmoveto
+ } exch cshow
+ 2 npop
+} def
+/jsp
+{
+ {
+ 2 npop
+ (0) exch 2 copy 0 exch put
+ _sp eq
+ {
+ exch 5 index 5 index 5 index 5 -1 roll widthshow
+ }
+ {
+ false charpath
+ } ifelse
+ 2 copy rmoveto
+ } exch cshow
+ 5 npop
+} def
+/pl
+{
+ transform
+ 0.25 sub round 0.25 add exch
+ 0.25 sub round 0.25 add exch
+ itransform
+} def
+/setstrokeadjust where
+{
+ pop true setstrokeadjust
+ /c
+ {
+ curveto
+ } def
+ /C
+ /c load def
+ /v
+ {
+ currentpoint 6 2 roll curveto
+ } def
+ /V
+ /v load def
+ /y
+ {
+ 2 copy curveto
+ } def
+ /Y
+ /y load def
+ /l
+ {
+ lineto
+ } def
+ /L
+ /l load def
+ /m
+ {
+ moveto
+ } def
+}
+{
+ /c
+ {
+ pl curveto
+ } def
+ /C
+ /c load def
+ /v
+ {
+ currentpoint 6 2 roll pl curveto
+ } def
+ /V
+ /v load def
+ /y
+ {
+ pl 2 copy curveto
+ } def
+ /Y
+ /y load def
+ /l
+ {
+ pl lineto
+ } def
+ /L
+ /l load def
+ /m
+ {
+ pl moveto
+ } def
+} ifelse
+/d
+{
+ setdash
+} def
+/cf
+{
+} def
+/i
+{
+ dup 0 eq
+ {
+ pop cf
+ } if
+ setflat
+} def
+/j
+{
+ setlinejoin
+} def
+/J
+{
+ setlinecap
+} def
+/M
+{
+ setmiterlimit
+} def
+/w
+{
+ setlinewidth
+} def
+/XR
+{
+ 0 ne
+ /_eo exch ddef
+} def
+/H
+{
+} def
+/h
+{
+ closepath
+} def
+/N
+{
+ _pola 0 eq
+ {
+ _doClip 1 eq
+ {
+ _eo {eoclip} {clip} ifelse /_doClip 0 ddef
+ } if
+ newpath
+ }
+ {
+ /CRender
+ {
+ N
+ } ddef
+ } ifelse
+} def
+/n
+{
+ N
+} def
+/F
+{
+ _pola 0 eq
+ {
+ _doClip 1 eq
+ {
+ gsave _pf grestore _eo {eoclip} {clip} ifelse newpath /_lp /none ddef _fc
+ /_doClip 0 ddef
+ }
+ {
+ _pf
+ } ifelse
+ }
+ {
+ /CRender
+ {
+ F
+ } ddef
+ } ifelse
+} def
+/f
+{
+ closepath
+ F
+} def
+/S
+{
+ _pola 0 eq
+ {
+ _doClip 1 eq
+ {
+ gsave _ps grestore _eo {eoclip} {clip} ifelse newpath /_lp /none ddef _sc
+ /_doClip 0 ddef
+ }
+ {
+ _ps
+ } ifelse
+ }
+ {
+ /CRender
+ {
+ S
+ } ddef
+ } ifelse
+} def
+/s
+{
+ closepath
+ S
+} def
+/B
+{
+ _pola 0 eq
+ {
+ _doClip 1 eq
+ gsave F grestore
+ {
+ gsave S grestore _eo {eoclip} {clip} ifelse newpath /_lp /none ddef _sc
+ /_doClip 0 ddef
+ }
+ {
+ S
+ } ifelse
+ }
+ {
+ /CRender
+ {
+ B
+ } ddef
+ } ifelse
+} def
+/b
+{
+ closepath
+ B
+} def
+/W
+{
+ /_doClip 1 ddef
+} def
+/*
+{
+ count 0 ne
+ {
+ dup type /stringtype eq
+ {
+ pop
+ } if
+ } if
+ newpath
+} def
+/u
+{
+} def
+/U
+{
+} def
+/q
+{
+ _pola 0 eq
+ {
+ gsave
+ } if
+} def
+/Q
+{
+ _pola 0 eq
+ {
+ grestore
+ } if
+} def
+/*u
+{
+ _pola 1 add /_pola exch ddef
+} def
+/*U
+{
+ _pola 1 sub /_pola exch ddef
+ _pola 0 eq
+ {
+ CRender
+ } if
+} def
+/D
+{
+ pop
+} def
+/*w
+{
+} def
+/*W
+{
+} def
+/`
+{
+ /_i save ddef
+ clipForward?
+ {
+ nulldevice
+ } if
+ 6 1 roll 4 npop
+ concat pop
+ userdict begin
+ /showpage
+ {
+ } def
+ 0 setgray
+ 0 setlinecap
+ 1 setlinewidth
+ 0 setlinejoin
+ 10 setmiterlimit
+ [] 0 setdash
+ /setstrokeadjust where {pop false setstrokeadjust} if
+ newpath
+ 0 setgray
+ false setoverprint
+} def
+/~
+{
+ end
+ _i restore
+} def
+/O
+{
+ 0 ne
+ /_of exch ddef
+ /_lp /none ddef
+} def
+/R
+{
+ 0 ne
+ /_os exch ddef
+ /_lp /none ddef
+} def
+/g
+{
+ /_gf exch ddef
+ /_fc
+ {
+ _lp /fill ne
+ {
+ _of setoverprint
+ _gf setgray
+ /_lp /fill ddef
+ } if
+ } ddef
+ /_pf
+ {
+ _fc
+ _eo {eofill} {fill} ifelse
+ } ddef
+ /_psf
+ {
+ _fc
+ ashow
+ } ddef
+ /_pjsf
+ {
+ _fc
+ awidthshow
+ } ddef
+ /_lp /none ddef
+} def
+/G
+{
+ /_gs exch ddef
+ /_sc
+ {
+ _lp /stroke ne
+ {
+ _os setoverprint
+ _gs setgray
+ /_lp /stroke ddef
+ } if
+ } ddef
+ /_ps
+ {
+ _sc
+ stroke
+ } ddef
+ /_pss
+ {
+ _sc
+ ss
+ } ddef
+ /_pjss
+ {
+ _sc
+ jss
+ } ddef
+ /_lp /none ddef
+} def
+/k
+{
+ _cf astore pop
+ /_fc
+ {
+ _lp /fill ne
+ {
+ _of setoverprint
+ _cf aload pop setcmykcolor
+ /_lp /fill ddef
+ } if
+ } ddef
+ /_pf
+ {
+ _fc
+ _eo {eofill} {fill} ifelse
+ } ddef
+ /_psf
+ {
+ _fc
+ ashow
+ } ddef
+ /_pjsf
+ {
+ _fc
+ awidthshow
+ } ddef
+ /_lp /none ddef
+} def
+/K
+{
+ _cs astore pop
+ /_sc
+ {
+ _lp /stroke ne
+ {
+ _os setoverprint
+ _cs aload pop setcmykcolor
+ /_lp /stroke ddef
+ } if
+ } ddef
+ /_ps
+ {
+ _sc
+ stroke
+ } ddef
+ /_pss
+ {
+ _sc
+ ss
+ } ddef
+ /_pjss
+ {
+ _sc
+ jss
+ } ddef
+ /_lp /none ddef
+} def
+/x
+{
+ /_gf exch ddef
+ findcmykcustomcolor
+ /_if exch ddef
+ /_fc
+ {
+ _lp /fill ne
+ {
+ _of setoverprint
+ _if _gf 1 exch sub setcustomcolor
+ /_lp /fill ddef
+ } if
+ } ddef
+ /_pf
+ {
+ _fc
+ _eo {eofill} {fill} ifelse
+ } ddef
+ /_psf
+ {
+ _fc
+ ashow
+ } ddef
+ /_pjsf
+ {
+ _fc
+ awidthshow
+ } ddef
+ /_lp /none ddef
+} def
+/X
+{
+ /_gs exch ddef
+ findcmykcustomcolor
+ /_is exch ddef
+ /_sc
+ {
+ _lp /stroke ne
+ {
+ _os setoverprint
+ _is _gs 1 exch sub setcustomcolor
+ /_lp /stroke ddef
+ } if
+ } ddef
+ /_ps
+ {
+ _sc
+ stroke
+ } ddef
+ /_pss
+ {
+ _sc
+ ss
+ } ddef
+ /_pjss
+ {
+ _sc
+ jss
+ } ddef
+ /_lp /none ddef
+} def
+/A
+{
+ pop
+} def
+/annotatepage
+{
+userdict /annotatepage 2 copy known {get exec} {pop pop} ifelse
+} def
+/XT {
+ pop pop
+} def
+/discard
+{
+ save /discardSave exch store
+ discardDict begin
+ /endString exch store
+ gt38?
+ {
+ 2 add
+ } if
+ load
+ stopped
+ pop
+ end
+ discardSave restore
+} bind def
+userdict /discardDict 7 dict dup begin
+put
+/pre38Initialize
+{
+ /endStringLength endString length store
+ /newBuff buffer 0 endStringLength getinterval store
+ /newBuffButFirst newBuff 1 endStringLength 1 sub getinterval store
+ /newBuffLast newBuff endStringLength 1 sub 1 getinterval store
+} def
+/shiftBuffer
+{
+ newBuff 0 newBuffButFirst putinterval
+ newBuffLast 0
+ currentfile read not
+ {
+ stop
+ } if
+ put
+} def
+0
+{
+ pre38Initialize
+ mark
+ currentfile newBuff readstring exch pop
+ {
+ {
+ newBuff endString eq
+ {
+ cleartomark stop
+ } if
+ shiftBuffer
+ } loop
+ }
+ {
+ stop
+ } ifelse
+} def
+1
+{
+ pre38Initialize
+ /beginString exch store
+ mark
+ currentfile newBuff readstring exch pop
+ {
+ {
+ newBuff beginString eq
+ {
+ /layerCount dup load 1 add store
+ }
+ {
+ newBuff endString eq
+ {
+ /layerCount dup load 1 sub store
+ layerCount 0 eq
+ {
+ cleartomark stop
+ } if
+ } if
+ } ifelse
+ shiftBuffer
+ } loop
+ } if
+} def
+2
+{
+ mark
+ {
+ currentfile buffer readline not
+ {
+ stop
+ } if
+ endString eq
+ {
+ cleartomark stop
+ } if
+ } loop
+} def
+3
+{
+ /beginString exch store
+ /layerCnt 1 store
+ mark
+ {
+ currentfile buffer readline not
+ {
+ stop
+ } if
+ dup beginString eq
+ {
+ pop /layerCnt dup load 1 add store
+ }
+ {
+ endString eq
+ {
+ layerCnt 1 eq
+ {
+ cleartomark stop
+ }
+ {
+ /layerCnt dup load 1 sub store
+ } ifelse
+ } if
+ } ifelse
+ } loop
+} def
+end
+userdict /clipRenderOff 15 dict dup begin
+put
+{
+ /n /N /s /S /f /F /b /B
+}
+{
+ {
+ _doClip 1 eq
+ {
+ /_doClip 0 ddef _eo {eoclip} {clip} ifelse
+ } if
+ newpath
+ } def
+} forall
+/Tr /pop load def
+/Bb {} def
+/BB /pop load def
+/Bg {12 npop} def
+/Bm {6 npop} def
+/Bc /Bm load def
+/Bh {4 npop} def
+end
+/Lb
+{
+ 4 npop
+ 6 1 roll
+ pop
+ 4 1 roll
+ pop pop pop
+ 0 eq
+ {
+ 0 eq
+ {
+ (%AI5_BeginLayer) 1 (%AI5_EndLayer--) discard
+ }
+ {
+
+ /clipForward? true def
+
+ /Tx /pop load def
+ /Tj /pop load def
+
+ currentdict end clipRenderOff begin begin
+ } ifelse
+ }
+ {
+ 0 eq
+ {
+ save /discardSave exch store
+ } if
+ } ifelse
+} bind def
+/LB
+{
+ discardSave dup null ne
+ {
+ restore
+ }
+ {
+ pop
+ clipForward?
+ {
+ currentdict
+ end
+ end
+ begin
+
+ /clipForward? false ddef
+ } if
+ } ifelse
+} bind def
+/Pb
+{
+ pop pop
+ 0 (%AI5_EndPalette) discard
+} bind def
+/Np
+{
+ 0 (%AI5_End_NonPrinting--) discard
+} bind def
+/Ln /pop load def
+/Ap
+/pop load def
+/Ar
+{
+ 72 exch div
+ 0 dtransform dup mul exch dup mul add sqrt
+ dup 1 lt
+ {
+ pop 1
+ } if
+ setflat
+} def
+/Mb
+{
+ q
+} def
+/Md
+{
+} def
+/MB
+{
+ Q
+} def
+/nc 3 dict def
+nc begin
+/setgray
+{
+ pop
+} bind def
+/setcmykcolor
+{
+ 4 npop
+} bind def
+/setcustomcolor
+{
+ 2 npop
+} bind def
+currentdict readonly pop
+end
+end
+setpacking
+%%EndResource
+%%EndProlog
+%%BeginSetup
+%%IncludeFont: Univers
+Adobe_level2_AI5 /initialize get exec
+Adobe_Illustrator_AI5_vars Adobe_Illustrator_AI5 Adobe_typography_AI5 /initialize get exec
+Adobe_ColorImage_AI6 /initialize get exec
+Adobe_Illustrator_AI5 /initialize get exec
+[
+39/quotesingle 96/grave 128/Adieresis/Aring/Ccedilla/Eacute/Ntilde/Odieresis
+/Udieresis/aacute/agrave/acircumflex/adieresis/atilde/aring/ccedilla/eacute
+/egrave/ecircumflex/edieresis/iacute/igrave/icircumflex/idieresis/ntilde
+/oacute/ograve/ocircumflex/odieresis/otilde/uacute/ugrave/ucircumflex
+/udieresis/dagger/degree/cent/sterling/section/bullet/paragraph/germandbls
+/registered/copyright/trademark/acute/dieresis/.notdef/AE/Oslash
+/.notdef/plusminus/.notdef/.notdef/yen/mu/.notdef/.notdef
+/.notdef/.notdef/.notdef/ordfeminine/ordmasculine/.notdef/ae/oslash
+/questiondown/exclamdown/logicalnot/.notdef/florin/.notdef/.notdef
+/guillemotleft/guillemotright/ellipsis/.notdef/Agrave/Atilde/Otilde/OE/oe
+/endash/emdash/quotedblleft/quotedblright/quoteleft/quoteright/divide
+/.notdef/ydieresis/Ydieresis/fraction/currency/guilsinglleft/guilsinglright
+/fi/fl/daggerdbl/periodcentered/quotesinglbase/quotedblbase/perthousand
+/Acircumflex/Ecircumflex/Aacute/Edieresis/Egrave/Iacute/Icircumflex
+/Idieresis/Igrave/Oacute/Ocircumflex/.notdef/Ograve/Uacute/Ucircumflex
+/Ugrave/dotlessi/circumflex/tilde/macron/breve/dotaccent/ring/cedilla
+/hungarumlaut/ogonek/caron
+TE
+%AI3_BeginEncoding: _Univers Univers
+[/_Univers/Univers 0 0 1 TZ
+%AI3_EndEncoding AdobeType
+%AI5_Begin_NonPrinting
+Np
+8 Bn
+%AI5_BeginGradient: (Black & White)
+(Black & White) 0 2 Bd
+[
+<
+FFFEFDFCFBFAF9F8F7F6F5F4F3F2F1F0EFEEEDECEBEAE9E8E7E6E5E4E3E2E1E0DFDEDDDCDBDAD9D8
+D7D6D5D4D3D2D1D0CFCECDCCCBCAC9C8C7C6C5C4C3C2C1C0BFBEBDBCBBBAB9B8B7B6B5B4B3B2B1B0
+AFAEADACABAAA9A8A7A6A5A4A3A2A1A09F9E9D9C9B9A999897969594939291908F8E8D8C8B8A8988
+87868584838281807F7E7D7C7B7A797877767574737271706F6E6D6C6B6A69686766656463626160
+5F5E5D5C5B5A595857565554535251504F4E4D4C4B4A494847464544434241403F3E3D3C3B3A3938
+37363534333231302F2E2D2C2B2A292827262524232221201F1E1D1C1B1A19181716151413121110
+0F0E0D0C0B0A09080706050403020100
+>
+0 %_Br
+[
+0 0 50 100 %_Bs
+1 0 50 0 %_Bs
+BD
+%AI5_EndGradient
+%AI5_BeginGradient: (Green & Blue)
+(Green & Blue) 0 2 Bd
+[
+<
+99999A9A9B9B9B9C9C9D9D9D9E9E9F9F9FA0A0A1A1A1A2A2A3A3A3A4A4A5A5A5A6A6A7A7A7A8A8A9
+A9A9AAAAABABABACACADADADAEAEAFAFAFB0B0B1B1B1B2B2B3B3B3B4B4B5B5B5B6B6B7B7B7B8B8B9
+B9B9BABABBBBBBBCBCBDBDBDBEBEBFBFBFC0C0C1C1C1C2C2C3C3C3C4C4C5C5C5C6C6C7C7C7C8C8C9
+C9C9CACACBCBCBCCCCCDCDCDCECECFCFCFD0D0D1D1D1D2D2D3D3D3D4D4D5D5D5D6D6D7D7D7D8D8D9
+D9D9DADADBDBDBDCDCDDDDDDDEDEDFDFDFE0E0E1E1E1E2E2E3E3E3E4E4E5E5E5E6E6E7E7E7E8E8E9
+E9E9EAEAEBEBEBECECEDEDEDEEEEEFEFEFF0F0F1F1F1F2F2F3F3F3F4F4F5F5F5F6F6F7F7F7F8F8F9
+F9F9FAFAFBFBFBFCFCFDFDFDFEFEFFFF
+>
+<
+000102020304050506070808090A0B0B0C0D0E0E0F101111121314141516171718191A1A1B1C1D1D
+1E1F20202122232324252626272829292A2B2C2C2D2E2F2F303132323334353536373838393A3B3B
+3C3D3E3E3F404141424344444546474748494A4A4B4C4D4D4E4F5050515253535455565657585959
+5A5B5C5C5D5E5F5F606162626364656566676868696A6B6B6C6D6E6E6F7071717273747475767777
+78797A7A7B7C7D7D7E7F80808182828384858586878888898A8B8B8C8D8E8E8F9091919293949495
+96979798999A9A9B9C9D9D9E9FA0A0A1A2A3A3A4A5A6A6A7A8A9A9AAABACACADAEAFAFB0B1B2B2B3
+B4B5B5B6B7B8B8B9BABBBBBCBDBEBEBF
+>
+<
+FFFEFDFCFBFAF9F8F7F6F5F4F3F2F1F0EFEEEDECEBEAE9E8E7E6E5E4E3E2E1E0DFDEDDDCDBDAD9D8
+D7D6D5D4D3D2D1D0CFCECDCCCBCAC9C8C7C6C5C4C3C2C1C0BFBEBDBCBBBAB9B8B7B6B5B4B3B2B1B0
+AFAEADACABAAA9A8A7A6A5A4A3A2A1A09F9E9D9C9B9A999897969594939291908F8E8D8C8B8A8988
+87868584838281807F7E7D7C7B7A797877767574737271706F6E6D6C6B6A69686766656463626160
+5F5E5D5C5B5A595857565554535251504F4E4D4C4B4A494847464544434241403F3E3D3C3B3A3938
+37363534333231302F2E2D2C2B2A292827262524232221201F1E1D1C1B1A19181716151413121110
+0F0E0D0C0B0A09080706050403020100
+>
+0
+1 %_Br
+[
+1 0.75 0 0 1 50 100 %_Bs
+0.6 0 1 0 1 50 0 %_Bs
+BD
+%AI5_EndGradient
+%AI5_BeginGradient: (Pink, Yellow, Green)
+(Pink, Yellow, Green) 0 3 Bd
+[
+<
+00000000000000000000000000000000000000010101010101010101010101010101010101010101
+01010101010202020202020202020202020202020202020202020203030303030303030303030303
+03030303030303030404040404040404040404040404040404040404050505050505050505050505
+05050505050505060606060606060606060606060606060606060707070707070707070707070707
+07070707080808080808080808080808080808080809090909090909090909090909090909090A0A
+0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0C0C0C0C0C0C0C0C0C
+0C0C0C0C0C0C0C0D0D0D0D0D
+>
+<
+050506060606070708080809090A0A0A0B0B0C0C0D0D0E0E0F0F1010111112121313141415151617
+17181819191A1A1B1C1C1D1D1E1F1F202021222223232425252626272828292A2A2B2C2C2D2D2E2F
+2F3031313233333435353637373839393A3B3B3C3D3E3E3F4040414242434445454647474849494A
+4B4C4C4D4E4F4F505151525354545556575758595A5A5B5C5C5D5E5F5F6061626363646566666768
+69696A6B6C6C6D6E6F707071727373747576777778797A7B7B7C7D7E7F7F80818283838485868787
+88898A8B8B8C8D8E8F8F9091929394949596979898999A9B9C9D9D9E9FA0A1A2A2A3A4A5A6A7A7A8
+A9AAABACADADAEAFB0B1B2B2
+>
+<
+CCCCCBCBCBCACACAC9C9C8C8C7C7C6C6C5C5C4C4C3C2C2C1C1C0C0BFBEBEBDBDBCBBBBBAB9B9B8B7
+B7B6B6B5B4B4B3B2B1B1B0AFAFAEADADACABAAAAA9A8A8A7A6A5A5A4A3A2A2A1A0A09F9E9D9C9C9B
+9A999998979696959493929291908F8E8E8D8C8B8A8A8988878686858483828181807F7E7D7C7C7B
+7A7978777776757473727171706F6E6D6C6B6A6A69686766656463636261605F5E5D5C5B5B5A5958
+5756555453525151504F4E4D4C4B4A49484746464544434241403F3E3D3C3B3A3938383736353433
+3231302F2E2D2C2B2A29282726252423222221201F1E1D1C1B1A191817161514131211100F0E0D0C
+0B0A09080706050403020100
+>
+0
+1 %_Br
+<
+737271706F6E6D6C6B6A696867666564636261605F5E5D5C5B5B5A59585756555453525150504F4E
+4D4C4B4A4949484746454443434241403F3E3E3D3C3B3A3A393837363635343333323130302F2E2D
+2D2C2B2A2A29282827262525242323222121201F1F1E1D1D1C1C1B1A1A1918181717161615141413
+1312121111100F0F0E0E0D0D0C0C0C0B0B0A0A090908080807070606060505050404040303030202
+020201010101010000000000
+>
+<
+00000000000000000000000001010101010101010101010101010101010101010101010102020202
+02020202020202020202020202020202020202020202030303030303030303030303030303030303
+03030303030303030303030303040404040404040404040404040404040404040404040404040404
+04040404040404040404050505050505050505050505050505050505050505050505050505050505
+050505050505050505050505
+>
+<
+BFBFBFC0C0C0C0C0C0C0C0C0C1C1C1C1C1C1C1C1C1C2C2C2C2C2C2C2C2C2C2C3C3C3C3C3C3C3C3C3
+C3C4C4C4C4C4C4C4C4C4C4C5C5C5C5C5C5C5C5C5C5C5C6C6C6C6C6C6C6C6C6C6C6C6C7C7C7C7C7C7
+C7C7C7C7C7C7C8C8C8C8C8C8C8C8C8C8C8C8C8C9C9C9C9C9C9C9C9C9C9C9C9C9C9C9CACACACACACA
+CACACACACACACACACACACBCBCBCBCBCBCBCBCBCBCBCBCBCBCBCBCBCBCBCBCBCBCCCCCCCCCCCCCCCC
+CCCCCCCCCCCCCCCCCCCCCCCC
+>
+0
+1 %_Br
+[
+0.05 0.7 0 0 1 50 100 %_Bs
+0 0.02 0.8 0 1 57 36 %_Bs
+0.45 0 0.75 0 1 37 0 %_Bs
+BD
+%AI5_EndGradient
+%AI5_BeginGradient: (Purple, Red & Yellow)
+(Purple, Red & Yellow) 0 3 Bd
+[
+0
+<
+FFFEFDFCFBFAF9F8F7F6F5F4F3F2F1F0EFEEEDECEBEAE9E8E7E6E5E4E3E2E1E0DFDEDDDCDBDAD9D8
+D7D6D5D4D3D2D1D0CFCECDCCCBCAC9C8C7C6C5C4C3C2C1C0BFBEBDBCBBBAB9B8B7B6B5B4B3B2B1B0
+AFAEADACABAAA9A8A7A6A5A4A3A2A1A09F9E9D9C9B9A999897969594939291908F8E8D8C8B8A8988
+87868584838281807F7E7D7C7B7A797877767574737271706F6E6D6C6B6A69686766656463626160
+5F5E5D5C5B5A595857565554535251504F4E4D4C4B4A494847464544434241403F3E3D3C3B3A3938
+37363534333231302F2E2D2C2B2A292827262524232221201F1E1D1C1B1A19181716151413121110
+0F0E0D0C0B0A
+>
+<
+CCCCCCCDCDCDCDCDCECECECECECFCFCFCFD0D0D0D0D0D1D1D1D1D1D2D2D2D2D2D3D3D3D3D3D4D4D4
+D4D5D5D5D5D5D6D6D6D6D6D7D7D7D7D7D8D8D8D8D8D9D9D9D9DADADADADADBDBDBDBDBDCDCDCDCDC
+DDDDDDDDDDDEDEDEDEDFDFDFDFDFE0E0E0E0E0E1E1E1E1E1E2E2E2E2E2E3E3E3E3E4E4E4E4E4E5E5
+E5E5E5E6E6E6E6E6E7E7E7E7E7E8E8E8E8E9E9E9E9E9EAEAEAEAEAEBEBEBEBEBECECECECECEDEDED
+EDEEEEEEEEEEEFEFEFEFEFF0F0F0F0F0F1F1F1F1F1F2F2F2F2F3F3F3F3F3F4F4F4F4F4F5F5F5F5F5
+F6F6F6F6F6F7F7F7F7F8F8F8F8F8F9F9F9F9F9FAFAFAFAFAFBFBFBFBFBFCFCFCFCFDFDFDFDFDFEFE
+FEFEFEFFFFFF
+>
+0
+1 %_Br
+<
+E5E4E3E2E1E0DFDEDDDCDBDAD9D8D7D6D5D4D3D2D1D0CFCECDCCCBCAC9C8C7C6C5C4C3C2C1C0BFBE
+BDBCBBBAB9B8B7B6B5B4B3B2B1B0AFAEADACABAAA9A8A7A6A5A4A3A2A1A09F9E9D9C9B9A99989796
+9594939291908F8E8D8C8B8A898887868584838281807F7E7D7C7B7A797877767574737271706F6E
+6D6C6B6A696867666564636261605F5E5D5C5B5A595857565554535251504F4E4D4C4B4A49484746
+4544434241403F3E3D3C3B3A393837363534333231302F2E2D2C2B2A292827262524232221201F1E
+1D1C1B1A191817161514131211100F0E0D0C0B0A09080706050403020100
+>
+<
+E5E6E6E6E6E6E6E6E6E7E7E7E7E7E7E7E7E7E8E8E8E8E8E8E8E8E8E9E9E9E9E9E9E9E9E9EAEAEAEA
+EAEAEAEAEAEBEBEBEBEBEBEBEBEBECECECECECECECECECEDEDEDEDEDEDEDEDEDEEEEEEEEEEEEEEEE
+EEEFEFEFEFEFEFEFEFEFF0F0F0F0F0F0F0F0F0F1F1F1F1F1F1F1F1F1F2F2F2F2F2F2F2F2F2F3F3F3
+F3F3F3F3F3F3F4F4F4F4F4F4F4F4F4F5F5F5F5F5F5F5F5F5F6F6F6F6F6F6F6F6F6F7F7F7F7F7F7F7
+F7F7F8F8F8F8F8F8F8F8F8F9F9F9F9F9F9F9F9F9FAFAFAFAFAFAFAFAFAFBFBFBFBFBFBFBFBFBFCFC
+FCFCFCFCFCFCFCFDFDFDFDFDFDFDFDFDFEFEFEFEFEFEFEFEFEFFFFFFFFFF
+>
+<
+00010203040405060708090A0B0C0C0D0E0F10111213141415161718191A1B1C1D1D1E1F20212223
+242525262728292A2B2C2D2D2E2F30313233343535363738393A3B3C3D3D3E3F4041424344454546
+4748494A4B4C4D4E4E4F50515253545556565758595A5B5C5D5E5E5F60616263646566666768696A
+6B6C6D6E6E6F70717273747576767778797A7B7C7D7E7F7F80818283848586878788898A8B8C8D8E
+8F8F90919293949596979798999A9B9C9D9E9F9FA0A1A2A3A4A5A6A7A7A8A9AAABACADAEAFAFB0B1
+B2B3B4B5B6B7B8B8B9BABBBCBDBEBFC0C0C1C2C3C4C5C6C7C8C8C9CACBCC
+>
+0
+1 %_Br
+[
+0 0.04 1 0 1 50 100 %_Bs
+0 1 0.8 0 1 50 50 %_Bs
+0.9 0.9 0 0 1 50 0 %_Bs
+BD
+%AI5_EndGradient
+%AI5_BeginGradient: (Rainbow)
+(Rainbow) 0 6 Bd
+[
+<
+FFFEFDFCFBFAF9F8F7F6F5F4F3F2F1F0EFEEEDECEBEAE9E8E7E6E5E4E3E2E1E0DFDEDDDCDBDAD9D8
+D7D6D5D4D3D2D1D0CFCECDCCCBCAC9C8C7C6C5C4C3C2C1C0BFBEBDBCBBBAB9B8B7B6B5B4B3B2B1B0
+AFAEADACABAAA9A8A7A6A5A4A3A2A1A09F9E9D9C9B9A999897969594939291908F8E8D8C8B8A8988
+87868584838281807F7E7D7C7B7A797877767574737271706F6E6D6C6B6A69686766656463626160
+5F5E5D5C5B5A595857565554535251504F4E4D4C4B4A494847464544434241403F3E3D3C3B3A3938
+37363534333231302F2E2D2C2B2A292827262524232221201F1E1D1C1B1A19181716151413121110
+0F0E0D0C0B0A09080706050403020100
+>
+1
+0
+0
+1 %_Br
+1
+<
+0708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E
+2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F50515253545556
+5758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E
+7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6
+A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7C8C9CACBCCCDCE
+CFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6
+F7F8F9FAFBFCFDFEFF
+>
+0
+0
+1 %_Br
+1
+<
+00000000000000000000000000000000000001010101010101010101010101010101010101010101
+01010101010101010101010101010202020202020202020202020202020202020202020202020202
+02020202020202020202030303030303030303030303030303030303030303030303030303030303
+03030303030304040404040404040404040404040404040404040404040404040404040404040404
+04040505050505050505050505050505050505050505050505050505050505050505050505050606
+06060606060606060606060606060606060606060606060606060606060606060606070707070707
+07070707070707070707070707070707
+>
+<
+FFFEFDFCFBFAF9F8F7F6F5F4F3F2F1F0EFEEEDECEBEAE9E8E7E6E5E4E3E2E1E0DFDEDDDCDBDAD9D8
+D7D6D5D4D3D2D1D0CFCECDCCCBCAC9C8C7C6C5C4C3C2C1C0BFBEBDBCBBBAB9B8B7B6B5B4B3B2B1B0
+AFAEADACABAAA9A8A7A6A5A4A3A2A1A09F9E9D9C9B9A999897969594939291908F8E8D8C8B8A8988
+87868584838281807F7E7D7C7B7A797877767574737271706F6E6D6C6B6A69686766656463626160
+5F5E5D5C5B5A595857565554535251504F4E4D4C4B4A494847464544434241403F3E3D3C3B3A3938
+37363534333231302F2E2D2C2B2A292827262524232221201F1E1D1C1B1A19181716151413121110
+0F0E0D0C0B0A09080706050403020100
+>
+0
+1 %_Br
+<
+000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627
+28292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F
+505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F7071727374757677
+78797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9F
+A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7
+C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEF
+F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF
+>
+0
+1
+0
+1 %_Br
+0
+<
+FFFEFDFCFBFAF9F8F7F6F5F4F3F2F1F0EFEEEDECEBEAE9E8E7E6E5E4E3E2E1E0DFDEDDDCDBDAD9D8
+D7D6D5D4D3D2D1D0CFCECDCCCBCAC9C8C7C6C5C4C3C2C1C0BFBEBDBCBBBAB9B8B7B6B5B4B3B2B1B0
+AFAEADACABAAA9A8A7A6A5A4A3A2A1A09F9E9D9C9B9A999897969594939291908F8E8D8C8B8A8988
+87868584838281807F7E7D7C7B7A797877767574737271706F6E6D6C6B6A69686766656463626160
+5F5E5D5C5B5A595857565554535251504F4E4D4C4B4A494847464544434241403F3E3D3C3B3A3938
+37363534333231302F2E2D2C2B2A292827262524232221201F1E1D1C1B1A19181716151413121110
+0F0E0D0C0B0A09080706050403020100
+>
+1
+0
+1 %_Br
+[
+0 1 0 0 1 50 100 %_Bs
+1 1 0 0 1 50 80 %_Bs
+1 0.0279 0 0 1 50 60 %_Bs
+1 0 1 0 1 50 40 %_Bs
+0 0 1 0 1 50 20 %_Bs
+0 1 1 0 1 50 0 %_Bs
+BD
+%AI5_EndGradient
+%AI5_BeginGradient: (Steel Bar)
+(Steel Bar) 0 3 Bd
+[
+<
+FFFEFDFCFBFAF9F8F7F6F5F4F3F2F1F0EFEEEDECEBEAE9E8E7E6E5E4E3E2E1E0DFDEDDDCDBDAD9D8
+D7D6D5D4D3D2D1D0CFCECDCCCBCAC9C8C7C6C5C4C3C2C1C0BFBEBDBCBBBAB9B8B7B6B5B4B3B2B1B0
+AFAEADACABAAA9A8A7A6A5A4A3A2A1A09F9E9D9C9B9A999897969594939291908F8E8D8C8B8A8988
+87868584838281807F7E7D7C7B7A797877767574737271706F6E6D6C6B6A69686766656463626160
+5F5E5D5C5B5A595857565554535251504F4E4D4C4B4A494847464544434241403F3E3D3C3B3A3938
+37363534333231302F2E2D2C2B2A292827262524232221201F1E1D1C1B1A19181716151413121110
+0F0E0D0C0B0A09080706050403020100
+>
+0 %_Br
+<
+000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627
+28292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F
+505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F7071727374757677
+78797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9F
+A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7
+C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEF
+F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF
+>
+0 %_Br
+[
+0 0 50 100 %_Bs
+1 0 50 70 %_Bs
+0 0 50 0 %_Bs
+BD
+%AI5_EndGradient
+%AI5_BeginGradient: (Yellow & Orange Radial)
+(Yellow & Orange Radial) 1 2 Bd
+[
+0
+<
+0001010203040506060708090A0B0C0C0D0E0F10111213131415161718191A1B1C1D1D1E1F202122
+232425262728292A2B2B2C2D2E2F303132333435363738393A3B3C3D3E3E3F404142434445464748
+494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F60606162636465666768696A6B6C6D6E6F
+707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C
+>
+<
+FFFFFFFFFEFEFEFEFEFEFEFDFDFDFDFDFDFCFCFCFCFCFCFBFBFBFBFBFBFAFAFAFAFAFAF9F9F9F9F9
+F9F8F8F8F8F8F8F7F7F7F7F7F7F6F6F6F6F6F6F5F5F5F5F5F5F4F4F4F4F4F3F3F3F3F3F3F2F2F2F2
+F2F2F1F1F1F1F1F0F0F0F0F0F0EFEFEFEFEFEFEEEEEEEEEEEDEDEDEDEDEDECECECECECEBEBEBEBEB
+EBEAEAEAEAEAE9E9E9E9E9E9E8E8E8E8E8E8E7E7E7E7E7E6E6E6E6E6E5
+>
+0
+1 %_Br
+[
+0 0 1 0 1 52 19 %_Bs
+0 0.55 0.9 0 1 50 100 %_Bs
+BD
+%AI5_EndGradient
+%AI5_BeginGradient: (Yellow & Purple Radial)
+(Yellow & Purple Radial) 1 2 Bd
+[
+<
+000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627
+28292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F
+505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F7071727374757677
+78797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9F
+A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7
+C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEF
+F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF
+>
+<
+1415161718191A1B1C1D1E1F1F202122232425262728292A2A2B2C2D2E2F30313233343536363738
+393A3B3C3D3E3F40414142434445464748494A4B4C4D4D4E4F50515253545556575858595A5B5C5D
+5E5F60616263646465666768696A6B6C6D6E6F6F707172737475767778797A7B7B7C7D7E7F808182
+83848586868788898A8B8C8D8E8F90919292939495969798999A9B9C9D9D9E9FA0A1A2A3A4A5A6A7
+A8A9A9AAABACADAEAFB0B1B2B3B4B4B5B6B7B8B9BABBBCBDBEBFC0C0C1C2C3C4C5C6C7C8C9CACBCB
+CCCDCECFD0D1D2D3D4D5D6D7D7D8D9DADBDCDDDEDFE0E1E2E2E3E4E5E6E7E8E9EAEBECEDEEEEEFF0
+F1F2F3F4F5F6F7F8F9F9FAFBFCFDFEFF
+>
+<
+ABAAAAA9A8A7A7A6A5A5A4A3A3A2A1A1A09F9F9E9D9D9C9B9B9A9999989797969595949393929191
+908F8F8E8D8D8C8B8B8A8989888787868585848383828181807F7F7E7D7D7C7B7B7A797978777776
+7575747373727171706F6F6E6D6D6C6B6B6A6969686767666565646362626160605F5E5E5D5C5C5B
+5A5A5958585756565554545352525150504F4E4E4D4C4C4B4A4A4948484746464544444342424140
+403F3E3E3D3C3C3B3A3A3938383736363534343332323130302F2E2E2D2C2C2B2A2A292828272626
+25242423222121201F1F1E1D1D1C1B1B1A1919181717161515141313121111100F0F0E0D0D0C0B0B
+0A090908070706050504030302010100
+>
+0
+1 %_Br
+[
+0 0.08 0.67 0 1 50 14 %_Bs
+1 1 0 0 1 50 100 %_Bs
+BD
+%AI5_EndGradient
+%AI5_End_NonPrinting--
+%AI5_BeginPalette
+0 0 Pb
+Pn
+Pc
+1 g
+Pc
+0 g
+Pc
+0 0 0 0 k
+Pc
+0.75 g
+Pc
+0.5 g
+Pc
+0.25 g
+Pc
+0 g
+Pc
+Bb
+2 (Black & White) -4014 4716 0 0 1 0 0 1 0 0 Bg
+0 BB
+Pc
+0.25 0 0 0 k
+Pc
+0.5 0 0 0 k
+Pc
+0.75 0 0 0 k
+Pc
+1 0 0 0 k
+Pc
+0.25 0.25 0 0 k
+Pc
+0.5 0.5 0 0 k
+Pc
+0.75 0.75 0 0 k
+Pc
+1 1 0 0 k
+Pc
+Bb
+2 (Pink, Yellow, Green) -4014 4716 0 0 1 0 0 1 0 0 Bg
+0 BB
+Pc
+0 0.25 0 0 k
+Pc
+0 0.5 0 0 k
+Pc
+0 0.75 0 0 k
+Pc
+0 1 0 0 k
+Pc
+0 0.25 0.25 0 k
+Pc
+0 0.5 0.5 0 k
+Pc
+0 0.75 0.75 0 k
+Pc
+0 1 1 0 k
+Pc
+Bb
+0 0 0 0 Bh
+2 (Yellow & Purple Radial) -4014 4716 0 0 1 0 0 1 0 0 Bg
+0 BB
+Pc
+0 0 0.25 0 k
+Pc
+0 0 0.5 0 k
+Pc
+0 0 0.75 0 k
+Pc
+0 0 1 0 k
+Pc
+0.25 0 0.25 0 k
+Pc
+0.5 0 0.5 0 k
+Pc
+0.75 0 0.75 0 k
+Pc
+1 0 1 0 k
+Pc
+Bb
+2 (Rainbow) -4014 4716 0 0 1 0 0 1 0 0 Bg
+0 BB
+Pc
+0.25 0.125 0 0 k
+Pc
+0.5 0.25 0 0 k
+Pc
+0.75 0.375 0 0 k
+Pc
+1 0.5 0 0 k
+Pc
+0.125 0.25 0 0 k
+Pc
+0.25 0.5 0 0 k
+Pc
+0.375 0.75 0 0 k
+Pc
+0.5 1 0 0 k
+Pc
+Bb
+2 (Steel Bar) -4014 4716 0 0 1 0 0 1 0 0 Bg
+0 BB
+Pc
+0 0.25 0.125 0 k
+Pc
+0 0.5 0.25 0 k
+Pc
+0 0.75 0.375 0 k
+Pc
+0 1 0.5 0 k
+Pc
+0 0.125 0.25 0 k
+Pc
+0 0.25 0.5 0 k
+Pc
+0 0.375 0.75 0 k
+Pc
+0 0.5 1 0 k
+Pc
+Bb
+2 (Purple, Red & Yellow) -4014 4716 0 0 1 0 0 1 0 0 Bg
+0 BB
+Pc
+0.125 0 0.25 0 k
+Pc
+0.25 0 0.5 0 k
+Pc
+0.375 0 0.75 0 k
+Pc
+0.5 0 1 0 k
+Pc
+0.25 0 0.125 0 k
+Pc
+0.5 0 0.25 0 k
+Pc
+0.75 0 0.375 0 k
+Pc
+1 0 0.5 0 k
+Pc
+Bb
+2 (Green & Blue) -4014 4716 0 0 1 0 0 1 0 0 Bg
+0 BB
+Pc
+0.25 0.125 0.125 0 k
+Pc
+0.5 0.25 0.25 0 k
+Pc
+0.75 0.375 0.375 0 k
+Pc
+1 0.5 0.5 0 k
+Pc
+0.25 0.25 0.125 0 k
+Pc
+0.5 0.5 0.25 0 k
+Pc
+0.75 0.75 0.375 0 k
+Pc
+1 1 0.5 0 k
+Pc
+Bb
+0 0 0 0 Bh
+2 (Yellow & Orange Radial) -4014 4716 0 0 1 0 0 1 0 0 Bg
+0 BB
+Pc
+0.125 0.25 0.125 0 k
+Pc
+0.25 0.5 0.25 0 k
+Pc
+0.375 0.75 0.375 0 k
+Pc
+0.5 1 0.5 0 k
+Pc
+0.125 0.25 0.25 0 k
+Pc
+0.25 0.5 0.5 0 k
+Pc
+0.375 0.75 0.75 0 k
+Pc
+0.5 1 1 0 k
+Pc
+0 0 0 0 k
+Pc
+0.125 0.125 0.25 0 k
+Pc
+0.25 0.25 0.5 0 k
+Pc
+0.375 0.375 0.75 0 k
+Pc
+0.5 0.5 1 0 k
+Pc
+0.25 0.125 0.25 0 k
+Pc
+0.5 0.25 0.5 0 k
+Pc
+0.75 0.375 0.75 0 k
+Pc
+1 0.5 1 0 k
+Pc
+PB
+%AI5_EndPalette
+%%EndSetup
+%AI5_BeginLayer
+1 1 1 1 0 0 0 79 128 255 Lb
+(Layer 1) Ln
+0 A
+800 Ar
+0 J 0 j 1 w 4 M []0 d
+%AI3_Note:
+0 D
+0 XR
+-4014 283.5 m
+4626 283.5 L
+(N) *
+453.5 4716 m
+453.5 -3924 L
+(N) *
+85 4716 m
+85 -3924 L
+(N) *
+-4014 765.5 m
+4626 765.5 L
+(N) *
+1 Ap
+0 R
+0 G
+[6 8 6 8 6 8 ]0 d
+439.3333 689 m
+439.3333 751 L
+354 751 L
+354 689 L
+439.3333 689 L
+s
+322 523 m
+322 734.3333 L
+107.6667 734.3333 L
+107.6667 523 L
+322 523 L
+s
+u
+0 Ap
+1.1 w []0 d
+137.6876 560.816 m
+114.2154 572.6036 L
+114.2154 595.9724 L
+137.6876 607.7602 L
+161.1596 595.9724 L
+161.1596 572.6036 L
+137.6876 560.816 L
+s
+0 To
+1 0 0 1 137.6875 586.8542 0 Tp
+TP
+-21.665 0 Td
+0 Tr
+0 O
+0 g
+1 w
+/_Univers 10 Tf
+0 Ts
+100 Tz
+0 Tt
+1 TA
+%_ 0 XL
+36 0 Xb
+XB
+0 0 5 TC
+100 100 200 TW
+0 0 0 Ti
+1 Ta
+0 0 2 2 3 Th
+0 Tq
+0 0 Tl
+0 Tc
+0 Tw
+(Standard\r) Tx
+12.2217 -12 Td
+(MIB) Tx
+(\r) TX
+TO
+U
+u
+0 R
+0 G
+261.6169 564.0939 m
+244.5463 572.6667 L
+244.5463 589.6621 L
+261.6169 598.235 L
+278.6875 589.6621 L
+278.6875 572.6667 L
+261.6169 564.0939 L
+s
+0 To
+1 0 0 1 252.1735 577.7306 0 Tp
+TP
+0 Tr
+0 O
+0 g
+0 Ta
+(MIB) Tx
+(\r) TX
+TO
+U
+u
+0 R
+0 G
+298.4248 564.0939 m
+281.3542 572.6667 L
+281.3542 589.6621 L
+298.4248 598.235 L
+315.4954 589.6621 L
+315.4954 572.6667 L
+298.4248 564.0939 L
+s
+0 To
+1 0 0 1 288.9813 577.7306 0 Tp
+TP
+0 Tr
+0 O
+0 g
+(MIB) Tx
+(\r) TX
+TO
+U
+u
+0 R
+0 G
+203.1875 564.6667 m
+186.1168 573.2395 L
+186.1168 590.2349 L
+203.1875 598.8079 L
+220.2579 590.2349 L
+220.2579 573.2395 L
+203.1875 564.6667 L
+s
+0 To
+1 0 0 1 193.744 578.3034 0 Tp
+TP
+0 Tr
+0 O
+0 g
+(MIB) Tx
+(\r) TX
+TO
+U
+u
+1 Ap
+0 R
+0 G
+173.7708 529.6568 m
+193.3397 529.6568 209.2039 539.1753 209.2039 550.9166 c
+209.2039 562.6579 193.3397 572.1765 173.7708 572.1765 c
+154.2019 572.1765 138.3377 562.6579 138.3377 550.9166 c
+138.3377 539.1753 154.2019 529.6568 173.7708 529.6568 c
+s
+0 To
+1 0 0 1 173.7708 553.4828 0 Tp
+TP
+-16.3867 0 Td
+0 Tr
+0 O
+0 g
+1 Ta
+(Master\r) Tx
+2.2253 -12 Td
+(Agent) Tx
+(\r) TX
+TO
+U
+u
+0 R
+0 G
+280.0208 533.9921 m
+295.676 533.9921 308.3674 541.6069 308.3674 551 c
+308.3674 560.393 295.676 568.008 280.0208 568.008 c
+264.3656 568.008 251.6742 560.393 251.6742 551 c
+251.6742 541.6069 264.3656 533.9921 280.0208 533.9921 c
+s
+0 To
+1 0 0 1 280.0208 553.5662 0 Tp
+TP
+-9.4434 0 Td
+0 Tr
+0 O
+0 g
+(Sub\r) Tx
+-4.718 -12 Td
+(Agent) Tx
+(\r) TX
+TO
+U
+0 Ap
+0 R
+0 G
+98.6458 481.9583 m
+438.6458 481.9583 l
+S
+0 To
+1 0 0 1 93.3333 499.3333 0 Tp
+TP
+0 Tr
+0 O
+0 g
+0 Ta
+(Manager) Tx
+(\r) TX
+TO
+0 R
+0 G
+104.5 496.3333 m
+104.5 482 l
+S
+u
+195.3333 496.75 m
+195.3333 482 l
+S
+u
+1 Ap
+216.8333 496.75 m
+216.8333 523 L
+173.8333 523 L
+173.8333 496.75 L
+216.8333 496.75 L
+s
+0 To
+1 0 0 1 180.0574 506.4412 0 Tp
+TP
+0 Tr
+0 O
+0 g
+(Erlang) Tx
+(\r) TX
+TO
+U
+U
+u
+0 Ap
+0 R
+0 G
+391.6667 496.75 m
+391.6667 482 l
+S
+u
+1 Ap
+413.1667 496.75 m
+413.1667 523 L
+370.1667 523 L
+370.1667 496.75 L
+413.1667 496.75 L
+s
+0 To
+1 0 0 1 376.3908 506.4412 0 Tp
+TP
+0 Tr
+0 O
+0 g
+(Erlang) Tx
+(\r) TX
+TO
+U
+U
+u
+0 R
+0 G
+204.5065 690.9501 m
+207.8201 690.9501 210.5065 693.6364 210.5065 696.9501 C
+210.5065 720.3831 L
+210.5065 723.6969 207.8201 726.3832 204.5065 726.3832 C
+188.1602 726.3832 L
+184.8466 726.3832 182.1601 723.6969 182.1601 720.3831 C
+182.1601 696.9501 L
+182.1601 693.6364 184.8466 690.9501 188.1602 690.9501 C
+204.5065 690.9501 L
+s
+0 To
+1 0 0 1 196.3333 711.2328 0 Tp
+TP
+-12.4963 0 Td
+0 Tr
+0 O
+0 g
+1 Ta
+(Appl.\r) Tx
+9.7168 -12 Td
+(1) Tx
+(\r) TX
+TO
+U
+u
+0 R
+0 G
+238.5065 676.9501 m
+241.8201 676.9501 244.5065 679.6364 244.5065 682.9501 C
+244.5065 706.3831 L
+244.5065 709.6969 241.8201 712.3832 238.5065 712.3832 C
+222.1602 712.3832 L
+218.8466 712.3832 216.1601 709.6969 216.1601 706.3831 C
+216.1601 682.9501 L
+216.1601 679.6364 218.8466 676.9501 222.1602 676.9501 C
+238.5065 676.9501 L
+s
+0 To
+1 0 0 1 230.3333 697.2328 0 Tp
+TP
+-12.4963 0 Td
+0 Tr
+0 O
+0 g
+(Appl.\r) Tx
+9.7168 -12 Td
+(2) Tx
+(\r) TX
+TO
+U
+u
+0 R
+0 G
+272.5065 662.6168 m
+275.8201 662.6168 278.5065 665.3031 278.5065 668.6168 C
+278.5065 692.0498 L
+278.5065 695.3636 275.8201 698.0499 272.5065 698.0499 C
+256.1602 698.0499 L
+252.8466 698.0499 250.1601 695.3636 250.1601 692.0498 C
+250.1601 668.6168 L
+250.1601 665.3031 252.8466 662.6168 256.1602 662.6168 C
+272.5065 662.6168 L
+s
+0 To
+1 0 0 1 264.3333 682.8995 0 Tp
+TP
+-12.4963 0 Td
+0 Tr
+0 O
+0 g
+(Appl.\r) Tx
+9.7168 -12 Td
+(3) Tx
+(\r) TX
+TO
+U
+u
+0 R
+0 G
+306.5065 648.6168 m
+309.8201 648.6168 312.5065 651.3031 312.5065 654.6168 C
+312.5065 678.0498 L
+312.5065 681.3636 309.8201 684.0499 306.5065 684.0499 C
+290.1602 684.0499 L
+286.8466 684.0499 284.1601 681.3636 284.1601 678.0498 C
+284.1601 654.6168 L
+284.1601 651.3031 286.8466 648.6168 290.1602 648.6168 C
+306.5065 648.6168 L
+s
+0 To
+1 0 0 1 298.3333 668.8995 0 Tp
+TP
+-12.4963 0 Td
+0 Tr
+0 O
+0 g
+(Appl.\r) Tx
+9.7168 -12 Td
+(4) Tx
+(\r) TX
+TO
+U
+u
+0 R
+0 G
+373.1026 619.6168 m
+376.4161 619.6168 379.1026 622.3031 379.1026 625.6168 C
+379.1026 649.0498 L
+379.1026 652.3636 376.4161 655.0499 373.1026 655.0499 C
+356.7563 655.0499 L
+353.4427 655.0499 350.7561 652.3636 350.7561 649.0498 C
+350.7561 625.6168 L
+350.7561 622.3031 353.4427 619.6168 356.7563 619.6168 C
+373.1026 619.6168 L
+s
+0 To
+1 0 0 1 364.9293 639.8995 0 Tp
+TP
+-12.4963 0 Td
+0 Tr
+0 O
+0 g
+(Appl.\r) Tx
+9.7168 -12 Td
+(5) Tx
+(\r) TX
+TO
+U
+u
+0 R
+0 G
+416.1732 703.6168 m
+419.4868 703.6168 422.1732 706.3031 422.1732 709.6168 C
+422.1732 733.0498 L
+422.1732 736.3636 419.4868 739.0499 416.1732 739.0499 C
+399.8269 739.0499 L
+396.5133 739.0499 393.8268 736.3636 393.8268 733.0498 C
+393.8268 709.6168 L
+393.8268 706.3031 396.5133 703.6168 399.8269 703.6168 C
+416.1732 703.6168 L
+s
+0 To
+1 0 0 1 408 723.8995 0 Tp
+TP
+-12.4963 0 Td
+0 Tr
+0 O
+0 g
+(Appl.\r) Tx
+9.7168 -12 Td
+(6) Tx
+(\r) TX
+TO
+U
+0 To
+1 0 0 1 210 738 0 Tp
+TP
+-16.9458 0 Td
+0 Tr
+(Node 1) Tx
+(\r) TX
+TO
+0 To
+1 0 0 1 395.6667 755 0 Tp
+TP
+-16.9458 0 Td
+0 Tr
+(Node 3) Tx
+(\r) TX
+TO
+0 To
+1 0 0 1 383.3333 670 0 Tp
+TP
+-16.9458 0 Td
+0 Tr
+(Node 2) Tx
+(\r) TX
+TO
+0 To
+1 0 0 1 255 467.6667 0 Tp
+TP
+-19.9951 0 Td
+0 Tr
+(Network) Tx
+(\r) TX
+TO
+0 To
+1 0 0 1 158.6667 503 0 Tp
+TP
+-10.553 0 Td
+0 Tr
+(UDP) Tx
+(\r) TX
+TO
+u
+u
+0 Ap
+0 R
+0 G
+196.1667 682.9167 m
+202.5 606.5833 l
+S
+0 O
+0 g
+203.7167 604.3142 m
+204.0775 606.0031 204.447 607.1121 204.8679 608.478 c
+199.8409 608.0609 l
+200.1046 607.6064 201.0285 605.7501 201.6624 604.1437 c
+202.3416 602.4246 202.8386 600.8558 203.0548 599.8294 c
+203.0987 600.8774 203.3303 602.5066 203.7167 604.3142 c
+f
+194.9499 685.1859 m
+194.5892 683.4969 194.2196 682.388 193.7987 681.022 c
+198.8258 681.4391 l
+198.5621 681.8936 197.6381 683.7499 197.0042 685.3563 c
+196.325 687.0755 195.828 688.6442 195.6119 689.6706 c
+195.5679 688.6227 195.3363 686.9934 194.9499 685.1859 c
+f
+U
+U
+0 R
+0 G
+110.3333 492.3333 m
+152.1209 494.1551 165.3333 502 v
+176 508.3333 183.3333 519.3333 182 530 c
+S
+276.3333 533.6667 m
+281.3333 517.6667 296.3333 512.3333 v
+310.4293 507.3215 326.0289 506.8196 344.3333 512 c
+362 517 365.6667 521.3333 375.6667 534.6667 c
+S
+0 To
+1 0 0 1 310 497 0 Tp
+TP
+-42.7673 0 Td
+0 Tr
+0 O
+0 g
+(Distributed Erlang) Tx
+(\r) TX
+TO
+u
+u
+0 R
+0 G
+233.6667 668.6667 m
+258.3333 605.3333 l
+S
+0 O
+0 g
+260.1455 603.5043 m
+260.0107 605.2261 260.0494 606.3943 260.0641 607.8236 c
+255.3637 605.993 l
+255.7458 605.6322 257.1599 604.1157 258.2248 602.7562 c
+259.3652 601.3015 260.2881 599.9391 260.7874 599.0167 c
+260.5313 600.0338 260.2896 601.6616 260.1455 603.5043 c
+f
+231.8545 670.4957 m
+231.9893 668.7739 231.9506 667.6056 231.9359 666.1764 c
+236.6363 668.007 l
+236.2542 668.3677 234.8401 669.8842 233.7752 671.2438 c
+232.6348 672.6985 231.7119 674.0609 231.2126 674.9833 c
+231.4687 673.9662 231.7104 672.3384 231.8545 670.4957 c
+f
+U
+U
+u
+u
+u
+0 R
+0 G
+268.8303 655 m
+286.3333 601.3333 l
+S
+0 O
+0 g
+288.0401 599.4055 m
+288.002 601.1321 288.1062 602.2964 288.201 603.7226 c
+283.4054 602.1585 l
+283.7667 601.777 285.0934 600.1835 286.0803 598.7664 c
+287.1373 597.25 287.9824 595.8379 288.4291 594.889 c
+288.2305 595.9188 288.0805 597.5576 288.0401 599.4055 c
+f
+267.1236 656.9278 m
+267.1616 655.2012 267.0575 654.0369 266.9626 652.6107 c
+271.7583 654.1748 l
+271.397 654.5563 270.0702 656.1498 269.0833 657.5669 c
+268.0263 659.0833 267.1813 660.4954 266.7345 661.4443 c
+266.9331 660.4145 267.0831 658.7757 267.1236 656.9278 c
+f
+U
+U
+U
+u
+u
+0 R
+0 G
+298.3333 640.3125 m
+298.3333 605.9792 l
+S
+0 O
+0 g
+299.3582 603.6172 m
+299.8574 605.2705 300.3174 606.3451 300.8498 607.6716 c
+295.8055 607.6716 l
+296.0307 607.1968 296.798 605.2705 297.2969 603.6172 c
+297.8316 601.8478 298.1972 600.2433 298.3277 599.2026 c
+298.4582 600.2433 298.8237 601.8478 299.3582 603.6172 c
+f
+297.3084 642.6745 m
+296.8092 641.0212 296.3492 639.9466 295.8168 638.6201 c
+300.8611 638.6201 l
+300.6359 639.0949 299.8686 641.0212 299.3697 642.6745 c
+298.835 644.4439 298.4694 646.0484 298.3389 647.0891 c
+298.2084 646.0484 297.8429 644.4439 297.3084 642.6745 c
+f
+U
+U
+u
+u
+0 R
+0 G
+217 550 m
+244 550 l
+S
+0 O
+0 g
+246.362 551.0249 m
+244.7087 551.5241 243.6341 551.9841 242.3076 552.5165 c
+242.3076 547.4722 l
+242.7824 547.6974 244.7087 548.4647 246.362 548.9636 c
+248.1314 549.4983 249.7359 549.8639 250.7766 549.9944 c
+249.7359 550.1249 248.1314 550.4904 246.362 551.0249 c
+f
+214.638 548.9751 m
+216.2913 548.4759 217.3659 548.0159 218.6924 547.4835 c
+218.6924 552.5278 l
+218.2176 552.3026 216.2913 551.5353 214.638 551.0364 c
+212.8686 550.5017 211.2641 550.1361 210.2234 550.0056 c
+211.2641 549.8751 212.8686 549.5096 214.638 548.9751 c
+f
+U
+U
+u
+0 R
+0 G
+364.9294 563.9595 m
+347.8588 572.5323 L
+347.8588 589.5277 L
+364.9294 598.1006 L
+382 589.5277 L
+382 572.5323 L
+364.9294 563.9595 L
+s
+0 To
+1 0 0 1 355.486 577.5962 0 Tp
+TP
+0 Tr
+0 O
+0 g
+0 Ta
+(MIB) Tx
+(\r) TX
+TO
+U
+u
+0 R
+0 G
+401.7373 563.9595 m
+384.6667 572.5323 L
+384.6667 589.5277 L
+401.7373 598.1006 L
+418.8079 589.5277 L
+418.8079 572.5323 L
+401.7373 563.9595 L
+s
+0 To
+1 0 0 1 392.2938 577.5962 0 Tp
+TP
+0 Tr
+0 O
+0 g
+(MIB) Tx
+(\r) TX
+TO
+U
+u
+1 Ap
+0 R
+0 G
+383.3333 533.8577 m
+398.9885 533.8577 411.6799 541.4725 411.6799 550.8656 c
+411.6799 560.2586 398.9885 567.8736 383.3333 567.8736 c
+367.6781 567.8736 354.9867 560.2586 354.9867 550.8656 c
+354.9867 541.4725 367.6781 533.8577 383.3333 533.8577 c
+s
+0 To
+1 0 0 1 383.3333 553.4318 0 Tp
+TP
+-9.4434 0 Td
+0 Tr
+0 O
+0 g
+1 Ta
+(Sub\r) Tx
+-4.718 -12 Td
+(Agent) Tx
+(\r) TX
+TO
+U
+0 R
+0 G
+[6 8 6 8 6 8 ]0 d
+439.3333 523 m
+439.3333 666.3333 L
+331.3333 666.3333 L
+331.3333 523 L
+439.3333 523 L
+s
+u
+0 Ap
+[]0 d
+365.0208 604.6458 m
+365.0208 612.6458 l
+S
+0 O
+0 g
+363.9959 615.0078 m
+363.4967 613.3545 363.0367 612.2799 362.5043 610.9534 c
+367.5486 610.9534 l
+367.3234 611.4282 366.5561 613.3545 366.0572 615.0078 c
+365.5225 616.7772 365.1569 618.3817 365.0264 619.4224 c
+364.8959 618.3817 364.5304 616.7772 363.9959 615.0078 c
+f
+366.0457 602.2838 m
+366.5449 603.9371 367.0049 605.0117 367.5373 606.3382 c
+362.493 606.3382 l
+362.7182 605.8634 363.4855 603.9371 363.9844 602.2838 c
+364.5191 600.5144 364.8847 598.9099 365.0152 597.8692 c
+365.1457 598.9099 365.5112 600.5144 366.0457 602.2838 c
+f
+U
+u
+u
+0 R
+0 G
+402.4166 605.2917 m
+411.3333 695.6667 l
+S
+0 O
+0 g
+410.5453 698.1179 m
+409.8862 696.5216 409.3229 695.4974 408.6628 694.2295 c
+413.6827 693.7342 l
+413.5052 694.2289 412.9308 696.2212 412.5966 697.9155 c
+412.2383 699.7288 412.032 701.3615 412.0043 702.4099 c
+411.7722 701.3871 411.251 699.8262 410.5453 698.1179 c
+f
+U
+403.2089 602.8419 m
+403.8653 604.4393 404.4268 605.4645 405.0846 606.7335 c
+400.0639 607.22 l
+400.2422 606.7257 400.8201 604.7344 401.1573 603.0407 c
+401.5188 601.228 401.7279 599.5957 401.7575 598.5473 c
+401.9877 599.5705 402.5063 601.1323 403.2089 602.8419 c
+f
+U
+LB
+%AI5_EndLayer--
+%%PageTrailer
+gsave annotatepage grestore showpage
+%%Trailer
+Adobe_Illustrator_AI5 /terminate get exec
+Adobe_ColorImage_AI6 /terminate get exec
+Adobe_typography_AI5 /terminate get exec
+Adobe_level2_AI5 /terminate get exec
+%%EOF
diff --git a/lib/snmp/doc/src/snmp-um-1-image-8.gif b/lib/snmp/doc/src/snmp-um-1-image-8.gif
new file mode 100644
index 0000000000..db224a1937
--- /dev/null
+++ b/lib/snmp/doc/src/snmp-um-1-image-8.gif
Binary files differ
diff --git a/lib/snmp/doc/src/snmp-um-1-image-8.ps b/lib/snmp/doc/src/snmp-um-1-image-8.ps
new file mode 100644
index 0000000000..b16739aba0
--- /dev/null
+++ b/lib/snmp/doc/src/snmp-um-1-image-8.ps
@@ -0,0 +1,2931 @@
+%!PS-Adobe-3.0 EPSF-3.0
+%%Creator: Adobe Illustrator(r) 6.0
+%%For: (Anna Fedoriw) (Ericsson Telecom)
+%%Title: (ProcessesOnOneNode.eps)
+%%CreationDate: (97-05-23) (14.05)
+%%BoundingBox: 84 522 452 731
+%%HiResBoundingBox: 84.5 522.5 451.1162 730.5099
+%%DocumentProcessColors: Black
+%%DocumentFonts: Univers
+%%DocumentSuppliedResources: procset Adobe_level2_AI5 1.0 0
+%%+ procset Adobe_typography_AI5 1.0 0
+%%+ procset Adobe_Illustrator_AI6_vars Adobe_Illustrator_AI6
+%%+ procset Adobe_Illustrator_AI5 1.0 0
+%AI5_FileFormat 2.0
+%AI3_ColorUsage: Black&White
+%%AI6_ColorSeparationSet: 1 1 (AI6 Default Color Separation Set)
+%%+ Options: 1 16 0 1 0 1 1 1 0 1 1 1 1 18 0 0 0 0 0 0 0 0 -1 -1
+%%+ PPD: 1 21 0 0 60 45 2 2 1 0 0 1 0 0 0 0 0 0 0 0 0 0 ()
+%AI3_TemplateBox: 306 396 306 396
+%AI3_TileBox: 21 -12 588 802
+%AI3_DocumentPreview: Macintosh_ColorPic
+%AI5_ArtSize: 595.2756 841.8898
+%AI5_RulerUnits: 1
+%AI5_ArtFlags: 0 0 0 1 0 0 1 1 0
+%AI5_TargetResolution: 800
+%AI5_NumLayers: 1
+%AI5_OpenToView: 2 860 1.5 1146 827 58 1 1 3 40
+%AI5_OpenViewLayers: 7
+%%EndComments
+%%BeginProlog
+%%BeginResource: procset Adobe_level2_AI5 1.2 0
+%%Title: (Adobe Illustrator (R) Version 5.0 Level 2 Emulation)
+%%Version: 1.2
+%%CreationDate: (04/10/93) ()
+%%Copyright: ((C) 1987-1993 Adobe Systems Incorporated All Rights Reserved)
+userdict /Adobe_level2_AI5 23 dict dup begin
+ put
+ /packedarray where not
+ {
+ userdict begin
+ /packedarray
+ {
+ array astore readonly
+ } bind def
+ /setpacking /pop load def
+ /currentpacking false def
+ end
+ 0
+ } if
+ pop
+ userdict /defaultpacking currentpacking put true setpacking
+ /initialize
+ {
+ Adobe_level2_AI5 begin
+ } bind def
+ /terminate
+ {
+ currentdict Adobe_level2_AI5 eq
+ {
+ end
+ } if
+ } bind def
+ mark
+ /setcustomcolor where not
+ {
+ /findcmykcustomcolor
+ {
+ 5 packedarray
+ } bind def
+ /setcustomcolor
+ {
+ exch aload pop pop
+ 4
+ {
+ 4 index mul 4 1 roll
+ } repeat
+ 5 -1 roll pop
+ setcmykcolor
+ }
+ def
+ } if
+
+ /gt38? mark {version cvr cvx exec} stopped {cleartomark true} {38 gt exch pop} ifelse def
+ userdict /deviceDPI 72 0 matrix defaultmatrix dtransform dup mul exch dup mul add sqrt put
+ userdict /level2?
+ systemdict /languagelevel known dup
+ {
+ pop systemdict /languagelevel get 2 ge
+ } if
+ put
+/level2ScreenFreq
+{
+ begin
+ 60
+ HalftoneType 1 eq
+ {
+ pop Frequency
+ } if
+ HalftoneType 2 eq
+ {
+ pop GrayFrequency
+ } if
+ HalftoneType 5 eq
+ {
+ pop Default level2ScreenFreq
+ } if
+ end
+} bind def
+userdict /currentScreenFreq
+ level2? {currenthalftone level2ScreenFreq} {currentscreen pop pop} ifelse put
+level2? not
+ {
+ /setcmykcolor where not
+ {
+ /setcmykcolor
+ {
+ exch .11 mul add exch .59 mul add exch .3 mul add
+ 1 exch sub setgray
+ } def
+ } if
+ /currentcmykcolor where not
+ {
+ /currentcmykcolor
+ {
+ 0 0 0 1 currentgray sub
+ } def
+ } if
+ /setoverprint where not
+ {
+ /setoverprint /pop load def
+ } if
+ /selectfont where not
+ {
+ /selectfont
+ {
+ exch findfont exch
+ dup type /arraytype eq
+ {
+ makefont
+ }
+ {
+ scalefont
+ } ifelse
+ setfont
+ } bind def
+ } if
+ /cshow where not
+ {
+ /cshow
+ {
+ [
+ 0 0 5 -1 roll aload pop
+ ] cvx bind forall
+ } bind def
+ } if
+ } if
+ cleartomark
+ /anyColor?
+ {
+ add add add 0 ne
+ } bind def
+ /testColor
+ {
+ gsave
+ setcmykcolor currentcmykcolor
+ grestore
+ } bind def
+ /testCMYKColorThrough
+ {
+ testColor anyColor?
+ } bind def
+ userdict /composite?
+ level2?
+ {
+ gsave 1 1 1 1 setcmykcolor currentcmykcolor grestore
+ add add add 4 eq
+ }
+ {
+ 1 0 0 0 testCMYKColorThrough
+ 0 1 0 0 testCMYKColorThrough
+ 0 0 1 0 testCMYKColorThrough
+ 0 0 0 1 testCMYKColorThrough
+ and and and
+ } ifelse
+ put
+ composite? not
+ {
+ userdict begin
+ gsave
+ /cyan? 1 0 0 0 testCMYKColorThrough def
+ /magenta? 0 1 0 0 testCMYKColorThrough def
+ /yellow? 0 0 1 0 testCMYKColorThrough def
+ /black? 0 0 0 1 testCMYKColorThrough def
+ grestore
+ /isCMYKSep? cyan? magenta? yellow? black? or or or def
+ /customColor? isCMYKSep? not def
+ end
+ } if
+ end defaultpacking setpacking
+%%EndResource
+%%BeginResource: procset Adobe_typography_AI5 1.0 1
+%%Title: (Typography Operators)
+%%Version: 1.0
+%%CreationDate:(03/26/93) ()
+%%Copyright: ((C) 1987-1993 Adobe Systems Incorporated All Rights Reserved)
+currentpacking true setpacking
+userdict /Adobe_typography_AI5 54 dict dup begin
+put
+/initialize
+{
+ begin
+ begin
+ Adobe_typography_AI5 begin
+ Adobe_typography_AI5
+ {
+ dup xcheck
+ {
+ bind
+ } if
+ pop pop
+ } forall
+ end
+ end
+ end
+ Adobe_typography_AI5 begin
+} def
+/terminate
+{
+ currentdict Adobe_typography_AI5 eq
+ {
+ end
+ } if
+} def
+/modifyEncoding
+{
+ /_tempEncode exch ddef
+ /_pntr 0 ddef
+ {
+ counttomark -1 roll
+ dup type dup /marktype eq
+ {
+ pop pop exit
+ }
+ {
+ /nametype eq
+ {
+ _tempEncode /_pntr dup load dup 3 1 roll 1 add ddef 3 -1 roll
+ put
+ }
+ {
+ /_pntr exch ddef
+ } ifelse
+ } ifelse
+ } loop
+ _tempEncode
+} def
+/TE
+{
+ StandardEncoding 256 array copy modifyEncoding
+ /_nativeEncoding exch def
+} def
+%
+/TZ
+{
+ dup type /arraytype eq
+ {
+ /_wv exch def
+ }
+ {
+ /_wv 0 def
+ } ifelse
+ /_useNativeEncoding exch def
+ pop pop
+ findfont _wv type /arraytype eq
+ {
+ _wv makeblendedfont
+ } if
+ dup length 2 add dict
+ begin
+ mark exch
+ {
+ 1 index /FID ne
+ {
+ def
+ } if
+ cleartomark mark
+ } forall
+ pop
+ /FontName exch def
+ counttomark 0 eq
+ {
+ 1 _useNativeEncoding eq
+ {
+ /Encoding _nativeEncoding def
+ } if
+ cleartomark
+ }
+ {
+ /Encoding load 256 array copy
+ modifyEncoding /Encoding exch def
+ } ifelse
+ FontName currentdict
+ end
+ definefont pop
+} def
+/tr
+{
+ _ax _ay 3 2 roll
+} def
+/trj
+{
+ _cx _cy _sp _ax _ay 6 5 roll
+} def
+/a0
+{
+ /Tx
+ {
+ dup
+ currentpoint 3 2 roll
+ tr _psf
+ newpath moveto
+ tr _ctm _pss
+ } ddef
+ /Tj
+ {
+ dup
+ currentpoint 3 2 roll
+ trj _pjsf
+ newpath moveto
+ trj _ctm _pjss
+ } ddef
+} def
+/a1
+{
+ /Tx
+ {
+ dup currentpoint 4 2 roll gsave
+ dup currentpoint 3 2 roll
+ tr _psf
+ newpath moveto
+ tr _ctm _pss
+ grestore 3 1 roll moveto tr sp
+ } ddef
+ /Tj
+ {
+ dup currentpoint 4 2 roll gsave
+ dup currentpoint 3 2 roll
+ trj _pjsf
+ newpath moveto
+ trj _ctm _pjss
+ grestore 3 1 roll moveto tr jsp
+ } ddef
+} def
+/e0
+{
+ /Tx
+ {
+ tr _psf
+ } ddef
+ /Tj
+ {
+ trj _pjsf
+ } ddef
+} def
+/e1
+{
+ /Tx
+ {
+ dup currentpoint 4 2 roll gsave
+ tr _psf
+ grestore 3 1 roll moveto tr sp
+ } ddef
+ /Tj
+ {
+ dup currentpoint 4 2 roll gsave
+ trj _pjsf
+ grestore 3 1 roll moveto tr jsp
+ } ddef
+} def
+/i0
+{
+ /Tx
+ {
+ tr sp
+ } ddef
+ /Tj
+ {
+ trj jsp
+ } ddef
+} def
+/i1
+{
+ W N
+} def
+/o0
+{
+ /Tx
+ {
+ tr sw rmoveto
+ } ddef
+ /Tj
+ {
+ trj swj rmoveto
+ } ddef
+} def
+/r0
+{
+ /Tx
+ {
+ tr _ctm _pss
+ } ddef
+ /Tj
+ {
+ trj _ctm _pjss
+ } ddef
+} def
+/r1
+{
+ /Tx
+ {
+ dup currentpoint 4 2 roll currentpoint gsave newpath moveto
+ tr _ctm _pss
+ grestore 3 1 roll moveto tr sp
+ } ddef
+ /Tj
+ {
+ dup currentpoint 4 2 roll currentpoint gsave newpath moveto
+ trj _ctm _pjss
+ grestore 3 1 roll moveto tr jsp
+ } ddef
+} def
+/To
+{
+ pop _ctm currentmatrix pop
+} def
+/TO
+{
+ iTe _ctm setmatrix newpath
+} def
+/Tp
+{
+ pop _tm astore pop _ctm setmatrix
+ _tDict begin
+ /W
+ {
+ } def
+ /h
+ {
+ } def
+} def
+/TP
+{
+ end
+ iTm 0 0 moveto
+} def
+/Tr
+{
+ _render 3 le
+ {
+ currentpoint newpath moveto
+ } if
+ dup 8 eq
+ {
+ pop 0
+ }
+ {
+ dup 9 eq
+ {
+ pop 1
+ } if
+ } ifelse
+ dup /_render exch ddef
+ _renderStart exch get load exec
+} def
+/iTm
+{
+ _ctm setmatrix _tm concat 0 _rise translate _hs 1 scale
+} def
+/Tm
+{
+ _tm astore pop iTm 0 0 moveto
+} def
+/Td
+{
+ _mtx translate _tm _tm concatmatrix pop iTm 0 0 moveto
+} def
+/iTe
+{
+ _render -1 eq
+ {
+ }
+ {
+ _renderEnd _render get dup null ne
+ {
+ load exec
+ }
+ {
+ pop
+ } ifelse
+ } ifelse
+ /_render -1 ddef
+} def
+/Ta
+{
+ pop
+} def
+/Tf
+{
+ dup 1000 div /_fScl exch ddef
+%
+ selectfont
+} def
+/Tl
+{
+ pop
+ 0 exch _leading astore pop
+} def
+/Tt
+{
+ pop
+} def
+/TW
+{
+ 3 npop
+} def
+/Tw
+{
+ /_cx exch ddef
+} def
+/TC
+{
+ 3 npop
+} def
+/Tc
+{
+ /_ax exch ddef
+} def
+/Ts
+{
+ /_rise exch ddef
+ currentpoint
+ iTm
+ moveto
+} def
+/Ti
+{
+ 3 npop
+} def
+/Tz
+{
+ 100 div /_hs exch ddef
+ iTm
+} def
+/TA
+{
+ pop
+} def
+/Tq
+{
+ pop
+} def
+/Th
+{
+ pop pop pop pop pop
+} def
+/TX
+{
+ pop
+} def
+/Tk
+{
+ exch pop _fScl mul neg 0 rmoveto
+} def
+/TK
+{
+ 2 npop
+} def
+/T*
+{
+ _leading aload pop neg Td
+} def
+/T*-
+{
+ _leading aload pop Td
+} def
+/T-
+{
+ _ax neg 0 rmoveto
+ _hyphen Tx
+} def
+/T+
+{
+} def
+/TR
+{
+ _ctm currentmatrix pop
+ _tm astore pop
+ iTm 0 0 moveto
+} def
+/TS
+{
+ currentfont 3 1 roll
+ /_Symbol_ _fScl 1000 mul selectfont
+
+ 0 eq
+ {
+ Tx
+ }
+ {
+ Tj
+ } ifelse
+ setfont
+} def
+/Xb
+{
+ pop pop
+} def
+/Tb /Xb load def
+/Xe
+{
+ pop pop pop pop
+} def
+/Te /Xe load def
+/XB
+{
+} def
+/TB /XB load def
+currentdict readonly pop
+end
+setpacking
+%%EndResource
+%%BeginProcSet: Adobe_ColorImage_AI6 1.0 0
+userdict /Adobe_ColorImage_AI6 known not
+{
+ userdict /Adobe_ColorImage_AI6 17 dict put
+} if
+userdict /Adobe_ColorImage_AI6 get begin
+
+ /initialize
+ {
+ Adobe_ColorImage_AI6 begin
+ Adobe_ColorImage_AI6
+ {
+ dup type /arraytype eq
+ {
+ dup xcheck
+ {
+ bind
+ } if
+ } if
+ pop pop
+ } forall
+ } def
+ /terminate { end } def
+
+ currentdict /Adobe_ColorImage_AI6_Vars known not
+ {
+ /Adobe_ColorImage_AI6_Vars 14 dict def
+ } if
+
+ Adobe_ColorImage_AI6_Vars begin
+ /channelcount 0 def
+ /sourcecount 0 def
+ /sourcearray 4 array def
+ /plateindex -1 def
+ /XIMask 0 def
+ /XIBinary 0 def
+ /XIChannelCount 0 def
+ /XIBitsPerPixel 0 def
+ /XIImageHeight 0 def
+ /XIImageWidth 0 def
+ /XIImageMatrix null def
+ /XIBuffer null def
+ /XIDataProc null def
+ end
+
+ /WalkRGBString null def
+ /WalkCMYKString null def
+
+ /StuffRGBIntoGrayString null def
+ /RGBToGrayImageProc null def
+ /StuffCMYKIntoGrayString null def
+ /CMYKToGrayImageProc null def
+ /ColorImageCompositeEmulator null def
+
+ /SeparateCMYKImageProc null def
+
+ /FourEqual null def
+ /TestPlateIndex null def
+
+ currentdict /_colorimage known not
+ {
+ /colorimage where
+ {
+ /colorimage get /_colorimage exch def
+ }
+ {
+ /_colorimage null def
+ } ifelse
+ } if
+
+ /_currenttransfer systemdict /currenttransfer get def
+
+ /colorimage null def
+ /XI null def
+
+
+ /WalkRGBString
+ {
+ 0 3 index
+
+ dup length 1 sub 0 3 3 -1 roll
+ {
+ 3 getinterval { } forall
+
+ 5 index exec
+
+ 3 index
+ } for
+
+ 5 { pop } repeat
+
+ } def
+
+
+ /WalkCMYKString
+ {
+ 0 3 index
+
+ dup length 1 sub 0 4 3 -1 roll
+ {
+ 4 getinterval { } forall
+
+ 6 index exec
+
+ 3 index
+
+ } for
+
+ 5 { pop } repeat
+
+ } def
+
+
+ /StuffRGBIntoGrayString
+ {
+ .11 mul exch
+
+ .59 mul add exch
+
+ .3 mul add
+
+ cvi 3 copy put
+
+ pop 1 add
+ } def
+
+
+ /RGBToGrayImageProc
+ {
+ Adobe_ColorImage_AI6_Vars begin
+ sourcearray 0 get exec
+ dup length 3 idiv string
+ dup 3 1 roll
+
+ /StuffRGBIntoGrayString load exch
+ WalkRGBString
+ end
+ } def
+
+
+ /StuffCMYKIntoGrayString
+ {
+ exch .11 mul add
+
+ exch .59 mul add
+
+ exch .3 mul add
+
+ dup 255 gt { pop 255 } if
+
+ 255 exch sub cvi 3 copy put
+
+ pop 1 add
+ } def
+
+
+ /CMYKToGrayImageProc
+ {
+ Adobe_ColorImage_AI6_Vars begin
+ sourcearray 0 get exec
+ dup length 4 idiv string
+ dup 3 1 roll
+
+ /StuffCMYKIntoGrayString load exch
+ WalkCMYKString
+ end
+ } def
+
+
+ /ColorImageCompositeEmulator
+ {
+ pop true eq
+ {
+ Adobe_ColorImage_AI6_Vars /sourcecount get 5 add { pop } repeat
+ }
+ {
+ Adobe_ColorImage_AI6_Vars /channelcount get 1 ne
+ {
+ Adobe_ColorImage_AI6_Vars begin
+ sourcearray 0 3 -1 roll put
+
+ channelcount 3 eq
+ {
+ /RGBToGrayImageProc
+ }
+ {
+ /CMYKToGrayImageProc
+ } ifelse
+ load
+ end
+ } if
+ image
+ } ifelse
+ } def
+
+
+ /SeparateCMYKImageProc
+ {
+ Adobe_ColorImage_AI6_Vars begin
+
+ sourcecount 0 ne
+ {
+ sourcearray plateindex get exec
+ }
+ {
+ sourcearray 0 get exec
+
+ dup length 4 idiv string
+
+ 0 2 index
+
+ plateindex 4 2 index length 1 sub
+ {
+ get 255 exch sub
+
+ 3 copy put pop 1 add
+
+ 2 index
+ } for
+
+ pop pop exch pop
+ } ifelse
+ end
+ } def
+
+
+ /FourEqual
+ {
+ 4 index ne
+ {
+ pop pop pop false
+ }
+ {
+ 4 index ne
+ {
+ pop pop false
+ }
+ {
+ 4 index ne
+ {
+ pop false
+ }
+ {
+ 4 index eq
+ } ifelse
+ } ifelse
+ } ifelse
+ } def
+
+
+ /TestPlateIndex
+ {
+ Adobe_ColorImage_AI6_Vars begin
+ /plateindex -1 def
+
+ /setcmykcolor where
+ {
+ pop
+ gsave
+ 1 0 0 0 setcmykcolor systemdict /currentgray get exec 1 exch sub
+ 0 1 0 0 setcmykcolor systemdict /currentgray get exec 1 exch sub
+ 0 0 1 0 setcmykcolor systemdict /currentgray get exec 1 exch sub
+ 0 0 0 1 setcmykcolor systemdict /currentgray get exec 1 exch sub
+ grestore
+
+ 1 0 0 0 FourEqual
+ {
+ /plateindex 0 def
+ }
+ {
+ 0 1 0 0 FourEqual
+ {
+ /plateindex 1 def
+ }
+ {
+ 0 0 1 0 FourEqual
+ {
+ /plateindex 2 def
+ }
+ {
+ 0 0 0 1 FourEqual
+ {
+ /plateindex 3 def
+ }
+ {
+ 0 0 0 0 FourEqual
+ {
+ /plateindex 5 def
+ } if
+ } ifelse
+ } ifelse
+ } ifelse
+ } ifelse
+ pop pop pop pop
+ } if
+ plateindex
+ end
+ } def
+
+
+ /colorimage
+ {
+ Adobe_ColorImage_AI6_Vars begin
+ /channelcount 1 index def
+ /sourcecount 2 index 1 eq { channelcount 1 sub } { 0 } ifelse def
+
+ 4 sourcecount add index dup
+ 8 eq exch 1 eq or not
+ end
+
+ {
+ /_colorimage load null ne
+ {
+ _colorimage
+ }
+ {
+ Adobe_ColorImage_AI6_Vars /sourcecount get
+ 7 add { pop } repeat
+ } ifelse
+ }
+ {
+ dup 3 eq
+ TestPlateIndex
+ dup -1 eq exch 5 eq or or
+ {
+ /_colorimage load null eq
+ {
+ ColorImageCompositeEmulator
+ }
+ {
+ dup 1 eq
+ {
+ pop pop image
+ }
+ {
+ Adobe_ColorImage_AI6_Vars /plateindex get 5 eq
+ {
+ gsave
+
+ 0 _currenttransfer exec
+ 1 _currenttransfer exec
+ eq
+ { 0 _currenttransfer exec 0.5 lt }
+ { 0 _currenttransfer exec 1 _currenttransfer exec gt } ifelse
+
+ { { pop 0 } } { { pop 1 } } ifelse
+ systemdict /settransfer get exec
+ } if
+
+ _colorimage
+
+ Adobe_ColorImage_AI6_Vars /plateindex get 5 eq
+ {
+ grestore
+ } if
+ } ifelse
+ } ifelse
+ }
+ {
+ dup 1 eq
+ {
+ pop pop
+ image
+ }
+ {
+ pop pop
+
+ Adobe_ColorImage_AI6_Vars begin
+ sourcecount -1 0
+ {
+ exch sourcearray 3 1 roll put
+ } for
+
+ /SeparateCMYKImageProc load
+ end
+
+ systemdict /image get exec
+ } ifelse
+ } ifelse
+ } ifelse
+ } def
+
+ /XI
+ {
+ Adobe_ColorImage_AI6_Vars begin
+ gsave
+ /XIMask exch 0 ne def
+ /XIBinary exch 0 ne def
+ pop
+ pop
+ /XIChannelCount exch def
+ /XIBitsPerPixel exch def
+ /XIImageHeight exch def
+ /XIImageWidth exch def
+ pop pop pop pop
+ /XIImageMatrix exch def
+
+ XIBitsPerPixel 1 eq
+ {
+ XIImageWidth 8 div ceiling cvi
+ }
+ {
+ XIImageWidth XIChannelCount mul
+ } ifelse
+ /XIBuffer exch string def
+
+ XIBinary
+ {
+ /XIDataProc { currentfile XIBuffer readstring pop } def
+ currentfile 128 string readline pop pop
+ }
+ {
+ /XIDataProc { currentfile XIBuffer readhexstring pop } def
+ } ifelse
+
+ 0 0 moveto
+ XIImageMatrix concat
+ XIImageWidth XIImageHeight scale
+
+ XIMask
+ {
+ XIImageWidth XIImageHeight
+ false
+ [ XIImageWidth 0 0 XIImageHeight neg 0 0 ]
+ /XIDataProc load
+
+ /_lp /null ddef
+ _fc
+ /_lp /imagemask ddef
+
+ imagemask
+ }
+ {
+ XIImageWidth XIImageHeight
+ XIBitsPerPixel
+ [ XIImageWidth 0 0 XIImageHeight neg 0 0 ]
+ /XIDataProc load
+
+ XIChannelCount 1 eq
+ {
+
+ gsave
+ 0 setgray
+
+ image
+
+ grestore
+ }
+ {
+ false
+ XIChannelCount
+ colorimage
+ } ifelse
+ } ifelse
+ grestore
+ end
+ } def
+
+end
+%%EndProcSet
+%%BeginResource: procset Adobe_Illustrator_AI5 1.1 0
+%%Title: (Adobe Illustrator (R) Version 5.0 Full Prolog)
+%%Version: 1.1
+%%CreationDate: (3/7/1994) ()
+%%Copyright: ((C) 1987-1994 Adobe Systems Incorporated All Rights Reserved)
+currentpacking true setpacking
+userdict /Adobe_Illustrator_AI5_vars 81 dict dup begin
+put
+/_eo false def
+/_lp /none def
+/_pf
+{
+} def
+/_ps
+{
+} def
+/_psf
+{
+} def
+/_pss
+{
+} def
+/_pjsf
+{
+} def
+/_pjss
+{
+} def
+/_pola 0 def
+/_doClip 0 def
+/cf currentflat def
+/_tm matrix def
+/_renderStart
+[
+/e0 /r0 /a0 /o0 /e1 /r1 /a1 /i0
+] def
+/_renderEnd
+[
+null null null null /i1 /i1 /i1 /i1
+] def
+/_render -1 def
+/_rise 0 def
+/_ax 0 def
+/_ay 0 def
+/_cx 0 def
+/_cy 0 def
+/_leading
+[
+0 0
+] def
+/_ctm matrix def
+/_mtx matrix def
+/_sp 16#020 def
+/_hyphen (-) def
+/_fScl 0 def
+/_cnt 0 def
+/_hs 1 def
+/_nativeEncoding 0 def
+/_useNativeEncoding 0 def
+/_tempEncode 0 def
+/_pntr 0 def
+/_tDict 2 dict def
+/_wv 0 def
+/Tx
+{
+} def
+/Tj
+{
+} def
+/CRender
+{
+} def
+/_AI3_savepage
+{
+} def
+/_gf null def
+/_cf 4 array def
+/_if null def
+/_of false def
+/_fc
+{
+} def
+/_gs null def
+/_cs 4 array def
+/_is null def
+/_os false def
+/_sc
+{
+} def
+/_pd 1 dict def
+/_ed 15 dict def
+/_pm matrix def
+/_fm null def
+/_fd null def
+/_fdd null def
+/_sm null def
+/_sd null def
+/_sdd null def
+/_i null def
+/discardSave null def
+/buffer 256 string def
+/beginString null def
+/endString null def
+/endStringLength null def
+/layerCnt 1 def
+/layerCount 1 def
+/perCent (%) 0 get def
+/perCentSeen? false def
+/newBuff null def
+/newBuffButFirst null def
+/newBuffLast null def
+/clipForward? false def
+end
+userdict /Adobe_Illustrator_AI5 known not {
+ userdict /Adobe_Illustrator_AI5 91 dict put
+} if
+userdict /Adobe_Illustrator_AI5 get begin
+/initialize
+{
+ Adobe_Illustrator_AI5 dup begin
+ Adobe_Illustrator_AI5_vars begin
+ discardDict
+ {
+ bind pop pop
+ } forall
+ dup /nc get begin
+ {
+ dup xcheck 1 index type /operatortype ne and
+ {
+ bind
+ } if
+ pop pop
+ } forall
+ end
+ newpath
+} def
+/terminate
+{
+ end
+ end
+} def
+/_
+null def
+/ddef
+{
+ Adobe_Illustrator_AI5_vars 3 1 roll put
+} def
+/xput
+{
+ dup load dup length exch maxlength eq
+ {
+ dup dup load dup
+ length 2 mul dict copy def
+ } if
+ load begin
+ def
+ end
+} def
+/npop
+{
+ {
+ pop
+ } repeat
+} def
+/sw
+{
+ dup length exch stringwidth
+ exch 5 -1 roll 3 index mul add
+ 4 1 roll 3 1 roll mul add
+} def
+/swj
+{
+ dup 4 1 roll
+ dup length exch stringwidth
+ exch 5 -1 roll 3 index mul add
+ 4 1 roll 3 1 roll mul add
+ 6 2 roll /_cnt 0 ddef
+ {
+ 1 index eq
+ {
+ /_cnt _cnt 1 add ddef
+ } if
+ } forall
+ pop
+ exch _cnt mul exch _cnt mul 2 index add 4 1 roll 2 index add 4 1 roll pop pop
+} def
+/ss
+{
+ 4 1 roll
+ {
+ 2 npop
+ (0) exch 2 copy 0 exch put pop
+ gsave
+ false charpath currentpoint
+ 4 index setmatrix
+ stroke
+ grestore
+ moveto
+ 2 copy rmoveto
+ } exch cshow
+ 3 npop
+} def
+/jss
+{
+ 4 1 roll
+ {
+ 2 npop
+ (0) exch 2 copy 0 exch put
+ gsave
+ _sp eq
+ {
+ exch 6 index 6 index 6 index 5 -1 roll widthshow
+ currentpoint
+ }
+ {
+ false charpath currentpoint
+ 4 index setmatrix stroke
+ } ifelse
+ grestore
+ moveto
+ 2 copy rmoveto
+ } exch cshow
+ 6 npop
+} def
+/sp
+{
+ {
+ 2 npop (0) exch
+ 2 copy 0 exch put pop
+ false charpath
+ 2 copy rmoveto
+ } exch cshow
+ 2 npop
+} def
+/jsp
+{
+ {
+ 2 npop
+ (0) exch 2 copy 0 exch put
+ _sp eq
+ {
+ exch 5 index 5 index 5 index 5 -1 roll widthshow
+ }
+ {
+ false charpath
+ } ifelse
+ 2 copy rmoveto
+ } exch cshow
+ 5 npop
+} def
+/pl
+{
+ transform
+ 0.25 sub round 0.25 add exch
+ 0.25 sub round 0.25 add exch
+ itransform
+} def
+/setstrokeadjust where
+{
+ pop true setstrokeadjust
+ /c
+ {
+ curveto
+ } def
+ /C
+ /c load def
+ /v
+ {
+ currentpoint 6 2 roll curveto
+ } def
+ /V
+ /v load def
+ /y
+ {
+ 2 copy curveto
+ } def
+ /Y
+ /y load def
+ /l
+ {
+ lineto
+ } def
+ /L
+ /l load def
+ /m
+ {
+ moveto
+ } def
+}
+{
+ /c
+ {
+ pl curveto
+ } def
+ /C
+ /c load def
+ /v
+ {
+ currentpoint 6 2 roll pl curveto
+ } def
+ /V
+ /v load def
+ /y
+ {
+ pl 2 copy curveto
+ } def
+ /Y
+ /y load def
+ /l
+ {
+ pl lineto
+ } def
+ /L
+ /l load def
+ /m
+ {
+ pl moveto
+ } def
+} ifelse
+/d
+{
+ setdash
+} def
+/cf
+{
+} def
+/i
+{
+ dup 0 eq
+ {
+ pop cf
+ } if
+ setflat
+} def
+/j
+{
+ setlinejoin
+} def
+/J
+{
+ setlinecap
+} def
+/M
+{
+ setmiterlimit
+} def
+/w
+{
+ setlinewidth
+} def
+/XR
+{
+ 0 ne
+ /_eo exch ddef
+} def
+/H
+{
+} def
+/h
+{
+ closepath
+} def
+/N
+{
+ _pola 0 eq
+ {
+ _doClip 1 eq
+ {
+ _eo {eoclip} {clip} ifelse /_doClip 0 ddef
+ } if
+ newpath
+ }
+ {
+ /CRender
+ {
+ N
+ } ddef
+ } ifelse
+} def
+/n
+{
+ N
+} def
+/F
+{
+ _pola 0 eq
+ {
+ _doClip 1 eq
+ {
+ gsave _pf grestore _eo {eoclip} {clip} ifelse newpath /_lp /none ddef _fc
+ /_doClip 0 ddef
+ }
+ {
+ _pf
+ } ifelse
+ }
+ {
+ /CRender
+ {
+ F
+ } ddef
+ } ifelse
+} def
+/f
+{
+ closepath
+ F
+} def
+/S
+{
+ _pola 0 eq
+ {
+ _doClip 1 eq
+ {
+ gsave _ps grestore _eo {eoclip} {clip} ifelse newpath /_lp /none ddef _sc
+ /_doClip 0 ddef
+ }
+ {
+ _ps
+ } ifelse
+ }
+ {
+ /CRender
+ {
+ S
+ } ddef
+ } ifelse
+} def
+/s
+{
+ closepath
+ S
+} def
+/B
+{
+ _pola 0 eq
+ {
+ _doClip 1 eq
+ gsave F grestore
+ {
+ gsave S grestore _eo {eoclip} {clip} ifelse newpath /_lp /none ddef _sc
+ /_doClip 0 ddef
+ }
+ {
+ S
+ } ifelse
+ }
+ {
+ /CRender
+ {
+ B
+ } ddef
+ } ifelse
+} def
+/b
+{
+ closepath
+ B
+} def
+/W
+{
+ /_doClip 1 ddef
+} def
+/*
+{
+ count 0 ne
+ {
+ dup type /stringtype eq
+ {
+ pop
+ } if
+ } if
+ newpath
+} def
+/u
+{
+} def
+/U
+{
+} def
+/q
+{
+ _pola 0 eq
+ {
+ gsave
+ } if
+} def
+/Q
+{
+ _pola 0 eq
+ {
+ grestore
+ } if
+} def
+/*u
+{
+ _pola 1 add /_pola exch ddef
+} def
+/*U
+{
+ _pola 1 sub /_pola exch ddef
+ _pola 0 eq
+ {
+ CRender
+ } if
+} def
+/D
+{
+ pop
+} def
+/*w
+{
+} def
+/*W
+{
+} def
+/`
+{
+ /_i save ddef
+ clipForward?
+ {
+ nulldevice
+ } if
+ 6 1 roll 4 npop
+ concat pop
+ userdict begin
+ /showpage
+ {
+ } def
+ 0 setgray
+ 0 setlinecap
+ 1 setlinewidth
+ 0 setlinejoin
+ 10 setmiterlimit
+ [] 0 setdash
+ /setstrokeadjust where {pop false setstrokeadjust} if
+ newpath
+ 0 setgray
+ false setoverprint
+} def
+/~
+{
+ end
+ _i restore
+} def
+/O
+{
+ 0 ne
+ /_of exch ddef
+ /_lp /none ddef
+} def
+/R
+{
+ 0 ne
+ /_os exch ddef
+ /_lp /none ddef
+} def
+/g
+{
+ /_gf exch ddef
+ /_fc
+ {
+ _lp /fill ne
+ {
+ _of setoverprint
+ _gf setgray
+ /_lp /fill ddef
+ } if
+ } ddef
+ /_pf
+ {
+ _fc
+ _eo {eofill} {fill} ifelse
+ } ddef
+ /_psf
+ {
+ _fc
+ ashow
+ } ddef
+ /_pjsf
+ {
+ _fc
+ awidthshow
+ } ddef
+ /_lp /none ddef
+} def
+/G
+{
+ /_gs exch ddef
+ /_sc
+ {
+ _lp /stroke ne
+ {
+ _os setoverprint
+ _gs setgray
+ /_lp /stroke ddef
+ } if
+ } ddef
+ /_ps
+ {
+ _sc
+ stroke
+ } ddef
+ /_pss
+ {
+ _sc
+ ss
+ } ddef
+ /_pjss
+ {
+ _sc
+ jss
+ } ddef
+ /_lp /none ddef
+} def
+/k
+{
+ _cf astore pop
+ /_fc
+ {
+ _lp /fill ne
+ {
+ _of setoverprint
+ _cf aload pop setcmykcolor
+ /_lp /fill ddef
+ } if
+ } ddef
+ /_pf
+ {
+ _fc
+ _eo {eofill} {fill} ifelse
+ } ddef
+ /_psf
+ {
+ _fc
+ ashow
+ } ddef
+ /_pjsf
+ {
+ _fc
+ awidthshow
+ } ddef
+ /_lp /none ddef
+} def
+/K
+{
+ _cs astore pop
+ /_sc
+ {
+ _lp /stroke ne
+ {
+ _os setoverprint
+ _cs aload pop setcmykcolor
+ /_lp /stroke ddef
+ } if
+ } ddef
+ /_ps
+ {
+ _sc
+ stroke
+ } ddef
+ /_pss
+ {
+ _sc
+ ss
+ } ddef
+ /_pjss
+ {
+ _sc
+ jss
+ } ddef
+ /_lp /none ddef
+} def
+/x
+{
+ /_gf exch ddef
+ findcmykcustomcolor
+ /_if exch ddef
+ /_fc
+ {
+ _lp /fill ne
+ {
+ _of setoverprint
+ _if _gf 1 exch sub setcustomcolor
+ /_lp /fill ddef
+ } if
+ } ddef
+ /_pf
+ {
+ _fc
+ _eo {eofill} {fill} ifelse
+ } ddef
+ /_psf
+ {
+ _fc
+ ashow
+ } ddef
+ /_pjsf
+ {
+ _fc
+ awidthshow
+ } ddef
+ /_lp /none ddef
+} def
+/X
+{
+ /_gs exch ddef
+ findcmykcustomcolor
+ /_is exch ddef
+ /_sc
+ {
+ _lp /stroke ne
+ {
+ _os setoverprint
+ _is _gs 1 exch sub setcustomcolor
+ /_lp /stroke ddef
+ } if
+ } ddef
+ /_ps
+ {
+ _sc
+ stroke
+ } ddef
+ /_pss
+ {
+ _sc
+ ss
+ } ddef
+ /_pjss
+ {
+ _sc
+ jss
+ } ddef
+ /_lp /none ddef
+} def
+/A
+{
+ pop
+} def
+/annotatepage
+{
+userdict /annotatepage 2 copy known {get exec} {pop pop} ifelse
+} def
+/XT {
+ pop pop
+} def
+/discard
+{
+ save /discardSave exch store
+ discardDict begin
+ /endString exch store
+ gt38?
+ {
+ 2 add
+ } if
+ load
+ stopped
+ pop
+ end
+ discardSave restore
+} bind def
+userdict /discardDict 7 dict dup begin
+put
+/pre38Initialize
+{
+ /endStringLength endString length store
+ /newBuff buffer 0 endStringLength getinterval store
+ /newBuffButFirst newBuff 1 endStringLength 1 sub getinterval store
+ /newBuffLast newBuff endStringLength 1 sub 1 getinterval store
+} def
+/shiftBuffer
+{
+ newBuff 0 newBuffButFirst putinterval
+ newBuffLast 0
+ currentfile read not
+ {
+ stop
+ } if
+ put
+} def
+0
+{
+ pre38Initialize
+ mark
+ currentfile newBuff readstring exch pop
+ {
+ {
+ newBuff endString eq
+ {
+ cleartomark stop
+ } if
+ shiftBuffer
+ } loop
+ }
+ {
+ stop
+ } ifelse
+} def
+1
+{
+ pre38Initialize
+ /beginString exch store
+ mark
+ currentfile newBuff readstring exch pop
+ {
+ {
+ newBuff beginString eq
+ {
+ /layerCount dup load 1 add store
+ }
+ {
+ newBuff endString eq
+ {
+ /layerCount dup load 1 sub store
+ layerCount 0 eq
+ {
+ cleartomark stop
+ } if
+ } if
+ } ifelse
+ shiftBuffer
+ } loop
+ } if
+} def
+2
+{
+ mark
+ {
+ currentfile buffer readline not
+ {
+ stop
+ } if
+ endString eq
+ {
+ cleartomark stop
+ } if
+ } loop
+} def
+3
+{
+ /beginString exch store
+ /layerCnt 1 store
+ mark
+ {
+ currentfile buffer readline not
+ {
+ stop
+ } if
+ dup beginString eq
+ {
+ pop /layerCnt dup load 1 add store
+ }
+ {
+ endString eq
+ {
+ layerCnt 1 eq
+ {
+ cleartomark stop
+ }
+ {
+ /layerCnt dup load 1 sub store
+ } ifelse
+ } if
+ } ifelse
+ } loop
+} def
+end
+userdict /clipRenderOff 15 dict dup begin
+put
+{
+ /n /N /s /S /f /F /b /B
+}
+{
+ {
+ _doClip 1 eq
+ {
+ /_doClip 0 ddef _eo {eoclip} {clip} ifelse
+ } if
+ newpath
+ } def
+} forall
+/Tr /pop load def
+/Bb {} def
+/BB /pop load def
+/Bg {12 npop} def
+/Bm {6 npop} def
+/Bc /Bm load def
+/Bh {4 npop} def
+end
+/Lb
+{
+ 4 npop
+ 6 1 roll
+ pop
+ 4 1 roll
+ pop pop pop
+ 0 eq
+ {
+ 0 eq
+ {
+ (%AI5_BeginLayer) 1 (%AI5_EndLayer--) discard
+ }
+ {
+
+ /clipForward? true def
+
+ /Tx /pop load def
+ /Tj /pop load def
+
+ currentdict end clipRenderOff begin begin
+ } ifelse
+ }
+ {
+ 0 eq
+ {
+ save /discardSave exch store
+ } if
+ } ifelse
+} bind def
+/LB
+{
+ discardSave dup null ne
+ {
+ restore
+ }
+ {
+ pop
+ clipForward?
+ {
+ currentdict
+ end
+ end
+ begin
+
+ /clipForward? false ddef
+ } if
+ } ifelse
+} bind def
+/Pb
+{
+ pop pop
+ 0 (%AI5_EndPalette) discard
+} bind def
+/Np
+{
+ 0 (%AI5_End_NonPrinting--) discard
+} bind def
+/Ln /pop load def
+/Ap
+/pop load def
+/Ar
+{
+ 72 exch div
+ 0 dtransform dup mul exch dup mul add sqrt
+ dup 1 lt
+ {
+ pop 1
+ } if
+ setflat
+} def
+/Mb
+{
+ q
+} def
+/Md
+{
+} def
+/MB
+{
+ Q
+} def
+/nc 3 dict def
+nc begin
+/setgray
+{
+ pop
+} bind def
+/setcmykcolor
+{
+ 4 npop
+} bind def
+/setcustomcolor
+{
+ 2 npop
+} bind def
+currentdict readonly pop
+end
+end
+setpacking
+%%EndResource
+%%EndProlog
+%%BeginSetup
+%%IncludeFont: Univers
+Adobe_level2_AI5 /initialize get exec
+Adobe_Illustrator_AI5_vars Adobe_Illustrator_AI5 Adobe_typography_AI5 /initialize get exec
+Adobe_ColorImage_AI6 /initialize get exec
+Adobe_Illustrator_AI5 /initialize get exec
+[
+39/quotesingle 96/grave 128/Adieresis/Aring/Ccedilla/Eacute/Ntilde/Odieresis
+/Udieresis/aacute/agrave/acircumflex/adieresis/atilde/aring/ccedilla/eacute
+/egrave/ecircumflex/edieresis/iacute/igrave/icircumflex/idieresis/ntilde
+/oacute/ograve/ocircumflex/odieresis/otilde/uacute/ugrave/ucircumflex
+/udieresis/dagger/degree/cent/sterling/section/bullet/paragraph/germandbls
+/registered/copyright/trademark/acute/dieresis/.notdef/AE/Oslash
+/.notdef/plusminus/.notdef/.notdef/yen/mu/.notdef/.notdef
+/.notdef/.notdef/.notdef/ordfeminine/ordmasculine/.notdef/ae/oslash
+/questiondown/exclamdown/logicalnot/.notdef/florin/.notdef/.notdef
+/guillemotleft/guillemotright/ellipsis/.notdef/Agrave/Atilde/Otilde/OE/oe
+/endash/emdash/quotedblleft/quotedblright/quoteleft/quoteright/divide
+/.notdef/ydieresis/Ydieresis/fraction/currency/guilsinglleft/guilsinglright
+/fi/fl/daggerdbl/periodcentered/quotesinglbase/quotedblbase/perthousand
+/Acircumflex/Ecircumflex/Aacute/Edieresis/Egrave/Iacute/Icircumflex
+/Idieresis/Igrave/Oacute/Ocircumflex/.notdef/Ograve/Uacute/Ucircumflex
+/Ugrave/dotlessi/circumflex/tilde/macron/breve/dotaccent/ring/cedilla
+/hungarumlaut/ogonek/caron
+TE
+%AI3_BeginEncoding: _Univers Univers
+[/_Univers/Univers 0 0 1 TZ
+%AI3_EndEncoding AdobeType
+%AI5_Begin_NonPrinting
+Np
+8 Bn
+%AI5_BeginGradient: (Black & White)
+(Black & White) 0 2 Bd
+[
+<
+FFFEFDFCFBFAF9F8F7F6F5F4F3F2F1F0EFEEEDECEBEAE9E8E7E6E5E4E3E2E1E0DFDEDDDCDBDAD9D8
+D7D6D5D4D3D2D1D0CFCECDCCCBCAC9C8C7C6C5C4C3C2C1C0BFBEBDBCBBBAB9B8B7B6B5B4B3B2B1B0
+AFAEADACABAAA9A8A7A6A5A4A3A2A1A09F9E9D9C9B9A999897969594939291908F8E8D8C8B8A8988
+87868584838281807F7E7D7C7B7A797877767574737271706F6E6D6C6B6A69686766656463626160
+5F5E5D5C5B5A595857565554535251504F4E4D4C4B4A494847464544434241403F3E3D3C3B3A3938
+37363534333231302F2E2D2C2B2A292827262524232221201F1E1D1C1B1A19181716151413121110
+0F0E0D0C0B0A09080706050403020100
+>
+0 %_Br
+[
+0 0 50 100 %_Bs
+1 0 50 0 %_Bs
+BD
+%AI5_EndGradient
+%AI5_BeginGradient: (Green & Blue)
+(Green & Blue) 0 2 Bd
+[
+<
+99999A9A9B9B9B9C9C9D9D9D9E9E9F9F9FA0A0A1A1A1A2A2A3A3A3A4A4A5A5A5A6A6A7A7A7A8A8A9
+A9A9AAAAABABABACACADADADAEAEAFAFAFB0B0B1B1B1B2B2B3B3B3B4B4B5B5B5B6B6B7B7B7B8B8B9
+B9B9BABABBBBBBBCBCBDBDBDBEBEBFBFBFC0C0C1C1C1C2C2C3C3C3C4C4C5C5C5C6C6C7C7C7C8C8C9
+C9C9CACACBCBCBCCCCCDCDCDCECECFCFCFD0D0D1D1D1D2D2D3D3D3D4D4D5D5D5D6D6D7D7D7D8D8D9
+D9D9DADADBDBDBDCDCDDDDDDDEDEDFDFDFE0E0E1E1E1E2E2E3E3E3E4E4E5E5E5E6E6E7E7E7E8E8E9
+E9E9EAEAEBEBEBECECEDEDEDEEEEEFEFEFF0F0F1F1F1F2F2F3F3F3F4F4F5F5F5F6F6F7F7F7F8F8F9
+F9F9FAFAFBFBFBFCFCFDFDFDFEFEFFFF
+>
+<
+000102020304050506070808090A0B0B0C0D0E0E0F101111121314141516171718191A1A1B1C1D1D
+1E1F20202122232324252626272829292A2B2C2C2D2E2F2F303132323334353536373838393A3B3B
+3C3D3E3E3F404141424344444546474748494A4A4B4C4D4D4E4F5050515253535455565657585959
+5A5B5C5C5D5E5F5F606162626364656566676868696A6B6B6C6D6E6E6F7071717273747475767777
+78797A7A7B7C7D7D7E7F80808182828384858586878888898A8B8B8C8D8E8E8F9091919293949495
+96979798999A9A9B9C9D9D9E9FA0A0A1A2A3A3A4A5A6A6A7A8A9A9AAABACACADAEAFAFB0B1B2B2B3
+B4B5B5B6B7B8B8B9BABBBBBCBDBEBEBF
+>
+<
+FFFEFDFCFBFAF9F8F7F6F5F4F3F2F1F0EFEEEDECEBEAE9E8E7E6E5E4E3E2E1E0DFDEDDDCDBDAD9D8
+D7D6D5D4D3D2D1D0CFCECDCCCBCAC9C8C7C6C5C4C3C2C1C0BFBEBDBCBBBAB9B8B7B6B5B4B3B2B1B0
+AFAEADACABAAA9A8A7A6A5A4A3A2A1A09F9E9D9C9B9A999897969594939291908F8E8D8C8B8A8988
+87868584838281807F7E7D7C7B7A797877767574737271706F6E6D6C6B6A69686766656463626160
+5F5E5D5C5B5A595857565554535251504F4E4D4C4B4A494847464544434241403F3E3D3C3B3A3938
+37363534333231302F2E2D2C2B2A292827262524232221201F1E1D1C1B1A19181716151413121110
+0F0E0D0C0B0A09080706050403020100
+>
+0
+1 %_Br
+[
+1 0.75 0 0 1 50 100 %_Bs
+0.6 0 1 0 1 50 0 %_Bs
+BD
+%AI5_EndGradient
+%AI5_BeginGradient: (Pink, Yellow, Green)
+(Pink, Yellow, Green) 0 3 Bd
+[
+<
+00000000000000000000000000000000000000010101010101010101010101010101010101010101
+01010101010202020202020202020202020202020202020202020203030303030303030303030303
+03030303030303030404040404040404040404040404040404040404050505050505050505050505
+05050505050505060606060606060606060606060606060606060707070707070707070707070707
+07070707080808080808080808080808080808080809090909090909090909090909090909090A0A
+0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0C0C0C0C0C0C0C0C0C
+0C0C0C0C0C0C0C0D0D0D0D0D
+>
+<
+050506060606070708080809090A0A0A0B0B0C0C0D0D0E0E0F0F1010111112121313141415151617
+17181819191A1A1B1C1C1D1D1E1F1F202021222223232425252626272828292A2A2B2C2C2D2D2E2F
+2F3031313233333435353637373839393A3B3B3C3D3E3E3F4040414242434445454647474849494A
+4B4C4C4D4E4F4F505151525354545556575758595A5A5B5C5C5D5E5F5F6061626363646566666768
+69696A6B6C6C6D6E6F707071727373747576777778797A7B7B7C7D7E7F7F80818283838485868787
+88898A8B8B8C8D8E8F8F9091929394949596979898999A9B9C9D9D9E9FA0A1A2A2A3A4A5A6A7A7A8
+A9AAABACADADAEAFB0B1B2B2
+>
+<
+CCCCCBCBCBCACACAC9C9C8C8C7C7C6C6C5C5C4C4C3C2C2C1C1C0C0BFBEBEBDBDBCBBBBBAB9B9B8B7
+B7B6B6B5B4B4B3B2B1B1B0AFAFAEADADACABAAAAA9A8A8A7A6A5A5A4A3A2A2A1A0A09F9E9D9C9C9B
+9A999998979696959493929291908F8E8E8D8C8B8A8A8988878686858483828181807F7E7D7C7C7B
+7A7978777776757473727171706F6E6D6C6B6A6A69686766656463636261605F5E5D5C5B5B5A5958
+5756555453525151504F4E4D4C4B4A49484746464544434241403F3E3D3C3B3A3938383736353433
+3231302F2E2D2C2B2A29282726252423222221201F1E1D1C1B1A191817161514131211100F0E0D0C
+0B0A09080706050403020100
+>
+0
+1 %_Br
+<
+737271706F6E6D6C6B6A696867666564636261605F5E5D5C5B5B5A59585756555453525150504F4E
+4D4C4B4A4949484746454443434241403F3E3E3D3C3B3A3A393837363635343333323130302F2E2D
+2D2C2B2A2A29282827262525242323222121201F1F1E1D1D1C1C1B1A1A1918181717161615141413
+1312121111100F0F0E0E0D0D0C0C0C0B0B0A0A090908080807070606060505050404040303030202
+020201010101010000000000
+>
+<
+00000000000000000000000001010101010101010101010101010101010101010101010102020202
+02020202020202020202020202020202020202020202030303030303030303030303030303030303
+03030303030303030303030303040404040404040404040404040404040404040404040404040404
+04040404040404040404050505050505050505050505050505050505050505050505050505050505
+050505050505050505050505
+>
+<
+BFBFBFC0C0C0C0C0C0C0C0C0C1C1C1C1C1C1C1C1C1C2C2C2C2C2C2C2C2C2C2C3C3C3C3C3C3C3C3C3
+C3C4C4C4C4C4C4C4C4C4C4C5C5C5C5C5C5C5C5C5C5C5C6C6C6C6C6C6C6C6C6C6C6C6C7C7C7C7C7C7
+C7C7C7C7C7C7C8C8C8C8C8C8C8C8C8C8C8C8C8C9C9C9C9C9C9C9C9C9C9C9C9C9C9C9CACACACACACA
+CACACACACACACACACACACBCBCBCBCBCBCBCBCBCBCBCBCBCBCBCBCBCBCBCBCBCBCCCCCCCCCCCCCCCC
+CCCCCCCCCCCCCCCCCCCCCCCC
+>
+0
+1 %_Br
+[
+0.05 0.7 0 0 1 50 100 %_Bs
+0 0.02 0.8 0 1 57 36 %_Bs
+0.45 0 0.75 0 1 37 0 %_Bs
+BD
+%AI5_EndGradient
+%AI5_BeginGradient: (Purple, Red & Yellow)
+(Purple, Red & Yellow) 0 3 Bd
+[
+0
+<
+FFFEFDFCFBFAF9F8F7F6F5F4F3F2F1F0EFEEEDECEBEAE9E8E7E6E5E4E3E2E1E0DFDEDDDCDBDAD9D8
+D7D6D5D4D3D2D1D0CFCECDCCCBCAC9C8C7C6C5C4C3C2C1C0BFBEBDBCBBBAB9B8B7B6B5B4B3B2B1B0
+AFAEADACABAAA9A8A7A6A5A4A3A2A1A09F9E9D9C9B9A999897969594939291908F8E8D8C8B8A8988
+87868584838281807F7E7D7C7B7A797877767574737271706F6E6D6C6B6A69686766656463626160
+5F5E5D5C5B5A595857565554535251504F4E4D4C4B4A494847464544434241403F3E3D3C3B3A3938
+37363534333231302F2E2D2C2B2A292827262524232221201F1E1D1C1B1A19181716151413121110
+0F0E0D0C0B0A
+>
+<
+CCCCCCCDCDCDCDCDCECECECECECFCFCFCFD0D0D0D0D0D1D1D1D1D1D2D2D2D2D2D3D3D3D3D3D4D4D4
+D4D5D5D5D5D5D6D6D6D6D6D7D7D7D7D7D8D8D8D8D8D9D9D9D9DADADADADADBDBDBDBDBDCDCDCDCDC
+DDDDDDDDDDDEDEDEDEDFDFDFDFDFE0E0E0E0E0E1E1E1E1E1E2E2E2E2E2E3E3E3E3E4E4E4E4E4E5E5
+E5E5E5E6E6E6E6E6E7E7E7E7E7E8E8E8E8E9E9E9E9E9EAEAEAEAEAEBEBEBEBEBECECECECECEDEDED
+EDEEEEEEEEEEEFEFEFEFEFF0F0F0F0F0F1F1F1F1F1F2F2F2F2F3F3F3F3F3F4F4F4F4F4F5F5F5F5F5
+F6F6F6F6F6F7F7F7F7F8F8F8F8F8F9F9F9F9F9FAFAFAFAFAFBFBFBFBFBFCFCFCFCFDFDFDFDFDFEFE
+FEFEFEFFFFFF
+>
+0
+1 %_Br
+<
+E5E4E3E2E1E0DFDEDDDCDBDAD9D8D7D6D5D4D3D2D1D0CFCECDCCCBCAC9C8C7C6C5C4C3C2C1C0BFBE
+BDBCBBBAB9B8B7B6B5B4B3B2B1B0AFAEADACABAAA9A8A7A6A5A4A3A2A1A09F9E9D9C9B9A99989796
+9594939291908F8E8D8C8B8A898887868584838281807F7E7D7C7B7A797877767574737271706F6E
+6D6C6B6A696867666564636261605F5E5D5C5B5A595857565554535251504F4E4D4C4B4A49484746
+4544434241403F3E3D3C3B3A393837363534333231302F2E2D2C2B2A292827262524232221201F1E
+1D1C1B1A191817161514131211100F0E0D0C0B0A09080706050403020100
+>
+<
+E5E6E6E6E6E6E6E6E6E7E7E7E7E7E7E7E7E7E8E8E8E8E8E8E8E8E8E9E9E9E9E9E9E9E9E9EAEAEAEA
+EAEAEAEAEAEBEBEBEBEBEBEBEBEBECECECECECECECECECEDEDEDEDEDEDEDEDEDEEEEEEEEEEEEEEEE
+EEEFEFEFEFEFEFEFEFEFF0F0F0F0F0F0F0F0F0F1F1F1F1F1F1F1F1F1F2F2F2F2F2F2F2F2F2F3F3F3
+F3F3F3F3F3F3F4F4F4F4F4F4F4F4F4F5F5F5F5F5F5F5F5F5F6F6F6F6F6F6F6F6F6F7F7F7F7F7F7F7
+F7F7F8F8F8F8F8F8F8F8F8F9F9F9F9F9F9F9F9F9FAFAFAFAFAFAFAFAFAFBFBFBFBFBFBFBFBFBFCFC
+FCFCFCFCFCFCFCFDFDFDFDFDFDFDFDFDFEFEFEFEFEFEFEFEFEFFFFFFFFFF
+>
+<
+00010203040405060708090A0B0C0C0D0E0F10111213141415161718191A1B1C1D1D1E1F20212223
+242525262728292A2B2C2D2D2E2F30313233343535363738393A3B3C3D3D3E3F4041424344454546
+4748494A4B4C4D4E4E4F50515253545556565758595A5B5C5D5E5E5F60616263646566666768696A
+6B6C6D6E6E6F70717273747576767778797A7B7C7D7E7F7F80818283848586878788898A8B8C8D8E
+8F8F90919293949596979798999A9B9C9D9E9F9FA0A1A2A3A4A5A6A7A7A8A9AAABACADAEAFAFB0B1
+B2B3B4B5B6B7B8B8B9BABBBCBDBEBFC0C0C1C2C3C4C5C6C7C8C8C9CACBCC
+>
+0
+1 %_Br
+[
+0 0.04 1 0 1 50 100 %_Bs
+0 1 0.8 0 1 50 50 %_Bs
+0.9 0.9 0 0 1 50 0 %_Bs
+BD
+%AI5_EndGradient
+%AI5_BeginGradient: (Rainbow)
+(Rainbow) 0 6 Bd
+[
+<
+FFFEFDFCFBFAF9F8F7F6F5F4F3F2F1F0EFEEEDECEBEAE9E8E7E6E5E4E3E2E1E0DFDEDDDCDBDAD9D8
+D7D6D5D4D3D2D1D0CFCECDCCCBCAC9C8C7C6C5C4C3C2C1C0BFBEBDBCBBBAB9B8B7B6B5B4B3B2B1B0
+AFAEADACABAAA9A8A7A6A5A4A3A2A1A09F9E9D9C9B9A999897969594939291908F8E8D8C8B8A8988
+87868584838281807F7E7D7C7B7A797877767574737271706F6E6D6C6B6A69686766656463626160
+5F5E5D5C5B5A595857565554535251504F4E4D4C4B4A494847464544434241403F3E3D3C3B3A3938
+37363534333231302F2E2D2C2B2A292827262524232221201F1E1D1C1B1A19181716151413121110
+0F0E0D0C0B0A09080706050403020100
+>
+1
+0
+0
+1 %_Br
+1
+<
+0708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E
+2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F50515253545556
+5758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E
+7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6
+A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7C8C9CACBCCCDCE
+CFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6
+F7F8F9FAFBFCFDFEFF
+>
+0
+0
+1 %_Br
+1
+<
+00000000000000000000000000000000000001010101010101010101010101010101010101010101
+01010101010101010101010101010202020202020202020202020202020202020202020202020202
+02020202020202020202030303030303030303030303030303030303030303030303030303030303
+03030303030304040404040404040404040404040404040404040404040404040404040404040404
+04040505050505050505050505050505050505050505050505050505050505050505050505050606
+06060606060606060606060606060606060606060606060606060606060606060606070707070707
+07070707070707070707070707070707
+>
+<
+FFFEFDFCFBFAF9F8F7F6F5F4F3F2F1F0EFEEEDECEBEAE9E8E7E6E5E4E3E2E1E0DFDEDDDCDBDAD9D8
+D7D6D5D4D3D2D1D0CFCECDCCCBCAC9C8C7C6C5C4C3C2C1C0BFBEBDBCBBBAB9B8B7B6B5B4B3B2B1B0
+AFAEADACABAAA9A8A7A6A5A4A3A2A1A09F9E9D9C9B9A999897969594939291908F8E8D8C8B8A8988
+87868584838281807F7E7D7C7B7A797877767574737271706F6E6D6C6B6A69686766656463626160
+5F5E5D5C5B5A595857565554535251504F4E4D4C4B4A494847464544434241403F3E3D3C3B3A3938
+37363534333231302F2E2D2C2B2A292827262524232221201F1E1D1C1B1A19181716151413121110
+0F0E0D0C0B0A09080706050403020100
+>
+0
+1 %_Br
+<
+000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627
+28292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F
+505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F7071727374757677
+78797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9F
+A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7
+C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEF
+F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF
+>
+0
+1
+0
+1 %_Br
+0
+<
+FFFEFDFCFBFAF9F8F7F6F5F4F3F2F1F0EFEEEDECEBEAE9E8E7E6E5E4E3E2E1E0DFDEDDDCDBDAD9D8
+D7D6D5D4D3D2D1D0CFCECDCCCBCAC9C8C7C6C5C4C3C2C1C0BFBEBDBCBBBAB9B8B7B6B5B4B3B2B1B0
+AFAEADACABAAA9A8A7A6A5A4A3A2A1A09F9E9D9C9B9A999897969594939291908F8E8D8C8B8A8988
+87868584838281807F7E7D7C7B7A797877767574737271706F6E6D6C6B6A69686766656463626160
+5F5E5D5C5B5A595857565554535251504F4E4D4C4B4A494847464544434241403F3E3D3C3B3A3938
+37363534333231302F2E2D2C2B2A292827262524232221201F1E1D1C1B1A19181716151413121110
+0F0E0D0C0B0A09080706050403020100
+>
+1
+0
+1 %_Br
+[
+0 1 0 0 1 50 100 %_Bs
+1 1 0 0 1 50 80 %_Bs
+1 0.0279 0 0 1 50 60 %_Bs
+1 0 1 0 1 50 40 %_Bs
+0 0 1 0 1 50 20 %_Bs
+0 1 1 0 1 50 0 %_Bs
+BD
+%AI5_EndGradient
+%AI5_BeginGradient: (Steel Bar)
+(Steel Bar) 0 3 Bd
+[
+<
+FFFEFDFCFBFAF9F8F7F6F5F4F3F2F1F0EFEEEDECEBEAE9E8E7E6E5E4E3E2E1E0DFDEDDDCDBDAD9D8
+D7D6D5D4D3D2D1D0CFCECDCCCBCAC9C8C7C6C5C4C3C2C1C0BFBEBDBCBBBAB9B8B7B6B5B4B3B2B1B0
+AFAEADACABAAA9A8A7A6A5A4A3A2A1A09F9E9D9C9B9A999897969594939291908F8E8D8C8B8A8988
+87868584838281807F7E7D7C7B7A797877767574737271706F6E6D6C6B6A69686766656463626160
+5F5E5D5C5B5A595857565554535251504F4E4D4C4B4A494847464544434241403F3E3D3C3B3A3938
+37363534333231302F2E2D2C2B2A292827262524232221201F1E1D1C1B1A19181716151413121110
+0F0E0D0C0B0A09080706050403020100
+>
+0 %_Br
+<
+000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627
+28292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F
+505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F7071727374757677
+78797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9F
+A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7
+C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEF
+F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF
+>
+0 %_Br
+[
+0 0 50 100 %_Bs
+1 0 50 70 %_Bs
+0 0 50 0 %_Bs
+BD
+%AI5_EndGradient
+%AI5_BeginGradient: (Yellow & Orange Radial)
+(Yellow & Orange Radial) 1 2 Bd
+[
+0
+<
+0001010203040506060708090A0B0C0C0D0E0F10111213131415161718191A1B1C1D1D1E1F202122
+232425262728292A2B2B2C2D2E2F303132333435363738393A3B3C3D3E3E3F404142434445464748
+494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F60606162636465666768696A6B6C6D6E6F
+707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C
+>
+<
+FFFFFFFFFEFEFEFEFEFEFEFDFDFDFDFDFDFCFCFCFCFCFCFBFBFBFBFBFBFAFAFAFAFAFAF9F9F9F9F9
+F9F8F8F8F8F8F8F7F7F7F7F7F7F6F6F6F6F6F6F5F5F5F5F5F5F4F4F4F4F4F3F3F3F3F3F3F2F2F2F2
+F2F2F1F1F1F1F1F0F0F0F0F0F0EFEFEFEFEFEFEEEEEEEEEEEDEDEDEDEDEDECECECECECEBEBEBEBEB
+EBEAEAEAEAEAE9E9E9E9E9E9E8E8E8E8E8E8E7E7E7E7E7E6E6E6E6E6E5
+>
+0
+1 %_Br
+[
+0 0 1 0 1 52 19 %_Bs
+0 0.55 0.9 0 1 50 100 %_Bs
+BD
+%AI5_EndGradient
+%AI5_BeginGradient: (Yellow & Purple Radial)
+(Yellow & Purple Radial) 1 2 Bd
+[
+<
+000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627
+28292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F
+505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F7071727374757677
+78797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9F
+A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7
+C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEF
+F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF
+>
+<
+1415161718191A1B1C1D1E1F1F202122232425262728292A2A2B2C2D2E2F30313233343536363738
+393A3B3C3D3E3F40414142434445464748494A4B4C4D4D4E4F50515253545556575858595A5B5C5D
+5E5F60616263646465666768696A6B6C6D6E6F6F707172737475767778797A7B7B7C7D7E7F808182
+83848586868788898A8B8C8D8E8F90919292939495969798999A9B9C9D9D9E9FA0A1A2A3A4A5A6A7
+A8A9A9AAABACADAEAFB0B1B2B3B4B4B5B6B7B8B9BABBBCBDBEBFC0C0C1C2C3C4C5C6C7C8C9CACBCB
+CCCDCECFD0D1D2D3D4D5D6D7D7D8D9DADBDCDDDEDFE0E1E2E2E3E4E5E6E7E8E9EAEBECEDEEEEEFF0
+F1F2F3F4F5F6F7F8F9F9FAFBFCFDFEFF
+>
+<
+ABAAAAA9A8A7A7A6A5A5A4A3A3A2A1A1A09F9F9E9D9D9C9B9B9A9999989797969595949393929191
+908F8F8E8D8D8C8B8B8A8989888787868585848383828181807F7F7E7D7D7C7B7B7A797978777776
+7575747373727171706F6F6E6D6D6C6B6B6A6969686767666565646362626160605F5E5E5D5C5C5B
+5A5A5958585756565554545352525150504F4E4E4D4C4C4B4A4A4948484746464544444342424140
+403F3E3E3D3C3C3B3A3A3938383736363534343332323130302F2E2E2D2C2C2B2A2A292828272626
+25242423222121201F1F1E1D1D1C1B1B1A1919181717161515141313121111100F0F0E0D0D0C0B0B
+0A090908070706050504030302010100
+>
+0
+1 %_Br
+[
+0 0.08 0.67 0 1 50 14 %_Bs
+1 1 0 0 1 50 100 %_Bs
+BD
+%AI5_EndGradient
+%AI5_End_NonPrinting--
+%AI5_BeginPalette
+0 2 Pb
+Pn
+Pc
+1 g
+Pc
+0 g
+Pc
+0 0 0 0 k
+Pc
+0.75 g
+Pc
+0.5 g
+Pc
+0.25 g
+Pc
+0 g
+Pc
+Bb
+2 (Black & White) -4014 4716 0 0 1 0 0 1 0 0 Bg
+0 BB
+Pc
+0.25 0 0 0 k
+Pc
+0.5 0 0 0 k
+Pc
+0.75 0 0 0 k
+Pc
+1 0 0 0 k
+Pc
+0.25 0.25 0 0 k
+Pc
+0.5 0.5 0 0 k
+Pc
+0.75 0.75 0 0 k
+Pc
+1 1 0 0 k
+Pc
+Bb
+2 (Pink, Yellow, Green) -4014 4716 0 0 1 0 0 1 0 0 Bg
+0 BB
+Pc
+0 0.25 0 0 k
+Pc
+0 0.5 0 0 k
+Pc
+0 0.75 0 0 k
+Pc
+0 1 0 0 k
+Pc
+0 0.25 0.25 0 k
+Pc
+0 0.5 0.5 0 k
+Pc
+0 0.75 0.75 0 k
+Pc
+0 1 1 0 k
+Pc
+Bb
+0 0 0 0 Bh
+2 (Yellow & Purple Radial) -4014 4716 0 0 1 0 0 1 0 0 Bg
+0 BB
+Pc
+0 0 0.25 0 k
+Pc
+0 0 0.5 0 k
+Pc
+0 0 0.75 0 k
+Pc
+0 0 1 0 k
+Pc
+0.25 0 0.25 0 k
+Pc
+0.5 0 0.5 0 k
+Pc
+0.75 0 0.75 0 k
+Pc
+1 0 1 0 k
+Pc
+Bb
+2 (Rainbow) -4014 4716 0 0 1 0 0 1 0 0 Bg
+0 BB
+Pc
+0.25 0.125 0 0 k
+Pc
+0.5 0.25 0 0 k
+Pc
+0.75 0.375 0 0 k
+Pc
+1 0.5 0 0 k
+Pc
+0.125 0.25 0 0 k
+Pc
+0.25 0.5 0 0 k
+Pc
+0.375 0.75 0 0 k
+Pc
+0.5 1 0 0 k
+Pc
+Bb
+2 (Steel Bar) -4014 4716 0 0 1 0 0 1 0 0 Bg
+0 BB
+Pc
+0 0.25 0.125 0 k
+Pc
+0 0.5 0.25 0 k
+Pc
+0 0.75 0.375 0 k
+Pc
+0 1 0.5 0 k
+Pc
+0 0.125 0.25 0 k
+Pc
+0 0.25 0.5 0 k
+Pc
+0 0.375 0.75 0 k
+Pc
+0 0.5 1 0 k
+Pc
+Bb
+2 (Purple, Red & Yellow) -4014 4716 0 0 1 0 0 1 0 0 Bg
+0 BB
+Pc
+0.125 0 0.25 0 k
+Pc
+0.25 0 0.5 0 k
+Pc
+0.375 0 0.75 0 k
+Pc
+0.5 0 1 0 k
+Pc
+0.25 0 0.125 0 k
+Pc
+0.5 0 0.25 0 k
+Pc
+0.75 0 0.375 0 k
+Pc
+1 0 0.5 0 k
+Pc
+Bb
+2 (Green & Blue) -4014 4716 0 0 1 0 0 1 0 0 Bg
+0 BB
+Pc
+0.25 0.125 0.125 0 k
+Pc
+0.5 0.25 0.25 0 k
+Pc
+0.75 0.375 0.375 0 k
+Pc
+1 0.5 0.5 0 k
+Pc
+0.25 0.25 0.125 0 k
+Pc
+0.5 0.5 0.25 0 k
+Pc
+0.75 0.75 0.375 0 k
+Pc
+1 1 0.5 0 k
+Pc
+Bb
+0 0 0 0 Bh
+2 (Yellow & Orange Radial) -4014 4716 0 0 1 0 0 1 0 0 Bg
+0 BB
+Pc
+0.125 0.25 0.125 0 k
+Pc
+0.25 0.5 0.25 0 k
+Pc
+0.375 0.75 0.375 0 k
+Pc
+0.5 1 0.5 0 k
+Pc
+0.125 0.25 0.25 0 k
+Pc
+0.25 0.5 0.5 0 k
+Pc
+0.375 0.75 0.75 0 k
+Pc
+0.5 1 1 0 k
+Pc
+0 0 0 0 k
+Pc
+0.125 0.125 0.25 0 k
+Pc
+0.25 0.25 0.5 0 k
+Pc
+0.375 0.375 0.75 0 k
+Pc
+0.5 0.5 1 0 k
+Pc
+0.25 0.125 0.25 0 k
+Pc
+0.5 0.25 0.5 0 k
+Pc
+0.75 0.375 0.75 0 k
+Pc
+1 0.5 1 0 k
+Pc
+PB
+%AI5_EndPalette
+%%EndSetup
+%AI5_BeginLayer
+1 1 1 1 0 0 0 79 128 255 Lb
+(Layer 1) Ln
+0 A
+800 Ar
+0 J 0 j 1 w 4 M []0 d
+%AI3_Note:
+0 D
+0 XR
+-4014 283.5 m
+4626 283.5 L
+(N) *
+453.5 4716 m
+453.5 -3924 L
+(N) *
+85 4716 m
+85 -3924 L
+(N) *
+-4014 765.5 m
+4626 765.5 L
+(N) *
+u
+1 Ap
+0 R
+0 G
+415.1831 559.9902 m
+434.752 559.9902 450.6162 569.5087 450.6162 581.25 c
+450.6162 592.9914 434.752 602.5099 415.1831 602.5099 c
+395.6142 602.5099 379.75 592.9914 379.75 581.25 c
+379.75 569.5087 395.6142 559.9902 415.1831 559.9902 c
+s
+0 To
+1 0 0 1 415.1831 577.8162 0 Tp
+TP
+-9.4434 0 Td
+0 Tr
+0 O
+0 g
+/_Univers 10 Tf
+0 Ts
+100 Tz
+0 Tt
+1 TA
+%_ 0 XL
+36 0 Xb
+XB
+0 0 5 TC
+100 100 200 TW
+0 0 0 Ti
+1 Ta
+0 0 2 2 3 Th
+0 Tq
+0 0 Tl
+0 Tc
+0 Tw
+(MIB) Tx
+(\r) TX
+TO
+U
+u
+0 R
+0 G
+341.4331 559.9902 m
+361.002 559.9902 376.8662 569.5087 376.8662 581.25 c
+376.8662 592.9914 361.002 602.5099 341.4331 602.5099 c
+321.8642 602.5099 306 592.9914 306 581.25 c
+306 569.5087 321.8642 559.9902 341.4331 559.9902 c
+s
+0 To
+1 0 0 1 341.4331 577.8162 0 Tp
+TP
+-9.4434 0 Td
+0 Tr
+0 O
+0 g
+(MIB) Tx
+(\r) TX
+TO
+U
+u
+0 R
+0 G
+267.6831 559.9902 m
+287.252 559.9902 303.1162 569.5087 303.1162 581.25 c
+303.1162 592.9914 287.252 602.5099 267.6831 602.5099 c
+248.1142 602.5099 232.25 592.9914 232.25 581.25 c
+232.25 569.5087 248.1142 559.9902 267.6831 559.9902 c
+s
+0 To
+1 0 0 1 267.6831 577.8162 0 Tp
+TP
+-12.7747 0 Td
+0 Tr
+0 O
+0 g
+(Net if) Tx
+(\r) TX
+TO
+U
+u
+0 R
+0 G
+415.1831 616.7402 m
+434.752 616.7402 450.6162 626.2587 450.6162 638 c
+450.6162 649.7414 434.752 659.2599 415.1831 659.2599 c
+395.6142 659.2599 379.75 649.7414 379.75 638 c
+379.75 626.2587 395.6142 616.7402 415.1831 616.7402 c
+s
+0 To
+1 0 0 1 415.1831 634.5662 0 Tp
+TP
+-6.9446 0 Td
+0 Tr
+0 O
+0 g
+(SA) Tx
+(\r) TX
+TO
+U
+u
+0 R
+0 G
+341.4331 616.7402 m
+361.002 616.7402 376.8662 626.2587 376.8662 638 c
+376.8662 649.7414 361.002 659.2599 341.4331 659.2599 c
+321.8642 659.2599 306 649.7414 306 638 c
+306 626.2587 321.8642 616.7402 341.4331 616.7402 c
+s
+0 To
+1 0 0 1 341.4331 634.5662 0 Tp
+TP
+-8.3289 0 Td
+0 Tr
+0 O
+0 g
+(MA) Tx
+(\r) TX
+TO
+U
+u
+0 R
+0 G
+267.6831 616.7402 m
+287.252 616.7402 303.1162 626.2587 303.1162 638 c
+303.1162 649.7414 287.252 659.2599 267.6831 659.2599 c
+248.1142 659.2599 232.25 649.7414 232.25 638 c
+232.25 626.2587 248.1142 616.7402 267.6831 616.7402 c
+s
+0 To
+1 0 0 1 267.6831 640.5662 0 Tp
+TP
+-21.3855 0 Td
+0 Tr
+0 O
+0 g
+(symbolic\r) Tx
+9.4434 -12 Td
+(store) Tx
+(\r) TX
+TO
+U
+u
+0 R
+0 G
+193.9331 616.7402 m
+213.502 616.7402 229.3662 626.2587 229.3662 638 c
+229.3662 649.7414 213.502 659.2599 193.9331 659.2599 c
+174.3642 659.2599 158.5 649.7414 158.5 638 c
+158.5 626.2587 174.3642 616.7402 193.9331 616.7402 c
+s
+0 To
+1 0 0 1 193.9331 634.5662 0 Tp
+TP
+-23.8831 0 Td
+0 Tr
+0 O
+0 g
+(note store) Tx
+(\r) TX
+TO
+U
+u
+0 R
+0 G
+120.4331 616.7402 m
+140.002 616.7402 155.8662 626.2587 155.8662 638 c
+155.8662 649.7414 140.002 659.2599 120.4331 659.2599 c
+100.8642 659.2599 85 649.7414 85 638 c
+85 626.2587 100.8642 616.7402 120.4331 616.7402 c
+s
+0 To
+1 0 0 1 120.4331 634.5662 0 Tp
+TP
+-18.6096 0 Td
+0 Tr
+0 O
+0 g
+(local db) Tx
+(\r) TX
+TO
+U
+u
+0 R
+0 G
+231 687.4902 m
+250.5689 687.4902 266.4331 697.0087 266.4331 708.75 c
+266.4331 720.4914 250.5689 730.0099 231 730.0099 c
+211.4311 730.0099 195.5669 720.4914 195.5669 708.75 c
+195.5669 697.0087 211.4311 687.4902 231 687.4902 c
+s
+0 To
+1 0 0 1 231 705.3162 0 Tp
+TP
+-25 0 Td
+0 Tr
+0 O
+0 g
+(supervisor) Tx
+(\r) TX
+TO
+U
+0 Ap
+0 R
+0 G
+96.6667 526 m
+156.6667 526 l
+S
+0 To
+1 0 0 1 171.6667 525 0 Tp
+TP
+-9.7229 0 Td
+0 Tr
+0 O
+0 g
+(Link) Tx
+(\r) TX
+TO
+0 R
+0 G
+193.9331 659.2599 m
+231 687.4902 l
+267.6831 659.2599 l
+S
+231 687.4902 m
+341.4331 659.2599 l
+S
+415.1831 659.2599 m
+231 687.4902 l
+120.4331 659.2599 l
+S
+341.4331 602.5 m
+341.4331 616.7402 l
+267.6831 602.5099 l
+S
+376.8662 638 m
+379.75 638 l
+S
+415.1831 616.7402 m
+415.1831 602.5099 l
+S
+LB
+%AI5_EndLayer--
+%%PageTrailer
+gsave annotatepage grestore showpage
+%%Trailer
+Adobe_Illustrator_AI5 /terminate get exec
+Adobe_ColorImage_AI6 /terminate get exec
+Adobe_typography_AI5 /terminate get exec
+Adobe_level2_AI5 /terminate get exec
+%%EOF
diff --git a/lib/snmp/doc/src/snmp.gif b/lib/snmp/doc/src/snmp.gif
new file mode 100644
index 0000000000..d9985f990b
--- /dev/null
+++ b/lib/snmp/doc/src/snmp.gif
Binary files differ
diff --git a/lib/snmp/doc/src/snmp.xml b/lib/snmp/doc/src/snmp.xml
new file mode 100644
index 0000000000..af0833f005
--- /dev/null
+++ b/lib/snmp/doc/src/snmp.xml
@@ -0,0 +1,608 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE erlref SYSTEM "erlref.dtd">
+
+<erlref>
+ <header>
+ <copyright>
+ <year>1996</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ 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.
+
+ </legalnotice>
+
+ <title>snmp</title>
+ <prepared></prepared>
+ <responsible></responsible>
+ <docno></docno>
+ <approved></approved>
+ <checked></checked>
+ <date></date>
+ <rev></rev>
+ <file>snmp.xml</file>
+ </header>
+ <module>snmp</module>
+ <modulesummary>Interface functions to the SNMP toolkit</modulesummary>
+ <description>
+ <p>The module <c>snmp</c> contains interface functions to the
+ SNMP toolkit.</p>
+ </description>
+
+ <section>
+ <title>Common Data Types</title>
+ <p>The following data-types are used in the functions below: </p>
+ <list type="bulleted">
+ <item>
+ <p><c>datetime() = {date(), time()}</c></p>
+ <p>See <seealso marker="stdlib:calendar">calendar</seealso>
+ for more info.</p>
+ </item>
+
+ </list>
+
+ <marker id="config"></marker>
+ </section>
+
+ <funcs>
+ <func>
+ <name>config() -> ok | {error, Reason}</name>
+ <fsummary>Configure with a simple interactive tool</fsummary>
+ <desc>
+ <p>A simple interactive configuration tool. Simple
+ configuration files can be generated, but more complex
+ configurations still have to be edited manually.
+ </p>
+ <p>The tool is a textual based tool that asks some questions
+ and generates <c>sys.config</c> and <c>*.conf</c> files.
+ </p>
+ <p><em>Note</em> that if the application shall support version 3,
+ then the crypto app must be started before running this function
+ (password generation).</p>
+ <p><em>Note</em> also that some of the configuration files for the
+ agent and manager share the same names. This means that
+ they have to be stored in <em>different</em> directories!</p>
+
+ <marker id="start"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>start() -> ok | {error, Reason}</name>
+ <name>start(Type) -> ok | {error, Reason}</name>
+ <fsummary>Start the SNMP application</fsummary>
+ <type>
+ <v>Type = start_type()</v>
+ </type>
+ <desc>
+ <p>Starts the SNMP application.</p>
+ <p>See <seealso marker="kernel:application">application</seealso> for more info.</p>
+
+ <marker id="start_agent"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>start_agent() -> ok | {error, Reason}</name>
+ <name>start_agent(Type) -> ok | {error, Reason}</name>
+ <fsummary>Start the agent part of the SNMP application</fsummary>
+ <type>
+ <v>Type = start_type()</v>
+ </type>
+ <desc>
+ <p>The SNMP application consists of several entities, of which the
+ agent is one. This function starts the agent entity of the
+ application.
+ </p>
+ <p>Note that the only way to actually start the agent in this way is
+ to add the agent related config after starting the application (e.g
+ it cannot be part of the normal application config; sys.config).
+ This is done by calling:
+ <c>application:set_env(snmp, agent, Conf)</c>.
+ </p>
+ <p>The default value for <c>Type</c> is <c>normal</c>.</p>
+
+ <marker id="start_manager"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>start_manager() -> ok | {error, Reason}</name>
+ <name>start_manager(Type) -> ok | {error, Reason}</name>
+ <fsummary>Start the manager part of the SNMP application</fsummary>
+ <type>
+ <v>Type = start_type()</v>
+ </type>
+ <desc>
+ <p>The SNMP application consists of several entities, of which the
+ manager is one. This function starts the manager entity of the
+ application.
+ </p>
+ <p>Note that the only way to actually start the manager in this way is
+ to add the manager related config after starting the application (e.g
+ it cannot be part of the normal application config; sys.config).
+ This is done by calling:
+ <c>application:set_env(snmp, manager, Conf)</c>.
+ </p>
+ <p>The default value for <c>Type</c> is <c>normal</c>.</p>
+
+ <marker id="dat"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>date_and_time() -> DateAndTime</name>
+ <fsummary>Return the current date and time as an OCTET STRING</fsummary>
+ <type>
+ <v>DateAndTime = [int()]</v>
+ </type>
+ <desc>
+ <p>Returns current date and time as the data type DateAndTime,
+ as specified in RFC1903. This is an OCTET STRING.</p>
+
+ <marker id="dat2ut_dst"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>date_and_time_to_universal_time_dst(DateAndTime) -> [utc()]</name>
+ <fsummary>Convert a DateAndTime value to a list of possible utc()</fsummary>
+ <type>
+ <v>DateAndTime = [int()]</v>
+ <v>utc() = {{Y,Mo,D},{H,M,S}}</v>
+ </type>
+ <desc>
+ <p>Converts a DateAndTime list to a list of possible universal
+ time(s). The universal time value on the same format as defined in
+ calendar(3). </p>
+
+ <marker id="dat2s"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>date_and_time_to_string(DateAndTime) -> string()</name>
+ <name>date_and_time_to_string(DateAndTime, Validate) -> string()</name>
+ <fsummary>Convert a DateAndTime value to a string</fsummary>
+ <type>
+ <v>DateAndTime = [int()]</v>
+ <v>Validate = fun(Kind, Data) -> boolean()</v>
+ </type>
+ <desc>
+ <p>Converts a DateAndTime list to a printable string, according
+ to the DISPLAY-HINT definition in RFC2579.</p>
+
+ <p>The validation fun, <c>Validate</c>, allows for a more "flexible"
+ validation of the <c>DateAndTime</c> argument. Whenever the data
+ is found to not follow RFC2579, the fun is called to allow a more
+ "lax" validation.
+ See the <seealso marker="#vdat">validate_date_and_time/2</seealso>
+ function for more info on the <c>Validate</c> fun. </p>
+
+ <marker id="dat2s2"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>date_and_time_to_string2(DateAndTime) -> string()</name>
+ <fsummary>Convert a DateAndTime value to a string</fsummary>
+ <type>
+ <v>DateAndTime = [int()]</v>
+ </type>
+ <desc>
+ <p>Converts a DateAndTime list to a printable string, according
+ to the DISPLAY-HINT definition in RFC2579, with the extension
+ that it also allows the values "hours from UTC" = 14 together with
+ "minutes from UTC" = 0. </p>
+
+ <marker id="lt2dat_dst"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>local_time_to_date_and_time_dst(Local) -> [DateAndTime]</name>
+ <fsummary>Convert a Local time value to a list of possible DateAndTime(s)</fsummary>
+ <type>
+ <v>Local = {{Y,Mo,D},{H,M,S}}</v>
+ <v>DateAndTime = [int()]</v>
+ </type>
+ <desc>
+ <p>Converts a local time value to a list of possible DateAndTime
+ list(s). The local time value on the same format as defined in
+ calendar(3).</p>
+
+ <marker id="ut2dat"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>universal_time_to_date_and_time(UTC) -> DateAndTime</name>
+ <fsummary>Convert a UTC value to DateAndTime</fsummary>
+ <type>
+ <v>UTC = {{Y,Mo,D},{H,M,S}}</v>
+ <v>DateAndTime = [int()]</v>
+ </type>
+ <desc>
+ <p>Converts a universal time value to a DateAndTime list. The
+ universal time value on the same format as defined in calendar(3).</p>
+
+ <marker id="vdat"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>validate_date_and_time(DateAndTime) -> bool()</name>
+ <name>validate_date_and_time(DateAndTime, Validate) -> bool()</name>
+ <fsummary>Check if a DateAndTime value is correct</fsummary>
+ <type>
+ <v>DateAndTime = term()</v>
+ <v>Validate = fun(Kind, Data) -> boolean()</v>
+ </type>
+ <desc>
+ <p>Checks if <c>DateAndTime</c> is a correct DateAndTime
+ value, as specified in RFC2579. This function can be used in
+ instrumentation functions to validate a DateAndTime value.</p>
+
+
+ <p>The validation fun, <c>Validate</c>, allows for a more "flexible"
+ validation of the <c>DateAndTime</c> argument. Whenever the data
+ is found to not follow RFC2579, the fun is called to allow a more
+ "lax" validation.
+ The input to the validation fun looks like this: </p>
+
+ <pre>
+ Kind Data
+ -------------- ----------------------
+ year {Year1, Year2}
+ month Month
+ day Day
+ hour Hour
+ minute Minute
+ seconds Seconds
+ deci_seconds DeciSeconds
+ diff [Sign, Hour, Minute]
+ valid_date {Year, Month, Day}
+ </pre>
+
+ <marker id="passwd2localized_key"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>passwd2localized_key(Alg, Passwd, EngineID) -> Key</name>
+ <fsummary>Generates an localized key</fsummary>
+ <type>
+ <v>Alg = algorithm()</v>
+ <v>algorithm() = md5 | sha</v>
+ <v>Passwd = string()</v>
+ <v>EngineID = string()</v>
+ <v>Key = list()</v>
+ </type>
+ <desc>
+ <p>Generates a key that can be used as an authentication
+ or privacy key using MD5 och SHA. The key is
+ localized for EngineID.</p>
+
+ <marker id="octet_string_to_bits"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>octet_string_to_bits(S) -> Val</name>
+ <fsummary>Convert an OCTET-STRING to BITS</fsummary>
+ <type>
+ <v>Val = bits()</v>
+ </type>
+ <desc>
+ <p>Utility function for converting a value of type
+ <c>OCTET-STRING</c> to <c>BITS</c>. </p>
+
+ <marker id="bits_to_octet_string"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>bits_to_octet_string(B) -> Val</name>
+ <fsummary>Convert an OCTET-STRING to BITS</fsummary>
+ <type>
+ <v>Val = octet_string()</v>
+ </type>
+ <desc>
+ <p>Utility function for converting a value of type <c>BITS</c>
+ to <c>OCTET-STRING</c>. </p>
+
+ <marker id="read_mib"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>read_mib(FileName) -> {ok, mib()} | {error, Reason}</name>
+ <fsummary></fsummary>
+ <type>
+ <v>FileName = string()</v>
+ <v>mib() = #mib{}</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Read a compiled mib.</p>
+
+ <marker id="log_to_txt"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile) -> ok | {error, Reason}</name>
+ <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Start) -> ok | {error, Reason}</name>
+ <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Start, Stop) -> ok | {error, Reason}</name>
+ <fsummary>Convert an Audit Trail Log to text format</fsummary>
+ <type>
+ <v>LogDir = string()</v>
+ <v>Mibs = [MibName]</v>
+ <v>OutFile = string()</v>
+ <v>MibName = string()</v>
+ <v>LogName = string()</v>
+ <v>LogFile = string()</v>
+ <v>Start = Stop = null | datetime() | {local_time,datetime()} | {universal_time,datetime()} </v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Converts an Audit Trail Log to a readable text file, where
+ each item has a trailing TAB character, and any TAB
+ character in the body of an item has been replaced by ESC
+ TAB.
+ </p>
+ <p>The function can be used on a running system, or by copying
+ the entire log directory and calling this function. SNMP
+ must be running in order to provide MIB information.
+ </p>
+ <p><c>LogDir</c> is the name of the directory where the audit
+ trail log is stored.
+ <c>Mibs</c> is a list of Mibs to be used. The function uses
+ the information in the Mibs to convert for example object
+ identifiers to their symbolic name.
+ <c>OutFile</c> is the name of the generated text-file.
+ <c>LogName</c> is the name of the log,
+ <c>LogFile</c> is the name of the log file.
+ <c>Start</c> is the start (first) date and time from which
+ log events will be converted and
+ <c>Stop</c> is the stop (last) date and time to which log
+ events will be converted.
+ </p>
+ <p>The format of an audit trail log text item is as follows:
+ </p>
+ <p><c>Tag Addr - Community [TimeStamp] Vsn</c><br></br>
+ <c>PDU</c></p>
+ <p>where <c>Tag</c> is <c>request</c>, <c>response</c>,
+ <c>report</c>, <c>trap</c> or <c>inform</c>; Addr is
+ <c>IP:Port</c> (or comma space separated list of such);
+ <c>Community</c> is the community parameter (SNMP version
+ v1 and v2), or <c>SecLevel:"AuthEngineID":"UserName"</c>
+ (SNMP v3); <c>TimeStamp</c> is a date and time stamp,
+ and <c>Vsn</c> is the SNMP version. <c>PDU</c> is a textual
+ version of the protocol data unit. There is a new line
+ between <c>Vsn</c> and <c>PDU</c>.</p>
+
+ <marker id="change_log_size"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>change_log_size(LogName, NewSize) -> ok | {error, Reason}</name>
+ <fsummary>Change the size of the Audit Trail Log</fsummary>
+ <type>
+ <v>LogName = string()</v>
+ <v>NewSize = {MaxBytes, MaxFiles}</v>
+ <v>MaxBytes = integer()</v>
+ <v>MaxFiles = integer()</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Changes the log size of the Audit Trail Log. The
+ application must be configured to use the audit trail log
+ function. Please refer to disk_log(3) in Kernel Reference
+ Manual for a description of how to change the log size.
+ </p>
+ <p>The change is permanent, as long as the log is not deleted.
+ That means, the log size is remembered across reboots.</p>
+
+ <marker id="print_version_info"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>print_version_info() -> void()</name>
+ <name>print_version_info(Prefix) -> void()</name>
+ <fsummary>Formatted print of result of the versions functions</fsummary>
+ <type>
+ <v>Prefix = string() | integer()</v>
+ </type>
+ <desc>
+ <p>Utility function(s) to produce a formatted printout of the versions
+ info generated by the <c>versions1</c> function</p>
+ <p>This is the same as doing, e.g.: </p>
+ <pre>
+ {ok, V} = snmp:versions1(),
+ snmp:print_versions(V).
+ </pre>
+
+ <marker id="versions1"></marker>
+ <marker id="versions2"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>versions1() -> {ok, Info} | {error, Reason}</name>
+ <name>versions2() -> {ok, Info} | {error, Reason}</name>
+ <fsummary>Retrieve various system and application info</fsummary>
+ <type>
+ <v>Info = [info()]</v>
+ <v>info() = term()</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Utility functions used to retrieve some system and
+ application info.</p>
+ <p>The difference between the two functions is in how they get
+ the modules to check. <c>versions1</c> uses the app-file and
+ <c>versions2</c> uses the function <c>application:get_key</c>.</p>
+
+ <marker id="print_versions"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>print_versions(VersionInfo) -> void()</name>
+ <name>print_versions(Prefix, VersionInfo) -> void()</name>
+ <fsummary>Formatted print of result of the versions functions</fsummary>
+ <type>
+ <v>VersionInfo = [version_info()]</v>
+ <v>version_info() = term()</v>
+ <v>Prefix = string() | integer()</v>
+ </type>
+ <desc>
+ <p>Utility function to produce a formatted printout of the versions
+ info generated by the <c>versions1</c> and <c>versions2</c>
+ functions</p>
+ <p>Example: </p>
+ <pre>
+ {ok, V} = snmp:versions1(),
+ snmp:print_versions(V).
+ </pre>
+
+ <marker id="enable_trace"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>enable_trace() -> void()</name>
+ <fsummary>Starts a tracer</fsummary>
+ <!--
+ <type>
+ <v>Prefix = string() | integer()</v>
+ </type>
+ -->
+ <desc>
+ <p>Starts a dbg tracer that prints trace events to stdout (using
+ plain io:format after a minor formatting). </p>
+
+ <marker id="disable_trace"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>disable_trace() -> void()</name>
+ <fsummary>Stop the tracer</fsummary>
+ <!--
+ <type>
+ <v>Prefix = string() | integer()</v>
+ </type>
+ -->
+ <desc>
+ <p>Stop the tracer. </p>
+
+ <marker id="set_trace1"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>set_trace(Targets) -> void()</name>
+ <fsummary>Set trace target</fsummary>
+ <type>
+ <v>Targets = target() | targets()</v>
+ <v>target() = module()</v>
+ <v>module() = atom()</v>
+ <v>targets() = [target() | {target(), target_options()}]</v>
+ <v>target_options() = [target_option()]</v>
+ <v>target_option() = {return_trace, boolean()} | {scope, scope()}</v>
+ <v>scope() = all_functions | exported_functions | function_name() | {function_name(), function_arity()}</v>
+ <v>function_name() = atom()</v>
+ <v>function_arity() = integer() >= 0</v>
+ </type>
+ <desc>
+ <p>This function is used to set up default trace on function(s)
+ for the given module or modules. The scope of the trace will be
+ all <em>exported</em> functions (both the call info and the return
+ value). Timestamp info will also be included. </p>
+
+ <marker id="reset_trace"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>reset_trace(Targets) -> void()</name>
+ <fsummary>Reset trace target</fsummary>
+ <type>
+ <v>Targets = module() | modules()</v>
+ <v>modules() = [module()]</v>
+ <v>module() = atom()</v>
+ </type>
+ <desc>
+ <p>This function is used to reset (disable) trace for the
+ given module(s). </p>
+
+ <marker id="set_trace2"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>set_trace(Targets, Opts) -> void()</name>
+ <fsummary>Set trace target</fsummary>
+ <type>
+ <v>Targets = target() | targets()</v>
+ <v>target() = module()</v>
+ <v>module() = atom()</v>
+ <v>targets() = [target() | {target(), target_options()}]</v>
+ <v>target_options() = [target_option()]</v>
+ <v>target_option() = {return_trace, boolean()} | {scope, scope()}</v>
+ <v>scope() = all_functions | exported_functions | function_name() | {function_name(), function_arity()}</v>
+ <v>function_name() = atom()</v>
+ <v>function_arity() = integer() >= 0</v>
+ <v>Opts = disable | trace_options()</v>
+ <v>trace_options() = [trace_option()]</v>
+ <v>trace_option() = {timestamp, boolean()} | target_option()</v>
+ </type>
+ <desc>
+ <p>This function is used to set up trace on function(s) for the given
+ module or modules. </p>
+
+ <p>The example below sets up trace on the exported functions (default)
+ of module <c>snmp_generic</c> and all functions of module
+ <c>snmp_generic_mnesia</c>. With return values (which is default)
+ and timestamps in both cases (which is also default): </p>
+
+ <pre>
+ snmp:enable_trace(),
+ snmp:set_trace([snmp_generic,
+ {snmp_generic_mnesia, [{scope, all_functions}]}]),
+ .
+ .
+ .
+ snmp:set_trace(snmp_generic, disable),
+ .
+ .
+ .
+ snmp:disable_trace(),
+ </pre>
+
+ </desc>
+ </func>
+
+ </funcs>
+
+ <section>
+ <title>See Also</title>
+ <p>calendar(3)
+ </p>
+ </section>
+
+</erlref>
+
diff --git a/lib/snmp/doc/src/snmp_advanced_agent.xml b/lib/snmp/doc/src/snmp_advanced_agent.xml
new file mode 100644
index 0000000000..6600206c2d
--- /dev/null
+++ b/lib/snmp/doc/src/snmp_advanced_agent.xml
@@ -0,0 +1,482 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE chapter SYSTEM "chapter.dtd">
+
+<chapter>
+ <header>
+ <copyright>
+ <year>1997</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ 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.
+
+ </legalnotice>
+
+ <title>Advanced Agent Topics</title>
+ <prepared></prepared>
+ <responsible></responsible>
+ <docno></docno>
+ <approved></approved>
+ <checked></checked>
+ <date></date>
+ <rev></rev>
+ <file>snmp_advanced_agent.xml</file>
+ </header>
+ <p>The chapter <em>Advanced Agent Topics</em> describes the more advanced
+ agent related features of the SNMP development tool. The following topics
+ are covered:
+ </p>
+ <list type="bulleted">
+ <item>When to use a Sub-agent</item>
+ <item>Agent semantics</item>
+ <item>Sub-agents and dependencies</item>
+ <item>Distributed tables</item>
+ <item>Fault tolerance</item>
+ <item>Using Mnesia tables as SNMP tables</item>
+ <item>Audit Trail Logging</item>
+ <item>Deviations from the standard
+ </item>
+ </list>
+
+ <section>
+ <title>When to use a Sub-agent</title>
+ <p>The section <em>When to use a Sub-agent</em> describes situations
+ where the mechanism of loading and unloading MIBs is insufficient.
+ In these cases a sub-agent is needed.
+ </p>
+
+ <section>
+ <title>Special Set Transaction Mechanism</title>
+ <p>Each sub-agent can implement its own mechanisms for
+ <c>set</c>, <c>get</c> and <c>get-next</c>. For example, if the
+ application requires the <c>get</c> mechanism to be
+ asynchronous, or needs a N-phase <c>set</c> mechanism, a
+ specialized sub-agent should be used.
+ </p>
+ <p>The toolkit allows different kinds of sub-agents at the same
+ time. Accordingly, different MIBs can have different <c>set</c>
+ or <c>get</c> mechanisms.
+ </p>
+ </section>
+
+ <section>
+ <title>Process Communication</title>
+ <p>A simple distributed agent can be managed without sub-agents.
+ The instrumentation functions can use distributed Erlang to
+ communicate with other parts of the application. However, a
+ sub-agent can be used on each node if this generates too much
+ unnecessary traffic. A sub-agent processes requests per
+ incoming SNMP request, not per variable. Therefore the network
+ traffic is minimized.
+ </p>
+ <p>If the instrumentation functions communicate with UNIX
+ processes, it might be a good idea to use a special
+ sub-agent. This sub-agent sends the SNMP request to the other
+ process in one packet in order to minimize context switches. For
+ example, if a whole MIB is implemented on the C level in UNIX,
+ but you still want to use the Erlang SNMP tool, then you may
+ have one special sub-agent, which sends the variables in the
+ request as a single operation down to C.
+ </p>
+ </section>
+
+ <section>
+ <title>Frequent Loading of MIBs</title>
+ <p>Loading and unloading of MIBs are quite cheap
+ operations. However, if the application does this very often,
+ perhaps several times per minute, it should load the MIBs once
+ and for all in a sub-agent. This sub-agent only registers and
+ unregisters itself under another agent instead of loading the
+ MIBs each time. This is cheaper than loading an MIB.
+ </p>
+ </section>
+
+ <section>
+ <title>Interaction With Other SNMP Agent Toolkits</title>
+ <p>If the SNMP agent needs to interact with sub-agents
+ constructed in another package, a special sub-agent should be
+ used, which communicates through a protocol specified by the
+ other package.
+ </p>
+ </section>
+ </section>
+
+ <section>
+ <title>Agent Semantics</title>
+ <p>The agent can be configured to be multi-threaded, to process
+ one incoming request at a time, or to have a request limit
+ enabled (this can be used for load control or to limit the effect
+ of DoS attacks). If it is multi-threaded, read requests (<c>get</c>,
+ <c>get-next</c> and <c>get-bulk</c>) and traps are processed in
+ parallel with each other and <c>set</c> requests. However, all
+ <c>set</c> requests are serialized, which means that if the agent
+ is waiting for the application to complete a complicated write
+ operation, it will not process any new write requests until this
+ operation is finished. It processes read requests and sends traps,
+ concurrently. The reason for not handle write requests in parallel is
+ that a complex locking mechanism would be needed even in the simplest
+ cases. Even with the scheme described above, the user must be
+ careful not to violate that the <c>set</c> requests are atoms.
+ If this is hard to do, do not use the multi-threaded feature.
+ </p>
+ <p>The order within an request is undefined and variables are not
+ processed in a defined order. Do not assume that the first
+ variable in the PDU will be processed before the second, even if
+ the agent processes variables in this order. It
+ cannot even be assumed that requests belonging to different
+ sub-agents have any order.
+ </p>
+ <p>If the manager tries to set the same variable many times in the
+ same PDU, the agent is free to improvise. There is no definition
+ which determines if the instrumentation will be called once or
+ twice. If called once only, there is no definition that determines
+ which of the new values is going to be supplied.
+ </p>
+ <p>When the agent receives a request, it keeps the request ID for
+ one second after the response is sent. If the agent receives
+ another request with the same request ID during this time, from
+ the same IP address and UDP port, that request will be
+ discarded. This mechanism has nothing to do with the function
+ <c>snmpa:current_request_id/0</c>.</p>
+ </section>
+
+ <section>
+ <title>Sub-agents and Dependencies </title>
+ <p>The toolkit supports the use of different types of sub-agents,
+ but not the construction of sub-agents.
+ </p>
+ <p>Also, the toolkit does not support dependencies between
+ sub-agents. A sub-agent should by definition be stand alone and it is
+ therefore not good design to create dependencies between them.
+ </p>
+ </section>
+
+ <section>
+ <title>Distributed Tables</title>
+ <p>A common situation in more complex systems is that the data in
+ a table is distributed. Different table rows are implemented in
+ different places. Some SNMP tool-kits dedicate an SNMP sub-agent for
+ each part of the table and load the corresponding MIB into all
+ sub-agents. The Master Agent is responsible for presenting the
+ distributed table as a single table to the manager. The toolkit
+ supplied uses a different method.
+ </p>
+ <p>The method used to implement distributed tables with this SNMP
+ tool is to implement a table coordinator process responsible for
+ coordinating the processes, which hold the table data and they
+ are called table holders. All table holders must in some way be
+ known by the coordinator; the structure of the table data
+ determines how this is achieved. The coordinator may require
+ that the table holders explicitly register themselves and specify
+ their information. In other cases, the table holders can be
+ determined once at compile time.
+ </p>
+ <p>When the instrumentation function for the distributed table is
+ called, the request should be forwarded to the table
+ coordinator. The coordinator finds the requested information among
+ the table holders and then returns the answer to the
+ instrumentation function. The SNMP toolkit contains no support for
+ coordination of tables since this must be independent of the
+ implementation.
+ </p>
+ <p>The advantages of separating the table coordinator from the
+ SNMP tool are:
+ </p>
+ <list type="bulleted">
+ <item>We do not need a sub-agent for each table holder. Normally,
+ the sub-agent is needed to take care of communication, but in
+ Distributed Erlang we use ordinary message passing.
+ </item>
+ <item>Most likely, some type of table coordinator already
+ exists. This process should take care of the instrumentation for
+ the table.
+ </item>
+ <item>The method used to present a distributed table is strongly
+ application dependent. The use of different masking techniques
+ is only valid for a small subset of problems and registering
+ every row in a distributed table makes it non-distributed.
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Fault Tolerance</title>
+ <p>The SNMP agent toolkit gets input from three different sources:
+ </p>
+ <list type="bulleted">
+ <item>UDP packets from the network</item>
+ <item>return values from the user defined instrumentation functions</item>
+ <item>return values from the MIB.
+ </item>
+ </list>
+ <p>The agent is highly fault tolerant. If the manager gets an
+ unexpected response from the agent, it is possible that some
+ instrumentation function has returned an erroneous value. The
+ agent will not crash even if the instrumentation does. It should
+ be noted that if an instrumentation function enters an infinite
+ loop, the agent will also be blocked forever. The supervisor ,or
+ the application, specifies how to restart the agent.
+ </p>
+
+ <section>
+ <title>Using the SNMP Agent in a Distributed Environment</title>
+ <p>The normal way to use the agent in a distributed
+ environment is to use one master agent located at one node,
+ and zero or more sub-agents located on other nodes. However,
+ this configuration makes the master agent node a single point
+ of failure. If that node goes down, the agent will not work.
+ </p>
+ <p>One solution to this problem is to make the snmp application
+ a distributed Erlang application, and that means, the agent
+ may be configured to run on one of several nodes. If the node
+ where it runs goes down, another node restarts the agent.
+ This is called <em>failover</em>. When the node starts again,
+ it may <em>takeover</em> the application. This solution to
+ the problem adds another problem. Generally, the new node has
+ another IP address than the first one, which may cause
+ problems in the communication between the SNMP managers and
+ the agent.
+ </p>
+ <p>If the snmp agent is configured as a distributed Erlang
+ application, it will during takeover try to load the same MIBs
+ that were loaded at the old node. It uses the same filenames
+ as the old node. If the MIBs are not located in the same
+ paths at the different nodes, the MIBs must be loaded
+ explicitly after takeover.
+ </p>
+ </section>
+ </section>
+
+ <section>
+ <title>Using Mnesia Tables as SNMP Tables</title>
+ <p>The Mnesia DBMS can be used for storing data of SNMP
+ tables. This means that an SNMP table can be implemented as a
+ Mnesia table, and that a Mnesia table can be made visible via
+ SNMP. This mapping is largely automated.
+ </p>
+ <p>There are three main reasons for using this mapping:
+ </p>
+ <list type="bulleted">
+ <item>We get all features of Mnesia, such as fault tolerance,
+ persistent data storage, replication, and so on.
+ </item>
+ <item>Much of the work involved is automated. This includes
+ <c>get-next</c> processing and <c>RowStatus</c> handling.
+ </item>
+ <item>The table may be used as an ordinary Mnesia table, using
+ the Mnesia API internally in the application at the same time as
+ it is visible through SNMP.
+ </item>
+ </list>
+ <p>When this mapping is used, insertion and deletion in the
+ original Mnesia table is slower, with a factor O(log n). The read
+ access is not affected.
+ </p>
+ <p>A drawback with implementing an SNMP table as a Mnesia table is
+ that the internal resource is forced to use the table definition
+ from the MIB, which means that the external data model must be
+ used internally. Actually, this is only partially true. The Mnesia
+ table may extend the SNMP table, which means that the Mnesia table
+ may have columns which are use internally and are not seen by
+ SNMP. Still, the data model from SNMP must be maintained. Although
+ this is undesirable, it is a pragmatic compromise in many
+ situations where simple and efficient implementation is preferable
+ to abstraction.
+ </p>
+
+ <section>
+ <title>Creating the Mnesia Table</title>
+ <p>The table must be created in Mnesia before the manager can
+ use it. The table must be declared as type <c>snmp</c>. This
+ makes the table ordered in accordance with the lexicographical
+ ordering rules of SNMP. The name of the Mnesia table must be
+ identical to the SNMP table name. The types of the INDEX fields
+ in the corresponding SNMP table must be specified.
+ </p>
+ <p>If the SNMP table has more than one INDEX column, the
+ corresponding Mnesia row is a tuple, where the first element
+ is a tuple with the INDEX columns. Generally, if the SNMP table
+ has <em>N</em> INDEX columns and <em>C</em> data columns, the
+ Mnesia table is of arity <em>(C-N)+1</em>, where the key is a
+ tuple of arity <em>N</em> if <em>N > 1</em>, or a single term
+ if <em>N = 1</em>.
+ </p>
+ <p>Refer to the Mnesia User's Guide for information on how to
+ declare a Mnesia table as an SNMP table.
+ </p>
+ <p>The following example illustrates a situation in which we
+ have an SNMP table that we wish to implement as a Mnesia
+ table. The table stores information about employees at a
+ company. Each employee is indexed with the department number and
+ the name.
+ </p>
+ <code type="none">
+ empTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF EmpEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A table with information about employees."
+ ::= { emp 1}
+ empEntry OBJECT-TYPE
+ SYNTAX EmpEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ ""
+ INDEX { empDepNo, empName }
+ ::= { empTable 1 }
+ EmpEntry ::=
+ SEQUENCE {
+ empDepNo INTEGER,
+ empName DisplayString,
+ empTelNo DisplayString
+ empStatus RowStatus
+ }
+ </code>
+ <p>The corresponding Mnesia table is specified as follows:
+ </p>
+ <code type="none">
+mnesia:create_table([{name, employees},
+ {snmp, [{key, {integer, string}}]},
+ {attributes, [key, telno, row_status]}]).
+ </code>
+ <note>
+ <p>In the Mnesia tables, the two key columns are stored as a
+ tuple with two elements. Therefore, the arity of the table is
+ 3.</p>
+ </note>
+ </section>
+
+ <section>
+ <title>Instrumentation Functions</title>
+ <p>The MIB table shown in the previous section can be compiled
+ as follows:
+ </p>
+ <pre>
+1> <input>snmpc:compile("EmpMIB", [{db, mnesia}]).</input>
+ </pre>
+ <p>This is all that has to be done! Now the manager can read,
+ add, and modify rows. Also, you can use the ordinary Mnesia API
+ to access the table from your programs. The only explicit action
+ is to create the Mnesia table, an action the user has to perform
+ in order to create the required table schemas.</p>
+ </section>
+
+ <section>
+ <title>Adding Own Actions</title>
+ <p>It is often necessary to take some specific action when a
+ table is modified. This is accomplished with an instrumentation
+ function. It executes some specific code when the table is set,
+ and passes all other requests down to the pre-defined function.
+ </p>
+ <p>The following example illustrates this idea:
+ </p>
+ <code type="none">
+emp_table(set, RowIndex, Cols) ->
+ notify_internal_resources(RowIndex, Cols),
+ snmp_generic:table_func(set, RowIndex, Cols, {empTable, mnesia});
+emp_table(Op, RowIndex, Cols) ->
+ snmp_generic:table_func(Op, RowIndex, Cols, {empTable, mnesia}).
+ </code>
+ <p>The default instrumentation functions are defined in the
+ module <c>snmp_generic</c>. Refer to the Reference Manual,
+ section SNMP, module <c>snmp_generic</c> for details.</p>
+ </section>
+
+ <section>
+ <title>Extending the Mnesia Table</title>
+ <p>A table may contain columns that are used internally, but
+ should not be visible to a manager. These internal columns must
+ be the last columns in the table. The <c>set</c> operation will
+ not work with this arrangement, because there are columns that
+ the agent does not know about. This situation is handled by
+ adding values for the internal columns in the <c>set</c>
+ function.
+ </p>
+ <p>To illustrate this, suppose we extend our Mnesia
+ <c>empTable</c> with one internal column. We create it as
+ before, but with an arity of 4, by adding another attribute.
+ </p>
+ <code type="none">
+mnesia:create_table([{name, employees},
+ {snmp, [{key, {integer, string}}]},
+ {attributes, {key, telno, row_status, internal_col}}]).
+ </code>
+ <p>The last column is the internal column. When performing a
+ <c>set</c> operation, which creates a row, we must give a
+ value to the internal column. The instrumentation functions will now
+ look as follows:
+ </p>
+ <code type="none">
+-define(createAndGo, 4).
+-define(createAndWait, 5).
+
+emp_table(set, RowIndex, Cols) ->
+ notify_internal_resources(RowIndex, Cols),
+ NewCols =
+ case is_row_created(empTable, Cols) of
+ true -> Cols ++ [{4, "internal"}]; % add internal column
+ false -> Cols % keep original cols
+ end,
+ snmp_generic:table_func(set, RowIndex, NewCols, {empTable, mnesia});
+emp_table(Op, RowIndex, Cols) ->
+ snmp_generic:table_func(Op, RowIndex, Cols, {empTable, mnesia}).
+
+is_row_created(Name, Cols) ->
+ case snmp_generic:get_status_col(Name, Cols) of
+ {ok, ?createAndGo} -> true;
+ {ok, ?createAndWait} -> true;
+ _ -> false
+ end.
+ </code>
+ <p>If a row is created, we always set the internal column to
+ <c>"internal"</c>.
+ </p>
+ </section>
+ </section>
+
+ <section>
+ <title>Deviations from the Standard</title>
+ <p>In some aspects the agent does not implement SNMP fully. Here
+ are the differences:
+ </p>
+ <list type="bulleted">
+ <item>The default functions and <c>snmp_generic</c> cannot
+ handle an object of type <c>NetworkAddress</c> as INDEX
+ (SNMPv1 only!). Use <c>IpAddress</c> instead.
+ </item>
+ <item>The agent does not check complex ranges specified for
+ INTEGER objects. In these cases it just checks that the value
+ lies within the minimum and maximum values specified. For
+ example, if the range is specified as <c>1..10 | 12..20</c>
+ the agent would let 11 through, but not 0 or 21. The
+ instrumentation functions must check the complex ranges
+ itself.
+ </item>
+ <item>The agent will never generate the <c>wrongEncoding</c>
+ error. If a variable binding is erroneous encoded, the
+ <c>asn1ParseError</c> counter will be incremented.
+ </item>
+ <item>A <c>tooBig</c> error in an SNMPv1 packet will always use
+ the <c>'NULL'</c> value in all variable bindings.
+ </item>
+ <item>The default functions and <c>snmp_generic</c> do not check
+ the range of each OCTET in textual conventions derived from
+ OCTET STRING, e.g. <c>DisplayString</c> and
+ <c>DateAndTime</c>. This must be checked in an overloaded
+ <c>is_set_ok</c> function.
+ </item>
+ </list>
+ </section>
+</chapter>
+
diff --git a/lib/snmp/doc/src/snmp_agent_config_files.xml b/lib/snmp/doc/src/snmp_agent_config_files.xml
new file mode 100644
index 0000000000..0bab563f87
--- /dev/null
+++ b/lib/snmp/doc/src/snmp_agent_config_files.xml
@@ -0,0 +1,464 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE chapter SYSTEM "chapter.dtd">
+
+<chapter>
+ <header>
+ <copyright>
+ <year>1997</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ 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.
+
+ </legalnotice>
+
+ <title>Definition of Agent Configuration Files</title>
+ <prepared></prepared>
+ <responsible></responsible>
+ <docno></docno>
+ <approved></approved>
+ <checked></checked>
+ <date></date>
+ <rev></rev>
+ <file>snmp_agent_config_files.xml</file>
+ </header>
+ <p>All configuration data must be included in configuration files
+ that are located in the configuration directory. The name of this
+ directory is given in the <c>config_dir</c> configuration
+ parameter. These files are read at start-up, and are used to
+ initialize the SNMPv2-MIB or STANDARD-MIB, SNMP-FRAMEWORK-MIB,
+ SNMP-MPD-MIB, SNMP-VIEW-BASED-ACM-MIB, SNMP-COMMUNITY-MIB,
+ SNMP-USER-BASED-SM-MIB, SNMP-TARGET-MIB and SNMP-NOTIFICATION-MIB
+ (refer to the <seealso marker="snmp_agent_funct_descr#management">Management of the Agent</seealso> for a description of the MIBs). </p>
+ <p>The files are: </p>
+ <list type="bulleted">
+ <item>
+ <p><c>agent.conf</c>: see
+ <seealso marker="#agent_information">Agent Information</seealso></p>
+ </item>
+ <item>
+ <p><c>standard.conf</c>: see
+ <seealso marker="#system_information">System Information</seealso></p>
+ </item>
+ <item>
+ <p><c>context.conf</c>: see
+ <seealso marker="#context">Contexts</seealso></p>
+ </item>
+ <item>
+ <p><c>community.conf</c>: see
+ <seealso marker="#community">Communities</seealso></p>
+ </item>
+ <item>
+ <p><c>target_addr.conf</c>: see
+ <seealso marker="#target_addr">Target Address Definitions</seealso></p>
+ </item>
+ <item>
+ <p><c>target_params.conf</c>: see
+ <seealso marker="#target_params">Target Parameters Definitions</seealso></p>
+ </item>
+ <item>
+ <p><c>vacm.conf</c>: see
+ <seealso marker="#vacm">MIB Views for VACM</seealso></p>
+ </item>
+ <item>
+ <p><c>usm.conf</c>: see
+ <seealso marker="#usm">Security data for USM</seealso></p>
+ </item>
+ <item>
+ <p><c>notify.conf</c>: see
+ <seealso marker="#notify">Notify Definitions</seealso></p>
+ </item>
+ </list>
+ <p>The directory where the configuration files are found is given as
+ a parameter to the agent. </p>
+ <p>The entry format in all files are Erlang terms, separated by a
+ '<em>.</em>' and a <em>newline</em>. In the following sections, the
+ formats of these terms are described. Comments may be specified as
+ ordinary Erlang comments. </p>
+ <p>Syntax errors in these files are discovered and reported with the
+ function <c>config_err/2</c> of the error report module at start-up. </p>
+
+ <section>
+ <marker id="agent_information"></marker>
+ <title>Agent Information</title>
+ <p>The agent information should be stored in a file called
+ <c>agent.conf</c>.
+ </p>
+ <p>Each entry is a tuple of size two:
+ </p>
+ <p><c>{AgentVariable, Value}.</c></p>
+ <list type="bulleted">
+ <item><c>AgentVariable</c> is one of the variables is
+ SNMP-FRAMEWORK-MIB or one of the internal variables
+ <c>intAgentUDPPort</c>, which defines which UDP port the agent
+ listens to, or <c>intAgentIpAddress</c>, which defines the IP
+ address of the agent.
+ </item>
+ <item><c>Value</c> is the value for the variable.
+ </item>
+ </list>
+ <p>The following example shows a <c>agent.conf</c> file:
+ </p>
+ <pre>
+{intAgentUDPPort, 4000}.
+{intAgentIpAddress,[141,213,11,24]}.
+{snmpEngineID, "mbj's engine"}.
+{snmpEngineMaxPacketSize, 484}.
+ </pre>
+ <p>The value of <c>snmpEngineID</c> is a string, which for a
+ deployed agent should have a very specific structure. See
+ RFC 2271/2571 for details.
+ </p>
+ </section>
+
+ <section>
+ <marker id="context"></marker>
+ <title>Contexts</title>
+ <p>The context information should be stored in a file called
+ <c>context.conf</c>. The default context <c>""</c>
+ need not be present.
+ </p>
+ <p>Each row defines a context in the agent. This information is
+ used in the table <c>vacmContextTable</c> in the
+ SNMP-VIEW-BASED-ACM-MIB.
+ </p>
+ <p>Each entry is a term:
+ </p>
+ <p><c>ContextName.</c></p>
+ <list type="bulleted">
+ <item><c>ContextName</c> is a string.
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <marker id="system_information"></marker>
+ <title>System Information</title>
+ <p>The system information should be stored in a file called
+ <c>standard.conf</c>.
+ </p>
+ <p>Each entry is a tuple of size two:
+ </p>
+ <p><c>{SystemVariable, Value}.</c></p>
+ <list type="bulleted">
+ <item><c>SystemVariable</c> is one of the variables in the
+ system group, or <c>snmpEnableAuthenTraps</c>.
+ </item>
+ <item><c>Value</c> is the value for the variable.
+ </item>
+ </list>
+ <p>The following example shows a valid <c>standard.conf</c> file:
+ </p>
+ <pre>
+{sysDescr, "Erlang SNMP agent"}.
+{sysObjectID, [1,2,3]}.
+{sysContact, "(mbj,eklas)@erlang.ericsson.se"}.
+{sysName, "test"}.
+{sysServices, 72}.
+{snmpEnableAuthenTraps, enabled}.
+ </pre>
+ <p>A value must be provided for all variables, which lack default
+ values in the MIB.
+ </p>
+ </section>
+
+ <section>
+ <marker id="community"></marker>
+ <title>Communities</title>
+ <p>The community information should be stored in a file called
+ <c>community.conf</c>. It must be present if the agent is
+ configured for SNMPv1 or SNMPv2c.
+ </p>
+ <p>The corresponding table is <c>snmpCommunityTable</c> in the
+ SNMP-COMMUNITY-MIB.
+ </p>
+ <p>Each entry is a term:
+ </p>
+ <p><c>{CommunityIndex, CommunityName, SecurityName, ContextName, TransportTag}.</c></p>
+ <list type="bulleted">
+ <item><c>CommunityIndex</c> is a non-empty string.
+ </item>
+ <item><c>CommunityName</c> is a string.
+ </item>
+ <item><c>SecurityName</c> is a string.
+ </item>
+ <item><c>ContextName</c> is a string.
+ </item>
+ <item><c>TransportTag</c> is a string.
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <marker id="vacm"></marker>
+ <title>MIB Views for VACM</title>
+ <p>The information about MIB Views for VACM should be stored in a
+ file called
+ <c>vacm.conf</c>.
+ </p>
+ <p>The corresponding tables are <c>vacmSecurityToGroupTable</c>,
+ <c>vacmAccessTable</c> and <c>vacmViewTreeFamilyTable</c> in the
+ SNMP-VIEW-BASED-ACM-MIB.
+ </p>
+ <p>Each entry is one of the terms, one entry corresponds to one
+ row in one of the tables.
+ </p>
+ <p><c>{vacmSecurityToGroup, SecModel, SecName, GroupName}.</c></p>
+ <p><c>{vacmAccess, GroupName, Prefix, SecModel, SecLevel, Match, ReadView, WriteView, NotifyView}.</c></p>
+ <p><c>{vacmViewTreeFamily, ViewIndex, ViewSubtree, ViewStatus, ViewMask}.</c></p>
+ <list type="bulleted">
+ <item>
+ <p><c>SecModel</c> is <c>any</c>, <c>v1</c>, <c>v2c</c>, or
+ <c>usm</c>.</p>
+ </item>
+ <item>
+ <p><c>SecName</c> is a string.</p>
+ </item>
+ <item>
+ <p><c>GroupName</c> is a string.</p>
+ </item>
+ <item>
+ <p><c>Prefix</c> is a string.</p>
+ </item>
+ <item>
+ <p><c>SecLevel</c> is <c>noAuthNoPriv</c>, <c>authNoPriv</c>,
+ or <c>authPriv</c></p>
+ </item>
+ <item>
+ <p><c>Match</c> is <c>prefix</c> or <c>exact</c>.</p>
+ </item>
+ <item>
+ <p><c>ReadView</c> is a string.</p>
+ </item>
+ <item>
+ <p><c>WriteView</c> is a string.</p>
+ </item>
+ <item>
+ <p><c>NotifyView</c> is a string.
+ </p>
+ </item>
+ <item>
+ <p><c>ViewIndex</c> is an integer.</p>
+ </item>
+ <item>
+ <p><c>ViewSubtree</c> is a list of integer.</p>
+ </item>
+ <item>
+ <p><c>ViewStatus</c> is either <c>included</c> or <c>excluded</c></p>
+ </item>
+ <item>
+ <p><c>ViewMask</c> is either <c>null</c> or a list of ones and
+ zeros. Ones nominate that an exact match is used for this
+ sub-identifier. Zeros are wild-cards which match any
+ sub-identifier. If the mask is shorter than the sub-tree, the
+ tail is regarded as all ones. <c>null</c> is shorthand for a
+ mask with all ones.</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <marker id="usm"></marker>
+ <title>Security data for USM</title>
+ <p>The information about Security data for USM should be stored in a
+ file called
+ <c>usm.conf</c>, which must be present if the agent is configured
+ for SNMPv3.
+ </p>
+ <p>The corresponding table is <c>usmUserTable</c> in the
+ SNMP-USER-BASED-SM-MIB.
+ </p>
+ <p>Each entry is a term:
+ </p>
+ <p><c>{EngineID, UserName, SecName, Clone, AuthP, AuthKeyC, OwnAuthKeyC, PrivP, PrivKeyC, OwnPrivKeyC, Public, AuthKey, PrivKey}.</c></p>
+ <list type="bulleted">
+ <item>
+ <p><c>EngineID</c> is a string.
+ </p>
+ </item>
+ <item>
+ <p><c>UserName</c> is a string.</p>
+ </item>
+ <item>
+ <p><c>SecName</c> is a string.</p>
+ </item>
+ <item>
+ <p><c>Clone</c> is <c>zeroDotZero</c> or a list of integers.</p>
+ </item>
+ <item>
+ <p><c>AuthP</c> is a <c>usmNoAuthProtocol</c>,
+ <c>usmHMACMD5AuthProtocol</c>, or <c>usmHMACSHAAuthProtocol</c>.</p>
+ </item>
+ <item>
+ <p><c>AuthKeyC</c> is a string.</p>
+ </item>
+ <item>
+ <p><c>OwnAuthKeyC</c> is a string.</p>
+ </item>
+ <item>
+ <p><c>PrivP</c> is a <c>usmNoPrivProtocol</c>,
+ <c>usmDESPrivProtocol</c> or <c>usmAesCfb128Protocol</c>.</p>
+ </item>
+ <item>
+ <p><c>PrivKeyC</c> is a string.</p>
+ </item>
+ <item>
+ <p><c>OwnPrivKeyC</c> is a string.</p>
+ </item>
+ <item>
+ <p><c>Public</c> is a string.</p>
+ </item>
+ <item>
+ <p><c>AuthKey</c> is a list (of integer). This is the User's secret
+ localized authentication key. It is not visible in the MIB. The length
+ of this key needs to be 16 if <c>usmHMACMD5AuthProtocol</c> is used, and
+ 20 if <c>usmHMACSHAAuthProtocol</c> is used.</p>
+ </item>
+ <item>
+ <p><c>PrivKey</c> is a list (of integer). This is the User's secret
+ localized encryption key. It is not visible in the MIB. The length
+ of this key needs to be 16 if <c>usmDESPrivProtocol</c> or
+ <c>usmAesCfb128Protocol</c> is used.
+ </p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <marker id="notify"></marker>
+ <title>Notify Definitions</title>
+ <p>The information about Notify Definitions should be stored in a
+ file called
+ <c>notify.conf</c>.
+ </p>
+ <p>The corresponding table is <c>snmpNotifyTable</c> in the
+ SNMP-NOTIFICATION-MIB.
+ </p>
+ <p>Each entry is a term:
+ </p>
+ <p><c>{NotifyName, Tag, Type}.</c></p>
+ <list type="bulleted">
+ <item>
+ <p><c>NotifyName</c> is a unique non-empty string.
+ </p>
+ </item>
+ <item>
+ <p><c>Tag</c> is a string.
+ </p>
+ </item>
+ <item>
+ <p><c>Type</c> is <c>trap</c> or <c>inform</c>.
+ </p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <marker id="target_addr"></marker>
+ <title>Target Address Definitions</title>
+ <p>The information about Target Address Definitions should be
+ stored in a file called
+ <c>target_addr.conf</c>.
+ </p>
+ <p>The corresponding tables are <c>snmpTargetAddrTable</c> in the
+ SNMP-TARGET-MIB and <c>snmpTargetAddrExtTable</c> in the SNMP-COMMUNITY-MIB.
+ </p>
+ <p>Each entry is a term:
+ </p>
+ <p><c>{TargetName, Ip, Udp, Timeout, RetryCount, TagList, ParamsName, EngineId}.</c> or <br></br>
+<c>{TargetName, Ip, Udp, Timeout, RetryCount, TagList, ParamsName, EngineId, TMask, MaxMessageSize}.</c></p>
+ <list type="bulleted">
+ <item>
+ <p><c>TargetName</c> is a unique non-empty string.
+ </p>
+ </item>
+ <item>
+ <p><c>Ip</c> is a list of four integers.
+ </p>
+ </item>
+ <item>
+ <p><c>Udp</c> is an integer.
+ </p>
+ </item>
+ <item>
+ <p><c>Timeout</c> is an integer.
+ </p>
+ </item>
+ <item>
+ <p><c>RetryCount</c> is an integer.
+ </p>
+ </item>
+ <item>
+ <p><c>TagList</c> is a string.
+ </p>
+ </item>
+ <item>
+ <p><c>ParamsName</c> is a string.
+ </p>
+ </item>
+ <item>
+ <p><c>EngineId</c> is a string or the atom <c>discovery</c>.
+ </p>
+ </item>
+ <item>
+ <p><c>TMask</c> is a string of size 0, or size 6 (default: []).
+ </p>
+ </item>
+ <item>
+ <p><c>MaxMessageSize</c> is an integer (default: 2048).
+ </p>
+ </item>
+ </list>
+ <p>Note that if <c>EngineId</c> has the value <c>discovery</c>,
+ the agent cannot send
+ <c>inform</c> messages to that manager until it has performed the
+ <em>discovery</em> process with that manager. </p>
+ </section>
+
+ <section>
+ <marker id="target_params"></marker>
+ <title>Target Parameters Definitions</title>
+ <p>The information about Target Parameters Definitions should be
+ stored in a file called
+ <c>target_params.conf</c>.
+ </p>
+ <p>The corresponding table is <c>snmpTargetParamsTable</c> in the
+ SNMP-TARGET-MIB.
+ </p>
+ <p>Each entry is a term:
+ </p>
+ <p><c>{ParamsName, MPModel, SecurityModel, SecurityName, SecurityLevel}.</c></p>
+ <list type="bulleted">
+ <item>
+ <p><c>ParamsName</c> is a unique non-empty string.
+ </p>
+ </item>
+ <item>
+ <p><c>MPModel</c> is <c>v1</c>, <c>v2c</c> or <c>v3</c></p>
+ </item>
+ <item>
+ <p><c>SecurityModel</c> is <c>v1</c>, <c>v2c</c>, or <c>usm</c>.
+ </p>
+ </item>
+ <item>
+ <p><c>SecurityName</c> is a string.
+ </p>
+ </item>
+ <item>
+ <p><c>SecurityLevel</c> is <c>noAuthNoPriv</c>, <c>authNoPriv</c>
+ or <c>authPriv</c>.
+ </p>
+ </item>
+ </list>
+ </section>
+</chapter>
+
diff --git a/lib/snmp/doc/src/snmp_agent_funct_descr.xml b/lib/snmp/doc/src/snmp_agent_funct_descr.xml
new file mode 100644
index 0000000000..9a1bf28ab1
--- /dev/null
+++ b/lib/snmp/doc/src/snmp_agent_funct_descr.xml
@@ -0,0 +1,947 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE chapter SYSTEM "chapter.dtd">
+
+<chapter>
+ <header>
+ <copyright>
+ <year>1997</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ 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.
+
+ </legalnotice>
+
+ <title>Agent Functional Description</title>
+ <prepared></prepared>
+ <responsible></responsible>
+ <docno></docno>
+ <approved></approved>
+ <checked></checked>
+ <date></date>
+ <rev></rev>
+ <file>snmp_agent_funct_descr.xml</file>
+ </header>
+ <p>The SNMP agent system consists of one Master Agent and
+ optional Sub-agents.
+ </p>
+ <p>The tool makes it easy to dynamically extend an SNMP agent in
+ run-time. MIBs can be loaded and unloaded at any time. It is also
+ easy to change the implementation of an MIB in run-time, without
+ having to recompile the MIB. The MIB implementation is clearly
+ separated from the agent.
+ </p>
+ <p>To facilitate incremental MIB implementation, the tool can
+ generate a prototype implementation for a whole MIB, or parts
+ thereof. This allows different MIBs and management applications to
+ be developed at the same time.
+ </p>
+
+ <section>
+ <title>Features</title>
+ <marker id="features"></marker>
+ <p>To implement an agent, the programmer writes instrumentation
+ functions for the variables and the tables in the MIBs that the
+ agent is going to support. A running prototype which handles <c>set</c>,
+ <c>get</c>, and <c>get-next</c> can be created without any programming.
+ </p>
+ <p>The toolkit provides the following:
+ </p>
+ <list type="bulleted">
+ <item>multi-lingual multi-threaded extensible SNMP agent</item>
+ <item>easy writing of instrumentation functions with a
+ high-level programming language</item>
+ <item>basic fault handling such as automatic type checking</item>
+ <item>access control</item>
+ <item>authentication</item>
+ <item>privacy through encryption</item>
+ <item>loading and unloading of MIBs in run-time</item>
+ <item>the ability to change instrumentation functions without
+ recompiling the MIB</item>
+ <item>rapid prototyping environment where the MIB compiler can
+ use generic instrumentation functions, which later can be
+ refined by the programmer</item>
+ <item>a simple and extensible model for transaction handling and
+ consistency checking of set-requests</item>
+ <item>support of the sub-agent concept via distributed Erlang</item>
+ <item>a mechanism for sending notifications (traps and informs)</item>
+ <item>support for implementing SNMP tables in the Mnesia DBMS.</item>
+ </list>
+ </section>
+
+ <section>
+ <title>SNMPv1, SNMPv2 and SNMPv3</title>
+ <marker id="versions"></marker>
+ <p>The SNMP development toolkit works with all three versions of
+ Standard Internet Management Framework; SNMPv1, SNMPv2 and SNMPv3.
+ They all share the same basic structure and components. And they
+ follow the same architecture.</p>
+ <p>The versions are defined in following RFCs</p>
+ <list type="bulleted">
+ <item>SNMPv1 RFC 1555, 1157 1212, 1213 and 1215</item>
+ <item>SNMPv2 RFC 1902 - 1907</item>
+ <item>SNMPv3 RFC 2570 - 2575</item>
+ </list>
+ <p>Over time, as the Framework has evolved from SNMPv1 , through SNMPv2,
+ to SNMPv3 the definitions of each of these architectural components
+ have become richer and more clearly defined, but the fundamental
+ architecture has remained consistent.</p>
+ <p>The main features of SNMPv2 compared to SNMPv1 are:
+ </p>
+ <list type="bulleted">
+ <item>The <c>get-bulk</c> operation for transferring large
+ amounts of data.
+ </item>
+ <item>Enhanced error codes.
+ </item>
+ <item>A more precise language for MIB specification</item>
+ </list>
+ <p>The standard documents that define SNMPv2 are incomplete, in
+ the sense that they do not specify how an SNMPv2 message looks
+ like. The message format and security issues are left to a
+ special Administrative Framework. One such framework is the
+ Community-based SNMPv2 Framework (SNMPv2c), which uses the same
+ message format and framework as SNMPv1. Other
+ experimental frameworks as exist, e.g. SNMPv2u and SNMPv2*.
+ </p>
+ <p>The SNMPv3 specifications take a modular
+ approach to SNMP. All modules are
+ separated from each other, and can be extended or replaced
+ individually. Examples of modules are Message definition,
+ Security and Access Control. The main features of SNMPv3 are:
+ </p>
+ <list type="bulleted">
+ <item>Encryption and authentication is added.
+ </item>
+ <item>MIBs for agent configuration are defined.</item>
+ </list>
+ <p>All these specifications are commonly referred to as "SNMPv3",
+ but it is actually only the Message module, which defines a new
+ message format, and Security module, which takes care of
+ encryption and authentication, that cannot be used with SNMPv1 or
+ SNMPv2c. In this version of the agent toolkit, all the standard
+ MIBs for agent configuration are used. This includes MIBs for
+ definition of management targets for notifications. These MIBs
+ are used regardless of which SNMP version the agent is configured
+ to use.
+ </p>
+ <p>The extensible agent in this toolkit understands the SNMPv1,
+ SNMPv2c and SNMPv3. Recall that SNMP consists of two separate
+ parts, the MIB definition language (SMI), and the protocol. On
+ the protocol level, the agent can be configured to speak v1, v2c,
+ v3 or any combination of them at the same time, i.e. a v1 request
+ gets an v1 reply, a v2c request gets a v2c reply, and a v3 request
+ gets a v3 reply. On the MIB level, the MIB compiler can compile
+ both SMIv1 and SMIv2 MIBs. Once compiled, any of the formats can
+ be loaded into the agent, regardless of which protocol version the
+ agent is configured to use. This means that the agent translates
+ from v2 notifications to v1 traps, and vice versa. For example,
+ v2 MIBs can be loaded into an agent that speaks v1 only. The
+ procedures for the translation between the two protocols are
+ described in RFC 1908 and RFC 2089.
+ </p>
+ <p>In order for an implementation to make full use of the enhanced
+ SNMPv2 error codes, it is essential that the instrumentation
+ functions always return SNMPv2 error codes, in case of error.
+ These are translated into the corresponding SNMPv1 error codes by
+ the agent, if necessary.</p>
+ <note>
+ <p>The translation from an SMIv1 MIB to an SNMPv2c or SNMPv3 reply
+ is always very straightforward, but the translation from a v2 MIB
+ to a v1 reply is somewhat more complicated. There is one data
+ type in SMIv2, called <c>Counter64</c>, that an SNMPv1 manager cannot
+ decode correctly. Therefore, an agent may never send a <c>Counter64</c>
+ object to an SNMPv1 manager. The common practice in these
+ situations is to simple ignore any <c>Counter64</c> objects, when sending
+ a reply or a trap to an SNMPv1 manager. For example, if an SNMPv1
+ manager tries to GET an object of type <c>Counter64</c>, he will get a
+ <c>noSuchName</c> error, while an SNMPv2 manager would get a
+ correct value.</p>
+ </note>
+ </section>
+
+ <section>
+ <title>Operation</title>
+ <marker id="operations"></marker>
+ <p>The following steps are needed to get a running agent:</p>
+ <list type="ordered">
+ <item>
+ <p>Write your MIB in SMI in a text file.</p>
+ </item>
+ <item>
+ <p>Write the instrumentation functions in Erlang and compile them.</p>
+ </item>
+ <item>
+ <p>Put their names in the association file.</p>
+ </item>
+ <item>
+ <p>Run the MIB together with the association file through the
+ MIB compiler.</p>
+ </item>
+ <item>
+ <p>Configure the application (agent).</p>
+ </item>
+ <item>
+ <p>Start the application (agent).</p>
+ </item>
+ <item>
+ <p>Load the compiled MIB into the agent.</p>
+ </item>
+ </list>
+ <p>The figures in this section illustrate the steps involved in
+ the development of an SNMP agent.</p>
+ <marker id="image-1"></marker>
+ <image file="snmp-um-1-image-1.gif">
+ <icaption>MIB Compiler Principles</icaption>
+ </image>
+ <p>The compiler parses the SMI file and associates each table or
+ variable with an instrumentation function (see the figure <seealso marker="#image-1">MIB Compiler Principles</seealso>). The actual
+ instrumentation functions are not needed at MIB compile time, only
+ their names.
+ </p>
+ <p>The binary output file produced by the compiler is read by the
+ agent at MIB load time (see the figure <seealso marker="#image-2">Starting the Agent</seealso>). The instrumentation is ordinary Erlang code which
+ is loaded explicitly or automatically the first time it is called.</p>
+ <marker id="image-2"></marker>
+ <image file="snmp-um-1-image-2.gif">
+ <icaption>Starting the Agent</icaption>
+ </image>
+ <p>The SNMP agent system consists of one Master Agent and optional
+ sub-agents. The Master Agent can be seen as a special kind of
+ sub-agent. It implements the core agent functionality, UDP packet
+ processing, type checking, access control, trap distribution, and
+ so on. From a user perspective, it is used as an ordinary
+ sub-agent.
+ </p>
+ <p>Sub-agents are only needed if your application requires special
+ support for distribution from the SNMP toolkit. A sub-agent can
+ also be used if the application requires a more complex set
+ transaction scheme than is found in the master agent.
+ </p>
+ <p>The following illustration shows how a system can look in runtime.</p>
+ <marker id="snmp_ch2_fig3"></marker>
+ <image file="snmp-um-1-image-3.gif">
+ <icaption>Architecture</icaption>
+ </image>
+ <p>A typical operation could include the following steps:</p>
+ <list type="ordered">
+ <item>The Manager sends a request to the Agent.</item>
+ <item>The Master Agent decodes the incoming UDP packet.</item>
+ <item>The Master Agent determines which items in the request
+ that should be processed here and which items should be
+ forwarded to its subagent.</item>
+ <item>Step 3 is repeated by all subagents.</item>
+ <item>Each sub-agent calls the instrumentation for its loaded MIBs.</item>
+ <item>The results of calling the instrumentation are propagated
+ back to the Master Agent.</item>
+ <item>The answer to the request is encoded to a UDP Protocol
+ Data Unit (PDU).</item>
+ </list>
+ <p>The sequence of steps shown is probably more complex than
+ normal, but it illustrates the amount of functionality which is
+ available. The following points should be noted:
+ </p>
+ <list type="bulleted">
+ <item>An agent can have many MIBs loaded at the same time.</item>
+ <item>Sub-agents can also have sub-agents. Each sub-agent can have
+ an arbitrary number of child sub-agents registered, forming a
+ hierarchy.</item>
+ <item>One MIB can communicate with many applications.</item>
+ <item>Instrumentation can use Distributed Erlang to communicate
+ with an application.</item>
+ </list>
+ <p>Most applications only need the Master Agent because an agent
+ can have multiple MIBs loaded at the same time.</p>
+ </section>
+
+ <section>
+ <title>Sub-agents and MIB Loading</title>
+ <marker id="sub_agent_mib_loading"></marker>
+ <p>Since applications tend to be transient (they are dynamically
+ loaded and unloaded), the management of these applications must be
+ dynamic as well. For example, if we have an equipment MIB for a
+ rack and different MIBs for boards, which can be installed in the
+ rack, the MIB for a card should be loaded when the card is
+ inserted, and unloaded when the card is removed.
+ </p>
+ <p>In this agent system, there are two ways to dynamically install
+ management information. The most common way is to load an MIB into
+ an agent. The other way is to use a sub-agent, which is controlled
+ by the application and is able to register and unregister itself. A
+ sub-agent can register itself for managing a sub-tree (not to be mixed up
+ with <c>erlang:register</c>). The sub-tree is identified by an
+ Object Identifier. When a sub-agent is registered, it receives all
+ requests for this particular sub-tree and it is responsible for
+ answering them. It should also be noted that a sub-agent can be
+ started and stopped at any time.
+ </p>
+ <p>Compared to other SNMP agent packages, there is a significant
+ difference in this way of using sub-agents. Other packages normally
+ use sub-agents to load and unload MIBs in run-time. In Erlang, it is
+ easy to load code in run-time and it is possible to load an MIB
+ into an existing sub-agent. It is not necessary to create a new process
+ for handling a new MIB.
+ </p>
+ <p>Sub-agents are used for the following reasons:
+ </p>
+ <list type="bulleted">
+ <item>to provide a more complex set-transaction scheme than
+ master agent</item>
+ <item>to avoid unnecessary process communication</item>
+ <item>to provide a more lightweight mechanism for loading and
+ unloading MIBs in run-time</item>
+ <item>to provide interaction with other SNMP agent toolkits.</item>
+ </list>
+ <p>Refer to the chapter
+ <seealso marker="snmp_advanced_agent">Advanced Agent Topics</seealso>
+ in this User's Guide for more information about these topics.
+ </p>
+ <p>The communication protocol between sub-agents is the normal
+ message passing which is used in distributed Erlang systems. This
+ implies that sub-agent communication is very efficient compared to
+ SMUX, DPI, AgentX, and similar protocols.</p>
+ </section>
+
+ <section>
+ <title>Contexts and Communities</title>
+ <marker id="context_and_communities"></marker>
+ <p>A context is a collection of management information accessible
+ by an SNMP entity. An instance of a management object may exist in
+ more than one context. An SNMP entity potentially has access to
+ many contexts.</p>
+ <p>Each managed object can exist in many instances within a
+ SNMP entity. To identify the instances, specified by an MIB module,
+ a method to distinguish the actual instance by its 'scope' or
+ context is used. Often the context is a physical or a logical device.
+ It can include multiple devices, a subset of a single device or a
+ subset of multiple devices, but the context is always
+ defined as a subset of a single SNMP entity. To be able to
+ identify a specific
+ item of management information within an SNMP entity, the context,
+ the object type and its instance must be used.</p>
+ <p>For example, the managed object type <c>ifDescr</c> from RFC1573, is
+ defined as the description of a network interface. To identify
+ the description of device-X's first network interface, four pieces
+ of information are needed: the snmpEngineID of the SNMP entity
+ which provides access to the management information at device-X,
+ the <c>contextName</c> (device-X), the managed object type
+ (<c>ifDescr</c>), and the instance ("1").
+ </p>
+ <p>In SNMPv1 and SNMPv2c, the community string in the message was
+ used for (at least) three different purposes:
+ </p>
+ <list type="bulleted">
+ <item>
+ <p>to identify the context</p>
+ </item>
+ <item>
+ <p>to provide authentication</p>
+ </item>
+ <item>
+ <p>to identify a set of trap targets</p>
+ </item>
+ </list>
+ <p>In SNMPv3, each of these usage areas has its own unique
+ mechanism. A context is identified by the name of the SNMP
+ entity, <c>contextEngineID</c>, and the name of the context,
+ <c>contextName</c>. Each SNMPv3 message contains values for these
+ two parameters.
+ </p>
+ <p>There is a MIB, SNMP-COMMUNITY-MIB, which maps a community
+ string to a <c>contextEngineID</c> and <c>contextName</c>. Thus,
+ each message, an SNMPv1, SNMPv2c or an SNMPv3 message, always
+ uniquely identifies a context.
+ </p>
+ <p>For an agent, the <c>contextEngineID</c> identified by a received
+ message, is always equal to the <c>snmpEngineID</c> of the agent.
+ Otherwise, the message was not intended for the agent. If the
+ agent is configured with more than one context, the
+ instrumentation code must be able to figure out for which context
+ the request was intended. There is a function
+ <c>snmpa:current_context/0</c> provided for this purpose.
+ </p>
+ <p>By default, the agent has no knowledge of any other contexts
+ than the default context, <c>""</c>. If it is to support more
+ contexts, these must be explicitly added, by using an appropriate
+ configuration file
+ <seealso marker="snmp_agent_config_files">Agent Configuration Files</seealso>.
+ </p>
+ </section>
+
+ <section>
+ <title>Management of the Agent</title>
+ <marker id="management"></marker>
+ <p>There is a set of standard MIBs, which are used to control and
+ configure an SNMP agent. All of these MIBs, with the exception of
+ the optional SNMP-PROXY-MIB (which is only used for proxy agents),
+ are implemented in this agent. Further, it is configurable which
+ of these MIBs are actually loaded, and thus made visible to SNMP
+ managers. For example, in a non-secure environment, it might be a
+ good idea to not make MIBs that define access control visible.
+ Note, the data the MIBs define is used internally in the
+ agent, even if the MIBs not are loaded. This chapter describes
+ these standard MIBs, and some aspects of their implementation.
+ </p>
+ <p>Any SNMP agent must implement the <c>system</c> group and the
+ <c>snmp</c> group, defined in MIB-II. The definitions of these
+ groups have changed from SNMPv1 to SNMPv2. MIBs and implementations
+ for both of these versions are Provided in the
+ distribution. The MIB file for SNMPv1 is called STANDARD-MIB, and the
+ corresponding for SNMPv2 is called SNMPv2-MIB. If the agent is
+ configured for SNMPv1 only, the STANDARD-MIB is loaded by default;
+ otherwise, the SNMPv2-MIB is loaded by default. It is possible to
+ override this default behavior, by explicitly loading another
+ version of this MIB, for example, you could choose to implement
+ the union of all objects in these two MIBs.
+ </p>
+ <p>An SNMPv3 agent must implement the SNMP-FRAMEWORK-MIB and
+ SNMP-MPD-MIB. These MIBs are loaded by default, if the agent is
+ configured for SNMPv3. These MIBs can be loaded for other
+ versions as well.
+ </p>
+ <p>There are five other standard MIBs, which also may be loaded
+ into the agent. These MIBs are:
+ </p>
+ <list type="bulleted">
+ <item>
+ <p>SNMP-TARGET-MIB and SNMP-NOTIFICATION-MIB, which defines
+ managed objects for configuration of management targets,
+ i.e. receivers of notifications (traps and informs). These
+ MIBs can be used with any SNMP version.
+ </p>
+ </item>
+ <item>
+ <p>SNMP-VIEW-BASED-ACM-MIB, which defined managed objects
+ for access control. This MIB can be used with any SNMP
+ version.
+ </p>
+ </item>
+ <item>
+ <p>SNMP-COMMUNITY-MIB, which defines managed objects for
+ coexistence of SNMPv1 and SNMPv2c with SNMPv3. This MIB is
+ only useful if SNMPv1 or SNMPv2c is used, possibly in
+ combination with SNMPv3.
+ </p>
+ </item>
+ <item>
+ <p>SNMP-USER-BASED-SM-MIB, which defines managed objects
+ for authentication and privacy. This MIB is only useful
+ with SNMPv3.
+ </p>
+ </item>
+ </list>
+ <p>All of these MIBs should be loaded into the Master Agent. Once
+ loaded, these MIBs are always available in all contexts.
+ </p>
+ <p>The ASN.1 code, the Erlang source code, and the generated
+ <c>.hrl</c> files for them are provided in the distribution and are
+ placed in the directories <c>mibs</c>, <c>src</c>, and <c>include</c>,
+ respectively, in the <c>snmp</c> application.
+ </p>
+ <p>The <c>.hrl</c> files are generated with
+ <c>snmpc:mib_to_hrl/1</c>. Include these files in your code as in
+ the following example:
+ </p>
+ <code type="none">
+-include_lib("snmp/include/SNMPv2-MIB.hrl").
+ </code>
+ <p>The initial values for the managed objects defined in these
+ tables, are read at start-up from a set of configuration files.
+ These are described in <seealso marker="snmp_config">Configuration Files</seealso>.
+ </p>
+
+ <section>
+ <title>STANDARD-MIB and SNMPv2-MIB</title>
+ <p>These MIBs contain the <c>snmp-</c> and <c>system</c> groups
+ from MIB-II which is defined in RFC1213 (STANDARD-MIB) or
+ RFC1907 (SNMPv2-MIB). They are implemented in the
+ <c>snmp_standard_mib</c> module. The <c>snmp</c> counters all
+ reside in volatile memory and the <c>system</c> and
+ <c>snmpEnableAuthenTraps</c> variables in persistent memory,
+ using the SNMP built-in database (refer to the Reference Manual,
+ section <c>snmp</c>, module <c>snmpa_local_db</c> for more
+ details).</p>
+ <p>If another implementation of any of these variables is needed,
+ e.g. to store the persistent variables in a Mnesia database,
+ an own implementation of the variables must be made. That MIB
+ will be compiled and loaded instead of the default MIB.
+ The new compiled MIB
+ must have the same name as the original MIB (i.e. STANDARD-MIB
+ or SNMPv2-MIB), and be located in the SNMP configuration
+ directory (see <seealso marker="snmp_config">Configuration Files</seealso>.)
+ </p>
+ <p>One of these MIBs is always loaded. If only SNMPv1 is used,
+ STANDARD-MIB is loaded, otherwise SNMPv2-MIB is loaded.
+ </p>
+
+ <section>
+ <title>Data Types</title>
+ <p>There are some new data types in SNMPv2 that are useful in
+ SNMPv1 as well. In the STANDARD-MIB, three data types are
+ defined, <c>RowStatus</c>, <c>TruthValue</c> and
+ <c>DateAndTime</c>. These data types are originally defined
+ as textual conventions in SNMPv2-TC (RFC1903).
+ </p>
+ </section>
+ </section>
+
+ <section>
+ <title>SNMP-FRAMEWORK-MIB and SNMP-MPD-MIB</title>
+ <p>The SNMP-FRAMEWORK-MIB and SNMP-MPD-MIB define additional
+ read-only managed objects, which
+ is used in the generic SNMP framework defined in RFC2271 and the
+ generic message processing and dispatching module defined in
+ RFC2272. They are generic in the sense that they are not tied
+ to any specific SNMP version.
+ </p>
+ <p>The objects in these MIBs are implemented in the modules
+ <c>snmp_framework_mib</c> and <c>snmp_standard_mib</c>,
+ respectively. All objects reside in volatile memory, and the
+ configuration files are always reread at start-up.
+ </p>
+ <p>If SNMPv3 is used, these MIBs are loaded by default.
+ </p>
+ </section>
+
+ <section>
+ <title>SNMP-TARGET-MIB and SNMP-NOTIFICATION-MIB</title>
+ <p>The SNMP-TARGET-MIB and SNMP-NOTIFICATION-MIB define managed
+ objects for configuration of notification receivers. They
+ are described in detail in RFC2273. Only a brief description
+ is given here.
+ </p>
+ <p>All tables in these MIBs have a column of type
+ <c>StorageType</c>. The value of this column specifies how each
+ row is stored, and what happens in case of a restart of the
+ agent. The implementation supports the values <c>volatile</c>
+ and <c>nonVolatile</c>. When the tables are initially filled
+ with data from the configuration files, these rows will
+ automatically have storage type <c>nonVolatile</c>. Should the
+ agent restart, all <c>nonVolatile</c> rows survive the restart,
+ while the <c>volatile</c> rows are lost.
+ The configuration files are not read at restart, by default.
+ </p>
+ <p>These MIBs are not loaded by default.
+ </p>
+
+ <section>
+ <title>snmpNotifyTable</title>
+ <p>An entry in the <c>snmpNotifyTable</c> selects a set
+ of management targets, which should receive notifications,
+ as well as the type (trap or inform) of notification that
+ should be sent to each selected management target.
+ When an application sends a notification using
+ the function <c>send_notification/5</c> or the function
+ <c>send_trap</c> the parameter <c>NotifyName</c>, specified in
+ the call, is used as an index in the table. The notification
+ is sent to the management targets selected by that entry.
+ </p>
+ </section>
+
+ <section>
+ <title>snmpTargetAddrTable</title>
+ <p>An entry in the <c>snmpTargetAddrTable</c> defines
+ transport parameters (such as
+ IP address and UDP port) for each management target. Each row
+ in the <c>snmpNotifyTable</c> refers to potentially many rows
+ in the <c>snmpTargetAddrTable</c>. Each row in the
+ <c>snmpTargetAddrTable</c>
+ refers to an entry in the <c>snmpTargetParamsTable</c>.
+ </p>
+ </section>
+
+ <section>
+ <title>snmpTargetParamsTable</title>
+ <p>An entry in the <c>snmpTargetParamsTable</c> defines
+ which SNMP version to use, and which security parameters to use.
+ </p>
+ <p>Which SNMP version to use is implicitly defined by
+ specifying the Message Processing Model. This version of the
+ agent handles the models <c>v1</c>, <c>v2c</c> and <c>v3</c>.
+ </p>
+ <p>Each row specifies which security model to use, along with
+ security level and security parameters.
+ </p>
+ </section>
+ </section>
+
+ <section>
+ <title>SNMP-VIEW-BASED-ACM-MIB</title>
+ <p>The SNMP-VIEW-BASED-ACM-MIB defines managed objects to
+ control access to the the managed objects for the managers.
+ The View Based Access Control Module (VACM) can be used with
+ any SNMP version. However, if it is used with SNMPv1 or SNMPv2c,
+ the SNMP-COMMUNITY-MIB defines additional objects to map
+ community strings to VACM parameters.
+ </p>
+ <p>All tables in this MIB have a column of type <c>StorageType</c>.
+ The value of this column specifies how each
+ row is stored, and what happens in case of a restart of the
+ agent. The implementation supports the values <c>volatile</c>
+ and <c>nonVolatile</c>. When the tables are initially filled
+ with data from the configuration files, these rows will
+ automatically have storage type <c>nonVolatile</c>. Should the
+ agent restart, all <c>nonVolatile</c> rows survive the restart,
+ while the <c>volatile</c> rows are lost.
+ The configuration files are not read at restart by default.
+ </p>
+ <p>This MIB is not loaded by default.
+ </p>
+ <p>VACM is described in detail in RFC2275. Here is only a brief
+ description given.
+ </p>
+ <p>The basic concept is that of a <em>MIB view</em>. An MIB view
+ is a subset of all the objects implemented by an agent. A
+ manager has access to a certain MIB view, depending on which
+ security parameters are used, in which context the request is
+ made, and which type of request is made.
+ </p>
+ <p>The following picture gives an overview of the mechanism to
+ select an MIB view:</p>
+ <image file="MIB_mechanism.gif">
+ <icaption>Overview of the mechanism of MIB selection</icaption>
+ </image>
+
+ <section>
+ <title>vacmContextTable</title>
+ <p>The <c>vacmContextTable</c> is a read-only table that lists all
+ available contexts.
+ </p>
+ </section>
+
+ <section>
+ <title>vacmSecurityToGroupTable</title>
+ <p>The <c>vacmSecurityToGroupTable</c> maps a <c>securityModel</c>
+ and a
+ <c>securityName</c> to a <c>groupName</c>.
+ </p>
+ </section>
+
+ <section>
+ <title>vacmAccessTable</title>
+ <p>The <c>vacmAccessTable</c> maps the <c>groupName</c> (found in
+ <c>vacmSecurityToGroupTable</c>), <c>contextName</c>,
+ <c>securityModel</c>, and <c>securityLevel</c> to an MIB view
+ for each type of operation (read, write, or notify). The MIB
+ view is represented as a <c>viewName</c>. The definition of
+ the MIB view represented by the <c>viewName</c> is found in
+ the <c>vacmViewTreeFamilyTable</c></p>
+ </section>
+
+ <section>
+ <title>vacmViewTreeFamilyTable</title>
+ <p>The <c>vacmViewTreeFamilyTable</c> is indexed by the
+ <c>viewName</c>, and defines
+ which objects are included in the MIB view.
+ </p>
+ <p>The MIB definition for the table looks as follows:</p>
+ <pre>
+VacmViewTreeFamilyEntry ::= SEQUENCE
+ {
+ vacmViewTreeFamilyViewName SnmpAdminString,
+ vacmViewTreeFamilySubtree OBJECT IDENTIFIER,
+ vacmViewTreeFamilyMask OCTET STRING,
+ vacmViewTreeFamilyType INTEGER,
+ vacmViewTreeFamilyStorageType StorageType,
+ vacmViewTreeFamilyStatus RowStatus
+ }
+
+INDEX { vacmViewTreeFamilyViewName,
+ vacmViewTreeFamilySubtree
+ }
+ </pre>
+ <p>Each <c>vacmViewTreeFamilyViewName</c> refers to a
+ collection of sub-trees.
+ </p>
+
+ <section>
+ <title>MIB View Semantics</title>
+ <p>An MIB view is a collection of included and excluded
+ sub-trees. A sub-tree is identified by an OBJECT IDENTIFIER. A
+ mask is associated with each sub-tree.
+ </p>
+ <p>For each possible MIB object instance, the instance
+ belongs to a sub-tree if:
+ </p>
+ <list type="bulleted">
+ <item>the OBJECT IDENTIFIER name of that MIB object
+ instance comprises at least as many sub-identifiers as
+ does the sub-tree, and
+ </item>
+ <item>each sub-identifier in the name of that MIB object
+ instance matches the corresponding sub-identifier of the
+ sub-tree whenever the corresponding bit of the associated
+ mask is 1 (0 is a wild card that matches anything).</item>
+ </list>
+ <p>Membership of an object instance in an MIB view is
+ determined by the following algorithm:
+ </p>
+ <list type="bulleted">
+ <item>If an MIB object instance does not belong to any of
+ the relevant sub-trees, then the instance is not in the
+ MIB view.
+ </item>
+ <item>If an MIB object instance belongs to exactly one
+ sub-tree, then the instance is included in, or excluded
+ from, the relevant MIB view according to the type of
+ that entry.
+ </item>
+ <item>If an MIB object instance belongs to more than one
+ sub-tree, then the sub-tree which comprises the greatest
+ number of sub-identifiers, and is the lexicographically
+ greatest, is used.
+ </item>
+ </list>
+ <note>
+ <p>If the OBJECT IDENTIFIER is longer than an OBJECT
+ IDENTIFIER of an object type in the MIB, it refers to
+ object instances. Because of this, it is possible to
+ control whether or not particular rows in a table shall be
+ visible.</p>
+ </note>
+ </section>
+ </section>
+ </section>
+
+ <section>
+ <title>SNMP-COMMUNITY-MIB</title>
+ <p>The SNMP-COMMUNITY-MIB defines managed objects that is used
+ for coexistence between SNMPv1 and SNMPv2c with SNMPv3.
+ Specifically, it contains objects for mapping between community
+ strings and version-independent SNMP message parameters. In
+ addition, this MIB provides a mechanism for performing source address
+ validation on incoming requests, and for selecting community
+ strings based on target addresses for outgoing notifications.
+ </p>
+ <p>All tables in this MIB have a column of type
+ <c>StorageType</c>. The value of this column specifies how each
+ row is stored, and what happens in case of a restart of the
+ agent. The implementation supports the values <c>volatile</c>
+ and <c>nonVolatile</c>. When the tables are initially filled
+ with data from the configuration files, these rows will
+ automatically have storage type <c>nonVolatile</c>. Should the
+ agent restart, all <c>nonVolatile</c> rows survive the restart,
+ while the <c>volatile</c> rows are lost.
+ The configuration files are not read at restart, by default.
+ </p>
+ <p>This MIB is not loaded by default.
+ </p>
+ </section>
+
+ <section>
+ <title>SNMP-USER-BASED-SM-MIB</title>
+ <p>The SNMP-USER-BASED-SM-MIB defines managed objects that is
+ used for the User-Based Security Model.
+ </p>
+ <p>All tables in this MIB have a column of type
+ <c>StorageType</c>. The value of the column specifies how each
+ row is stored, and what happens in case of a restart of the
+ agent. The implementation supports the values <c>volatile</c>
+ and <c>nonVolatile</c>. When the tables are initially filled
+ with data from the configuration files, these rows will
+ automatically have storage type <c>nonVolatile</c>. Should the
+ agent restart, all <c>nonVolatile</c> rows survive the restart,
+ while the <c>volatile</c> rows are lost.
+ The configuration files are not read at restart, by default.
+ </p>
+ <p>This MIB is not loaded by default.
+ </p>
+ </section>
+
+ <section>
+ <title>OTP-SNMPEA-MIB</title>
+ <p>The OTP-SNMPEA-MIB was used in earlier versions of the agent, before
+ standard MIBs existed for access control, MIB views, and trap
+ target specification. All objects in this MIB are now obsolete.
+ </p>
+ </section>
+ </section>
+
+ <section>
+ <title>Notifications</title>
+ <marker id="notifications"></marker>
+ <p>Notifications are defined in SMIv1 with the TRAP-TYPE macro in
+ the definition of an MIB (see RFC1215). The corresponding
+ macro in SMIv2 is NOTIFICATION-TYPE. When an application
+ decides to send a notification, it calls one of the following
+ functions:
+ </p>
+ <code type="none">
+snmpa:send_notification(Agent, Notification, Receiver
+ [, NotifyName, ContextName, Varbinds])
+snmpa:send_trap(Agent, Notification, Community [, Receiver, Varbinds])
+ </code>
+ <p>providing the registered name or process identifier of the
+ agent where the MIB, which defines the notification is loaded and
+ the symbolic name of the notification.
+ </p>
+ <p>If the <c>send_notification/3,4</c> function is used, all
+ management targets are selected, as defined in RFC2273. The
+ <c>Receiver</c> parameter defines where the agent should send
+ information about the delivery of inform requests.
+ </p>
+ <p>If the <c>send_notification/5</c> function is used, an
+ <c>NotifyName</c> must be provided. This parameter is used as an
+ index in the <c>snmpNotifyTable</c>, and the management targets
+ defined by that single entry is used.
+ </p>
+ <p>The <c>send_notification/6</c> function is the most general
+ version of the function. A <c>ContextName</c> must be specified,
+ from which the notification will be sent. If this parameter is
+ not specified, the default context (<c>""</c>) is used.
+ </p>
+ <p>The function <c>send_trap</c> is kept for backwards
+ compatibility and should not be used in new code. Applications
+ that use this function will
+ continue to work. The <c>snmpNotifyName</c> is used as the
+ community string by the agent when a notification is sent.
+ </p>
+
+ <section>
+ <title>Notification Sending</title>
+ <p>The simplest way to send a notification is to call the function
+ <c>snmpa:send_notification(Agent, Notification, no_receiver)</c>.
+ In this case, the agent performs a get-operation to retrieve the
+ object values that are defined in the notification
+ specification (with the TRAP-TYPE or NOTIFICATION-TYPE macros).
+ The notification is sent to all managers defined in the target
+ and notify tables, either unacknowledged as traps, or
+ acknowledged as inform requests.
+ </p>
+ <p>If the caller of the function wants to know whether or not
+ acknowledgments are received for a certain notification
+ (provided it is sent as an inform), the <c>Receiver</c>
+ parameter can be specified as <c>{Tag, ProcessName}</c> (refer
+ to the Reference Manual, section snmp, module <c>snmp</c> for
+ more details). In this case, the agent send a message
+ <c>{snmp_notification, Tag, {got_response, ManagerAddr}}</c> or
+ <c>{snmp_notification, Tag, {no_response, ManagerAddr}}</c> for
+ each management target.
+ </p>
+ <p>Sometimes it is not possible to retrieve the values for some
+ of the objects in the notification specification with a
+ get-operation. However, they are known when the
+ <c>send_notification</c> function is called. This is the case if
+ an object is an element in a table. It is possible to give the
+ values of some objects to the <c>send_notification</c> function
+ <c>snmpa:send_notification(Agent, Notification, Receiver, Varbinds)</c>. In this function, <c>Varbinds</c> is a list of
+ <c>Varbind</c>, where each <c>Varbind</c> is one of:
+ </p>
+ <list type="bulleted">
+ <item><c>{Variable, Value}</c>, where <c>Variable</c> is the
+ symbolic name of a scalar variable referred to in the notification
+ specification.
+ </item>
+ <item><c>{Column, RowIndex, Value}</c>, where <c>Column</c> is
+ the symbolic name of a column variable. <c>RowIndex</c> is a
+ list of indices for the specified element. If this is the
+ case, the OBJECT IDENTIFIER sent in the trap is the
+ <c>RowIndex</c> appended to the OBJECT IDENTIFIER for the
+ table column. This is the OBJECT IDENTIFIER which specifies
+ the element.
+ </item>
+ <item><c>{OID, Value}</c>, where <c>OID</c> is the OBJECT
+ IDENTIFIER for an instance of an object, scalar variable or
+ column variable.
+ </item>
+ </list>
+ <p>For example, to specify that <c>sysLocation</c> should have the
+ value <c>"upstairs"</c> in the notification, we could use one of:
+ </p>
+ <list type="bulleted">
+ <item><c>{sysLocation, "upstairs"}</c> or</item>
+ <item><c>{[1,3,6,1,2,1,1,6,0], "upstairs"}</c></item>
+ </list>
+ <p>It is also possible to specify names and values for extra
+ variables that should be sent in the notification, but were not
+ defined in the notification specification.
+ </p>
+ <p>The notification is sent to all management targets found in
+ the tables. However, make sure that each manager has access to
+ the variables in the notification. If a variable is outside a
+ manager's MIB view, this manager will not receive the
+ notification.
+ </p>
+ <note>
+ <p>By definition, it is not possible to send objects with
+ ACCESS <c>not-accessible</c> in notifications. However,
+ historically this is often done and for this reason we allow
+ it in notification sending. If a variable has ACCESS
+ <c>not-accessible</c>, the user must provide a value for the
+ variable in the <c>Varbinds</c> list. It is not possible for
+ the agent to perform a get-operation to retrieve this value.
+ </p>
+ </note>
+ </section>
+
+ <section>
+ <title>Notification Filters</title>
+ <p>It is possible to add <em>notification filters</em> to an agent.
+ These filters will be called when a notification is to be
+ sent. Their purpose is to allow modification, suppression or
+ other type of actions.</p>
+ <p>A notification filter is a module implementing the
+ <seealso marker="snmpa_notification_filter">snmpa_notification_filter</seealso> behaviour. A filter is added/deleted using the functions:
+ <seealso marker="snmpa#register_notification_filter">snmpa:register_notification_filter</seealso> and
+ <seealso marker="snmpa#unregister_notification_filter">snmpa:unregister_notification_filter</seealso>.</p>
+ <p>Unless otherwise specified, the order of the registered filters
+ will be the order in which they are registered.</p>
+ </section>
+
+ <section>
+ <title>Sub-agent Path</title>
+ <p>If a value for an object is not given to the
+ <c>send_notification</c> function, the sub-agent will perform a
+ get-operation to retrieve it. If the object is not implemented
+ in this sub-agent, its parent agent tries to perform a
+ get-operation to retrieve it. If the object is not implemented
+ in this agent either, it forwards the object to its parent, and
+ so on. Eventually the Master Agent is reached and at this point
+ all unknown object values must be resolved. If some object is
+ unknown even to the Master Agent, this is regarded as an error
+ and is reported with a call to <c>user_err/2</c> of the
+ error report module. No notifications are sent in this case.
+ </p>
+ <p>For a given notification, the variables, which are referred to
+ in the notification specification, must be implemented by the
+ agent that has the MIB loaded, or by some parent to this
+ agent. If not, the application must provide values for the
+ unknown variables. The application must also provide values for
+ all elements in tables.
+ </p>
+ </section>
+ </section>
+
+ <section>
+ <title>Discovery</title>
+ <marker id="discovery"></marker>
+ <p>The <em>sender</em> is <em>authoritative</em> for messages containing
+ payload which does <em>not</em> expect a response (for example
+ SNMPv2-Trap, Response or Report PDU). </p>
+ <p>The <em>receiver</em> is <em>authoritative</em> for messages containing
+ payload which expects a response (for example
+ Get, GetNext, Get-Bulk, Set or Inform PDU). </p>
+ <p>The agent can both perform and respond to discovery.</p>
+ <p>The agent responds to discovery autonomously, without interaction
+ by the user. </p>
+ <p>Initiating discovery towards a manager is done by calling the
+ <seealso marker="snmpa#discovery">discovery</seealso> function.
+ The <c>EngineId</c> field of the target (manager) entry in the
+ <seealso marker="snmp_agent_config_files#target_addr">target_addr.conf</seealso> file has to have the value <c>discovery</c>.
+ Note that if the manager does not respond, the <c>Timeout</c> and
+ <c>RetryCount</c>
+ fields decide how long the function will hang before it returns. </p>
+ <p>Discovery can only be performed towards one manager at a time.</p>
+ </section>
+
+</chapter>
+
diff --git a/lib/snmp/doc/src/snmp_agent_netif.xml b/lib/snmp/doc/src/snmp_agent_netif.xml
new file mode 100644
index 0000000000..1f2dbe80db
--- /dev/null
+++ b/lib/snmp/doc/src/snmp_agent_netif.xml
@@ -0,0 +1,268 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE chapter SYSTEM "chapter.dtd">
+
+<chapter>
+ <header>
+ <copyright>
+ <year>1997</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ 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.
+
+ </legalnotice>
+
+ <title>Definition of Agent Net if</title>
+ <prepared></prepared>
+ <responsible></responsible>
+ <docno></docno>
+ <approved></approved>
+ <checked></checked>
+ <date></date>
+ <rev></rev>
+ <file>snmp_agent_netif.xml</file>
+ </header>
+ <p></p>
+ <image file="snmp_agent_netif_1.gif">
+ <icaption>The Purpose of Agent Net if</icaption>
+ </image>
+ <p>The Network Interface (Net if) process delivers SNMP PDUs to a
+ master agent, and receives SNMP PDUs from the master agent. The most
+ common behaviour of a Net if process is that is receives bytes from
+ a network, decodes them into an SNMP PDU, which it sends to a master
+ agent. When the master agent has processed the PDU, it sends a
+ response PDU to the Net if process, which encodes the PDU into bytes
+ and transmits the bytes onto the network.
+ </p>
+ <p>However, that simple behaviour can be modified in numerous
+ ways. For example, the Net if process can apply some kind of
+ encrypting/decrypting scheme on the bytes or
+ act as a proxy filter, which sends some packets to a proxy agent and
+ some packets to the master agent.
+ </p>
+ <p>It is also possible to write your own Net if process. The default
+ Net if process is implemented in the module <c>snmpa_net_if</c> and
+ it uses UDP as the transport protocol.
+ </p>
+ <p>This section describes how to write a Net if process.
+ </p>
+
+ <section>
+ <marker id="mandatory_functions"></marker>
+ <title>Mandatory Functions</title>
+ <p>A Net if process must implement the SNMP agent
+ <seealso marker="snmpa_network_interface">network interface behaviour</seealso>.
+ </p>
+ </section>
+
+ <section>
+ <title>Messages</title>
+ <p>The section <em>Messages</em> describes mandatory messages, which
+ Net if must send and be able to receive.
+ </p>
+
+ <section>
+ <title>Outgoing Messages</title>
+ <p>Net if must send the following message when it receives an
+ SNMP PDU from the network that is aimed for the MasterAgent:
+ </p>
+ <pre>
+MasterAgent ! {snmp_pdu, Vsn, Pdu, PduMS, ACMData, From, Extra}
+ </pre>
+ <list type="bulleted">
+ <item><c>Vsn</c> is either <c>'version-1'</c>,
+ <c>'version-2'</c>, or <c>'version-3'</c>.
+ </item>
+ <item><c>Pdu</c> is an SNMP PDU record, as defined in
+ <c>snmp_types.hrl</c>, with the SNMP request.
+ </item>
+ <item><c>PduMS</c> is the Maximum Size of the response Pdu
+ allowed. Normally this is returned from
+ <c>snmpa_mpd:process_packet</c> (see Reference Manual).
+ </item>
+ <item><c>ACMData</c> is data used by the Access Control Module
+ in use. Normally this is returned from
+ <c>snmpa_mpd:process_packet</c> (see Reference Manual).
+ </item>
+ <item><c>From</c> is the source address. If UDP over IP is
+ used, this should be a 2-tuple <c>{IP, UDPport}</c>, where
+ <c>IP</c> is a 4-tuple with the IP address, and <c>UDPport</c>
+ is an integer.
+ </item>
+ <item><c>Extra</c> is any term the Net if process wishes to
+ send to the agent. This term can be retrieved by the
+ instrumentation functions by calling
+ <c>snmp:current_net_if_data()</c>. This data is also sent back
+ to the Net if process when the agent generates a response to
+ the request.</item>
+ </list>
+ <p>The following message is used to report that a response to a
+ request has been received. The only request an agent can send
+ is an Inform-Request.
+ </p>
+ <pre>
+Pid ! {snmp_response_received, Vsn, Pdu, From}
+ </pre>
+ <list type="bulleted">
+ <item><c>Pid</c> is the Process that waits for the response
+ for the request. The Pid was specified in the
+ <c>send_pdu_req</c> message <seealso marker="#message">(see below)</seealso>.
+ </item>
+ <item><c>Vsn</c> is either <c>'version-1'</c>, <c>'version-2'</c>, or
+ <c>'version-3'</c>.
+ </item>
+ <item><c>Pdu</c> is the SNMP Pdu received
+ </item>
+ <item><c>From</c> is the source address. If UDP over IP is
+ used, this should be a 2-tuple <c>{IP, UDPport}</c>, where
+ <c>IP</c> is a 4-tuple with the IP address, and <c>UDPport</c>
+ is an integer.
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Incoming Messages</title>
+ <p>This section describes the incoming messages which a Net if
+ process must be able to receive.
+ </p>
+ <list type="bulleted">
+ <item>
+ <p><c>{snmp_response, Vsn, Pdu, Type, ACMData, To, Extra}</c></p>
+ <p>This message is sent to the Net if process from a master
+ agent as a response to a previously received request.
+ </p>
+ <list type="bulleted">
+ <item><c>Vsn</c> is either <c>'version-1'</c>,
+ <c>'version-2'</c>, or <c>'version-3'</c>.
+ </item>
+ <item><c>Pdu</c> is an SNMP PDU record (as defined in
+ snmp_types.hrl) with the SNMP response.
+ </item>
+ <item><c>Type</c> is the <c>#pdu.type</c> of the original
+ request.
+ </item>
+ <item><c>ACMData</c> is data used by the Access Control
+ Module in use. Normally this is just sent to
+ <c>snmpa_mpd:generate_response_message</c> (see Reference Manual).
+ </item>
+ <item><c>To</c> is the destination address. If UDP over IP
+ is used, this should be a 2-tuple <c>{IP, UDPport}</c>,
+ where <c>IP</c> is a 4-tuple with the IP address, and
+ <c>UDPport</c> is an integer.
+ </item>
+ <item><c>Extra</c> is the term that the Net if process
+ sent to the agent when the request was sent to the agent.
+ </item>
+ </list>
+ </item>
+ <item>
+ <p><c>{discarded_pdu, Vsn, ReqId, ACMData, Variable, Extra}</c></p>
+ <p>This message is sent from a master agent if it for some
+ reason decided to discard the pdu.
+ </p>
+ <list type="bulleted">
+ <item><c>Vsn</c> is either <c>'version-1'</c>,
+ <c>'version-2'</c>, or <c>'version-3'</c>.
+ </item>
+ <item><c>ReqId</c> is the request id of the original
+ request.
+ </item>
+ <item><c>ACMData</c> is data used by the Access Control
+ Module in use. Normally this is just sent to
+ <c>snmpa_mpd:generate_response_message</c> (see Reference Manual).
+ </item>
+ <item><c>Variable</c> is the name of an snmp counter that
+ represents the error, e.g. <c>snmpInBadCommunityUses</c>.
+ </item>
+ <item><c>Extra</c> is the term that the Net if process
+ sent to the agent when the request was sent to the agent.
+ </item>
+ </list>
+ </item>
+ <item>
+ <p><c>{send_pdu, Vsn, Pdu, MsgData, To}</c></p>
+ <p>This message is sent from a master agent when a trap is
+ to be sent.
+ </p>
+ <list type="bulleted">
+ <item><c>Vsn</c> is either <c>'version-1'</c>,
+ <c>'version-2'</c>, or <c>'version-3'</c>.
+ </item>
+ <item><c>Pdu</c> is an SNMP PDU record (as defined in
+ snmp_types.hrl) with the SNMP response.
+ </item>
+ <item><c>MsgData</c> is the message specific data used in
+ the SNMP message. This value is normally sent to
+ <c>snmpa_mpd:generate_message/4</c>. In SNMPv1 and
+ SNMPv2c, this message data is the community string. In
+ SNMPv3, it is the context information.
+ </item>
+ <item><c>To</c> is a list of the destination addresses and
+ their corresponding security parameters. This value is
+ normally sent to <c>snmpa_mpd:generate_message/4</c>.
+ </item>
+ </list>
+ </item>
+ <item>
+ <p><c>{send_pdu_req, Vsn, Pdu, MsgData, To, Pid}</c></p>
+ <p>This <marker id="message"></marker>
+ message is sent from a master
+ agent when a request is
+ to be sent. The only request an agent can send is
+ Inform-Request. The net if process needs to remember the
+ request id and the Pid, and when a response is received for
+ the request id, send it to Pid, using a
+ <c>snmp_response_received</c> message.
+ </p>
+ <list type="bulleted">
+ <item><c>Vsn</c> is either <c>'version-1'</c>,
+ <c>'version-2'</c>, or <c>'version-3'</c>.
+ </item>
+ <item><c>Pdu</c> is an SNMP PDU record (as defined in
+ snmp_types.hrl) with the SNMP response.
+ </item>
+ <item><c>MsgData</c> is the message specific data used in
+ the SNMP message. This value is normally sent to
+ <c>snmpa_mpd:generate_message/4</c>. In SNMPv1 and
+ SNMPv2c, this message data is the community string. In
+ SNMPv3, it is the context information.
+ </item>
+ <item><c>To</c> is a list of the destination addresses and
+ their corresponding security parameters. This value is
+ normally sent to <c>snmpa_mpd:generate_message/4</c>.
+ </item>
+ <item><c>Pid</c> is a process identifier.
+ </item>
+ </list>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Notes</title>
+ <p>Since the Net if process is responsible for encoding and
+ decoding of SNMP messages, it must also update the relevant
+ counters in the SNMP group in MIB-II. It can use the functions
+ in the module <c>snmpa_mpd</c> for this purpose (refer to the
+ Reference Manual, section <c>snmp</c>,
+ module <seealso marker="snmp_pdus">snmpa_mpd</seealso>
+ for more details.)
+ </p>
+ <p>There are also some useful functions for encoding and
+ decoding of SNMP messages in the module
+ <seealso marker="snmp_pdus">snmp_pdus</seealso>.
+ </p>
+ </section>
+ </section>
+</chapter>
+
diff --git a/lib/snmp/doc/src/snmp_agent_netif_1.gif b/lib/snmp/doc/src/snmp_agent_netif_1.gif
new file mode 100644
index 0000000000..8687ae56fb
--- /dev/null
+++ b/lib/snmp/doc/src/snmp_agent_netif_1.gif
Binary files differ
diff --git a/lib/snmp/doc/src/snmp_agent_netif_1.ps b/lib/snmp/doc/src/snmp_agent_netif_1.ps
new file mode 100644
index 0000000000..40a6376591
--- /dev/null
+++ b/lib/snmp/doc/src/snmp_agent_netif_1.ps
@@ -0,0 +1,2909 @@
+%!PS-Adobe-3.0 EPSF-3.0
+%%Creator: Adobe Illustrator(r) 6.0
+%%For: (Anna Fedoriw) (Ericsson Telecom)
+%%Title: (PurposeofNetif.eps)
+%%CreationDate: (97-05-23) (14.06)
+%%BoundingBox: 89 539 446 708
+%%HiResBoundingBox: 89.6046 539.5735 445.5998 707.3677
+%%DocumentProcessColors: Black
+%%DocumentFonts: Univers
+%%DocumentSuppliedResources: procset Adobe_level2_AI5 1.0 0
+%%+ procset Adobe_typography_AI5 1.0 0
+%%+ procset Adobe_Illustrator_AI6_vars Adobe_Illustrator_AI6
+%%+ procset Adobe_Illustrator_AI5 1.0 0
+%AI5_FileFormat 2.0
+%AI3_ColorUsage: Black&White
+%%AI6_ColorSeparationSet: 1 1 (AI6 Default Color Separation Set)
+%%+ Options: 1 16 0 1 0 1 1 1 0 1 1 1 1 18 0 0 0 0 0 0 0 0 -1 -1
+%%+ PPD: 1 21 0 0 60 45 2 2 1 0 0 1 0 0 0 0 0 0 0 0 0 0 ()
+%AI3_TemplateBox: 306 396 306 396
+%AI3_TileBox: 21 -12 588 802
+%AI3_DocumentPreview: Macintosh_ColorPic
+%AI5_ArtSize: 595.2756 841.8898
+%AI5_RulerUnits: 1
+%AI5_ArtFlags: 0 0 0 1 0 0 1 1 0
+%AI5_TargetResolution: 800
+%AI5_NumLayers: 1
+%AI5_OpenToView: 2 796 1.5 1146 827 58 1 1 3 40
+%AI5_OpenViewLayers: 7
+%%EndComments
+%%BeginProlog
+%%BeginResource: procset Adobe_level2_AI5 1.2 0
+%%Title: (Adobe Illustrator (R) Version 5.0 Level 2 Emulation)
+%%Version: 1.2
+%%CreationDate: (04/10/93) ()
+%%Copyright: ((C) 1987-1993 Adobe Systems Incorporated All Rights Reserved)
+userdict /Adobe_level2_AI5 23 dict dup begin
+ put
+ /packedarray where not
+ {
+ userdict begin
+ /packedarray
+ {
+ array astore readonly
+ } bind def
+ /setpacking /pop load def
+ /currentpacking false def
+ end
+ 0
+ } if
+ pop
+ userdict /defaultpacking currentpacking put true setpacking
+ /initialize
+ {
+ Adobe_level2_AI5 begin
+ } bind def
+ /terminate
+ {
+ currentdict Adobe_level2_AI5 eq
+ {
+ end
+ } if
+ } bind def
+ mark
+ /setcustomcolor where not
+ {
+ /findcmykcustomcolor
+ {
+ 5 packedarray
+ } bind def
+ /setcustomcolor
+ {
+ exch aload pop pop
+ 4
+ {
+ 4 index mul 4 1 roll
+ } repeat
+ 5 -1 roll pop
+ setcmykcolor
+ }
+ def
+ } if
+
+ /gt38? mark {version cvr cvx exec} stopped {cleartomark true} {38 gt exch pop} ifelse def
+ userdict /deviceDPI 72 0 matrix defaultmatrix dtransform dup mul exch dup mul add sqrt put
+ userdict /level2?
+ systemdict /languagelevel known dup
+ {
+ pop systemdict /languagelevel get 2 ge
+ } if
+ put
+/level2ScreenFreq
+{
+ begin
+ 60
+ HalftoneType 1 eq
+ {
+ pop Frequency
+ } if
+ HalftoneType 2 eq
+ {
+ pop GrayFrequency
+ } if
+ HalftoneType 5 eq
+ {
+ pop Default level2ScreenFreq
+ } if
+ end
+} bind def
+userdict /currentScreenFreq
+ level2? {currenthalftone level2ScreenFreq} {currentscreen pop pop} ifelse put
+level2? not
+ {
+ /setcmykcolor where not
+ {
+ /setcmykcolor
+ {
+ exch .11 mul add exch .59 mul add exch .3 mul add
+ 1 exch sub setgray
+ } def
+ } if
+ /currentcmykcolor where not
+ {
+ /currentcmykcolor
+ {
+ 0 0 0 1 currentgray sub
+ } def
+ } if
+ /setoverprint where not
+ {
+ /setoverprint /pop load def
+ } if
+ /selectfont where not
+ {
+ /selectfont
+ {
+ exch findfont exch
+ dup type /arraytype eq
+ {
+ makefont
+ }
+ {
+ scalefont
+ } ifelse
+ setfont
+ } bind def
+ } if
+ /cshow where not
+ {
+ /cshow
+ {
+ [
+ 0 0 5 -1 roll aload pop
+ ] cvx bind forall
+ } bind def
+ } if
+ } if
+ cleartomark
+ /anyColor?
+ {
+ add add add 0 ne
+ } bind def
+ /testColor
+ {
+ gsave
+ setcmykcolor currentcmykcolor
+ grestore
+ } bind def
+ /testCMYKColorThrough
+ {
+ testColor anyColor?
+ } bind def
+ userdict /composite?
+ level2?
+ {
+ gsave 1 1 1 1 setcmykcolor currentcmykcolor grestore
+ add add add 4 eq
+ }
+ {
+ 1 0 0 0 testCMYKColorThrough
+ 0 1 0 0 testCMYKColorThrough
+ 0 0 1 0 testCMYKColorThrough
+ 0 0 0 1 testCMYKColorThrough
+ and and and
+ } ifelse
+ put
+ composite? not
+ {
+ userdict begin
+ gsave
+ /cyan? 1 0 0 0 testCMYKColorThrough def
+ /magenta? 0 1 0 0 testCMYKColorThrough def
+ /yellow? 0 0 1 0 testCMYKColorThrough def
+ /black? 0 0 0 1 testCMYKColorThrough def
+ grestore
+ /isCMYKSep? cyan? magenta? yellow? black? or or or def
+ /customColor? isCMYKSep? not def
+ end
+ } if
+ end defaultpacking setpacking
+%%EndResource
+%%BeginResource: procset Adobe_typography_AI5 1.0 1
+%%Title: (Typography Operators)
+%%Version: 1.0
+%%CreationDate:(03/26/93) ()
+%%Copyright: ((C) 1987-1993 Adobe Systems Incorporated All Rights Reserved)
+currentpacking true setpacking
+userdict /Adobe_typography_AI5 54 dict dup begin
+put
+/initialize
+{
+ begin
+ begin
+ Adobe_typography_AI5 begin
+ Adobe_typography_AI5
+ {
+ dup xcheck
+ {
+ bind
+ } if
+ pop pop
+ } forall
+ end
+ end
+ end
+ Adobe_typography_AI5 begin
+} def
+/terminate
+{
+ currentdict Adobe_typography_AI5 eq
+ {
+ end
+ } if
+} def
+/modifyEncoding
+{
+ /_tempEncode exch ddef
+ /_pntr 0 ddef
+ {
+ counttomark -1 roll
+ dup type dup /marktype eq
+ {
+ pop pop exit
+ }
+ {
+ /nametype eq
+ {
+ _tempEncode /_pntr dup load dup 3 1 roll 1 add ddef 3 -1 roll
+ put
+ }
+ {
+ /_pntr exch ddef
+ } ifelse
+ } ifelse
+ } loop
+ _tempEncode
+} def
+/TE
+{
+ StandardEncoding 256 array copy modifyEncoding
+ /_nativeEncoding exch def
+} def
+%
+/TZ
+{
+ dup type /arraytype eq
+ {
+ /_wv exch def
+ }
+ {
+ /_wv 0 def
+ } ifelse
+ /_useNativeEncoding exch def
+ pop pop
+ findfont _wv type /arraytype eq
+ {
+ _wv makeblendedfont
+ } if
+ dup length 2 add dict
+ begin
+ mark exch
+ {
+ 1 index /FID ne
+ {
+ def
+ } if
+ cleartomark mark
+ } forall
+ pop
+ /FontName exch def
+ counttomark 0 eq
+ {
+ 1 _useNativeEncoding eq
+ {
+ /Encoding _nativeEncoding def
+ } if
+ cleartomark
+ }
+ {
+ /Encoding load 256 array copy
+ modifyEncoding /Encoding exch def
+ } ifelse
+ FontName currentdict
+ end
+ definefont pop
+} def
+/tr
+{
+ _ax _ay 3 2 roll
+} def
+/trj
+{
+ _cx _cy _sp _ax _ay 6 5 roll
+} def
+/a0
+{
+ /Tx
+ {
+ dup
+ currentpoint 3 2 roll
+ tr _psf
+ newpath moveto
+ tr _ctm _pss
+ } ddef
+ /Tj
+ {
+ dup
+ currentpoint 3 2 roll
+ trj _pjsf
+ newpath moveto
+ trj _ctm _pjss
+ } ddef
+} def
+/a1
+{
+ /Tx
+ {
+ dup currentpoint 4 2 roll gsave
+ dup currentpoint 3 2 roll
+ tr _psf
+ newpath moveto
+ tr _ctm _pss
+ grestore 3 1 roll moveto tr sp
+ } ddef
+ /Tj
+ {
+ dup currentpoint 4 2 roll gsave
+ dup currentpoint 3 2 roll
+ trj _pjsf
+ newpath moveto
+ trj _ctm _pjss
+ grestore 3 1 roll moveto tr jsp
+ } ddef
+} def
+/e0
+{
+ /Tx
+ {
+ tr _psf
+ } ddef
+ /Tj
+ {
+ trj _pjsf
+ } ddef
+} def
+/e1
+{
+ /Tx
+ {
+ dup currentpoint 4 2 roll gsave
+ tr _psf
+ grestore 3 1 roll moveto tr sp
+ } ddef
+ /Tj
+ {
+ dup currentpoint 4 2 roll gsave
+ trj _pjsf
+ grestore 3 1 roll moveto tr jsp
+ } ddef
+} def
+/i0
+{
+ /Tx
+ {
+ tr sp
+ } ddef
+ /Tj
+ {
+ trj jsp
+ } ddef
+} def
+/i1
+{
+ W N
+} def
+/o0
+{
+ /Tx
+ {
+ tr sw rmoveto
+ } ddef
+ /Tj
+ {
+ trj swj rmoveto
+ } ddef
+} def
+/r0
+{
+ /Tx
+ {
+ tr _ctm _pss
+ } ddef
+ /Tj
+ {
+ trj _ctm _pjss
+ } ddef
+} def
+/r1
+{
+ /Tx
+ {
+ dup currentpoint 4 2 roll currentpoint gsave newpath moveto
+ tr _ctm _pss
+ grestore 3 1 roll moveto tr sp
+ } ddef
+ /Tj
+ {
+ dup currentpoint 4 2 roll currentpoint gsave newpath moveto
+ trj _ctm _pjss
+ grestore 3 1 roll moveto tr jsp
+ } ddef
+} def
+/To
+{
+ pop _ctm currentmatrix pop
+} def
+/TO
+{
+ iTe _ctm setmatrix newpath
+} def
+/Tp
+{
+ pop _tm astore pop _ctm setmatrix
+ _tDict begin
+ /W
+ {
+ } def
+ /h
+ {
+ } def
+} def
+/TP
+{
+ end
+ iTm 0 0 moveto
+} def
+/Tr
+{
+ _render 3 le
+ {
+ currentpoint newpath moveto
+ } if
+ dup 8 eq
+ {
+ pop 0
+ }
+ {
+ dup 9 eq
+ {
+ pop 1
+ } if
+ } ifelse
+ dup /_render exch ddef
+ _renderStart exch get load exec
+} def
+/iTm
+{
+ _ctm setmatrix _tm concat 0 _rise translate _hs 1 scale
+} def
+/Tm
+{
+ _tm astore pop iTm 0 0 moveto
+} def
+/Td
+{
+ _mtx translate _tm _tm concatmatrix pop iTm 0 0 moveto
+} def
+/iTe
+{
+ _render -1 eq
+ {
+ }
+ {
+ _renderEnd _render get dup null ne
+ {
+ load exec
+ }
+ {
+ pop
+ } ifelse
+ } ifelse
+ /_render -1 ddef
+} def
+/Ta
+{
+ pop
+} def
+/Tf
+{
+ dup 1000 div /_fScl exch ddef
+%
+ selectfont
+} def
+/Tl
+{
+ pop
+ 0 exch _leading astore pop
+} def
+/Tt
+{
+ pop
+} def
+/TW
+{
+ 3 npop
+} def
+/Tw
+{
+ /_cx exch ddef
+} def
+/TC
+{
+ 3 npop
+} def
+/Tc
+{
+ /_ax exch ddef
+} def
+/Ts
+{
+ /_rise exch ddef
+ currentpoint
+ iTm
+ moveto
+} def
+/Ti
+{
+ 3 npop
+} def
+/Tz
+{
+ 100 div /_hs exch ddef
+ iTm
+} def
+/TA
+{
+ pop
+} def
+/Tq
+{
+ pop
+} def
+/Th
+{
+ pop pop pop pop pop
+} def
+/TX
+{
+ pop
+} def
+/Tk
+{
+ exch pop _fScl mul neg 0 rmoveto
+} def
+/TK
+{
+ 2 npop
+} def
+/T*
+{
+ _leading aload pop neg Td
+} def
+/T*-
+{
+ _leading aload pop Td
+} def
+/T-
+{
+ _ax neg 0 rmoveto
+ _hyphen Tx
+} def
+/T+
+{
+} def
+/TR
+{
+ _ctm currentmatrix pop
+ _tm astore pop
+ iTm 0 0 moveto
+} def
+/TS
+{
+ currentfont 3 1 roll
+ /_Symbol_ _fScl 1000 mul selectfont
+
+ 0 eq
+ {
+ Tx
+ }
+ {
+ Tj
+ } ifelse
+ setfont
+} def
+/Xb
+{
+ pop pop
+} def
+/Tb /Xb load def
+/Xe
+{
+ pop pop pop pop
+} def
+/Te /Xe load def
+/XB
+{
+} def
+/TB /XB load def
+currentdict readonly pop
+end
+setpacking
+%%EndResource
+%%BeginProcSet: Adobe_ColorImage_AI6 1.0 0
+userdict /Adobe_ColorImage_AI6 known not
+{
+ userdict /Adobe_ColorImage_AI6 17 dict put
+} if
+userdict /Adobe_ColorImage_AI6 get begin
+
+ /initialize
+ {
+ Adobe_ColorImage_AI6 begin
+ Adobe_ColorImage_AI6
+ {
+ dup type /arraytype eq
+ {
+ dup xcheck
+ {
+ bind
+ } if
+ } if
+ pop pop
+ } forall
+ } def
+ /terminate { end } def
+
+ currentdict /Adobe_ColorImage_AI6_Vars known not
+ {
+ /Adobe_ColorImage_AI6_Vars 14 dict def
+ } if
+
+ Adobe_ColorImage_AI6_Vars begin
+ /channelcount 0 def
+ /sourcecount 0 def
+ /sourcearray 4 array def
+ /plateindex -1 def
+ /XIMask 0 def
+ /XIBinary 0 def
+ /XIChannelCount 0 def
+ /XIBitsPerPixel 0 def
+ /XIImageHeight 0 def
+ /XIImageWidth 0 def
+ /XIImageMatrix null def
+ /XIBuffer null def
+ /XIDataProc null def
+ end
+
+ /WalkRGBString null def
+ /WalkCMYKString null def
+
+ /StuffRGBIntoGrayString null def
+ /RGBToGrayImageProc null def
+ /StuffCMYKIntoGrayString null def
+ /CMYKToGrayImageProc null def
+ /ColorImageCompositeEmulator null def
+
+ /SeparateCMYKImageProc null def
+
+ /FourEqual null def
+ /TestPlateIndex null def
+
+ currentdict /_colorimage known not
+ {
+ /colorimage where
+ {
+ /colorimage get /_colorimage exch def
+ }
+ {
+ /_colorimage null def
+ } ifelse
+ } if
+
+ /_currenttransfer systemdict /currenttransfer get def
+
+ /colorimage null def
+ /XI null def
+
+
+ /WalkRGBString
+ {
+ 0 3 index
+
+ dup length 1 sub 0 3 3 -1 roll
+ {
+ 3 getinterval { } forall
+
+ 5 index exec
+
+ 3 index
+ } for
+
+ 5 { pop } repeat
+
+ } def
+
+
+ /WalkCMYKString
+ {
+ 0 3 index
+
+ dup length 1 sub 0 4 3 -1 roll
+ {
+ 4 getinterval { } forall
+
+ 6 index exec
+
+ 3 index
+
+ } for
+
+ 5 { pop } repeat
+
+ } def
+
+
+ /StuffRGBIntoGrayString
+ {
+ .11 mul exch
+
+ .59 mul add exch
+
+ .3 mul add
+
+ cvi 3 copy put
+
+ pop 1 add
+ } def
+
+
+ /RGBToGrayImageProc
+ {
+ Adobe_ColorImage_AI6_Vars begin
+ sourcearray 0 get exec
+ dup length 3 idiv string
+ dup 3 1 roll
+
+ /StuffRGBIntoGrayString load exch
+ WalkRGBString
+ end
+ } def
+
+
+ /StuffCMYKIntoGrayString
+ {
+ exch .11 mul add
+
+ exch .59 mul add
+
+ exch .3 mul add
+
+ dup 255 gt { pop 255 } if
+
+ 255 exch sub cvi 3 copy put
+
+ pop 1 add
+ } def
+
+
+ /CMYKToGrayImageProc
+ {
+ Adobe_ColorImage_AI6_Vars begin
+ sourcearray 0 get exec
+ dup length 4 idiv string
+ dup 3 1 roll
+
+ /StuffCMYKIntoGrayString load exch
+ WalkCMYKString
+ end
+ } def
+
+
+ /ColorImageCompositeEmulator
+ {
+ pop true eq
+ {
+ Adobe_ColorImage_AI6_Vars /sourcecount get 5 add { pop } repeat
+ }
+ {
+ Adobe_ColorImage_AI6_Vars /channelcount get 1 ne
+ {
+ Adobe_ColorImage_AI6_Vars begin
+ sourcearray 0 3 -1 roll put
+
+ channelcount 3 eq
+ {
+ /RGBToGrayImageProc
+ }
+ {
+ /CMYKToGrayImageProc
+ } ifelse
+ load
+ end
+ } if
+ image
+ } ifelse
+ } def
+
+
+ /SeparateCMYKImageProc
+ {
+ Adobe_ColorImage_AI6_Vars begin
+
+ sourcecount 0 ne
+ {
+ sourcearray plateindex get exec
+ }
+ {
+ sourcearray 0 get exec
+
+ dup length 4 idiv string
+
+ 0 2 index
+
+ plateindex 4 2 index length 1 sub
+ {
+ get 255 exch sub
+
+ 3 copy put pop 1 add
+
+ 2 index
+ } for
+
+ pop pop exch pop
+ } ifelse
+ end
+ } def
+
+
+ /FourEqual
+ {
+ 4 index ne
+ {
+ pop pop pop false
+ }
+ {
+ 4 index ne
+ {
+ pop pop false
+ }
+ {
+ 4 index ne
+ {
+ pop false
+ }
+ {
+ 4 index eq
+ } ifelse
+ } ifelse
+ } ifelse
+ } def
+
+
+ /TestPlateIndex
+ {
+ Adobe_ColorImage_AI6_Vars begin
+ /plateindex -1 def
+
+ /setcmykcolor where
+ {
+ pop
+ gsave
+ 1 0 0 0 setcmykcolor systemdict /currentgray get exec 1 exch sub
+ 0 1 0 0 setcmykcolor systemdict /currentgray get exec 1 exch sub
+ 0 0 1 0 setcmykcolor systemdict /currentgray get exec 1 exch sub
+ 0 0 0 1 setcmykcolor systemdict /currentgray get exec 1 exch sub
+ grestore
+
+ 1 0 0 0 FourEqual
+ {
+ /plateindex 0 def
+ }
+ {
+ 0 1 0 0 FourEqual
+ {
+ /plateindex 1 def
+ }
+ {
+ 0 0 1 0 FourEqual
+ {
+ /plateindex 2 def
+ }
+ {
+ 0 0 0 1 FourEqual
+ {
+ /plateindex 3 def
+ }
+ {
+ 0 0 0 0 FourEqual
+ {
+ /plateindex 5 def
+ } if
+ } ifelse
+ } ifelse
+ } ifelse
+ } ifelse
+ pop pop pop pop
+ } if
+ plateindex
+ end
+ } def
+
+
+ /colorimage
+ {
+ Adobe_ColorImage_AI6_Vars begin
+ /channelcount 1 index def
+ /sourcecount 2 index 1 eq { channelcount 1 sub } { 0 } ifelse def
+
+ 4 sourcecount add index dup
+ 8 eq exch 1 eq or not
+ end
+
+ {
+ /_colorimage load null ne
+ {
+ _colorimage
+ }
+ {
+ Adobe_ColorImage_AI6_Vars /sourcecount get
+ 7 add { pop } repeat
+ } ifelse
+ }
+ {
+ dup 3 eq
+ TestPlateIndex
+ dup -1 eq exch 5 eq or or
+ {
+ /_colorimage load null eq
+ {
+ ColorImageCompositeEmulator
+ }
+ {
+ dup 1 eq
+ {
+ pop pop image
+ }
+ {
+ Adobe_ColorImage_AI6_Vars /plateindex get 5 eq
+ {
+ gsave
+
+ 0 _currenttransfer exec
+ 1 _currenttransfer exec
+ eq
+ { 0 _currenttransfer exec 0.5 lt }
+ { 0 _currenttransfer exec 1 _currenttransfer exec gt } ifelse
+
+ { { pop 0 } } { { pop 1 } } ifelse
+ systemdict /settransfer get exec
+ } if
+
+ _colorimage
+
+ Adobe_ColorImage_AI6_Vars /plateindex get 5 eq
+ {
+ grestore
+ } if
+ } ifelse
+ } ifelse
+ }
+ {
+ dup 1 eq
+ {
+ pop pop
+ image
+ }
+ {
+ pop pop
+
+ Adobe_ColorImage_AI6_Vars begin
+ sourcecount -1 0
+ {
+ exch sourcearray 3 1 roll put
+ } for
+
+ /SeparateCMYKImageProc load
+ end
+
+ systemdict /image get exec
+ } ifelse
+ } ifelse
+ } ifelse
+ } def
+
+ /XI
+ {
+ Adobe_ColorImage_AI6_Vars begin
+ gsave
+ /XIMask exch 0 ne def
+ /XIBinary exch 0 ne def
+ pop
+ pop
+ /XIChannelCount exch def
+ /XIBitsPerPixel exch def
+ /XIImageHeight exch def
+ /XIImageWidth exch def
+ pop pop pop pop
+ /XIImageMatrix exch def
+
+ XIBitsPerPixel 1 eq
+ {
+ XIImageWidth 8 div ceiling cvi
+ }
+ {
+ XIImageWidth XIChannelCount mul
+ } ifelse
+ /XIBuffer exch string def
+
+ XIBinary
+ {
+ /XIDataProc { currentfile XIBuffer readstring pop } def
+ currentfile 128 string readline pop pop
+ }
+ {
+ /XIDataProc { currentfile XIBuffer readhexstring pop } def
+ } ifelse
+
+ 0 0 moveto
+ XIImageMatrix concat
+ XIImageWidth XIImageHeight scale
+
+ XIMask
+ {
+ XIImageWidth XIImageHeight
+ false
+ [ XIImageWidth 0 0 XIImageHeight neg 0 0 ]
+ /XIDataProc load
+
+ /_lp /null ddef
+ _fc
+ /_lp /imagemask ddef
+
+ imagemask
+ }
+ {
+ XIImageWidth XIImageHeight
+ XIBitsPerPixel
+ [ XIImageWidth 0 0 XIImageHeight neg 0 0 ]
+ /XIDataProc load
+
+ XIChannelCount 1 eq
+ {
+
+ gsave
+ 0 setgray
+
+ image
+
+ grestore
+ }
+ {
+ false
+ XIChannelCount
+ colorimage
+ } ifelse
+ } ifelse
+ grestore
+ end
+ } def
+
+end
+%%EndProcSet
+%%BeginResource: procset Adobe_Illustrator_AI5 1.1 0
+%%Title: (Adobe Illustrator (R) Version 5.0 Full Prolog)
+%%Version: 1.1
+%%CreationDate: (3/7/1994) ()
+%%Copyright: ((C) 1987-1994 Adobe Systems Incorporated All Rights Reserved)
+currentpacking true setpacking
+userdict /Adobe_Illustrator_AI5_vars 81 dict dup begin
+put
+/_eo false def
+/_lp /none def
+/_pf
+{
+} def
+/_ps
+{
+} def
+/_psf
+{
+} def
+/_pss
+{
+} def
+/_pjsf
+{
+} def
+/_pjss
+{
+} def
+/_pola 0 def
+/_doClip 0 def
+/cf currentflat def
+/_tm matrix def
+/_renderStart
+[
+/e0 /r0 /a0 /o0 /e1 /r1 /a1 /i0
+] def
+/_renderEnd
+[
+null null null null /i1 /i1 /i1 /i1
+] def
+/_render -1 def
+/_rise 0 def
+/_ax 0 def
+/_ay 0 def
+/_cx 0 def
+/_cy 0 def
+/_leading
+[
+0 0
+] def
+/_ctm matrix def
+/_mtx matrix def
+/_sp 16#020 def
+/_hyphen (-) def
+/_fScl 0 def
+/_cnt 0 def
+/_hs 1 def
+/_nativeEncoding 0 def
+/_useNativeEncoding 0 def
+/_tempEncode 0 def
+/_pntr 0 def
+/_tDict 2 dict def
+/_wv 0 def
+/Tx
+{
+} def
+/Tj
+{
+} def
+/CRender
+{
+} def
+/_AI3_savepage
+{
+} def
+/_gf null def
+/_cf 4 array def
+/_if null def
+/_of false def
+/_fc
+{
+} def
+/_gs null def
+/_cs 4 array def
+/_is null def
+/_os false def
+/_sc
+{
+} def
+/_pd 1 dict def
+/_ed 15 dict def
+/_pm matrix def
+/_fm null def
+/_fd null def
+/_fdd null def
+/_sm null def
+/_sd null def
+/_sdd null def
+/_i null def
+/discardSave null def
+/buffer 256 string def
+/beginString null def
+/endString null def
+/endStringLength null def
+/layerCnt 1 def
+/layerCount 1 def
+/perCent (%) 0 get def
+/perCentSeen? false def
+/newBuff null def
+/newBuffButFirst null def
+/newBuffLast null def
+/clipForward? false def
+end
+userdict /Adobe_Illustrator_AI5 known not {
+ userdict /Adobe_Illustrator_AI5 91 dict put
+} if
+userdict /Adobe_Illustrator_AI5 get begin
+/initialize
+{
+ Adobe_Illustrator_AI5 dup begin
+ Adobe_Illustrator_AI5_vars begin
+ discardDict
+ {
+ bind pop pop
+ } forall
+ dup /nc get begin
+ {
+ dup xcheck 1 index type /operatortype ne and
+ {
+ bind
+ } if
+ pop pop
+ } forall
+ end
+ newpath
+} def
+/terminate
+{
+ end
+ end
+} def
+/_
+null def
+/ddef
+{
+ Adobe_Illustrator_AI5_vars 3 1 roll put
+} def
+/xput
+{
+ dup load dup length exch maxlength eq
+ {
+ dup dup load dup
+ length 2 mul dict copy def
+ } if
+ load begin
+ def
+ end
+} def
+/npop
+{
+ {
+ pop
+ } repeat
+} def
+/sw
+{
+ dup length exch stringwidth
+ exch 5 -1 roll 3 index mul add
+ 4 1 roll 3 1 roll mul add
+} def
+/swj
+{
+ dup 4 1 roll
+ dup length exch stringwidth
+ exch 5 -1 roll 3 index mul add
+ 4 1 roll 3 1 roll mul add
+ 6 2 roll /_cnt 0 ddef
+ {
+ 1 index eq
+ {
+ /_cnt _cnt 1 add ddef
+ } if
+ } forall
+ pop
+ exch _cnt mul exch _cnt mul 2 index add 4 1 roll 2 index add 4 1 roll pop pop
+} def
+/ss
+{
+ 4 1 roll
+ {
+ 2 npop
+ (0) exch 2 copy 0 exch put pop
+ gsave
+ false charpath currentpoint
+ 4 index setmatrix
+ stroke
+ grestore
+ moveto
+ 2 copy rmoveto
+ } exch cshow
+ 3 npop
+} def
+/jss
+{
+ 4 1 roll
+ {
+ 2 npop
+ (0) exch 2 copy 0 exch put
+ gsave
+ _sp eq
+ {
+ exch 6 index 6 index 6 index 5 -1 roll widthshow
+ currentpoint
+ }
+ {
+ false charpath currentpoint
+ 4 index setmatrix stroke
+ } ifelse
+ grestore
+ moveto
+ 2 copy rmoveto
+ } exch cshow
+ 6 npop
+} def
+/sp
+{
+ {
+ 2 npop (0) exch
+ 2 copy 0 exch put pop
+ false charpath
+ 2 copy rmoveto
+ } exch cshow
+ 2 npop
+} def
+/jsp
+{
+ {
+ 2 npop
+ (0) exch 2 copy 0 exch put
+ _sp eq
+ {
+ exch 5 index 5 index 5 index 5 -1 roll widthshow
+ }
+ {
+ false charpath
+ } ifelse
+ 2 copy rmoveto
+ } exch cshow
+ 5 npop
+} def
+/pl
+{
+ transform
+ 0.25 sub round 0.25 add exch
+ 0.25 sub round 0.25 add exch
+ itransform
+} def
+/setstrokeadjust where
+{
+ pop true setstrokeadjust
+ /c
+ {
+ curveto
+ } def
+ /C
+ /c load def
+ /v
+ {
+ currentpoint 6 2 roll curveto
+ } def
+ /V
+ /v load def
+ /y
+ {
+ 2 copy curveto
+ } def
+ /Y
+ /y load def
+ /l
+ {
+ lineto
+ } def
+ /L
+ /l load def
+ /m
+ {
+ moveto
+ } def
+}
+{
+ /c
+ {
+ pl curveto
+ } def
+ /C
+ /c load def
+ /v
+ {
+ currentpoint 6 2 roll pl curveto
+ } def
+ /V
+ /v load def
+ /y
+ {
+ pl 2 copy curveto
+ } def
+ /Y
+ /y load def
+ /l
+ {
+ pl lineto
+ } def
+ /L
+ /l load def
+ /m
+ {
+ pl moveto
+ } def
+} ifelse
+/d
+{
+ setdash
+} def
+/cf
+{
+} def
+/i
+{
+ dup 0 eq
+ {
+ pop cf
+ } if
+ setflat
+} def
+/j
+{
+ setlinejoin
+} def
+/J
+{
+ setlinecap
+} def
+/M
+{
+ setmiterlimit
+} def
+/w
+{
+ setlinewidth
+} def
+/XR
+{
+ 0 ne
+ /_eo exch ddef
+} def
+/H
+{
+} def
+/h
+{
+ closepath
+} def
+/N
+{
+ _pola 0 eq
+ {
+ _doClip 1 eq
+ {
+ _eo {eoclip} {clip} ifelse /_doClip 0 ddef
+ } if
+ newpath
+ }
+ {
+ /CRender
+ {
+ N
+ } ddef
+ } ifelse
+} def
+/n
+{
+ N
+} def
+/F
+{
+ _pola 0 eq
+ {
+ _doClip 1 eq
+ {
+ gsave _pf grestore _eo {eoclip} {clip} ifelse newpath /_lp /none ddef _fc
+ /_doClip 0 ddef
+ }
+ {
+ _pf
+ } ifelse
+ }
+ {
+ /CRender
+ {
+ F
+ } ddef
+ } ifelse
+} def
+/f
+{
+ closepath
+ F
+} def
+/S
+{
+ _pola 0 eq
+ {
+ _doClip 1 eq
+ {
+ gsave _ps grestore _eo {eoclip} {clip} ifelse newpath /_lp /none ddef _sc
+ /_doClip 0 ddef
+ }
+ {
+ _ps
+ } ifelse
+ }
+ {
+ /CRender
+ {
+ S
+ } ddef
+ } ifelse
+} def
+/s
+{
+ closepath
+ S
+} def
+/B
+{
+ _pola 0 eq
+ {
+ _doClip 1 eq
+ gsave F grestore
+ {
+ gsave S grestore _eo {eoclip} {clip} ifelse newpath /_lp /none ddef _sc
+ /_doClip 0 ddef
+ }
+ {
+ S
+ } ifelse
+ }
+ {
+ /CRender
+ {
+ B
+ } ddef
+ } ifelse
+} def
+/b
+{
+ closepath
+ B
+} def
+/W
+{
+ /_doClip 1 ddef
+} def
+/*
+{
+ count 0 ne
+ {
+ dup type /stringtype eq
+ {
+ pop
+ } if
+ } if
+ newpath
+} def
+/u
+{
+} def
+/U
+{
+} def
+/q
+{
+ _pola 0 eq
+ {
+ gsave
+ } if
+} def
+/Q
+{
+ _pola 0 eq
+ {
+ grestore
+ } if
+} def
+/*u
+{
+ _pola 1 add /_pola exch ddef
+} def
+/*U
+{
+ _pola 1 sub /_pola exch ddef
+ _pola 0 eq
+ {
+ CRender
+ } if
+} def
+/D
+{
+ pop
+} def
+/*w
+{
+} def
+/*W
+{
+} def
+/`
+{
+ /_i save ddef
+ clipForward?
+ {
+ nulldevice
+ } if
+ 6 1 roll 4 npop
+ concat pop
+ userdict begin
+ /showpage
+ {
+ } def
+ 0 setgray
+ 0 setlinecap
+ 1 setlinewidth
+ 0 setlinejoin
+ 10 setmiterlimit
+ [] 0 setdash
+ /setstrokeadjust where {pop false setstrokeadjust} if
+ newpath
+ 0 setgray
+ false setoverprint
+} def
+/~
+{
+ end
+ _i restore
+} def
+/O
+{
+ 0 ne
+ /_of exch ddef
+ /_lp /none ddef
+} def
+/R
+{
+ 0 ne
+ /_os exch ddef
+ /_lp /none ddef
+} def
+/g
+{
+ /_gf exch ddef
+ /_fc
+ {
+ _lp /fill ne
+ {
+ _of setoverprint
+ _gf setgray
+ /_lp /fill ddef
+ } if
+ } ddef
+ /_pf
+ {
+ _fc
+ _eo {eofill} {fill} ifelse
+ } ddef
+ /_psf
+ {
+ _fc
+ ashow
+ } ddef
+ /_pjsf
+ {
+ _fc
+ awidthshow
+ } ddef
+ /_lp /none ddef
+} def
+/G
+{
+ /_gs exch ddef
+ /_sc
+ {
+ _lp /stroke ne
+ {
+ _os setoverprint
+ _gs setgray
+ /_lp /stroke ddef
+ } if
+ } ddef
+ /_ps
+ {
+ _sc
+ stroke
+ } ddef
+ /_pss
+ {
+ _sc
+ ss
+ } ddef
+ /_pjss
+ {
+ _sc
+ jss
+ } ddef
+ /_lp /none ddef
+} def
+/k
+{
+ _cf astore pop
+ /_fc
+ {
+ _lp /fill ne
+ {
+ _of setoverprint
+ _cf aload pop setcmykcolor
+ /_lp /fill ddef
+ } if
+ } ddef
+ /_pf
+ {
+ _fc
+ _eo {eofill} {fill} ifelse
+ } ddef
+ /_psf
+ {
+ _fc
+ ashow
+ } ddef
+ /_pjsf
+ {
+ _fc
+ awidthshow
+ } ddef
+ /_lp /none ddef
+} def
+/K
+{
+ _cs astore pop
+ /_sc
+ {
+ _lp /stroke ne
+ {
+ _os setoverprint
+ _cs aload pop setcmykcolor
+ /_lp /stroke ddef
+ } if
+ } ddef
+ /_ps
+ {
+ _sc
+ stroke
+ } ddef
+ /_pss
+ {
+ _sc
+ ss
+ } ddef
+ /_pjss
+ {
+ _sc
+ jss
+ } ddef
+ /_lp /none ddef
+} def
+/x
+{
+ /_gf exch ddef
+ findcmykcustomcolor
+ /_if exch ddef
+ /_fc
+ {
+ _lp /fill ne
+ {
+ _of setoverprint
+ _if _gf 1 exch sub setcustomcolor
+ /_lp /fill ddef
+ } if
+ } ddef
+ /_pf
+ {
+ _fc
+ _eo {eofill} {fill} ifelse
+ } ddef
+ /_psf
+ {
+ _fc
+ ashow
+ } ddef
+ /_pjsf
+ {
+ _fc
+ awidthshow
+ } ddef
+ /_lp /none ddef
+} def
+/X
+{
+ /_gs exch ddef
+ findcmykcustomcolor
+ /_is exch ddef
+ /_sc
+ {
+ _lp /stroke ne
+ {
+ _os setoverprint
+ _is _gs 1 exch sub setcustomcolor
+ /_lp /stroke ddef
+ } if
+ } ddef
+ /_ps
+ {
+ _sc
+ stroke
+ } ddef
+ /_pss
+ {
+ _sc
+ ss
+ } ddef
+ /_pjss
+ {
+ _sc
+ jss
+ } ddef
+ /_lp /none ddef
+} def
+/A
+{
+ pop
+} def
+/annotatepage
+{
+userdict /annotatepage 2 copy known {get exec} {pop pop} ifelse
+} def
+/XT {
+ pop pop
+} def
+/discard
+{
+ save /discardSave exch store
+ discardDict begin
+ /endString exch store
+ gt38?
+ {
+ 2 add
+ } if
+ load
+ stopped
+ pop
+ end
+ discardSave restore
+} bind def
+userdict /discardDict 7 dict dup begin
+put
+/pre38Initialize
+{
+ /endStringLength endString length store
+ /newBuff buffer 0 endStringLength getinterval store
+ /newBuffButFirst newBuff 1 endStringLength 1 sub getinterval store
+ /newBuffLast newBuff endStringLength 1 sub 1 getinterval store
+} def
+/shiftBuffer
+{
+ newBuff 0 newBuffButFirst putinterval
+ newBuffLast 0
+ currentfile read not
+ {
+ stop
+ } if
+ put
+} def
+0
+{
+ pre38Initialize
+ mark
+ currentfile newBuff readstring exch pop
+ {
+ {
+ newBuff endString eq
+ {
+ cleartomark stop
+ } if
+ shiftBuffer
+ } loop
+ }
+ {
+ stop
+ } ifelse
+} def
+1
+{
+ pre38Initialize
+ /beginString exch store
+ mark
+ currentfile newBuff readstring exch pop
+ {
+ {
+ newBuff beginString eq
+ {
+ /layerCount dup load 1 add store
+ }
+ {
+ newBuff endString eq
+ {
+ /layerCount dup load 1 sub store
+ layerCount 0 eq
+ {
+ cleartomark stop
+ } if
+ } if
+ } ifelse
+ shiftBuffer
+ } loop
+ } if
+} def
+2
+{
+ mark
+ {
+ currentfile buffer readline not
+ {
+ stop
+ } if
+ endString eq
+ {
+ cleartomark stop
+ } if
+ } loop
+} def
+3
+{
+ /beginString exch store
+ /layerCnt 1 store
+ mark
+ {
+ currentfile buffer readline not
+ {
+ stop
+ } if
+ dup beginString eq
+ {
+ pop /layerCnt dup load 1 add store
+ }
+ {
+ endString eq
+ {
+ layerCnt 1 eq
+ {
+ cleartomark stop
+ }
+ {
+ /layerCnt dup load 1 sub store
+ } ifelse
+ } if
+ } ifelse
+ } loop
+} def
+end
+userdict /clipRenderOff 15 dict dup begin
+put
+{
+ /n /N /s /S /f /F /b /B
+}
+{
+ {
+ _doClip 1 eq
+ {
+ /_doClip 0 ddef _eo {eoclip} {clip} ifelse
+ } if
+ newpath
+ } def
+} forall
+/Tr /pop load def
+/Bb {} def
+/BB /pop load def
+/Bg {12 npop} def
+/Bm {6 npop} def
+/Bc /Bm load def
+/Bh {4 npop} def
+end
+/Lb
+{
+ 4 npop
+ 6 1 roll
+ pop
+ 4 1 roll
+ pop pop pop
+ 0 eq
+ {
+ 0 eq
+ {
+ (%AI5_BeginLayer) 1 (%AI5_EndLayer--) discard
+ }
+ {
+
+ /clipForward? true def
+
+ /Tx /pop load def
+ /Tj /pop load def
+
+ currentdict end clipRenderOff begin begin
+ } ifelse
+ }
+ {
+ 0 eq
+ {
+ save /discardSave exch store
+ } if
+ } ifelse
+} bind def
+/LB
+{
+ discardSave dup null ne
+ {
+ restore
+ }
+ {
+ pop
+ clipForward?
+ {
+ currentdict
+ end
+ end
+ begin
+
+ /clipForward? false ddef
+ } if
+ } ifelse
+} bind def
+/Pb
+{
+ pop pop
+ 0 (%AI5_EndPalette) discard
+} bind def
+/Np
+{
+ 0 (%AI5_End_NonPrinting--) discard
+} bind def
+/Ln /pop load def
+/Ap
+/pop load def
+/Ar
+{
+ 72 exch div
+ 0 dtransform dup mul exch dup mul add sqrt
+ dup 1 lt
+ {
+ pop 1
+ } if
+ setflat
+} def
+/Mb
+{
+ q
+} def
+/Md
+{
+} def
+/MB
+{
+ Q
+} def
+/nc 3 dict def
+nc begin
+/setgray
+{
+ pop
+} bind def
+/setcmykcolor
+{
+ 4 npop
+} bind def
+/setcustomcolor
+{
+ 2 npop
+} bind def
+currentdict readonly pop
+end
+end
+setpacking
+%%EndResource
+%%EndProlog
+%%BeginSetup
+%%IncludeFont: Univers
+Adobe_level2_AI5 /initialize get exec
+Adobe_Illustrator_AI5_vars Adobe_Illustrator_AI5 Adobe_typography_AI5 /initialize get exec
+Adobe_ColorImage_AI6 /initialize get exec
+Adobe_Illustrator_AI5 /initialize get exec
+[
+39/quotesingle 96/grave 128/Adieresis/Aring/Ccedilla/Eacute/Ntilde/Odieresis
+/Udieresis/aacute/agrave/acircumflex/adieresis/atilde/aring/ccedilla/eacute
+/egrave/ecircumflex/edieresis/iacute/igrave/icircumflex/idieresis/ntilde
+/oacute/ograve/ocircumflex/odieresis/otilde/uacute/ugrave/ucircumflex
+/udieresis/dagger/degree/cent/sterling/section/bullet/paragraph/germandbls
+/registered/copyright/trademark/acute/dieresis/.notdef/AE/Oslash
+/.notdef/plusminus/.notdef/.notdef/yen/mu/.notdef/.notdef
+/.notdef/.notdef/.notdef/ordfeminine/ordmasculine/.notdef/ae/oslash
+/questiondown/exclamdown/logicalnot/.notdef/florin/.notdef/.notdef
+/guillemotleft/guillemotright/ellipsis/.notdef/Agrave/Atilde/Otilde/OE/oe
+/endash/emdash/quotedblleft/quotedblright/quoteleft/quoteright/divide
+/.notdef/ydieresis/Ydieresis/fraction/currency/guilsinglleft/guilsinglright
+/fi/fl/daggerdbl/periodcentered/quotesinglbase/quotedblbase/perthousand
+/Acircumflex/Ecircumflex/Aacute/Edieresis/Egrave/Iacute/Icircumflex
+/Idieresis/Igrave/Oacute/Ocircumflex/.notdef/Ograve/Uacute/Ucircumflex
+/Ugrave/dotlessi/circumflex/tilde/macron/breve/dotaccent/ring/cedilla
+/hungarumlaut/ogonek/caron
+TE
+%AI3_BeginEncoding: _Univers Univers
+[/_Univers/Univers 0 0 1 TZ
+%AI3_EndEncoding AdobeType
+%AI5_Begin_NonPrinting
+Np
+8 Bn
+%AI5_BeginGradient: (Black & White)
+(Black & White) 0 2 Bd
+[
+<
+FFFEFDFCFBFAF9F8F7F6F5F4F3F2F1F0EFEEEDECEBEAE9E8E7E6E5E4E3E2E1E0DFDEDDDCDBDAD9D8
+D7D6D5D4D3D2D1D0CFCECDCCCBCAC9C8C7C6C5C4C3C2C1C0BFBEBDBCBBBAB9B8B7B6B5B4B3B2B1B0
+AFAEADACABAAA9A8A7A6A5A4A3A2A1A09F9E9D9C9B9A999897969594939291908F8E8D8C8B8A8988
+87868584838281807F7E7D7C7B7A797877767574737271706F6E6D6C6B6A69686766656463626160
+5F5E5D5C5B5A595857565554535251504F4E4D4C4B4A494847464544434241403F3E3D3C3B3A3938
+37363534333231302F2E2D2C2B2A292827262524232221201F1E1D1C1B1A19181716151413121110
+0F0E0D0C0B0A09080706050403020100
+>
+0 %_Br
+[
+0 0 50 100 %_Bs
+1 0 50 0 %_Bs
+BD
+%AI5_EndGradient
+%AI5_BeginGradient: (Green & Blue)
+(Green & Blue) 0 2 Bd
+[
+<
+99999A9A9B9B9B9C9C9D9D9D9E9E9F9F9FA0A0A1A1A1A2A2A3A3A3A4A4A5A5A5A6A6A7A7A7A8A8A9
+A9A9AAAAABABABACACADADADAEAEAFAFAFB0B0B1B1B1B2B2B3B3B3B4B4B5B5B5B6B6B7B7B7B8B8B9
+B9B9BABABBBBBBBCBCBDBDBDBEBEBFBFBFC0C0C1C1C1C2C2C3C3C3C4C4C5C5C5C6C6C7C7C7C8C8C9
+C9C9CACACBCBCBCCCCCDCDCDCECECFCFCFD0D0D1D1D1D2D2D3D3D3D4D4D5D5D5D6D6D7D7D7D8D8D9
+D9D9DADADBDBDBDCDCDDDDDDDEDEDFDFDFE0E0E1E1E1E2E2E3E3E3E4E4E5E5E5E6E6E7E7E7E8E8E9
+E9E9EAEAEBEBEBECECEDEDEDEEEEEFEFEFF0F0F1F1F1F2F2F3F3F3F4F4F5F5F5F6F6F7F7F7F8F8F9
+F9F9FAFAFBFBFBFCFCFDFDFDFEFEFFFF
+>
+<
+000102020304050506070808090A0B0B0C0D0E0E0F101111121314141516171718191A1A1B1C1D1D
+1E1F20202122232324252626272829292A2B2C2C2D2E2F2F303132323334353536373838393A3B3B
+3C3D3E3E3F404141424344444546474748494A4A4B4C4D4D4E4F5050515253535455565657585959
+5A5B5C5C5D5E5F5F606162626364656566676868696A6B6B6C6D6E6E6F7071717273747475767777
+78797A7A7B7C7D7D7E7F80808182828384858586878888898A8B8B8C8D8E8E8F9091919293949495
+96979798999A9A9B9C9D9D9E9FA0A0A1A2A3A3A4A5A6A6A7A8A9A9AAABACACADAEAFAFB0B1B2B2B3
+B4B5B5B6B7B8B8B9BABBBBBCBDBEBEBF
+>
+<
+FFFEFDFCFBFAF9F8F7F6F5F4F3F2F1F0EFEEEDECEBEAE9E8E7E6E5E4E3E2E1E0DFDEDDDCDBDAD9D8
+D7D6D5D4D3D2D1D0CFCECDCCCBCAC9C8C7C6C5C4C3C2C1C0BFBEBDBCBBBAB9B8B7B6B5B4B3B2B1B0
+AFAEADACABAAA9A8A7A6A5A4A3A2A1A09F9E9D9C9B9A999897969594939291908F8E8D8C8B8A8988
+87868584838281807F7E7D7C7B7A797877767574737271706F6E6D6C6B6A69686766656463626160
+5F5E5D5C5B5A595857565554535251504F4E4D4C4B4A494847464544434241403F3E3D3C3B3A3938
+37363534333231302F2E2D2C2B2A292827262524232221201F1E1D1C1B1A19181716151413121110
+0F0E0D0C0B0A09080706050403020100
+>
+0
+1 %_Br
+[
+1 0.75 0 0 1 50 100 %_Bs
+0.6 0 1 0 1 50 0 %_Bs
+BD
+%AI5_EndGradient
+%AI5_BeginGradient: (Pink, Yellow, Green)
+(Pink, Yellow, Green) 0 3 Bd
+[
+<
+00000000000000000000000000000000000000010101010101010101010101010101010101010101
+01010101010202020202020202020202020202020202020202020203030303030303030303030303
+03030303030303030404040404040404040404040404040404040404050505050505050505050505
+05050505050505060606060606060606060606060606060606060707070707070707070707070707
+07070707080808080808080808080808080808080809090909090909090909090909090909090A0A
+0A0A0A0A0A0A0A0A0A0A0A0A0A0A0A0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0B0C0C0C0C0C0C0C0C0C
+0C0C0C0C0C0C0C0D0D0D0D0D
+>
+<
+050506060606070708080809090A0A0A0B0B0C0C0D0D0E0E0F0F1010111112121313141415151617
+17181819191A1A1B1C1C1D1D1E1F1F202021222223232425252626272828292A2A2B2C2C2D2D2E2F
+2F3031313233333435353637373839393A3B3B3C3D3E3E3F4040414242434445454647474849494A
+4B4C4C4D4E4F4F505151525354545556575758595A5A5B5C5C5D5E5F5F6061626363646566666768
+69696A6B6C6C6D6E6F707071727373747576777778797A7B7B7C7D7E7F7F80818283838485868787
+88898A8B8B8C8D8E8F8F9091929394949596979898999A9B9C9D9D9E9FA0A1A2A2A3A4A5A6A7A7A8
+A9AAABACADADAEAFB0B1B2B2
+>
+<
+CCCCCBCBCBCACACAC9C9C8C8C7C7C6C6C5C5C4C4C3C2C2C1C1C0C0BFBEBEBDBDBCBBBBBAB9B9B8B7
+B7B6B6B5B4B4B3B2B1B1B0AFAFAEADADACABAAAAA9A8A8A7A6A5A5A4A3A2A2A1A0A09F9E9D9C9C9B
+9A999998979696959493929291908F8E8E8D8C8B8A8A8988878686858483828181807F7E7D7C7C7B
+7A7978777776757473727171706F6E6D6C6B6A6A69686766656463636261605F5E5D5C5B5B5A5958
+5756555453525151504F4E4D4C4B4A49484746464544434241403F3E3D3C3B3A3938383736353433
+3231302F2E2D2C2B2A29282726252423222221201F1E1D1C1B1A191817161514131211100F0E0D0C
+0B0A09080706050403020100
+>
+0
+1 %_Br
+<
+737271706F6E6D6C6B6A696867666564636261605F5E5D5C5B5B5A59585756555453525150504F4E
+4D4C4B4A4949484746454443434241403F3E3E3D3C3B3A3A393837363635343333323130302F2E2D
+2D2C2B2A2A29282827262525242323222121201F1F1E1D1D1C1C1B1A1A1918181717161615141413
+1312121111100F0F0E0E0D0D0C0C0C0B0B0A0A090908080807070606060505050404040303030202
+020201010101010000000000
+>
+<
+00000000000000000000000001010101010101010101010101010101010101010101010102020202
+02020202020202020202020202020202020202020202030303030303030303030303030303030303
+03030303030303030303030303040404040404040404040404040404040404040404040404040404
+04040404040404040404050505050505050505050505050505050505050505050505050505050505
+050505050505050505050505
+>
+<
+BFBFBFC0C0C0C0C0C0C0C0C0C1C1C1C1C1C1C1C1C1C2C2C2C2C2C2C2C2C2C2C3C3C3C3C3C3C3C3C3
+C3C4C4C4C4C4C4C4C4C4C4C5C5C5C5C5C5C5C5C5C5C5C6C6C6C6C6C6C6C6C6C6C6C6C7C7C7C7C7C7
+C7C7C7C7C7C7C8C8C8C8C8C8C8C8C8C8C8C8C8C9C9C9C9C9C9C9C9C9C9C9C9C9C9C9CACACACACACA
+CACACACACACACACACACACBCBCBCBCBCBCBCBCBCBCBCBCBCBCBCBCBCBCBCBCBCBCCCCCCCCCCCCCCCC
+CCCCCCCCCCCCCCCCCCCCCCCC
+>
+0
+1 %_Br
+[
+0.05 0.7 0 0 1 50 100 %_Bs
+0 0.02 0.8 0 1 57 36 %_Bs
+0.45 0 0.75 0 1 37 0 %_Bs
+BD
+%AI5_EndGradient
+%AI5_BeginGradient: (Purple, Red & Yellow)
+(Purple, Red & Yellow) 0 3 Bd
+[
+0
+<
+FFFEFDFCFBFAF9F8F7F6F5F4F3F2F1F0EFEEEDECEBEAE9E8E7E6E5E4E3E2E1E0DFDEDDDCDBDAD9D8
+D7D6D5D4D3D2D1D0CFCECDCCCBCAC9C8C7C6C5C4C3C2C1C0BFBEBDBCBBBAB9B8B7B6B5B4B3B2B1B0
+AFAEADACABAAA9A8A7A6A5A4A3A2A1A09F9E9D9C9B9A999897969594939291908F8E8D8C8B8A8988
+87868584838281807F7E7D7C7B7A797877767574737271706F6E6D6C6B6A69686766656463626160
+5F5E5D5C5B5A595857565554535251504F4E4D4C4B4A494847464544434241403F3E3D3C3B3A3938
+37363534333231302F2E2D2C2B2A292827262524232221201F1E1D1C1B1A19181716151413121110
+0F0E0D0C0B0A
+>
+<
+CCCCCCCDCDCDCDCDCECECECECECFCFCFCFD0D0D0D0D0D1D1D1D1D1D2D2D2D2D2D3D3D3D3D3D4D4D4
+D4D5D5D5D5D5D6D6D6D6D6D7D7D7D7D7D8D8D8D8D8D9D9D9D9DADADADADADBDBDBDBDBDCDCDCDCDC
+DDDDDDDDDDDEDEDEDEDFDFDFDFDFE0E0E0E0E0E1E1E1E1E1E2E2E2E2E2E3E3E3E3E4E4E4E4E4E5E5
+E5E5E5E6E6E6E6E6E7E7E7E7E7E8E8E8E8E9E9E9E9E9EAEAEAEAEAEBEBEBEBEBECECECECECEDEDED
+EDEEEEEEEEEEEFEFEFEFEFF0F0F0F0F0F1F1F1F1F1F2F2F2F2F3F3F3F3F3F4F4F4F4F4F5F5F5F5F5
+F6F6F6F6F6F7F7F7F7F8F8F8F8F8F9F9F9F9F9FAFAFAFAFAFBFBFBFBFBFCFCFCFCFDFDFDFDFDFEFE
+FEFEFEFFFFFF
+>
+0
+1 %_Br
+<
+E5E4E3E2E1E0DFDEDDDCDBDAD9D8D7D6D5D4D3D2D1D0CFCECDCCCBCAC9C8C7C6C5C4C3C2C1C0BFBE
+BDBCBBBAB9B8B7B6B5B4B3B2B1B0AFAEADACABAAA9A8A7A6A5A4A3A2A1A09F9E9D9C9B9A99989796
+9594939291908F8E8D8C8B8A898887868584838281807F7E7D7C7B7A797877767574737271706F6E
+6D6C6B6A696867666564636261605F5E5D5C5B5A595857565554535251504F4E4D4C4B4A49484746
+4544434241403F3E3D3C3B3A393837363534333231302F2E2D2C2B2A292827262524232221201F1E
+1D1C1B1A191817161514131211100F0E0D0C0B0A09080706050403020100
+>
+<
+E5E6E6E6E6E6E6E6E6E7E7E7E7E7E7E7E7E7E8E8E8E8E8E8E8E8E8E9E9E9E9E9E9E9E9E9EAEAEAEA
+EAEAEAEAEAEBEBEBEBEBEBEBEBEBECECECECECECECECECEDEDEDEDEDEDEDEDEDEEEEEEEEEEEEEEEE
+EEEFEFEFEFEFEFEFEFEFF0F0F0F0F0F0F0F0F0F1F1F1F1F1F1F1F1F1F2F2F2F2F2F2F2F2F2F3F3F3
+F3F3F3F3F3F3F4F4F4F4F4F4F4F4F4F5F5F5F5F5F5F5F5F5F6F6F6F6F6F6F6F6F6F7F7F7F7F7F7F7
+F7F7F8F8F8F8F8F8F8F8F8F9F9F9F9F9F9F9F9F9FAFAFAFAFAFAFAFAFAFBFBFBFBFBFBFBFBFBFCFC
+FCFCFCFCFCFCFCFDFDFDFDFDFDFDFDFDFEFEFEFEFEFEFEFEFEFFFFFFFFFF
+>
+<
+00010203040405060708090A0B0C0C0D0E0F10111213141415161718191A1B1C1D1D1E1F20212223
+242525262728292A2B2C2D2D2E2F30313233343535363738393A3B3C3D3D3E3F4041424344454546
+4748494A4B4C4D4E4E4F50515253545556565758595A5B5C5D5E5E5F60616263646566666768696A
+6B6C6D6E6E6F70717273747576767778797A7B7C7D7E7F7F80818283848586878788898A8B8C8D8E
+8F8F90919293949596979798999A9B9C9D9E9F9FA0A1A2A3A4A5A6A7A7A8A9AAABACADAEAFAFB0B1
+B2B3B4B5B6B7B8B8B9BABBBCBDBEBFC0C0C1C2C3C4C5C6C7C8C8C9CACBCC
+>
+0
+1 %_Br
+[
+0 0.04 1 0 1 50 100 %_Bs
+0 1 0.8 0 1 50 50 %_Bs
+0.9 0.9 0 0 1 50 0 %_Bs
+BD
+%AI5_EndGradient
+%AI5_BeginGradient: (Rainbow)
+(Rainbow) 0 6 Bd
+[
+<
+FFFEFDFCFBFAF9F8F7F6F5F4F3F2F1F0EFEEEDECEBEAE9E8E7E6E5E4E3E2E1E0DFDEDDDCDBDAD9D8
+D7D6D5D4D3D2D1D0CFCECDCCCBCAC9C8C7C6C5C4C3C2C1C0BFBEBDBCBBBAB9B8B7B6B5B4B3B2B1B0
+AFAEADACABAAA9A8A7A6A5A4A3A2A1A09F9E9D9C9B9A999897969594939291908F8E8D8C8B8A8988
+87868584838281807F7E7D7C7B7A797877767574737271706F6E6D6C6B6A69686766656463626160
+5F5E5D5C5B5A595857565554535251504F4E4D4C4B4A494847464544434241403F3E3D3C3B3A3938
+37363534333231302F2E2D2C2B2A292827262524232221201F1E1D1C1B1A19181716151413121110
+0F0E0D0C0B0A09080706050403020100
+>
+1
+0
+0
+1 %_Br
+1
+<
+0708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F202122232425262728292A2B2C2D2E
+2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F50515253545556
+5758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F707172737475767778797A7B7C7D7E
+7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9FA0A1A2A3A4A5A6
+A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7C8C9CACBCCCDCE
+CFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6
+F7F8F9FAFBFCFDFEFF
+>
+0
+0
+1 %_Br
+1
+<
+00000000000000000000000000000000000001010101010101010101010101010101010101010101
+01010101010101010101010101010202020202020202020202020202020202020202020202020202
+02020202020202020202030303030303030303030303030303030303030303030303030303030303
+03030303030304040404040404040404040404040404040404040404040404040404040404040404
+04040505050505050505050505050505050505050505050505050505050505050505050505050606
+06060606060606060606060606060606060606060606060606060606060606060606070707070707
+07070707070707070707070707070707
+>
+<
+FFFEFDFCFBFAF9F8F7F6F5F4F3F2F1F0EFEEEDECEBEAE9E8E7E6E5E4E3E2E1E0DFDEDDDCDBDAD9D8
+D7D6D5D4D3D2D1D0CFCECDCCCBCAC9C8C7C6C5C4C3C2C1C0BFBEBDBCBBBAB9B8B7B6B5B4B3B2B1B0
+AFAEADACABAAA9A8A7A6A5A4A3A2A1A09F9E9D9C9B9A999897969594939291908F8E8D8C8B8A8988
+87868584838281807F7E7D7C7B7A797877767574737271706F6E6D6C6B6A69686766656463626160
+5F5E5D5C5B5A595857565554535251504F4E4D4C4B4A494847464544434241403F3E3D3C3B3A3938
+37363534333231302F2E2D2C2B2A292827262524232221201F1E1D1C1B1A19181716151413121110
+0F0E0D0C0B0A09080706050403020100
+>
+0
+1 %_Br
+<
+000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627
+28292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F
+505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F7071727374757677
+78797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9F
+A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7
+C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEF
+F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF
+>
+0
+1
+0
+1 %_Br
+0
+<
+FFFEFDFCFBFAF9F8F7F6F5F4F3F2F1F0EFEEEDECEBEAE9E8E7E6E5E4E3E2E1E0DFDEDDDCDBDAD9D8
+D7D6D5D4D3D2D1D0CFCECDCCCBCAC9C8C7C6C5C4C3C2C1C0BFBEBDBCBBBAB9B8B7B6B5B4B3B2B1B0
+AFAEADACABAAA9A8A7A6A5A4A3A2A1A09F9E9D9C9B9A999897969594939291908F8E8D8C8B8A8988
+87868584838281807F7E7D7C7B7A797877767574737271706F6E6D6C6B6A69686766656463626160
+5F5E5D5C5B5A595857565554535251504F4E4D4C4B4A494847464544434241403F3E3D3C3B3A3938
+37363534333231302F2E2D2C2B2A292827262524232221201F1E1D1C1B1A19181716151413121110
+0F0E0D0C0B0A09080706050403020100
+>
+1
+0
+1 %_Br
+[
+0 1 0 0 1 50 100 %_Bs
+1 1 0 0 1 50 80 %_Bs
+1 0.0279 0 0 1 50 60 %_Bs
+1 0 1 0 1 50 40 %_Bs
+0 0 1 0 1 50 20 %_Bs
+0 1 1 0 1 50 0 %_Bs
+BD
+%AI5_EndGradient
+%AI5_BeginGradient: (Steel Bar)
+(Steel Bar) 0 3 Bd
+[
+<
+FFFEFDFCFBFAF9F8F7F6F5F4F3F2F1F0EFEEEDECEBEAE9E8E7E6E5E4E3E2E1E0DFDEDDDCDBDAD9D8
+D7D6D5D4D3D2D1D0CFCECDCCCBCAC9C8C7C6C5C4C3C2C1C0BFBEBDBCBBBAB9B8B7B6B5B4B3B2B1B0
+AFAEADACABAAA9A8A7A6A5A4A3A2A1A09F9E9D9C9B9A999897969594939291908F8E8D8C8B8A8988
+87868584838281807F7E7D7C7B7A797877767574737271706F6E6D6C6B6A69686766656463626160
+5F5E5D5C5B5A595857565554535251504F4E4D4C4B4A494847464544434241403F3E3D3C3B3A3938
+37363534333231302F2E2D2C2B2A292827262524232221201F1E1D1C1B1A19181716151413121110
+0F0E0D0C0B0A09080706050403020100
+>
+0 %_Br
+<
+000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627
+28292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F
+505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F7071727374757677
+78797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9F
+A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7
+C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEF
+F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF
+>
+0 %_Br
+[
+0 0 50 100 %_Bs
+1 0 50 70 %_Bs
+0 0 50 0 %_Bs
+BD
+%AI5_EndGradient
+%AI5_BeginGradient: (Yellow & Orange Radial)
+(Yellow & Orange Radial) 1 2 Bd
+[
+0
+<
+0001010203040506060708090A0B0C0C0D0E0F10111213131415161718191A1B1C1D1D1E1F202122
+232425262728292A2B2B2C2D2E2F303132333435363738393A3B3C3D3E3E3F404142434445464748
+494A4B4C4D4E4F505152535455565758595A5B5C5D5E5F60606162636465666768696A6B6C6D6E6F
+707172737475767778797A7B7C7D7E7F808182838485868788898A8B8C
+>
+<
+FFFFFFFFFEFEFEFEFEFEFEFDFDFDFDFDFDFCFCFCFCFCFCFBFBFBFBFBFBFAFAFAFAFAFAF9F9F9F9F9
+F9F8F8F8F8F8F8F7F7F7F7F7F7F6F6F6F6F6F6F5F5F5F5F5F5F4F4F4F4F4F3F3F3F3F3F3F2F2F2F2
+F2F2F1F1F1F1F1F0F0F0F0F0F0EFEFEFEFEFEFEEEEEEEEEEEDEDEDEDEDEDECECECECECEBEBEBEBEB
+EBEAEAEAEAEAE9E9E9E9E9E9E8E8E8E8E8E8E7E7E7E7E7E6E6E6E6E6E5
+>
+0
+1 %_Br
+[
+0 0 1 0 1 52 19 %_Bs
+0 0.55 0.9 0 1 50 100 %_Bs
+BD
+%AI5_EndGradient
+%AI5_BeginGradient: (Yellow & Purple Radial)
+(Yellow & Purple Radial) 1 2 Bd
+[
+<
+000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F2021222324252627
+28292A2B2C2D2E2F303132333435363738393A3B3C3D3E3F404142434445464748494A4B4C4D4E4F
+505152535455565758595A5B5C5D5E5F606162636465666768696A6B6C6D6E6F7071727374757677
+78797A7B7C7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C9D9E9F
+A0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBCBDBEBFC0C1C2C3C4C5C6C7
+C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDCDDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEF
+F0F1F2F3F4F5F6F7F8F9FAFBFCFDFEFF
+>
+<
+1415161718191A1B1C1D1E1F1F202122232425262728292A2A2B2C2D2E2F30313233343536363738
+393A3B3C3D3E3F40414142434445464748494A4B4C4D4D4E4F50515253545556575858595A5B5C5D
+5E5F60616263646465666768696A6B6C6D6E6F6F707172737475767778797A7B7B7C7D7E7F808182
+83848586868788898A8B8C8D8E8F90919292939495969798999A9B9C9D9D9E9FA0A1A2A3A4A5A6A7
+A8A9A9AAABACADAEAFB0B1B2B3B4B4B5B6B7B8B9BABBBCBDBEBFC0C0C1C2C3C4C5C6C7C8C9CACBCB
+CCCDCECFD0D1D2D3D4D5D6D7D7D8D9DADBDCDDDEDFE0E1E2E2E3E4E5E6E7E8E9EAEBECEDEEEEEFF0
+F1F2F3F4F5F6F7F8F9F9FAFBFCFDFEFF
+>
+<
+ABAAAAA9A8A7A7A6A5A5A4A3A3A2A1A1A09F9F9E9D9D9C9B9B9A9999989797969595949393929191
+908F8F8E8D8D8C8B8B8A8989888787868585848383828181807F7F7E7D7D7C7B7B7A797978777776
+7575747373727171706F6F6E6D6D6C6B6B6A6969686767666565646362626160605F5E5E5D5C5C5B
+5A5A5958585756565554545352525150504F4E4E4D4C4C4B4A4A4948484746464544444342424140
+403F3E3E3D3C3C3B3A3A3938383736363534343332323130302F2E2E2D2C2C2B2A2A292828272626
+25242423222121201F1F1E1D1D1C1B1B1A1919181717161515141313121111100F0F0E0D0D0C0B0B
+0A090908070706050504030302010100
+>
+0
+1 %_Br
+[
+0 0.08 0.67 0 1 50 14 %_Bs
+1 1 0 0 1 50 100 %_Bs
+BD
+%AI5_EndGradient
+%AI5_End_NonPrinting--
+%AI5_BeginPalette
+0 2 Pb
+Pn
+Pc
+1 g
+Pc
+0 g
+Pc
+0 0 0 0 k
+Pc
+0.75 g
+Pc
+0.5 g
+Pc
+0.25 g
+Pc
+0 g
+Pc
+Bb
+2 (Black & White) -4014 4716 0 0 1 0 0 1 0 0 Bg
+0 BB
+Pc
+0.25 0 0 0 k
+Pc
+0.5 0 0 0 k
+Pc
+0.75 0 0 0 k
+Pc
+1 0 0 0 k
+Pc
+0.25 0.25 0 0 k
+Pc
+0.5 0.5 0 0 k
+Pc
+0.75 0.75 0 0 k
+Pc
+1 1 0 0 k
+Pc
+Bb
+2 (Pink, Yellow, Green) -4014 4716 0 0 1 0 0 1 0 0 Bg
+0 BB
+Pc
+0 0.25 0 0 k
+Pc
+0 0.5 0 0 k
+Pc
+0 0.75 0 0 k
+Pc
+0 1 0 0 k
+Pc
+0 0.25 0.25 0 k
+Pc
+0 0.5 0.5 0 k
+Pc
+0 0.75 0.75 0 k
+Pc
+0 1 1 0 k
+Pc
+Bb
+0 0 0 0 Bh
+2 (Yellow & Purple Radial) -4014 4716 0 0 1 0 0 1 0 0 Bg
+0 BB
+Pc
+0 0 0.25 0 k
+Pc
+0 0 0.5 0 k
+Pc
+0 0 0.75 0 k
+Pc
+0 0 1 0 k
+Pc
+0.25 0 0.25 0 k
+Pc
+0.5 0 0.5 0 k
+Pc
+0.75 0 0.75 0 k
+Pc
+1 0 1 0 k
+Pc
+Bb
+2 (Rainbow) -4014 4716 0 0 1 0 0 1 0 0 Bg
+0 BB
+Pc
+0.25 0.125 0 0 k
+Pc
+0.5 0.25 0 0 k
+Pc
+0.75 0.375 0 0 k
+Pc
+1 0.5 0 0 k
+Pc
+0.125 0.25 0 0 k
+Pc
+0.25 0.5 0 0 k
+Pc
+0.375 0.75 0 0 k
+Pc
+0.5 1 0 0 k
+Pc
+Bb
+2 (Steel Bar) -4014 4716 0 0 1 0 0 1 0 0 Bg
+0 BB
+Pc
+0 0.25 0.125 0 k
+Pc
+0 0.5 0.25 0 k
+Pc
+0 0.75 0.375 0 k
+Pc
+0 1 0.5 0 k
+Pc
+0 0.125 0.25 0 k
+Pc
+0 0.25 0.5 0 k
+Pc
+0 0.375 0.75 0 k
+Pc
+0 0.5 1 0 k
+Pc
+Bb
+2 (Purple, Red & Yellow) -4014 4716 0 0 1 0 0 1 0 0 Bg
+0 BB
+Pc
+0.125 0 0.25 0 k
+Pc
+0.25 0 0.5 0 k
+Pc
+0.375 0 0.75 0 k
+Pc
+0.5 0 1 0 k
+Pc
+0.25 0 0.125 0 k
+Pc
+0.5 0 0.25 0 k
+Pc
+0.75 0 0.375 0 k
+Pc
+1 0 0.5 0 k
+Pc
+Bb
+2 (Green & Blue) -4014 4716 0 0 1 0 0 1 0 0 Bg
+0 BB
+Pc
+0.25 0.125 0.125 0 k
+Pc
+0.5 0.25 0.25 0 k
+Pc
+0.75 0.375 0.375 0 k
+Pc
+1 0.5 0.5 0 k
+Pc
+0.25 0.25 0.125 0 k
+Pc
+0.5 0.5 0.25 0 k
+Pc
+0.75 0.75 0.375 0 k
+Pc
+1 1 0.5 0 k
+Pc
+Bb
+0 0 0 0 Bh
+2 (Yellow & Orange Radial) -4014 4716 0 0 1 0 0 1 0 0 Bg
+0 BB
+Pc
+0.125 0.25 0.125 0 k
+Pc
+0.25 0.5 0.25 0 k
+Pc
+0.375 0.75 0.375 0 k
+Pc
+0.5 1 0.5 0 k
+Pc
+0.125 0.25 0.25 0 k
+Pc
+0.25 0.5 0.5 0 k
+Pc
+0.375 0.75 0.75 0 k
+Pc
+0.5 1 1 0 k
+Pc
+0 0 0 0 k
+Pc
+0.125 0.125 0.25 0 k
+Pc
+0.25 0.25 0.5 0 k
+Pc
+0.375 0.375 0.75 0 k
+Pc
+0.5 0.5 1 0 k
+Pc
+0.25 0.125 0.25 0 k
+Pc
+0.5 0.25 0.5 0 k
+Pc
+0.75 0.375 0.75 0 k
+Pc
+1 0.5 1 0 k
+Pc
+PB
+%AI5_EndPalette
+%%EndSetup
+%AI5_BeginLayer
+1 1 1 1 0 0 0 79 128 255 Lb
+(Layer 1) Ln
+0 A
+800 Ar
+0 J 0 j 1 w 4 M []0 d
+%AI3_Note:
+0 D
+0 XR
+-4014 283.5 m
+4626 283.5 L
+(N) *
+453.5 4716 m
+453.5 -3924 L
+(N) *
+85 4716 m
+85 -3924 L
+(N) *
+-4014 765.5 m
+4626 765.5 L
+(N) *
+u
+0 R
+0.25 G
+2 w
+152.7439 649.8296 m
+164.3439 653.4296 158.3439 667.0297 v
+153.0847 678.9503 141.5439 672.6297 y
+141.9635 683.3994 130.3438 683.8297 v
+119.5438 684.2297 118.7438 672.6297 y
+113.429 685.1021 100.7437 677.0297 v
+91.9437 671.4297 96.3437 661.0297 y
+85.9436 655.0296 93.1437 643.0296 v
+98.1213 634.7336 107.5437 638.6296 y
+105.5437 626.6295 118.7438 627.0295 v
+131.9438 627.4295 130.3438 638.6296 y
+138.0225 629.4983 148.3439 636.2296 v
+157.5439 642.2296 152.7439 649.8296 y
+s
+0 To
+1 0 0 1 125.3333 652 0 Tp
+TP
+-19.9951 0 Td
+0 Tr
+0 O
+0 g
+1 w
+/_Univers 10 Tf
+0 Ts
+100 Tz
+0 Tt
+1 TA
+%_ 0 XL
+36 0 Xb
+XB
+0 0 5 TC
+100 100 200 TW
+0 0 0 Ti
+1 Ta
+0 0 2 2 3 Th
+0 Tq
+0 0 Tl
+0 Tc
+0 Tw
+(Network) Tx
+(\r) TX
+TO
+U
+1 Ap
+0 R
+0 G
+245 630.7402 m
+256.7413 630.7402 266.2598 640.2587 266.2598 652 c
+266.2598 663.7413 256.7413 673.2598 245 673.2598 c
+233.2587 673.2598 223.7402 663.7413 223.7402 652 c
+223.7402 640.2587 233.2587 630.7402 245 630.7402 c
+s
+u
+409.6667 630.7402 m
+429.2355 630.7402 445.0998 640.2587 445.0998 652 c
+445.0998 663.7414 429.2355 673.2599 409.6667 673.2599 c
+390.0978 673.2599 374.2335 663.7414 374.2335 652 c
+374.2335 640.2587 390.0978 630.7402 409.6667 630.7402 c
+s
+0 To
+1 0 0 1 409.6667 654.5662 0 Tp
+TP
+-16.3867 0 Td
+0 Tr
+0 O
+0 g
+(Master\r) Tx
+2.2253 -12 Td
+(Agent) Tx
+(\r) TX
+TO
+U
+0 To
+1 0 0 1 415 698 0 Tp
+TP
+0 Tr
+(\r) Tx
+TO
+u
+0 R
+0 G
+341.6667 540.0735 m
+361.2355 540.0735 377.0998 549.592 377.0998 561.3333 c
+377.0998 573.0747 361.2355 582.5932 341.6667 582.5932 c
+322.0978 582.5932 306.2335 573.0747 306.2335 561.3333 c
+306.2335 549.592 322.0978 540.0735 341.6667 540.0735 c
+s
+0 To
+1 0 0 1 341.6667 563.8995 0 Tp
+TP
+-29.1626 0 Td
+0 Tr
+0 O
+0 g
+(Proxy Agent\r) Tx
+2.7771 -12 Td
+(Subsystem) Tx
+(\r) TX
+TO
+U
+u
+u
+0 Ap
+0 R
+0 G
+274.4641 652 m
+366 652 l
+S
+0 O
+0 g
+368.362 653.0249 m
+366.7087 653.5241 365.6341 653.9841 364.3076 654.5165 c
+364.3076 649.4722 l
+364.7824 649.6974 366.7087 650.4647 368.362 650.9636 c
+370.1314 651.4983 371.7359 651.8639 372.7766 651.9944 c
+371.7359 652.1249 370.1314 652.4904 368.362 653.0249 c
+f
+U
+272.1021 650.9751 m
+273.7554 650.4759 274.83 650.0159 276.1565 649.4835 c
+276.1565 654.5278 l
+275.6817 654.3026 273.7554 653.5353 272.1021 653.0364 c
+270.3327 652.5017 268.7282 652.1361 267.6875 652.0056 c
+268.7282 651.8751 270.3327 651.5096 272.1021 650.9751 c
+f
+U
+u
+0 R
+0 G
+265.2292 630.5208 m
+314.2292 584.5208 l
+S
+0 O
+0 g
+316.6527 583.6514 m
+315.789 585.147 315.3204 586.2179 314.7176 587.5139 c
+311.2651 583.8362 l
+311.7654 583.6754 313.695 582.9164 315.2419 582.1486 c
+316.8979 581.3274 318.3179 580.4958 319.166 579.8786 c
+318.4966 580.6861 317.5769 582.0507 316.6527 583.6514 c
+f
+262.8056 631.3902 m
+263.6693 629.8947 264.1379 628.8238 264.7407 627.5278 c
+268.1932 631.2055 l
+267.6929 631.3663 265.7633 632.1252 264.2164 632.8931 c
+262.5604 633.7143 261.1404 634.5459 260.2923 635.163 c
+260.9617 634.3556 261.8814 632.9909 262.8056 631.3902 c
+f
+U
+0 To
+1 0 0 1 245 648.5662 0 Tp
+TP
+-12.7747 0 Td
+0 Tr
+(Net if) Tx
+(\r) TX
+TO
+0 To
+1 0 0 1 319.6667 656.6667 0 Tp
+TP
+-31.1438 0 Td
+0 Tr
+(Erlang T) Tx 1 104 Tk
+(erms) Tx
+(\r) TX
+TO
+0 To
+1 0 0 1 294.3333 606.3333 0 Tp
+TP
+-73.335 0 Td
+0 Tr
+2 Ta
+(Proxy agent\312\312\312\312\312\312\r) Tx
+-33.8769 -12 Td
+(specific representation) Tx
+(\r) TX
+TO
+0 To
+1 0 0 1 263.6667 601.3333 0 Tp
+TP
+0 Tr
+(\r) Tx
+TO
+u
+0 R
+0 G
+168 652 m
+215.3333 652 l
+B
+217.6953 653.0249 m
+216.042 653.5241 214.9674 653.9841 213.6409 654.5165 c
+213.6409 649.4722 l
+214.1157 649.6974 216.042 650.4647 217.6953 650.9636 c
+219.4647 651.4983 221.0692 651.8639 222.1099 651.9944 c
+221.0692 652.1249 219.4647 652.4904 217.6953 653.0249 c
+f
+165.638 650.9751 m
+167.2913 650.4759 168.3659 650.0159 169.6924 649.4835 c
+169.6924 654.5278 l
+169.2176 654.3026 167.2913 653.5353 165.638 653.0364 c
+163.8686 652.5017 162.2641 652.1361 161.2234 652.0056 c
+162.2641 651.8751 163.8686 651.5096 165.638 650.9751 c
+f
+U
+0 To
+1 0 0 1 190.75 656.25 0 Tp
+TP
+-13.0579 0 Td
+0 Tr
+1 Ta
+(Bytes) Tx
+(\r) TX
+TO
+LB
+%AI5_EndLayer--
+%%PageTrailer
+gsave annotatepage grestore showpage
+%%Trailer
+Adobe_Illustrator_AI5 /terminate get exec
+Adobe_ColorImage_AI6 /terminate get exec
+Adobe_typography_AI5 /terminate get exec
+Adobe_level2_AI5 /terminate get exec
+%%EOF
diff --git a/lib/snmp/doc/src/snmp_app.xml b/lib/snmp/doc/src/snmp_app.xml
new file mode 100644
index 0000000000..460f0b8018
--- /dev/null
+++ b/lib/snmp/doc/src/snmp_app.xml
@@ -0,0 +1,708 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE appref SYSTEM "appref.dtd">
+
+<appref>
+ <header>
+ <copyright>
+ <year>1997</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ 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.
+
+ </legalnotice>
+
+ <title>snmp</title>
+ <prepared></prepared>
+ <responsible></responsible>
+ <docno></docno>
+ <approved></approved>
+ <checked></checked>
+ <date></date>
+ <rev></rev>
+ <file>snmp.xml</file>
+ </header>
+ <app>snmp</app>
+ <appsummary>The SNMP Application</appsummary>
+ <description>
+ <p>This chapter describes the <c>snmp</c>
+ application in OTP. The SNMP application provides the following
+ services:</p>
+ <list type="bulleted">
+ <item>
+ <p>a multilingual extensible SNMP agent</p>
+ </item>
+ <item>
+ <p>a SNMP manager</p>
+ </item>
+ <item>
+ <p>a MIB compiler</p>
+ </item>
+ </list>
+
+ </description>
+
+ <section>
+ <marker id="configuration_params"></marker>
+ <title>Configuration</title>
+ <p>The following configuration parameters are defined for the SNMP
+ application. Refer to application(3) for more information about
+ configuration parameters.
+ </p>
+
+ <p>The snmp part of the config file specifying the configuration
+ parameters is basically the following tuple:</p>
+ <pre>
+ {snmp, snmp_components_config()}
+ </pre>
+
+ <p>A minimal config file for starting a node with both a manager
+ and an agent:</p>
+ <pre>
+ [{snmp,
+ [{agent, [{db_dir, "/tmp/snmp/agent/db"},
+ {config, [{dir, "/tmp/snmp/agent/conf"}]}]},
+ {manager, [{config, [{dir, "/tmp/snmp/manager/conf"},
+ {db_dir, "/tmp/snmp/manager/db"}]}]}]}
+ ]
+ }
+ ].
+ </pre>
+
+ <p>Each snmp component has it's own set of configuration parameters,
+ even though some of the types are common to both components. </p>
+
+ <!-- Also in snmp_config.xml -->
+
+ <pre>
+ snmp_components_config() -> [snmp_component_config()]
+ snmp_component_config() -> {agent, agent_options()} | {manager, manager_options()}
+ agent_options() = [agent_option()]
+ agent_option() = {restart_type, restart_type()} |
+ {agent_type, agent_type()} |
+ {agent_verbosity, verbosity()} |
+ {discovery, agent_discovery()} |
+ {versions, versions()} |
+ {priority, priority()} |
+ {multi_threaded, multi_threaded()} |
+ {db_dir, db_dir()} |
+ {db_init_error, db_init_error()} |
+ {local_db, local_db()} |
+ {net_if, agent_net_if()} |
+ {mibs, mibs()} |
+ {mib_storage, mib_storage()} |
+ {mib_server, mib_server()} |
+ {audit_trail_log, audit_trail_log()} |
+ {error_report_mod, error_report_mod()} |
+ {note_store, note_store()} |
+ {symbolic_store, symbolic_store()} |
+ {target_cache, target_cache()} |
+ {config, agent_config()}
+ manager_options() = [manager_option()]
+ manager_option() = {restart_type, restart_type()} |
+ {net_if, manager_net_if()} |
+ {server, server()} |
+ {note_store, note_store()} |
+ {config, manager_config()} |
+ {inform_request_behaviour, manager_irb()} |
+ {mibs, manager_mibs()} |
+ {priority, priority()} |
+ {audit_trail_log, audit_trail_log()} |
+ {versions, versions()} |
+ {def_user_mod, def_user_module() |
+ {def_user_data, def_user_data()}
+ </pre>
+
+ <p>Agent specific config options and types:</p>
+ <taglist>
+ <tag><c><![CDATA[agent_type() = master | sub <optional>]]></c></tag>
+ <item>
+ <p>If <c>master</c>, one master agent is
+ started. Otherwise, no agents are started. </p>
+ <p>Default is <c>master</c>.</p>
+ </item>
+
+ <tag><c><![CDATA[agent_discovery() = [agent_discovery_opt()] <optional>]]></c></tag>
+ <item>
+ <p><c>agent_discovery_opt() =
+ {terminating, agent_terminating_discovery_opts()} |
+ {originating, agent_originating_discovery_opts()}</c></p>
+ <p>The <c>terminating</c> options effects discovery initiated by
+ a manager. </p>
+ <p>The <c>originating</c> options effects discovery initiated
+ by this agent. </p>
+ <p>For defaults see the options in <c>agent_discovery_opt()</c>.</p>
+ </item>
+
+ <tag><c><![CDATA[agent_terminating_discovery_opts() = [agent_terminating_discovery_opt()] <optional>]]></c></tag>
+ <item>
+ <p><c>agent_terminating_discovery_opt() =
+ {enable, boolean()} |
+ {stage2, discovery | plain} |
+ {trigger_username, string()}</c></p>
+ <p>These are options effecting discovery <c>terminating</c> in this
+ agent (i.e. initiated by a manager). </p>
+ <p>The default values for the <c>terminating</c>
+ discovery options are: </p>
+ <list type="bulleted">
+ <item>enable: <c>true</c></item>
+ <item>stage2: <c>discovery</c></item>
+ <item>trigger_username: <c>""</c></item>
+ </list>
+ </item>
+
+ <tag><c><![CDATA[agent_originating_discovery_opts() = [agent_originating_discovery_opt()] <optional>]]></c></tag>
+ <item>
+ <p><c>agent_originating_discovery_opt() =
+ {enable, boolean()}</c></p>
+ <p>These are options effecting discovery <c>originating</c> in this
+ agent. </p>
+ <p>The default values for the <c>originating</c>
+ discovery options are: </p>
+ <list type="bulleted">
+ <item>enable: <c>true</c></item>
+ </list>
+ </item>
+
+ <tag><c><![CDATA[multi_threaded() = bool() <optional>]]></c></tag>
+ <item>
+ <p>If <c>true</c>, the agent is multi-threaded, with one
+ thread for each get request. </p>
+ <p>Default is <c>false</c>.</p>
+ </item>
+
+ <tag><c><![CDATA[db_dir() = string() <mandatory>]]></c></tag>
+ <item>
+ <p>Defines where the SNMP agent internal db files are stored.</p>
+ </item>
+
+ <tag><c><![CDATA[local_db() = [local_db_opt()] <optional>]]></c></tag>
+ <item>
+ <p><c>local_db_opt() = {repair, agent_repair()} | {auto_save, agent_auto_save()} | {verbosity, verbosity()}</c></p>
+ <p>Defines options specific for the SNMP agent local database.</p>
+ <p>For defaults see the options in <c>local_db_opt()</c>.</p>
+ </item>
+
+ <tag><c><![CDATA[agent_repair() = false | true | force <optional>]]></c></tag>
+ <item>
+ <p>When starting snmpa_local_db it always tries to open an
+ existing database. If <c>false</c>, and some errors occur, a new
+ database is created instead. If <c>true</c>, an existing file
+ will be repaired. If <c>force</c>, the table will be repaired
+ even if it was properly closed. </p>
+ <p>Default is <c>true</c>.</p>
+ </item>
+
+ <tag><c><![CDATA[agent_auto_save() = integer() | infinity <optional>]]></c></tag>
+ <item>
+ <p>The auto save interval. The table is flushed to disk
+ whenever not accessed for this amount of time.</p>
+ <p>Default is <c>5000</c>.</p>
+ </item>
+
+ <tag><c><![CDATA[agent_net_if() = [agent_net_if_opt()] <optional>]]></c></tag>
+ <item>
+ <p><c>agent_net_if_opt() = {module, agent_net_if_module()} | {verbosity, verbosity()} | {options, agent_net_if_options()}</c></p>
+ <p>Defines options specific for the SNMP agent network interface
+ entity. </p>
+ <p>For defaults see the options in <c>agent_net_if_opt()</c>.</p>
+ </item>
+
+ <tag><c><![CDATA[agent_net_if_module() = atom() <optional>]]></c></tag>
+ <item>
+ <p>Module which handles the network interface part for the
+ SNMP agent. Must implement the
+ <seealso marker="snmpa_network_interface">snmpa_network_interface</seealso> behaviour.</p>
+ <p>Default is <c>snmpa_net_if</c>.</p>
+ </item>
+
+ <tag><c><![CDATA[agent_net_if_options() = [agent_net_if_option()] <optional>]]></c></tag>
+ <item>
+ <p><c>agent_net_if_option() = {bind_to, bind_to()} |
+ {sndbuf, sndbuf()} |
+ {recbuf, recbuf()} |
+ {no_reuse, no_reuse()} |
+ {req_limit, req_limit()} |
+ {filter, agent_net_if_filter_options()}</c></p>
+ <p>These options are actually specific to the used module.
+ The ones shown here are applicable to the default
+ <c>agent_net_if_module()</c>.</p>
+ <p>For defaults see the options in <c>agent_net_if_option()</c>.</p>
+ </item>
+
+ <tag><c><![CDATA[req_limit() = integer() | infinity <optional>]]></c></tag>
+ <item>
+ <p>Max number of simultaneous requests handled by the agent.</p>
+ <p>Default is <c>infinity</c>.</p>
+ </item>
+
+ <tag><c><![CDATA[agent_net_if_filter_options() = [agent_net_if_filter_option()] <optional>]]></c></tag>
+ <item>
+ <p><c>agent_net_if_filter_option() = {module, agent_net_if_filter_module()}</c></p>
+ <p>These options are actually specific to the used module.
+ The ones shown here are applicable to the default
+ <c><![CDATA[agent_net_if_filter_module()]]></c>.</p>
+ <p>For defaults see the options in
+ <c>agent_net_if_filter_option()</c>.</p>
+ </item>
+
+ <tag><c><![CDATA[agent_net_if_filter_module() = atom() <optional>]]></c></tag>
+ <item>
+ <p>Module which handles the network interface filter part for the
+ SNMP agent. Must implement the
+ <seealso marker="snmpa_network_interface_filter">snmpa_network_interface_filter</seealso> behaviour.</p>
+ <p>Default is <c>snmpa_net_if_filter</c>.</p>
+ </item>
+
+ <tag><c><![CDATA[agent_mibs() = [string()] <optional>]]></c></tag>
+ <item>
+ <p>Specifies a list of MIBs (including path) that defines which MIBs
+ are initially loaded into the SNMP master agent. </p>
+ <p>Note that the following mibs will always be loaded:</p>
+ <list type="bulleted">
+ <item>version v1: <c>STANDARD-MIB</c></item>
+ <item>version v2: <c>SNMPv2</c></item>
+ <item>version v3: <c>SNMPv2</c>, <c>SNMP-FRAMEWORK-MIB</c>
+ and <c>SNMP-MPD-MIB</c></item>
+ </list>
+ <p>Default is <c>[]</c>.</p>
+ </item>
+
+ <tag><c><![CDATA[mib_storage() = ets | {ets, Dir} | {ets, Dir, Action} | dets | {dets, Dir} | {dets, Dir, Action} | mnesia | {mnesia, Nodes} | {mnesia, Nodes, Action} <optional>]]></c></tag>
+ <item>
+ <p>Specifies how info retrieved from the mibs will be stored.</p>
+ <p>If <c>mib_storage</c> is <c>{ets, Dir}</c>, the table will also be
+ stored on file. If <c>Dir</c> is <c>default</c>, then <c>db_dir</c>
+ will be used.</p>
+ <p>If <c>mib_storage</c> is <c>dets</c> or if <c>Dir</c> is
+ <c>default</c>, then <c>db_dir</c> will be used for <c>Dir</c>.</p>
+ <p>If <c>mib_storage</c> is <c>mnesia</c> then <c>erlang:nodes()</c>
+ will be used for <c>Nodes</c>.</p>
+ <p>Default is <c>ets</c>. </p>
+ <p><c>Dir = default | string()</c>. Dir is the directory where the
+ files will be stored. If <c>default</c>, then <c>db_dir</c> will be
+ used.</p>
+ <p><c>Nodes = visible | connected | [node()]</c>.
+ <c>Nodes = visible</c> is translated to
+ <c>erlang:nodes(visible)</c>.
+ <c>Nodes = connected</c> is translated to
+ <c>erlang:nodes(connected)</c>.
+ If <c>Nodes = []</c> then the own node is assumed.</p>
+ <p><c>Action = clear | keep</c>. Default is <c>keep</c>.
+ <c>Action</c> is used to specify what shall be done if the
+ mnesia/dets table already exist.</p>
+ </item>
+
+ <tag><c><![CDATA[mib_server() = [mib_server_opt()] <optional>]]></c></tag>
+ <item>
+ <p><c>mib_server_opt() = {mibentry_override, mibentry_override()} | {trapentry_override, trapentry_override()} | {verbosity, verbosity()} | {cache, mibs_cache()}</c></p>
+ <p>Defines options specific for the SNMP agent mib server. </p>
+ <p>For defaults see the options in <c>mib_server_opt()</c>.</p>
+ </item>
+
+ <tag><c><![CDATA[mibentry_override() = bool() <optional>]]></c></tag>
+ <item>
+ <p>If this value is false, then when loading a mib each mib-
+ entry is checked prior to installation of the mib.
+ The purpose of the check is to prevent that the same symbolic
+ mibentry name is used for different oid's.</p>
+ <p>Default is <c>false</c>.</p>
+ </item>
+
+ <tag><c><![CDATA[trapentry_override() = bool() <optional>]]></c></tag>
+ <item>
+ <p>If this value is false, then when loading a mib each trap
+ is checked prior to installation of the mib.
+ The purpose of the check is to prevent that the same symbolic
+ trap name is used for different trap's.</p>
+ <p>Default is <c>false</c>.</p>
+ </item>
+
+ <tag><c><![CDATA[mibs_cache() = bool() | mibs_cache_opts() <optional>]]></c></tag>
+ <item>
+ <p>Shall the agent utilize the mib server lookup cache or not.</p>
+ <p>Default is <c>true</c> (in which case the <c>mibs_cache_opts()</c>
+ default values apply).</p>
+ </item>
+
+ <tag><c><![CDATA[mibs_cache_opts() = [mibs_cache_opt()] <optional>]]></c></tag>
+ <item>
+ <p><c>mibs_cache_opt() = {autogc, mibs_cache_autogc()} | {gclimit, mibs_cache_gclimit()} | {age, mibs_cache_age()}</c></p>
+ <p>Defines options specific for the SNMP agent mib server cache. </p>
+ <p>For defaults see the options in <c>mibs_cache_opt()</c>.</p>
+ </item>
+
+ <tag><c><![CDATA[mibs_cache_autogc() = bool() <optional>]]></c></tag>
+ <item>
+ <p>Defines if the mib server shall perform cache gc automatically or
+ leave it to the user (see
+ <seealso marker="snmpa#gc_mibs_cache">gc_mibs_cache/0,1,2,3</seealso>). </p>
+ <p>Default is <c>false</c>.</p>
+ </item>
+
+ <tag><c><![CDATA[mibs_cache_age() = integer() > 0 <optional>]]></c></tag>
+ <item>
+ <p>Defines how old the entries in the cache will be allowed before
+ they are GC'ed (assuming GC is performed). Each entry in the
+ cache is "touched" whenever it is accessed. </p>
+ <p>The age is defined in milliseconds. </p>
+ <p>Default is <c>10 timutes</c>.</p>
+ </item>
+
+ <tag><c><![CDATA[mibs_cache_gclimit() = integer() > 0 | infinity <optional>]]></c></tag>
+ <item>
+ <p>When performing a GC, this is the max number of cache entries
+ that will be deleted from the cache. </p>
+ <p>The reason for having this limit is that if the cache is
+ large, the GC can potentially take a long time, during which
+ the agent is locked. </p>
+ <p>Default is <c>100</c>.</p>
+ </item>
+
+ <tag><c><![CDATA[error_report_mod() = atom() <optional>]]></c></tag>
+ <item>
+ <p>Defines an error report module, implementing the
+ <seealso marker="snmpa_error_report">snmpa_error_report</seealso>
+ behaviour. Two modules are provided with the toolkit:
+ <c>snmpa_error_logger</c> and <c>snmpa_error_io</c>.</p>
+ <p>Default is <c>snmpa_error_logger</c>.</p>
+ </item>
+
+ <tag><c>symbolic_store() = [symbolic_store_opt()]</c></tag>
+ <item>
+ <p><c>symbolic_store_opt() = {verbosity, verbosity()}</c></p>
+ <p>Defines options specific for the SNMP agent symbolic store. </p>
+ <p>For defaults see the options in <c>symbolic_store_opt()</c>.</p>
+ </item>
+
+ <tag><c>target_cache() = [target_cache_opt()]</c></tag>
+ <item>
+ <p><c>target_cache_opt() = {verbosity, verbosity()}</c></p>
+ <p>Defines options specific for the SNMP agent target cache. </p>
+ <p>For defaults see the options in <c>target_cache_opt()</c>.</p>
+ </item>
+ <tag><c><![CDATA[agent_config() = [agent_config_opt()] <mandatory>]]></c></tag>
+ <item>
+ <p><c>agent_config_opt() = {dir, agent_config_dir()} | {force_load, force_load()} | {verbosity, verbosity()}</c></p>
+ <p>Defines specific config related options for the SNMP agent. </p>
+ <p>For defaults see the options in <c>agent_config_opt()</c>.</p>
+ </item>
+ <tag><c><![CDATA[agent_config_dir = dir() <mandatory>]]></c></tag>
+ <item>
+ <p>Defines where the SNMP agent configuration files are stored.</p>
+ </item>
+
+ <tag><c><![CDATA[force_load() = bool() <optional>]]></c></tag>
+ <item>
+ <p>If <c>true</c> the configuration files are re-read
+ during start-up, and the contents of the configuration
+ database ignored. Thus, if <c>true</c>, changes to
+ the configuration database are lost upon reboot of the
+ agent. </p>
+ <p>Default is <c>false</c>.</p>
+ </item>
+ </taglist>
+
+ <p>Manager specific config options and types:</p>
+ <taglist>
+ <tag><c><![CDATA[server() = [server_opt()] <optional>]]></c></tag>
+ <item>
+ <p><c>server_opt() = {timeout, server_timeout()} | {verbosity, verbosity()}</c></p>
+ <p>Specifies the options for the manager server process.</p>
+ <p>Default is <c>silence</c>.</p>
+ </item>
+ <tag><c><![CDATA[server_timeout() = integer() <optional>]]></c></tag>
+ <item>
+ <p>Asynchroneous request cleanup time. For every requests,
+ some info is stored internally, in order to be able to
+ deliver the reply (when it arrives) to the proper destination.
+ If the reply arrives, this info will be deleted. But if
+ there is no reply (in time), the info has to be deleted
+ after the <em>best before</em> time has been passed.
+ This cleanup will be performed at regular intervals, defined
+ by the <c>server_timeout()</c> time.
+ The information will have an <em>best before</em> time,
+ defined by the <c>Expire</c> time given when calling the
+ request function (see
+ <seealso marker="snmpm#async_get">async_get</seealso>,
+ <seealso marker="snmpm#async_get_next">async_get_next</seealso> and
+ <seealso marker="snmpm#async_set">async_set</seealso>).</p>
+ <p>Time in milli-seconds.</p>
+ <p>Default is <c>30000</c>.</p>
+ </item>
+
+ <tag><c><![CDATA[manager_config() = [manager_config_opt()] <mandatory>]]></c></tag>
+ <item>
+ <p><c>manager_config_opt() = {dir, manager_config_dir()} | {db_dir, manager_db_dir()} | {db_init_error, db_init_error()} | {repair, manager_repair()} | {auto_save, manager_auto_save()} | {verbosity, verbosity()}</c></p>
+ <p>Defines specific config related options for the SNMP manager. </p>
+ <p>For defaults see the options in <c>manager_config_opt()</c>.</p>
+ </item>
+
+ <tag><c><![CDATA[manager_config_dir = dir() <mandatory>]]></c></tag>
+ <item>
+ <p>Defines where the SNMP manager configuration files are stored.</p>
+ </item>
+
+ <tag><c><![CDATA[manager_db_dir = dir() <mandatory>]]></c></tag>
+ <item>
+ <p>Defines where the SNMP manager store persistent data.</p>
+ </item>
+
+ <tag><c><![CDATA[manager_repair() = false | true | force <optional>]]></c></tag>
+ <item>
+ <p>Defines the repair option for the persistent database (if
+ and how the table is repaired when opened). </p>
+ <p>Default is <c>true</c>.</p>
+ </item>
+
+ <tag><c><![CDATA[manager_auto_save() = integer() | infinity <optional>]]></c></tag>
+ <item>
+ <p>The auto save interval. The table is flushed to disk
+ whenever not accessed for this amount of time.</p>
+ <p>Default is <c>5000</c>.</p>
+ </item>
+
+ <tag><c><![CDATA[manager_irb() = auto | user | {user, integer()} <optional>]]></c></tag>
+ <item>
+ <p>This option defines how the manager will handle the sending of
+ response (acknowledgment) to received inform-requests. </p>
+ <list type="bulleted">
+ <item>
+ <p><c>auto</c> - The manager will autonomously send response
+ (acknowledgment&gt; to inform-request messages.</p>
+ </item>
+ <item>
+ <p><c>{user, integer()}</c> - The manager will send response
+ (acknowledgment) to inform-request messages when the
+ <seealso marker="snmpm_user#handle_inform">handle_inform</seealso>
+ function completes. The integer is the time, in milli-seconds,
+ that the manager will consider the stored inform-request info
+ valid.</p>
+ </item>
+ <item>
+ <p><c>user</c> - Same as <c>{user, integer()}</c>, except that
+ the default time, 15 seconds (15000), is used.</p>
+ </item>
+ </list>
+ <p>See
+ <seealso marker="snmpm_network_interface">snmpm_network_interface</seealso>,
+ <seealso marker="snmpm_user">handle_inform</seealso> and
+ <seealso marker="snmp_manager_netif">definition of the manager net if</seealso> for more info.</p>
+ <p>Default is <c>auto</c>.</p>
+ </item>
+
+ <tag><c><![CDATA[manager_mibs() = [string()] <optional>]]></c></tag>
+ <item>
+ <p>Specifies a list of MIBs (including path) and defines which MIBs
+ are initially loaded into the SNMP manager. </p>
+ <p>Default is <c>[]</c>.</p>
+ </item>
+
+ <tag><c><![CDATA[manager_net_if() = [manager_net_if_opt()] <optional>]]></c></tag>
+ <item>
+ <p><c>manager_net_if_opt() = {module, manager_net_if_module()} |
+ {verbosity, verbosity()} |
+ {options, manager_net_if_options()}</c></p>
+ <p>Defines options specific for the SNMP manager network interface
+ entity. </p>
+ <p>For defaults see the options in <c>manager_net_if_opt()</c>.</p>
+ </item>
+
+ <tag><c><![CDATA[manager_net_if_options() = [manager_net_if_option()] <optional>]]></c></tag>
+ <item>
+ <p><c>manager_net_if_option() = {bind_to, bind_to()} |
+ {sndbuf, sndbuf()} |
+ {recbuf, recbuf()} |
+ {no_reuse, no_reuse()} |
+ {filter, manager_net_if_filter_options()} </c></p>
+ <p>These options are actually specific to the used module.
+ The ones shown here are applicable to the default
+ <c>manager_net_if_module()</c>.</p>
+ <p>For defaults see the options in <c>manager_net_if_option()</c>.</p>
+ </item>
+
+ <tag><c><![CDATA[manager_net_if_module() = atom() <optional>]]></c></tag>
+ <item>
+ <p>Module which handles the network interface part for the
+ SNMP manager. Must implement the
+ <seealso marker="snmpm_network_interface">snmpm_network_interface</seealso> behaviour.</p>
+ <p>Default is <c>snmpm_net_if</c>.</p>
+ </item>
+
+ <tag><c><![CDATA[manager_net_if_filter_options() = [manager_net_if_filter_option()] <optional>]]></c></tag>
+ <item>
+ <p><c>manager_net_if_filter_option() = {module, manager_net_if_filter_module()}</c></p>
+ <p>These options are actually specific to the used module.
+ The ones shown here are applicable to the default
+ <c><![CDATA[manager_net_if_filter_module()]]></c>.</p>
+ <p>For defaults see the options in
+ <c>manager_net_if_filter_option()</c>.</p>
+ </item>
+
+ <tag><c><![CDATA[manager_net_if_filter_module() = atom() <optional>]]></c></tag>
+ <item>
+ <p>Module which handles the network interface filter part for the
+ SNMP manager. Must implement the
+ <seealso marker="snmpm_network_interface_filter">snmpm_network_interface_filter</seealso> behaviour.</p>
+ <p>Default is <c>snmpm_net_if_filter</c>.</p>
+ </item>
+
+ <tag><c><![CDATA[def_user_module() = atom() <optional>]]></c></tag>
+ <item>
+ <p>The module implementing the default user. See the
+ <seealso marker="snmpm_user">snmpm_user</seealso> behaviour.</p>
+ <p>Default is <c>snmpm_user_default</c>.</p>
+ </item>
+
+ <tag><c><![CDATA[def_user_data() = term() <optional>]]></c></tag>
+ <item>
+ <p>Data for the default user. Passed to the user module when
+ calling the callback functions.</p>
+ <p>Default is <c>undefined</c>.</p>
+ </item>
+ </taglist>
+
+ <p>Common config types:</p>
+ <taglist>
+ <tag><c>restart_type() = permanent | transient | temporary</c></tag>
+ <item>
+ <p>See <seealso marker="stdlib:supervisor#child_spec">supervisor</seealso>
+ documentation for more info.</p>
+ <p>Default is <c>permanent</c> for the agent and <c>transient</c>
+ for the manager.</p>
+ </item>
+ <tag><c>db_init_error() = terminate | create</c></tag>
+ <item>
+ <p>Defines what to do if the agent or manager is unable to open an
+ existing database file. <c>terminate</c> means that the
+ agent/manager will terminate and <c>create</c> means that the
+ agent/manager will remove the faulty file(s) and create new ones.</p>
+ <p>Default is <c>terminate</c>.</p>
+ </item>
+ <tag><c><![CDATA[priority() = atom() <optional>]]></c></tag>
+ <item>
+ <p>Defines the Erlang priority for all SNMP processes.</p>
+ <p>Default is <c>normal</c>.</p>
+ </item>
+ <tag><c><![CDATA[versions() = [version()] <optional>]]></c></tag>
+ <item>
+ <p><c>version() = v1 | v2 | v3</c></p>
+ <p>Which SNMP versions shall be accepted/used.</p>
+ <p>Default is <c>[v1,v2,v3]</c>.</p>
+ </item>
+ <tag><c><![CDATA[verbosity() = silence | info | log | debug | trace <optional>]]></c></tag>
+ <item>
+ <p>Verbosity for a SNMP process. This specifies now much debug info
+ is printed.</p>
+ <p>Default is <c>silence</c>.</p>
+ </item>
+ <tag><c><![CDATA[bind_to() = bool() <optional>]]></c></tag>
+ <item>
+ <p>If <c>true</c>, net_if binds to the IP address.
+ If <c>false</c>, net_if listens on any IP address on the host
+ where it is running. </p>
+ <p>Default is <c>false</c>.</p>
+ </item>
+ <tag><c><![CDATA[no_reuse() = bool() <optional>]]></c></tag>
+ <item>
+ <p>If <c>true</c>, net_if does not specify that the IP
+ and port address should be reusable. If <c>false</c>,
+ the address is set to reusable. </p>
+ <p>Default is <c>false</c>.</p>
+ </item>
+ <tag><c><![CDATA[recbuf() = integer() <optional>]]></c></tag>
+ <item>
+ <p>Receive buffer size. </p>
+ <p>Default value is defined by <c>gen_udp</c>.</p>
+ </item>
+ <tag><c><![CDATA[sndbuf() = integer() <optional>]]></c></tag>
+ <item>
+ <p>Send buffer size. </p>
+ <p>Default value is defined by <c>gen_udp</c>.</p>
+ </item>
+ <tag><c><![CDATA[note_store() = [note_store_opt()] <optional>]]></c></tag>
+ <item>
+ <p><c>note_store_opt() = {timeout, note_store_timeout()} | {verbosity, verbosity()}</c></p>
+ <p>Specifies the start-up verbosity for the SNMP note store.</p>
+ <p>For defaults see the options in <c>note_store_opt()</c>.</p>
+ </item>
+ <tag><c><![CDATA[note_store_timeout() = integer() <optional>]]></c></tag>
+ <item>
+ <p>Note cleanup time. When storing a note in the note store,
+ each note is given lifetime. Every <c>timeout</c> the note_store
+ process performs a GC to remove the expired note's. Time in
+ milli-seconds.</p>
+ <p>Default is <c>30000</c>.</p>
+ </item>
+ <tag><c><![CDATA[audit_trail_log() = [audit_trail_log_opt()] <optional>]]></c></tag>
+ <item>
+ <p><c>audit_trail_log_opt() = {type, atl_type()} | {dir, atl_dir()} | {size, atl_size()} | {repair, atl_repair()}</c></p>
+ <p>If present, this option specifies the options for the
+ audit trail logging. The <c>disk_log</c> module is used
+ to maintain a wrap log. If present, the <c>dir</c> and
+ <c>size</c> options are mandatory.</p>
+ <p>If not present, audit trail logging is not used.</p>
+ </item>
+ <tag><c><![CDATA[atl_type() = read | write | read_write <optional>]]></c></tag>
+ <item>
+ <p>Specifies what type of an audit trail log should be used.
+ The effect of the type is actually different for the the agent
+ and the manager. </p>
+ <p>For the agent:</p>
+ <list type="bulleted">
+ <item>If <c>write</c> is specified, only set requests are logged. </item>
+ <item>If <c>read</c> is specified, only get requests are logged. </item>
+ <item>If <c>read_write</c>, all requests are logged. </item>
+ </list>
+ <p>For the manager:</p>
+ <list type="bulleted">
+ <item>If <c>write</c> is specified, only sent messages are logged. </item>
+ <item>If <c>read</c> is specified, only received messages are logged. </item>
+ <item>If <c>read_write</c>, both outgoing and incoming messages are
+ logged. </item>
+ </list>
+ <p>Default is <c>read_write</c>.</p>
+ </item>
+ <tag><c><![CDATA[atl_dir = dir() <mandatory>]]></c></tag>
+ <item>
+ <p>Specifies where the audit trail log should be stored.</p>
+ <p>If <c>audit_trail_log</c> specifies that logging should take
+ place, this parameter <em>must</em> be defined.</p>
+ </item>
+ <tag><c><![CDATA[atl_size() = {integer(), integer()} <mandatory>]]></c></tag>
+ <item>
+ <p>Specifies the size of the audit
+ trail log. This parameter is sent to <c>disk_log</c>. </p>
+ <p>If <c>audit_trail_log</c> specifies that logging should
+ take place, this parameter <em>must</em> be defined.</p>
+ </item>
+ <tag><c><![CDATA[atl_repair() = true | false | truncate | snmp_repair <optional>]]></c></tag>
+ <item>
+ <p>Specifies if and how the audit trail log shall be repaired
+ when opened. Unless this parameter has the value <c>snmp_repair</c>
+ it is sent to <c>disk_log</c>. If, on the other hand, the value is
+ <c>snmp_repair</c>, snmp attempts to handle certain faults on it's
+ own. And even if it cannot repair the file, it does not truncate it
+ directly, but instead <em>moves it aside</em> for later off-line
+ analysis.</p>
+ <p>Default is <c>true</c>.</p>
+ </item>
+ </taglist>
+ </section>
+
+ <section>
+ <title>See Also</title>
+ <p>application(3), disk_log(3)</p>
+ </section>
+
+</appref>
+
diff --git a/lib/snmp/doc/src/snmp_app_a.xml b/lib/snmp/doc/src/snmp_app_a.xml
new file mode 100644
index 0000000000..5192279a45
--- /dev/null
+++ b/lib/snmp/doc/src/snmp_app_a.xml
@@ -0,0 +1,108 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE chapter SYSTEM "chapter.dtd">
+
+<chapter>
+ <header>
+ <copyright>
+ <year>1997</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ 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.
+
+ </legalnotice>
+
+ <title>SNMP Appendix A</title>
+ <prepared></prepared>
+ <responsible></responsible>
+ <docno></docno>
+ <approved></approved>
+ <checked></checked>
+ <date></date>
+ <rev></rev>
+ <file>snmp_app_a.xml</file>
+ </header>
+
+ <section>
+ <title>Appendix A</title>
+ <p>This appendix describes the conversion of SNMPv2 to SNMPv1
+ error messages. The instrumentation functions should return v2
+ error messages.
+ </p>
+ <p>Mapping of SNMPv2 error message to SNMPv1:
+ </p>
+ <table>
+ <row>
+ <cell align="left" valign="middle">SNMPv2 message</cell>
+ <cell align="left" valign="middle">SNMPv1 message</cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle">noError</cell>
+ <cell align="left" valign="middle">noError</cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle">genErr</cell>
+ <cell align="left" valign="middle">genErr</cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle">noAccess</cell>
+ <cell align="left" valign="middle">noSuchName</cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle">wrongType</cell>
+ <cell align="left" valign="middle">badValue</cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle">wrongLength</cell>
+ <cell align="left" valign="middle">badValue</cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle">wrongEncoding</cell>
+ <cell align="left" valign="middle">badValue</cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle">wrongValue</cell>
+ <cell align="left" valign="middle">badValue</cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle">noCreation</cell>
+ <cell align="left" valign="middle">noSuchName</cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle">inconsistentValue</cell>
+ <cell align="left" valign="middle">badValue</cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle">resourceUnavailable</cell>
+ <cell align="left" valign="middle">genErr</cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle">commitFailed</cell>
+ <cell align="left" valign="middle">genErr</cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle">undoFailed</cell>
+ <cell align="left" valign="middle">genErr</cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle">notWritable</cell>
+ <cell align="left" valign="middle">noSuchName</cell>
+ </row>
+ <row>
+ <cell align="left" valign="middle">inconsistentName</cell>
+ <cell align="left" valign="middle">noSuchName</cell>
+ </row>
+ <tcaption>Error Messages</tcaption>
+ </table>
+ </section>
+</chapter>
+
diff --git a/lib/snmp/doc/src/snmp_app_b.xml b/lib/snmp/doc/src/snmp_app_b.xml
new file mode 100644
index 0000000000..536a4b5c6f
--- /dev/null
+++ b/lib/snmp/doc/src/snmp_app_b.xml
@@ -0,0 +1,511 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE chapter SYSTEM "chapter.dtd">
+
+<chapter>
+ <header>
+ <copyright>
+ <year>1997</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ 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.
+
+ </legalnotice>
+
+ <title>SNMP Appendix B</title>
+ <prepared></prepared>
+ <responsible></responsible>
+ <docno></docno>
+ <approved></approved>
+ <checked></checked>
+ <date></date>
+ <rev></rev>
+ <file>snmp_app_b.xml</file>
+ </header>
+
+ <section>
+ <title>Appendix B</title>
+
+ <section>
+ <title>RowStatus (from RFC1903)</title>
+ <pre>
+RowStatus ::= TEXTUAL-CONVENTION
+ STATUS current
+ DESCRIPTION
+ "The RowStatus textual convention is used to manage the
+ creation and deletion of conceptual rows, and is used as the
+ value of the SYNTAX clause for the status column of a
+ conceptual row (as described in Section 7.7.1 in RFC1902.)
+
+ The status column has six defined values:
+
+ - `active', which indicates that the conceptual row is
+ available for use by the managed device;
+
+ - `notInService', which indicates that the conceptual
+ row exists in the agent, but is unavailable for use by
+ the managed device (see NOTE below);
+
+ - `notReady', which indicates that the conceptual row
+ exists in the agent, but is missing information
+ necessary in order to be available for use by the
+ managed device;
+
+ - `createAndGo', which is supplied by a management
+ station wishing to create a new instance of a
+ conceptual row and to have its status automatically set
+ to active, making it available for use by the managed
+ device;
+
+ - `createAndWait', which is supplied by a management
+ station wishing to create a new instance of a
+ conceptual row (but not make it available for use by
+ the managed device); and,
+
+ - `destroy', which is supplied by a management station
+ wishing to delete all of the instances associated with
+ an existing conceptual row.
+
+ Whereas five of the six values (all except `notReady') may
+ be specified in a management protocol set operation, only
+ three values will be returned in response to a management
+ protocol retrieval operation: `notReady', `notInService' or
+ `active'. That is, when queried, an existing conceptual row
+ has only three states: it is either available for use by
+ the managed device (the status column has value `active');
+ it is not available for use by the managed device, though
+ the agent has sufficient information to make it so (the
+ status column has value `notInService'); or, it is not
+ available for use by the managed device, and an attempt to
+ make it so would fail because the agent has insufficient
+ information (the state column has value `notReady').
+
+
+ NOTE WELL
+
+ This textual convention may be used for a MIB table,
+ irrespective of whether the values of that table's
+ conceptual rows are able to be modified while it is
+ active, or whether its conceptual rows must be taken
+ out of service in order to be modified. That is, it is
+ the responsibility of the DESCRIPTION clause of the
+ status column to specify whether the status column must
+ not be `active' in order for the value of some other
+ column of the same conceptual row to be modified. If
+ such a specification is made, affected columns may be
+ changed by an SNMP set PDU if the RowStatus would not
+ be equal to `active' either immediately before or after
+ processing the PDU. In other words, if the PDU also
+ contained a varbind that would change the RowStatus
+ value, the column in question may be changed if the
+ RowStatus was not equal to `active' as the PDU was
+ received, or if the varbind sets the status to a value
+ other than 'active'.
+
+
+ Also note that whenever any elements of a row exist, the
+ RowStatus column must also exist.
+
+ To summarize the effect of having a conceptual row with a
+ status column having a SYNTAX clause value of RowStatus,
+ consider the following state diagram:
+
+
+ STATE
+ +--------------+-----------+-------------+-------------
+ | A | B | C | D
+ | |status col.|status column|
+ |status column | is | is |status column
+ ACTION |does not exist| notReady | notInService| is active
+--------------+--------------+-----------+-------------+-------------
+set status |noError ->D|inconsist- |inconsistent-|inconsistent-
+column to | or | entValue| Value| Value
+createAndGo |inconsistent- | | |
+ | Value| | |
+--------------+--------------+-----------+-------------+-------------
+set status |noError see 1|inconsist- |inconsistent-|inconsistent-
+column to | or | entValue| Value| Value
+createAndWait |wrongValue | | |
+--------------+--------------+-----------+-------------+-------------
+set status |inconsistent- |inconsist- |noError |noError
+column to | Value| entValue| |
+active | | | |
+ | | or | |
+ | | | |
+ | |see 2 ->D| ->D| ->D
+--------------+--------------+-----------+-------------+-------------
+set status |inconsistent- |inconsist- |noError |noError ->C
+column to | Value| entValue| |
+notInService | | | |
+ | | or | | or
+ | | | |
+ | |see 3 ->C| ->C|wrongValue
+--------------+--------------+-----------+-------------+-------------
+set status |noError |noError |noError |noError
+column to | | | |
+destroy | ->A| ->A| ->A| ->A
+--------------+--------------+-----------+-------------+-------------
+set any other |see 4 |noError |noError |see 5
+column to some| | | |
+value | | see 1| ->C| ->D
+--------------+--------------+-----------+-------------+-------------
+
+ (1) goto B or C, depending on information available to the
+ agent.
+
+ (2) if other variable bindings included in the same PDU,
+ provide values for all columns which are missing but
+ required, then return noError and goto D.
+
+ (3) if other variable bindings included in the same PDU,
+ provide values for all columns which are missing but
+ required, then return noError and goto C.
+
+ (4) at the discretion of the agent, the return value may be
+ either:
+
+ inconsistentName: because the agent does not choose to
+ create such an instance when the corresponding
+ RowStatus instance does not exist, or
+
+ inconsistentValue: if the supplied value is
+ inconsistent with the state of some other MIB object's
+ value, or
+
+ noError: because the agent chooses to create the
+ instance.
+
+ If noError is returned, then the instance of the status
+ column must also be created, and the new state is B or C,
+ depending on the information available to the agent. If
+ inconsistentName or inconsistentValue is returned, the row
+ remains in state A.
+
+ (5) depending on the MIB definition for the column/table,
+ either noError or inconsistentValue may be returned.
+
+ NOTE: Other processing of the set request may result in a
+ response other than noError being returned, e.g.,
+ wrongValue, noCreation, etc.
+
+
+ Conceptual Row Creation
+
+ There are four potential interactions when creating a
+ conceptual row: selecting an instance-identifier which is
+ not in use; creating the conceptual row; initializing any
+ objects for which the agent does not supply a default; and,
+ making the conceptual row available for use by the managed
+ device.
+
+
+ Interaction 1: Selecting an Instance-Identifier
+
+ The algorithm used to select an instance-identifier varies
+ for each conceptual row. In some cases, the instance-
+ identifier is semantically significant, e.g., the
+ destination address of a route, and a management station
+ selects the instance-identifier according to the semantics.
+
+ In other cases, the instance-identifier is used solely to
+ distinguish conceptual rows, and a management station
+ without specific knowledge of the conceptual row might
+ examine the instances present in order to determine an
+ unused instance-identifier. (This approach may be used, but
+ it is often highly sub-optimal; however, it is also a
+ questionable practice for a naive management station to
+ attempt conceptual row creation.)
+
+ Alternately, the MIB module which defines the conceptual row
+ might provide one or more objects which provide assistance
+ in determining an unused instance-identifier. For example,
+ if the conceptual row is indexed by an integer-value, then
+ an object having an integer-valued SYNTAX clause might be
+ defined for such a purpose, allowing a management station to
+ issue a management protocol retrieval operation. In order
+ to avoid unnecessary collisions between competing management
+ stations, `adjacent' retrievals of this object should be
+ different.
+
+ Finally, the management station could select a pseudo-random
+ number to use as the index. In the event that this index
+ was already in use and an inconsistentValue was returned in
+ response to the management protocol set operation, the
+ management station should simply select a new pseudo-random
+ number and retry the operation.
+
+ A MIB designer should choose between the two latter
+ algorithms based on the size of the table (and therefore the
+ efficiency of each algorithm). For tables in which a large
+ number of entries are expected, it is recommended that a MIB
+ object be defined that returns an acceptable index for
+ creation. For tables with small numbers of entries, it is
+ recommended that the latter pseudo-random index mechanism be
+ used.
+
+
+ Interaction 2: Creating the Conceptual Row
+
+ Once an unused instance-identifier has been selected, the
+ management station determines if it wishes to create and
+ activate the conceptual row in one transaction or in a
+ negotiated set of interactions.
+
+ Interaction 2a: Creating and Activating the Conceptual Row
+
+ The management station must first determine the column
+ requirements, i.e., it must determine those columns for
+ which it must or must not provide values. Depending on the
+ complexity of the table and the management station's
+ knowledge of the agent's capabilities, this determination
+ can be made locally by the management station. Alternately,
+ the management station issues a management protocol get
+ operation to examine all columns in the conceptual row that
+ it wishes to create. In response, for each column, there
+ are three possible outcomes:
+
+ - a value is returned, indicating that some other
+ management station has already created this conceptual
+ row. We return to interaction 1.
+
+ - the exception `noSuchInstance' is returned,
+ indicating that the agent implements the object-type
+ associated with this column, and that this column in at
+ least one conceptual row would be accessible in the MIB
+ view used by the retrieval were it to exist. For those
+ columns to which the agent provides read-create access,
+ the `noSuchInstance' exception tells the management
+ station that it should supply a value for this column
+ when the conceptual row is to be created.
+
+ - the exception `noSuchObject' is returned, indicating
+ that the agent does not implement the object-type
+ associated with this column or that there is no
+ conceptual row for which this column would be
+ accessible in the MIB view used by the retrieval. As
+ such, the management station cannot issue any
+ management protocol set operations to create an
+ instance of this column.
+
+ Once the column requirements have been determined, a
+ management protocol set operation is accordingly issued.
+ This operation also sets the new instance of the status
+ column to `createAndGo'.
+
+ When the agent processes the set operation, it verifies that
+ it has sufficient information to make the conceptual row
+ available for use by the managed device. The information
+ available to the agent is provided by two sources: the
+ management protocol set operation which creates the
+ conceptual row, and, implementation-specific defaults
+ supplied by the agent (note that an agent must provide
+ implementation-specific defaults for at least those objects
+ which it implements as read-only). If there is sufficient
+ information available, then the conceptual row is created, a
+ `noError' response is returned, the status column is set to
+ `active', and no further interactions are necessary (i.e.,
+ interactions 3 and 4 are skipped). If there is insufficient
+ information, then the conceptual row is not created, and the
+ set operation fails with an error of `inconsistentValue'.
+ On this error, the management station can issue a management
+ protocol retrieval operation to determine if this was
+ because it failed to specify a value for a required column,
+ or, because the selected instance of the status column
+ already existed. In the latter case, we return to
+ interaction 1. In the former case, the management station
+ can re-issue the set operation with the additional
+ information, or begin interaction 2 again using
+ `createAndWait' in order to negotiate creation of the
+ conceptual row.
+
+ NOTE WELL
+
+ Regardless of the method used to determine the column
+ requirements, it is possible that the management
+ station might deem a column necessary when, in fact,
+ the agent will not allow that particular columnar
+ instance to be created or written. In this case, the
+ management protocol set operation will fail with an
+ error such as `noCreation' or `notWritable'. In this
+ case, the management station decides whether it needs
+ to be able to set a value for that particular columnar
+ instance. If not, the management station re-issues the
+ management protocol set operation, but without setting
+ a value for that particular columnar instance;
+ otherwise, the management station aborts the row
+ creation algorithm.
+
+ Interaction 2b: Negotiating the Creation of the Conceptual
+ Row
+
+ The management station issues a management protocol set
+ operation which sets the desired instance of the status
+ column to `createAndWait'. If the agent is unwilling to
+ process a request of this sort, the set operation fails with
+ an error of `wrongValue'. (As a consequence, such an agent
+ must be prepared to accept a single management protocol set
+ operation, i.e., interaction 2a above, containing all of the
+ columns indicated by its column requirements.) Otherwise,
+ the conceptual row is created, a `noError' response is
+ returned, and the status column is immediately set to either
+ `notInService' or `notReady', depending on whether it has
+ sufficient information to make the conceptual row available
+ for use by the managed device. If there is sufficient
+ information available, then the status column is set to
+ `notInService'; otherwise, if there is insufficient
+ information, then the status column is set to `notReady'.
+ Regardless, we proceed to interaction 3.
+
+ Interaction 3: Initializing non-defaulted Objects
+
+ The management station must now determine the column
+ requirements. It issues a management protocol get operation
+ to examine all columns in the created conceptual row. In
+ the response, for each column, there are three possible
+ outcomes:
+
+ - a value is returned, indicating that the agent
+ implements the object-type associated with this column
+ and had sufficient information to provide a value. For
+ those columns to which the agent provides read-create
+ access (and for which the agent allows their values to
+ be changed after their creation), a value return tells
+ the management station that it may issue additional
+ management protocol set operations, if it desires, in
+ order to change the value associated with this column.
+
+ - the exception `noSuchInstance' is returned,
+ indicating that the agent implements the object-type
+ associated with this column, and that this column in at
+ least one conceptual row would be accessible in the MIB
+ view used by the retrieval were it to exist. However,
+ the agent does not have sufficient information to
+ provide a value, and until a value is provided, the
+ conceptual row may not be made available for use by the
+ managed device. For those columns to which the agent
+ provides read-create access, the `noSuchInstance'
+ exception tells the management station that it must
+ issue additional management protocol set operations, in
+ order to provide a value associated with this column.
+
+ - the exception `noSuchObject' is returned, indicating
+ that the agent does not implement the object-type
+ associated with this column or that there is no
+ conceptual row for which this column would be
+ accessible in the MIB view used by the retrieval. As
+ such, the management station cannot issue any
+ management protocol set operations to create an
+ instance of this column.
+
+ If the value associated with the status column is
+ `notReady', then the management station must first deal with
+ all `noSuchInstance' columns, if any. Having done so, the
+ value of the status column becomes `notInService', and we
+ proceed to interaction 4.
+
+ Interaction 4: Making the Conceptual Row Available
+
+ Once the management station is satisfied with the values
+ associated with the columns of the conceptual row, it issues
+ a management protocol set operation to set the status column
+ to `active'. If the agent has sufficient information to
+ make the conceptual row available for use by the managed
+ device, the management protocol set operation succeeds (a
+ `noError' response is returned). Otherwise, the management
+ protocol set operation fails with an error of
+ `inconsistentValue'.
+
+
+ NOTE WELL
+
+ A conceptual row having a status column with value
+ `notInService' or `notReady' is unavailable to the
+ managed device. As such, it is possible for the
+ managed device to create its own instances during the
+ time between the management protocol set operation
+ which sets the status column to `createAndWait' and the
+ management protocol set operation which sets the status
+ column to `active'. In this case, when the management
+ protocol set operation is issued to set the status
+ column to `active', the values held in the agent
+ supersede those used by the managed device.
+
+ If the management station is prevented from setting the
+ status column to `active' (e.g., due to management station
+ or network failure) the conceptual row will be left in the
+ `notInService' or `notReady' state, consuming resources
+ indefinitely. The agent must detect conceptual rows that
+ have been in either state for an abnormally long period of
+ time and remove them. It is the responsibility of the
+ DESCRIPTION clause of the status column to indicate what an
+ abnormally long period of time would be. This period of
+ time should be long enough to allow for human response time
+ (including `think time') between the creation of the
+ conceptual row and the setting of the status to `active'.
+ In the absence of such information in the DESCRIPTION
+ clause, it is suggested that this period be approximately 5
+ minutes in length. This removal action applies not only to
+ newly-created rows, but also to previously active rows which
+ are set to, and left in, the notInService state for a
+ prolonged period exceeding that which is considered normal
+ for such a conceptual row.
+
+
+ Conceptual Row Suspension
+
+ When a conceptual row is `active', the management station
+ may issue a management protocol set operation which sets the
+ instance of the status column to `notInService'. If the
+ agent is unwilling to do so, the set operation fails with an
+ error of `wrongValue'. Otherwise, the conceptual row is
+ taken out of service, and a `noError' response is returned.
+ It is the responsibility of the DESCRIPTION clause of the
+ status column to indicate under what circumstances the
+ status column should be taken out of service (e.g., in order
+ for the value of some other column of the same conceptual
+ row to be modified).
+
+
+ Conceptual Row Deletion
+
+ For deletion of conceptual rows, a management protocol set
+ operation is issued which sets the instance of the status
+ column to `destroy'. This request may be made regardless of
+ the current value of the status column (e.g., it is possible
+ to delete conceptual rows which are either `notReady',
+ `notInService' or `active'.) If the operation succeeds,
+ then all instances associated with the conceptual row are
+ immediately removed."
+
+
+ SYNTAX INTEGER {
+ -- the following two values are states:
+ -- these values may be read or written
+ active(1),
+ notInService(2),
+
+ -- the following value is a state:
+ -- this value may be read, but not written
+ notReady(3),
+
+ -- the following three values are
+ -- actions: these values may be written,
+ -- but are never read
+ createAndGo(4),
+ createAndWait(5),
+ destroy(6)
+ }
+ </pre>
+ </section>
+ </section>
+</chapter>
+
diff --git a/lib/snmp/doc/src/snmp_audit_trail_log.xml b/lib/snmp/doc/src/snmp_audit_trail_log.xml
new file mode 100644
index 0000000000..9a49a0175b
--- /dev/null
+++ b/lib/snmp/doc/src/snmp_audit_trail_log.xml
@@ -0,0 +1,81 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE chapter SYSTEM "chapter.dtd">
+
+<chapter>
+ <header>
+ <copyright>
+ <year>2004</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ 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.
+
+ </legalnotice>
+
+ <title>Audit Trail Log</title>
+ <prepared></prepared>
+ <responsible></responsible>
+ <docno></docno>
+ <approved></approved>
+ <checked></checked>
+ <date></date>
+ <rev></rev>
+ <file>snmp_audit_trail_log.xml</file>
+ </header>
+ <p>The chapter <em>Audit Trail Log</em> describes the audit trail logging.
+ </p>
+ <p>Both the agent and the manager can be configured to log
+ incoming and outgoing messages. It uses the Erlang standard log
+ mechanism <c>disk_log</c> for logging. The size and location of
+ the log files are configurable. A wrap log is used, which means
+ that when the log has grown to a maximum size, it starts from the
+ beginning of the log, overwriting existing log records.
+ </p>
+ <p>The log can be either a <c>read</c>, <c>write</c> or a
+ <c>read_write</c>.
+ </p>
+
+ <section>
+ <title>Agent Logging</title>
+ <p>For the agent, a <c>write</c>, means that all <c>set</c>
+ requests and their responses are stored. No <c>get</c> requests
+ or traps are stored in a <c>write</c>. A <c>read_write</c>,
+ all requests, responses and traps are stored.
+ </p>
+ <p>The log uses a raw data format (basically the BER encoded
+ message), in order to minimize the CPU load needed for the log
+ mechanism. This means that the log is not human readable, but
+ needs to be formatted off-line before it can be read. Use the
+ function
+ <seealso marker="snmpa#log_to_txt">snmpa:log_to_txt</seealso>
+ for this purpose.
+ </p>
+ </section>
+
+ <section>
+ <title>Manager Logging</title>
+ <p>For the manager, a <c>write</c>, means that all
+ requests (<c>set</c> and <c>get</c>) and their responses are stored.
+ No traps are stored in a <c>write</c>. A <c>read_write</c>,
+ all requests, responses and traps are stored.
+ </p>
+ <p>The log uses a raw data format (basically the BER encoded
+ message), in order to minimize the CPU load needed for the log
+ mechanism. This means that the log is not human readable, but
+ needs to be formatted off-line before it can be read. Use the
+ function
+ <seealso marker="snmpm#log_to_txt">snmpm:log_to_txt</seealso>
+ for this purpose.
+ </p>
+ </section>
+</chapter>
+
diff --git a/lib/snmp/doc/src/snmp_community_mib.xml b/lib/snmp/doc/src/snmp_community_mib.xml
new file mode 100644
index 0000000000..7c7386af19
--- /dev/null
+++ b/lib/snmp/doc/src/snmp_community_mib.xml
@@ -0,0 +1,136 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE erlref SYSTEM "erlref.dtd">
+
+<erlref>
+ <header>
+ <copyright>
+ <year>1999</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ 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.
+
+ </legalnotice>
+
+ <title>snmp_community_mib</title>
+ <prepared></prepared>
+ <responsible></responsible>
+ <docno></docno>
+ <approved></approved>
+ <checked></checked>
+ <date></date>
+ <rev></rev>
+ <file>snmp_community_mib.xml</file>
+ </header>
+ <module>snmp_community_mib</module>
+ <modulesummary>Instrumentation Functions for SNMP-COMMUNITY-MIB</modulesummary>
+ <description>
+ <p>The module <c>snmp_community_mib</c> implements the instrumentation
+ functions for the
+ SNMP-COMMUNITY-MIB, and functions for configuring the database.
+ </p>
+ <p>The configuration files are described in the SNMP User's Manual.</p>
+ </description>
+ <funcs>
+ <func>
+ <name>configure(ConfDir) -> void()</name>
+ <fsummary>Configure the SNMP-COMMUNITY-MIB</fsummary>
+ <type>
+ <v>ConfDir = string()</v>
+ </type>
+ <desc>
+ <p>This function is called from the supervisor at system
+ start-up.
+ </p>
+ <p>Inserts all data in the configuration files into the
+ database and destroys all old rows with StorageType
+ <c>volatile</c>. The rows created from the configuration file
+ will have StorageType <c>nonVolatile</c>.
+ </p>
+ <p>All <c>snmp</c> counters are set to zero.
+ </p>
+ <p>If an error is found in the configuration file, it is
+ reported using the function <c>config_err/2</c> of the error,
+ report module and the function fails with reason
+ <c>configuration_error</c>.
+ </p>
+ <p><c>ConfDir</c> is a string which points to the directory
+ where the configuration files are found.
+ </p>
+ <p>The configuration file read is: <c>community.conf</c>.
+ </p>
+ </desc>
+ </func>
+ <func>
+ <name>reconfigure(ConfDir) -> void()</name>
+ <fsummary>Configure the SNMP-COMMUNITY-MIB</fsummary>
+ <type>
+ <v>ConfDir = string()</v>
+ </type>
+ <desc>
+ <p>Inserts all data in the configuration files into the
+ database and destroys all old data, including the rows with
+ StorageType <c>nonVolatile</c>. The rows created from the
+ configuration file will have StorageType <c>nonVolatile</c>.
+ </p>
+ <p>Thus, the data in the SNMP-COMMUNITY-MIB, after this
+ function has been called, is from the configuration files.
+ </p>
+ <p>All <c>snmp</c> counters are set to zero.
+ </p>
+ <p>If an error is found in the configuration file, it is
+ reported using the function <c>config_err/2</c> of the error report
+ module, and the function fails with reason
+ <c>configuration_error</c>.
+ </p>
+ <p><c>ConfDir</c> is a string which points to the directory
+ where the configuration files are found.
+ </p>
+ <p>The configuration file read is: <c>community.conf</c>.</p>
+ <marker id="add_community"></marker>
+ </desc>
+ </func>
+ <func>
+ <name>add_community(Idx, CommName, SecName, CtxName, TransportTag) -> Ret</name>
+ <fsummary>Added one community</fsummary>
+ <type>
+ <v>Idx = string()</v>
+ <v>CommName = string()</v>
+ <v>SecName = string()</v>
+ <v>CtxName = string()</v>
+ <v>TransportTag = string()</v>
+ <v>Ret = {ok, Key} | {error, Reason}</v>
+ <v>Key = term()</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Adds a community to the agent config.
+ Equivalent to one line in the <c>community.conf</c> file.</p>
+ <marker id="delete_community"></marker>
+ </desc>
+ </func>
+ <func>
+ <name>delete_community(Key) -> Ret</name>
+ <fsummary>Delete one community</fsummary>
+ <type>
+ <v>Key = term()</v>
+ <v>Ret = ok | {error, Reason}</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Delete a community from the agent config.</p>
+ </desc>
+ </func>
+ </funcs>
+
+</erlref>
+
diff --git a/lib/snmp/doc/src/snmp_config.xml b/lib/snmp/doc/src/snmp_config.xml
new file mode 100644
index 0000000000..073cdde308
--- /dev/null
+++ b/lib/snmp/doc/src/snmp_config.xml
@@ -0,0 +1,1030 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE chapter SYSTEM "chapter.dtd">
+
+<chapter>
+ <header>
+ <copyright>
+ <year>1997</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ 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.
+
+ </legalnotice>
+
+ <title>Running the application</title>
+ <prepared></prepared>
+ <responsible></responsible>
+ <docno></docno>
+ <approved></approved>
+ <checked></checked>
+ <date></date>
+ <rev></rev>
+ <file>snmp_config.xml</file>
+ </header>
+ <p>The chapter <em>Running the application</em> describes how the
+ application is configured and started.
+ The topics include:</p>
+ <list type="bulleted">
+ <item>configuration directories and parameters</item>
+ <item>modifying the configuration files</item>
+ <item>starting the application (agent and/or manager)</item>
+ <item>debugging the application (agent and/or manager)</item>
+ </list>
+ <p>Refer also to the chapter(s)
+ <seealso marker="snmp_agent_config_files">Definition of Agent Configuration Files</seealso> and
+ <seealso marker="snmp_manager_config_files">Definition of Manager Configuration Files</seealso> which contains more detailed information
+ about the agent and manager configuration files.</p>
+
+ <section>
+ <marker id="configuration_params"></marker>
+ <title>Configuring the application</title>
+ <p>The following two directories must exist in the system
+ to run the agent:</p>
+ <list type="bulleted">
+ <item>
+ <p>the <em>configuration directory</em> stores all
+ configuration files used by the agent (refer to the chapter
+ <seealso marker="snmp_agent_config_files">Definition of Agent Configuration Files</seealso> for more information). </p>
+ </item>
+ <item>the <em>database directory</em> stores the internal
+ database files.</item>
+ </list>
+ <p>The following directory must exist in the system
+ to run the manager:</p>
+ <list type="bulleted">
+ <item>
+ <p>the <em>configuration directory</em> stores all
+ configuration files used by the manager (refer to the chapter
+ <seealso marker="snmp_manager_config_files">Definition of Manager Configuration Files</seealso> for more information). </p>
+ </item>
+ <item>
+ <p>the <em>database directory</em> stores the internal
+ database files. </p>
+ </item>
+ </list>
+
+ <p>The agent and manager uses (application) configuration parameters to
+ find out where these directories are located. The parameters should be
+ defined in an Erlang system configuration file. The following
+ configuration parameters are defined for the SNMP application:</p>
+
+ <!-- Also in snmp_app.xml -->
+
+ <pre>
+ agent_options() = [agent_option()]
+ agent_option() = {restart_type, restart_type()} |
+ {agent_type, agent_type()} |
+ {agent_verbosity, verbosity()} |
+ {versions, versions()} |
+ {discovery, agent_discovery()} |
+ {priority, priority()} |
+ {multi_threaded, multi_threaded()} |
+ {db_dir, db_dir()} |
+ {db_init_error, db_init_error()} |
+ {local_db, local_db()} |
+ {net_if, agent_net_if()} |
+ {mibs, mibs()} |
+ {mib_storage, mib_storage()} |
+ {mib_server, mib_server()} |
+ {audit_trail_log, audit_trail_log()} |
+ {error_report_mod, error_report_mod()} |
+ {note_store, note_store()} |
+ {symbolic_store, symbolic_store()} |
+ {target_cache, target_cache()} |
+ {config, agent_config()}
+ manager_options() = [manager_option()]
+ manager_option() = {restart_type, restart_type()} |
+ {net_if, manager_net_if()} |
+ {server, server()} |
+ {note_store, note_store()} |
+ {config, manager_config()} |
+ {inform_request_behaviour, manager_irb()} |
+ {mibs, manager_mibs()} |
+ {priority, priority()} |
+ {audit_trail_log, audit_trail_log()} |
+ {versions, versions()} |
+ {def_user_mod, def_user_module() |
+ {def_user_data, def_user_data()}
+ </pre>
+
+ <p>Agent specific config options and types:</p>
+ <taglist>
+ <tag><c><![CDATA[agent_type() = master | sub <optional>]]></c></tag>
+ <item>
+ <p>If <c>master</c>, one master agent is
+ started. Otherwise, no agents are started. </p>
+ <p>Default is <c>master</c>.</p>
+ </item>
+
+ <tag><c><![CDATA[agent_discovery() = [agent_discovery_opt()] <optional>]]></c></tag>
+ <item>
+ <p><c>agent_discovery_opt() =
+ {terminating, agent_terminating_discovery_opts()} |
+ {originating, agent_originating_discovery_opts()}</c></p>
+ <p>The <c>terminating</c> options effects discovery initiated by
+ a manager. </p>
+ <p>The <c>originating</c> options effects discovery initiated
+ by this agent. </p>
+ <p>For defaults see the options in <c>agent_discovery_opt()</c>.</p>
+ </item>
+
+ <tag><c><![CDATA[agent_terminating_discovery_opts() = [agent_terminating_discovery_opt()] <optional>]]></c></tag>
+ <item>
+ <p><c>agent_terminating_discovery_opt() =
+ {enable, boolean()} |
+ {stage2, discovery | plain} |
+ {trigger_username, string()}</c></p>
+ <p>These are options effecting discovery <c>terminating</c> in this
+ agent (i.e. initiated by a manager). </p>
+ <p>The default values for the <c>terminating</c>
+ discovery options are: </p>
+ <list type="bulleted">
+ <item>enable: <c>true</c></item>
+ <item>stage2: <c>discovery</c></item>
+ <item>trigger_username: <c>""</c></item>
+ </list>
+ </item>
+
+ <tag><c><![CDATA[agent_originating_discovery_opts() = [agent_originating_discovery_opt()] <optional>]]></c></tag>
+ <item>
+ <p><c>agent_originating_discovery_opt() =
+ {enable, boolean()}</c></p>
+ <p>These are options effecting discovery <c>originating</c> in this
+ agent. </p>
+ <p>The default values for the <c>originating</c>
+ discovery options are: </p>
+ <list type="bulleted">
+ <item>enable: <c>true</c></item>
+ </list>
+ </item>
+
+ <tag><c><![CDATA[multi_threaded() = bool() <optional>]]></c></tag>
+ <item>
+ <p>If <c>true</c>, the agent is multi-threaded, with one
+ thread for each get request. </p>
+ <p>Default is <c>false</c>.</p>
+ </item>
+
+ <tag><c><![CDATA[db_dir() = string() <mandatory>]]></c></tag>
+ <item>
+ <p>Defines where the SNMP agent internal db files are stored.</p>
+ </item>
+
+ <tag><c><![CDATA[local_db() = [local_db_opt()] <optional>]]></c></tag>
+ <item>
+ <p><c>local_db_opt() = {repair, agent_repair()} | {auto_save, agent_auto_save()} | {verbosity, verbosity()}</c></p>
+ <p>Defines options specific for the SNMP agent local database.</p>
+ <p>For defaults see the options in <c>local_db_opt()</c>.</p>
+ </item>
+
+ <tag><c><![CDATA[agent_repair() = false | true | force <optional>]]></c></tag>
+ <item>
+ <p>When starting snmpa_local_db it always tries to open an
+ existing database. If <c>false</c>, and some errors occur, a new
+ database is created instead. If <c>true</c>, an existing file
+ will be repaired. If <c>force</c>, the table will be repaired
+ even if it was properly closed. </p>
+ <p>Default is <c>true</c>.</p>
+ </item>
+
+ <tag><c><![CDATA[agent_auto_save() = integer() | infinity <optional>]]></c></tag>
+ <item>
+ <p>The auto save interval. The table is flushed to disk
+ whenever not accessed for this amount of time.</p>
+ <p>Default is <c>5000</c>.</p>
+ </item>
+
+ <tag><c><![CDATA[agent_net_if() = [agent_net_if_opt()] <optional>]]></c></tag>
+ <item>
+ <p><c>agent_net_if_option() = {module, agent_net_if_module()} |
+ {verbosity, verbosity()} |
+ {options, agent_net_if_options()}</c></p>
+ <p>Defines options specific for the SNMP agent network interface
+ entity. </p>
+ <p>For defaults see the options in <c>agent_net_if_opt()</c>.</p>
+ </item>
+
+ <tag><c><![CDATA[agent_net_if_module() = atom() <optional>]]></c></tag>
+ <item>
+ <p>Module which handles the network interface part for the
+ SNMP agent. Must implement the
+ <seealso marker="snmpa_network_interface">snmpa_network_interface</seealso> behaviour.</p>
+ <p>Default is <c>snmpa_net_if</c>.</p>
+ </item>
+
+ <tag><c><![CDATA[agent_net_if_options() = [agent_net_if_option()] <optional>]]></c></tag>
+ <item>
+ <p><c>agent_net_if_option() = {bind_to, bind_to()} |
+ {sndbuf, sndbuf()} |
+ {recbuf, recbuf()} |
+ {no_reuse, no_reuse()} |
+ {req_limit, req_limit()} |
+ {filter, agent_net_if_filter_options()}</c></p>
+ <p>These options are actually specific to the used module.
+ The ones shown here are applicable to the default
+ <c>agent_net_if_module()</c>.</p>
+ <p>For defaults see the options in <c>agent_net_if_option()</c>.</p>
+ </item>
+
+ <tag><c><![CDATA[agent_net_if_filter_options() = [agent_net_if_filter_option()] <optional>]]></c></tag>
+ <item>
+ <p><c><![CDATA[agent_net_if_filter_option() = {module, agent_net_if_filter_module()}]]></c></p>
+ <p>These options are actually specific to the used module.
+ The ones shown here are applicable to the default
+ <c>agent_net_if_filter_module()</c>.</p>
+ <p>For defaults see the options in <c>agent_net_if_filter_option()</c>.</p>
+ </item>
+
+ <tag><c><![CDATA[agent_net_if_filter_module() = atom() <optional>]]></c></tag>
+ <item>
+ <p>Module which handles the network interface filter part for the
+ SNMP agent. Must implement the
+ <seealso marker="snmpa_network_interface_filter">snmpa_network_interface_filter
+ </seealso> behaviour.</p>
+ <p>Default is <c>snmpa_net_if_filter</c>.</p>
+ </item>
+
+ <tag><c><![CDATA[req_limit() = integer() | infinity <optional>]]></c></tag>
+ <item>
+ <p>Max number of simultaneous requests handled by the agent.</p>
+ <p>Default is <c>infinity</c>.</p>
+ </item>
+
+ <tag><c><![CDATA[agent_mibs() = [string()] <optional>]]></c></tag>
+ <item>
+ <p>Specifies a list of MIBs (including path) that defines which MIBs
+ are initially loaded into the SNMP master agent. </p>
+ <p>Note that the following will always be loaded:</p>
+ <list type="bulleted">
+ <item>version v1: <c>STANDARD-MIB</c></item>
+ <item>version v2: <c>SNMPv2</c></item>
+ <item>version v3: <c>SNMPv2</c>, <c>SNMP-FRAMEWORK-MIB</c>
+ and <c>SNMP-MPD-MIB</c></item>
+ </list>
+ <p>Default is <c>[]</c>.</p>
+ </item>
+
+ <tag><c><![CDATA[mib_storage() = ets | {ets, Dir} | {ets, Dir, Action} | dets | {dets, Dir} | {dets, Dir, Action} | mnesia | {mnesia, Nodes} | {mnesia, Nodes, Action} <optional>]]></c></tag>
+ <item>
+ <p>Specifies how info retrieved from the mibs will be stored.</p>
+ <p>If <c>mib_storage</c> is <c>{ets, Dir}</c>, the table will also be
+ stored on file. If <c>Dir</c> is <c>default</c>, then <c>db_dir</c>
+ will be used.</p>
+ <p>If <c>mib_storage</c> is <c>dets</c> or if <c>Dir</c> is
+ <c>default</c>, then <c>db_dir</c> will be used for <c>Dir</c>.</p>
+ <p>If <c>mib_storage</c> is <c>mnesia</c> then <c>erlang:nodes()</c>
+ will be used for <c>Nodes</c>.</p>
+ <p>Default is <c>ets</c>. </p>
+ <p><c>Dir = default | string()</c>. Dir is the directory where the
+ files will be stored. If <c>default</c>, then <c>db_dir</c> will be
+ used.</p>
+ <p><c>Nodes = visible | connected | [node()]</c>.
+ <c>Nodes = visible</c> is translated to
+ <c>erlang:nodes(visible)</c>.
+ <c>Nodes = connected</c> is translated to
+ <c>erlang:nodes(connected)</c>.
+ If <c>Nodes = []</c> then the own node is assumed.</p>
+ <p><c>Action = clear | keep</c>. Default is <c>keep</c>.
+ <c>Action</c> is used to specify what shall be done if the
+ mnesia/dets table already exist.</p>
+ </item>
+
+ <tag><c><![CDATA[mib_server() = [mib_server_opt()] <optional>]]></c></tag>
+ <item>
+ <p><c>mib_server_opt() = {mibentry_override, mibentry_override()} | {trapentry_override, trapentry_override()} | {verbosity, verbosity()} | {cache, mibs_cache()}</c></p>
+ <p>Defines options specific for the SNMP agent mib server. </p>
+ <p>For defaults see the options in <c>mib_server_opt()</c>.</p>
+ </item>
+
+ <tag><c><![CDATA[mibentry_override() = bool() <optional>]]></c></tag>
+ <item>
+ <p>If this value is false, then when loading a mib each mib-
+ entry is checked prior to installation of the mib.
+ The purpose of the check is to prevent that the same symbolic
+ mibentry name is used for different oid's.</p>
+ <p>Default is <c>false</c>.</p>
+ </item>
+
+ <tag><c><![CDATA[trapentry_override() = bool() <optional>]]></c></tag>
+ <item>
+ <p>If this value is false, then when loading a mib each trap
+ is checked prior to installation of the mib.
+ The purpose of the check is to prevent that the same symbolic
+ trap name is used for different trap's.</p>
+ <p>Default is <c>false</c>.</p>
+ </item>
+
+ <tag><c><![CDATA[mibs_cache() = bool() | mibs_cache_opts() <optional>]]></c></tag>
+ <item>
+ <p>Shall the agent utilize the mib server lookup cache or not.</p>
+ <p>Default is <c>true</c> (in which case the <c>mibs_cache_opts()</c>
+ default values apply).</p>
+ </item>
+
+ <tag><c><![CDATA[mibs_cache_opts() = [mibs_cache_opt()] <optional>]]></c></tag>
+ <item>
+ <p><c>mibs_cache_opt() = {autogc, mibs_cache_autogc()} | {gclimit, mibs_cache_gclimit()} | {age, mibs_cache_age()}</c></p>
+ <p>Defines options specific for the SNMP agent mib server cache. </p>
+ <p>For defaults see the options in <c>mibs_cache_opt()</c>.</p>
+ </item>
+
+ <tag><c><![CDATA[mibs_cache_autogc() = bool() <optional>]]></c></tag>
+ <item>
+ <p>Defines if the mib server shall perform cache gc automatically or
+ leave it to the user (see
+ <seealso marker="snmpa#gc_mibs_cache">gc_mibs_cache/0,1,2,3</seealso>). </p>
+ <p>Default is <c>false</c>.</p>
+ </item>
+
+ <tag><c><![CDATA[mibs_cache_age() = integer() > 0 <optional>]]></c></tag>
+ <item>
+ <p>Defines how old the entries in the cache will be allowed before
+ they are GC'ed (assuming GC is performed). Each entry in the
+ cache is "touched" whenever it is accessed. </p>
+ <p>The age is defined in milliseconds. </p>
+ <p>Default is <c>10 timutes</c>.</p>
+ </item>
+
+ <tag><c><![CDATA[mibs_cache_gclimit() = integer() > 0 | infinity <optional>]]></c></tag>
+ <item>
+ <p>When performing a GC, this is the max number of cache entries
+ that will be deleted from the cache. </p>
+ <p>The reason for having this limit is that if the cache is
+ large, the GC can potentially take a long time, during which
+ the agent is locked. </p>
+ <p>Default is <c>100</c>.</p>
+ </item>
+
+ <tag><c><![CDATA[error_report_mod() = atom() <optional>]]></c></tag>
+ <item>
+ <p>Defines an error report module, implementing the
+ <seealso marker="snmpa_error_report">snmpa_error_report</seealso>
+ behaviour. Two modules are provided with the toolkit:
+ <c>snmpa_error_logger</c> and <c>snmpa_error_io</c>.</p>
+ <p>Default is <c>snmpa_error_logger</c>.</p>
+ </item>
+
+ <tag><c>symbolic_store() = [symbolic_store_opt()]</c></tag>
+ <item>
+ <p><c>symbolic_store_opt() = {verbosity, verbosity()}</c></p>
+ <p>Defines options specific for the SNMP agent symbolic store. </p>
+ <p>For defaults see the options in <c>symbolic_store_opt()</c>.</p>
+ </item>
+
+ <tag><c>target_cache() = [target_cache_opt()]</c></tag>
+ <item>
+ <p><c>target_cache_opt() = {verbosity, verbosity()}</c></p>
+ <p>Defines options specific for the SNMP agent target cache. </p>
+ <p>For defaults see the options in <c>target_cache_opt()</c>.</p>
+ </item>
+ <tag><c><![CDATA[agent_config() = [agent_config_opt()] <mandatory>]]></c></tag>
+ <item>
+ <p><c>agent_config_opt() = {dir, agent_config_dir()} | {force_load, force_load()} | {verbosity, verbosity()}</c></p>
+ <p>Defines specific config related options for the SNMP agent. </p>
+ <p>For defaults see the options in <c>agent_config_opt()</c>.</p>
+ </item>
+
+ <tag><c><![CDATA[agent_config_dir = dir() <mandatory>]]></c></tag>
+ <item>
+ <p>Defines where the SNMP agent configuration files are stored.</p>
+ </item>
+
+ <tag><c><![CDATA[force_load() = bool() <optional>]]></c></tag>
+ <item>
+ <p>If <c>true</c> the configuration files are re-read
+ during start-up, and the contents of the configuration
+ database ignored. Thus, if <c>true</c>, changes to
+ the configuration database are lost upon reboot of the
+ agent. </p>
+ <p>Default is <c>false</c>.</p>
+ </item>
+ </taglist>
+
+ <p>Manager specific config options and types:</p>
+ <taglist>
+ <tag><c><![CDATA[server() = [server_opt()] <optional>]]></c></tag>
+ <item>
+ <p><c>server_opt() = {timeout, server_timeout()} | {verbosity, verbosity()}</c></p>
+ <p>Specifies the options for the manager server process.</p>
+ <p>Default is <c>silence</c>.</p>
+ </item>
+ <tag><c><![CDATA[server_timeout() = integer() <optional>]]></c></tag>
+ <item>
+ <p>Asynchroneous request cleanup time. For every requests,
+ some info is stored internally, in order to be able to
+ deliver the reply (when it arrives) to the proper destination.
+ If the reply arrives, this info will be deleted. But if
+ there is no reply (in time), the info has to be deleted
+ after the <em>best before</em> time has been passed.
+ This cleanup will be performed at regular intervals, defined
+ by the <c>server_timeout()</c> time.
+ The information will have a <em>best before</em> time,
+ defined by the <c>Expire</c> time given when calling the
+ request function (see
+ <seealso marker="snmpm#async_get">async_get</seealso>,
+ <seealso marker="snmpm#async_get_next">async_get_next</seealso> and
+ <seealso marker="snmpm#async_set">async_set</seealso>).</p>
+ <p>Time in milli-seconds.</p>
+ <p>Default is <c>30000</c>.</p>
+ </item>
+
+ <tag><c><![CDATA[manager_config() = [manager_config_opt()] <mandatory>]]></c></tag>
+ <item>
+ <p><c>manager_config_opt() = {dir, manager_config_dir()} | {db_dir, manager_db_dir()} | {db_init_error, db_init_error()} | {repair, manager_repair()} | {auto_save, manager_auto_save()} | {verbosity, verbosity()}</c></p>
+ <p>Defines specific config related options for the SNMP manager. </p>
+ <p>For defaults see the options in <c>manager_config_opt()</c>.</p>
+ </item>
+
+ <tag><c><![CDATA[manager_config_dir = dir() <mandatory>]]></c></tag>
+ <item>
+ <p>Defines where the SNMP manager configuration files are stored.</p>
+ </item>
+
+ <tag><c><![CDATA[manager_db_dir = dir() <mandatory>]]></c></tag>
+ <item>
+ <p>Defines where the SNMP manager store persistent data.</p>
+ </item>
+
+ <tag><c><![CDATA[manager_repair() = false | true | force <optional>]]></c></tag>
+ <item>
+ <p>Defines the repair option for the persistent database (if
+ and how the table is repaired when opened). </p>
+ <p>Default is <c>true</c>.</p>
+ </item>
+
+ <tag><c><![CDATA[manager_auto_save() = integer() | infinity <optional>]]></c></tag>
+ <item>
+ <p>The auto save interval. The table is flushed to disk
+ whenever not accessed for this amount of time.</p>
+ <p>Default is <c>5000</c>.</p>
+ </item>
+
+ <tag><c><![CDATA[manager_irb() = auto | user | {user, integer()} <optional>]]></c></tag>
+ <item>
+ <p>This option defines how the manager will handle the sending of
+ response (acknowledgment) to received inform-requests. </p>
+ <list type="bulleted">
+ <item>
+ <p><c>auto</c> - The manager will autonomously send response
+ (acknowledgment&gt; to inform-request messages.</p>
+ </item>
+ <item>
+ <p><c>{user, integer()}</c> - The manager will send response
+ (acknowledgment) to inform-request messages when the
+ <seealso marker="snmpm_user#handle_inform">handle_inform</seealso>
+ function completes. The integer is the time, in milli-seconds,
+ that the manager will consider the stored inform-request info
+ valid.</p>
+ </item>
+ <item>
+ <p><c>user</c> - Same as <c>{user, integer()}</c>, except that
+ the default time, 15000 milli-seconds, is used.</p>
+ </item>
+ </list>
+ <p>See
+ <seealso marker="snmpm_network_interface">snmpm_network_interface</seealso>,
+ <seealso marker="snmpm_user">handle_inform</seealso> and
+ <seealso marker="snmp_manager_netif">definition of the manager net if</seealso> for more info.</p>
+ <p>Default is <c>auto</c>.</p>
+ </item>
+
+ <tag><c><![CDATA[manager_mibs() = [string()] <optional>]]></c></tag>
+ <item>
+ <p>Specifies a list of MIBs (including path) and defines which MIBs
+ are initially loaded into the SNMP manager. </p>
+ <p>Default is <c>[]</c>.</p>
+ </item>
+
+ <tag><c><![CDATA[manager_net_if() = [manager_net_if_opt()] <optional>]]></c></tag>
+ <item>
+ <p><c>manager_net_if_opt() = {module, manager_net_if_module()} |
+ {verbosity, verbosity()} |
+ {options, manager_net_if_options()}</c></p>
+ <p>Defines options specific for the SNMP manager network interface
+ entity. </p>
+ <p>For defaults see the options in <c>manager_net_if_opt()</c>.</p>
+ </item>
+
+ <tag><c><![CDATA[manager_net_if_options() = [manager_net_if_option()] <optional>]]></c></tag>
+ <item>
+ <p><c>manager_net_if_option() = {bind_to, bind_to()} |
+ {sndbuf, sndbuf()} |
+ {recbuf, recbuf()} |
+ {no_reuse, no_reuse()} |
+ {filter, manager_net_if_filter_options()}</c></p>
+ <p>These options are actually specific to the used module.
+ The ones shown here are applicable to the default
+ <c>manager_net_if_module()</c>.</p>
+ <p>For defaults see the options in <c>manager_net_if_option()</c>.</p>
+ </item>
+
+ <tag><c><![CDATA[manager_net_if_module() = atom() <optional>]]></c></tag>
+ <item>
+ <p>Module which handles the network interface part for the
+ SNMP manager. Must implement the
+ <seealso marker="snmpm_network_interface">snmpm_network_interface</seealso> behaviour.</p>
+ <p>Default is <c>snmpm_net_if</c>.</p>
+ </item>
+
+ <tag><c><![CDATA[manager_net_if_filter_options() = [manager_net_if_filter_option()] <optional>]]></c></tag>
+ <item>
+ <p><c>manager_net_if_filter_option() = {module, manager_net_if_filter_module()}</c></p>
+ <p>These options are actually specific to the used module.
+ The ones shown here are applicable to the default
+ <c><![CDATA[manager_net_if_filter_module()]]></c>.</p>
+ <p>For defaults see the options in
+ <c>manager_net_if_filter_option()</c>.</p>
+ </item>
+
+ <tag><c><![CDATA[manager_net_if_filter_module() = atom() <optional>]]></c></tag>
+ <item>
+ <p>Module which handles the network interface filter part for the
+ SNMP manager. Must implement the
+ <seealso marker="snmpm_network_interface_filter">snmpm_network_interface_filter</seealso> behaviour.</p>
+ <p>Default is <c>snmpm_net_if_filter</c>.</p>
+ </item>
+
+ <tag><c><![CDATA[def_user_module() = atom() <optional>]]></c></tag>
+ <item>
+ <p>The module implementing the default user. See the
+ <seealso marker="snmpm_user">snmpm_user</seealso> behaviour.</p>
+ <p>Default is <c>snmpm_user_default</c>.</p>
+ </item>
+
+ <tag><c><![CDATA[def_user_data() = term() <optional>]]></c></tag>
+ <item>
+ <p>Data for the default user. Passed to the user when calling
+ the callback functions.</p>
+ <p>Default is <c>undefined</c>.</p>
+ </item>
+ </taglist>
+
+ <p>Common config types:</p>
+ <taglist>
+ <tag><c>restart_type() = permanent | transient | temporary</c></tag>
+ <item>
+ <p>See <seealso marker="stdlib:supervisor#child_spec">supervisor</seealso>
+ documentation for more info.</p>
+ <p>Default is <c>permanent</c> for the agent and <c>transient</c>
+ for the manager.</p>
+ </item>
+
+ <tag><c>db_init_error() = terminate | create</c></tag>
+ <item>
+ <p>Defines what to do if the agent is unable to open an
+ existing database file. <c>terminate</c> means that the
+ agent/manager will terminate and <c>create</c> means that the
+ agent/manager will remove the faulty file(s) and create new ones.</p>
+ <p>Default is <c>terminate</c>.</p>
+ </item>
+
+ <tag><c><![CDATA[priority() = atom() <optional>]]></c></tag>
+ <item>
+ <p>Defines the Erlang priority for all SNMP processes.</p>
+ <p>Default is <c>normal</c>.</p>
+ </item>
+
+ <tag><c><![CDATA[versions() = [version()] <optional>]]></c></tag>
+ <item>
+ <p><c>version() = v1 | v2 | v3</c></p>
+ <p>Which SNMP versions shall be accepted/used.</p>
+ <p>Default is <c>[v1,v2,v3]</c>.</p>
+ </item>
+
+ <tag><c><![CDATA[verbosity() = silence | info | log | debug | trace <optional>]]></c></tag>
+ <item>
+ <p>Verbosity for a SNMP process. This specifies now much debug info
+ is printed.</p>
+ <p>Default is <c>silence</c>.</p>
+ </item>
+
+ <tag><c><![CDATA[bind_to() = bool() <optional>]]></c></tag>
+ <item>
+ <p>If <c>true</c>, net_if binds to the IP address.
+ If <c>false</c>, net_if listens on any IP address on the host
+ where it is running. </p>
+ <p>Default is <c>false</c>.</p>
+ </item>
+
+ <tag><c><![CDATA[no_reuse() = bool() <optional>]]></c></tag>
+ <item>
+ <p>If <c>true</c>, net_if does not specify that the IP
+ and port address should be reusable. If <c>false</c>,
+ the address is set to reusable. </p>
+ <p>Default is <c>false</c>.</p>
+ </item>
+
+ <tag><c><![CDATA[recbuf() = integer() <optional>]]></c></tag>
+ <item>
+ <p>Receive buffer size. </p>
+ <p>Default value is defined by <c>gen_udp</c>.</p>
+ </item>
+ <tag><c><![CDATA[sndbuf() = integer() <optional>]]></c></tag>
+ <item>
+ <p>Send buffer size. </p>
+ <p>Default value is defined by <c>gen_udp</c>.</p>
+ </item>
+
+ <tag><c><![CDATA[note_store() = [note_store_opt()] <optional>]]></c></tag>
+ <item>
+ <p><c>note_store_opt() = {timeout, note_store_timeout()} | {verbosity, verbosity()}</c></p>
+ <p>Specifies the options for the SNMP note store.</p>
+ <p>For defaults see the options in <c>note_store_opt()</c>.</p>
+ </item>
+
+ <tag><c><![CDATA[note_store_timeout() = integer() <optional>]]></c></tag>
+ <item>
+ <p>Note cleanup time. When storing a note in the note store,
+ each note is given lifetime. Every <c>timeout</c> the note_store
+ process performs a GC to remove the expired note's. Time in
+ milli-seconds.</p>
+ <p>Default is <c>30000</c>.</p>
+ </item>
+
+ <tag><c><![CDATA[audit_trail_log() [audit_trail_log_opt()] <optional>]]></c></tag>
+ <item>
+ <p><c>audit_trail_log_opt() = {type, atl_type()} | {dir, atl_dir()} | {size, atl_size()} | {repair, atl_repair()}</c></p>
+ <p>If present, this option specifies the options for the
+ <em>audit trail logging</em>. The <c>disk_log</c> module is used
+ to maintain a wrap log. If present, the <c>dir</c> and
+ <c>size</c> options are mandatory.</p>
+ <p>If not present, audit trail logging is not used.</p>
+ </item>
+
+ <tag><c><![CDATA[atl_type() = read | write | read_write <optional>]]></c></tag>
+ <item>
+ <p>Specifies what type of an audit trail log should be used.
+ The effect of the type is actually different for the the agent
+ and the manager. </p>
+ <p>For the agent:</p>
+ <list type="bulleted">
+ <item>If <c>write</c> is specified, only set requests are logged. </item>
+ <item>If <c>read</c> is specified, only get requests are logged. </item>
+ <item>If <c>read_write</c>, all requests are logged. </item>
+ </list>
+ <p>For the manager:</p>
+ <list type="bulleted">
+ <item>If <c>write</c> is specified, only sent messages are logged. </item>
+ <item>If <c>read</c> is specified, only received messages are logged. </item>
+ <item>If <c>read_write</c>, both outgoing and incoming messages are
+ logged. </item>
+ </list>
+ <p>Default is <c>read_write</c>.</p>
+ </item>
+
+ <tag><c><![CDATA[atl_dir = dir() <mandatory>]]></c></tag>
+ <item>
+ <p>Specifies where the audit trail log should be stored.</p>
+ <p>If <c>audit_trail_log</c> specifies that logging should take
+ place, this parameter <em>must</em> be defined.</p>
+ </item>
+
+ <tag><c><![CDATA[atl_size() = {integer(), integer()} <mandatory>]]></c></tag>
+ <item>
+ <p>Specifies the size of the audit
+ trail log. This parameter is sent to <c>disk_log</c>. </p>
+ <p>If <c>audit_trail_log</c> specifies that logging should
+ take place, this parameter <em>must</em> be defined.</p>
+ </item>
+
+ <tag><c><![CDATA[atl_repair() = true | false | truncate | snmp_repair <optional>]]></c></tag>
+ <item>
+ <p>Specifies if and how the audit trail log shall be repaired
+ when opened. Unless this parameter has the value <c>snmp_repair</c>
+ it is sent to <c>disk_log</c>. If, on the other hand, the value is
+ <c>snmp_repair</c>, snmp attempts to handle certain faults on it's
+ own. And even if it cannot repair the file, it does not truncate it
+ directly, but instead <em>moves it aside</em> for later off-line
+ analysis.</p>
+ <p>Default is <c>true</c>.</p>
+ </item>
+ </taglist>
+ </section>
+
+ <section>
+ <title>Modifying the Configuration Files</title>
+ <p>To to start the application (agent and/or manager), the
+ configuration files must be modified and there are two ways
+ of doing this. Either edit the files manually, or run the
+ configuration tool as follows.</p>
+ <p>If authentication or encryption is used (SNMPv3 only), start
+ the <c>crypto</c> application.</p>
+ <pre>
+1> snmp:config().
+
+Simple SNMP configuration tool (version 4.0)
+------------------------------------------------
+Note: Non-trivial configurations still has to be
+ done manually. IP addresses may be entered
+ as dront.ericsson.se (UNIX only) or
+ 123.12.13.23
+------------------------------------------------
+
+Configure an agent (y/n)? [y]
+
+Agent system config:
+--------------------
+1. Agent process priority (low/normal/high) [normal]
+2. What SNMP version(s) should be used (1,2,3,1&amp;2,1&amp;2&amp;3,2&amp;3)? [3] 1&amp;2&amp;3
+3. Configuration directory (absolute path)? [/ldisk/snmp] /ldisk/snmp/agent/conf
+4. Config verbosity (silence/info/log/debug/trace)? [silence]
+5. Database directory (absolute path)? [/ldisk/snmp] /ldisk/snmp/agent/db
+6. Mib storage type (ets/dets/mnesia)? [ets]
+7. Target cache verbosity (silence/info/log/debug/trace)? [silence]
+8. Symbolic store verbosity (silence/info/log/debug/trace)? [silence]
+9. Local DB verbosity (silence/info/log/debug/trace)? [silence]
+10. Local DB repair (true/false/force)? [true]
+11. Local DB auto save (infinity/milli seconds)? [5000]
+12. Error report module? [snmpa_error_logger]
+13. Agent type (master/sub)? [master]
+14. Master-agent verbosity (silence/info/log/debug/trace)? [silence] log
+15. Shall the agent re-read the configuration files during startup
+ (and ignore the configuration database) (true/false)? [true]
+16. Multi threaded agent (true/false)? [false] true
+17. Check for duplicate mib entries when installing a mib (true/false)? [false]
+18. Check for duplicate trap names when installing a mib (true/false)? [false]
+19. Mib server verbosity (silence/info/log/debug/trace)? [silence]
+20. Mib server cache (true/false)? [true]
+21. Note store verbosity (silence/info/log/debug/trace)? [silence]
+22. Note store GC timeout? [30000]
+23. Shall the agent use an audit trail log (y/n)? [n] y
+23b. Audit trail log type (write/read_write)? [read_write]
+23c. Where to store the audit trail log? [/ldisk/snmp] /ldisk/snmp/agent/log
+23d. Max number of files? [10]
+23e. Max size (in bytes) of each file? [10240]
+23f. Audit trail log repair (true/false/truncate)? [true]
+24. Which network interface module shall be used? [snmpa_net_if]
+25. Network interface verbosity (silence/info/log/debug/trace)? [silence] log
+25a. Bind the agent IP address (true/false)? [false]
+25b. Shall the agents IP address and port be not reusable (true/false)? [false]
+25c. Agent request limit (used for flow control) (infinity/pos integer)? [infinity] 32
+25d. Receive buffer size of the agent (in bytes) (default/pos integer)? [default]
+25e. Send buffer size of the agent (in bytes) (default/pos integer)? [default]
+25f. Do you wish to specify a network interface filter module (or use default) [default]
+
+Agent snmp config:
+------------------
+1. System name (sysName standard variable) [bmk's agent]
+2. Engine ID (snmpEngineID standard variable) [bmk's engine]
+3. Max message size? [484]
+4. The UDP port the agent listens to. (standard 161) [4000]
+5. IP address for the agent (only used as id
+ when sending traps) [127.0.0.1]
+6. IP address for the manager (only this manager
+ will have access to the agent, traps are sent
+ to this one) [127.0.0.1]
+7. To what UDP port at the manager should traps
+ be sent (standard 162)? [5000]
+8. Do you want a none- minimum- or semi-secure configuration?
+ Note that if you chose v1 or v2, you won't get any security for these
+ requests (none, minimum, semi_des, semi_aes) [minimum]
+making sure crypto server is started...
+8b. Give a password of at least length 8. It is used to generate
+ private keys for the configuration: kalle-anka
+9. Current configuration files will now be overwritten. Ok (y/n)? [y]
+
+- - - - - - - - - - - - -
+Info: 1. SecurityName "initial" has noAuthNoPriv read access
+ and authenticated write access to the "restricted"
+ subtree.
+ 2. SecurityName "all-rights" has noAuthNoPriv read/write
+ access to the "internet" subtree.
+ 3. Standard traps are sent to the manager.
+ 4. Community "public" is mapped to security name "initial".
+ 5. Community "all-rights" is mapped to security name "all-rights".
+The following agent files were written: agent.conf, community.conf,
+standard.conf, target_addr.conf, target_params.conf,
+notify.conf, vacm.conf and usm.conf
+- - - - - - - - - - - - -
+
+Configure a manager (y/n)? [y]
+
+Manager system config:
+----------------------
+1. Manager process priority (low/normal/high) [normal]
+2. What SNMP version(s) should be used (1,2,3,1&amp;2,1&amp;2&amp;3,2&amp;3)? [3] 1&amp;2&amp;3
+3. Configuration directory (absolute path)? [/ldisk/snmp] /ldisk/snmp/manager/conf
+4. Config verbosity (silence/info/log/debug/trace)? [silence] log
+5. Database directory (absolute path)? [/ldisk/snmp] /ldisk/snmp/manager/db
+6. Database repair (true/false/force)? [true]
+7. Database auto save (infinity/milli seconds)? [5000]
+8. Inform request behaviour (auto/user)? [auto]
+9. Server verbosity (silence/info/log/debug/trace)? [silence] log
+10. Server GC timeout? [30000]
+11. Note store verbosity (silence/info/log/debug/trace)? [silence]
+12. Note store GC timeout? [30000]
+13. Which network interface module shall be used? [snmpm_net_if]
+14. Network interface verbosity (silence/info/log/debug/trace)? [silence] log
+15. Bind the manager IP address (true/false)? [false]
+16. Shall the manager IP address and port be not reusable (true/false)? [false]
+17. Receive buffer size of the manager (in bytes) (default/pos integer)? [default]
+18. Send buffer size of the manager (in bytes) (default/pos integer)? [default]
+19. Shall the manager use an audit trail log (y/n)? [n] y
+19b. Where to store the audit trail log? [/ldisk/snmp] /ldisk/snmp/manager/log
+19c. Max number of files? [10]
+19d. Max size (in bytes) of each file? [10240]
+19e. Audit trail log repair (true/false/truncate)? [true]
+20. Do you wish to assign a default user [yes] or use
+ the default settings [no] (y/n)? [n]
+
+Manager snmp config:
+--------------------
+1. Engine ID (snmpEngineID standard variable) [bmk's engine]
+2. Max message size? [484]
+3. IP address for the manager (only used as id
+ when sending requests) [127.0.0.1]
+4. Port number (standard 162)? [5000]
+5. Configure a user of this manager (y/n)? [y]
+5b. User id? kalle
+5c. User callback module? snmpm_user_default
+5d. User (callback) data? [undefined]
+5. Configure a user of this manager (y/n)? [y] n
+6. Configure an agent handled by this manager (y/n)? [y]
+6b. User id? kalle
+6c. Target name? [bmk's agent]
+6d. Version (1/2/3)? [1] 3
+6e. Community string ? [public]
+6f. Engine ID (snmpEngineID standard variable) [bmk's engine]
+6g. IP address for the agent [127.0.0.1]
+6h. The UDP port the agent listens to. (standard 161) [4000]
+6i. Retransmission timeout (infinity/pos integer)? [infinity]
+6j. Max message size? [484]
+6k. Security model (any/v1/v2c/usm)? [any] usm
+6l. Security name? ["initial"]
+6m. Security level (noAuthNoPriv/authNoPriv/authPriv)? [noAuthNoPriv] authPriv
+6. Configure an agent handled by this manager (y/n)? [y] n
+7. Configure an usm user handled by this manager (y/n)? [y]
+7a. Engine ID [bmk's engine]
+7b. User name? hobbes
+7c. Security name? [hobbes]
+7d. Authentication protocol (no/sha/md5)? [no] sha
+7e Authentication [sha] key (length 0 or 20)? [""] [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20]
+7d. Priv protocol (no/des/aes)? [no] des
+7f Priv [des] key (length 0 or 16)? [""] 10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25
+7. Configure an usm user handled by this manager (y/n)? [y] n
+8. Current configuration files will now be overwritten. Ok (y/n)? [y]
+
+- - - - - - - - - - - - -
+The following manager files were written: manager.conf, agents.conf , users.conf and usm.conf
+- - - - - - - - - - - - -
+
+--------------------
+Configuration directory for system file (absolute path)? [/ldisk/snmp]
+ok
+ </pre>
+ </section>
+
+ <section>
+ <title>Starting the application</title>
+ <p>Start Erlang with the command:</p>
+ <code type="none">
+erl -config /tmp/snmp/sys
+ </code>
+ <p>If authentication or encryption is used (SNMPv3 only), start
+ the <c>crypto</c> application. If this step is forgotten, the
+ agent will not start, but report a
+ <c>{config_error,{unsupported_crypto,_}}</c> error.</p>
+ <pre>
+1> <input>application:start(crypto).</input>
+ok
+ </pre>
+ <pre>
+2> <input>application:start(snmp).</input>
+ok
+ </pre>
+ </section>
+
+ <section>
+ <marker id="verbosity"></marker>
+ <title>Debugging the application</title>
+ <p>It is possible to debug every (non-supervisor) process of the
+ application (both agent and manager), possibly with the exception
+ of the net_if module(s), which could be supplied by a user of the
+ application). This is done by calling the
+ <c>snmpa:verbosity/2</c> and <c>snmpm:verbosity/2</c> function(s)
+ and/or using
+ <seealso marker="#configuration_params">configuration parameters</seealso>.
+ The verbosity itself has several <em>levels</em>: <c>silence | info | log | debug | trace</c>. For the lowest verbosity <c>silence</c>,
+ nothing is printed. The higher the verbosity, the more is printed.
+ Default value is always <c>silence</c>.</p>
+ <pre>
+3> <input>snmpa:verbosity(master_agent, log).</input>
+ok
+5> <input>snmpa:verbosity(net_if, log).</input>
+ok
+6>
+%% Example of output from the agent when a get-next-request arrives:
+** SNMP NET-IF LOG:
+ got packet from {147,12,12,12}:5000
+
+** SNMP NET-IF MPD LOG:
+ v1, community: all-rights
+
+** SNMP NET-IF LOG:
+ got pdu from {147,12,12,12}:5000 {pdu, 'get-next-request',
+ 62612569,noError,0,
+ [{varbind,[1,1],'NULL','NULL',1}]}
+
+** SNMP MASTER-AGENT LOG:
+ apply: snmp_generic,variable_func,[get,{sysDescr,persistent}]
+
+** SNMP MASTER-AGENT LOG:
+ returned: {value,"Erlang SNMP agent"}
+
+** SNMP NET-IF LOG:
+ reply pdu: {pdu,'get-response',62612569,noError,0,
+ [{varbind,[1,3,6,1,2,1,1,1,0],
+ 'OCTET STRING',
+ "Erlang SNMP agent",1}]}
+
+** SNMP NET-IF INFO: time in agent: 19711 mysec
+ </pre>
+
+ <p>Other useful function(s) for debugging the agent are: </p>
+ <taglist>
+ <tag><c><![CDATA[snmpa:info/0,1]]></c></tag>
+ <item>
+ <p><seealso marker="snmpa#info">info</seealso> is used to retrieve a list of miscellaneous agent information.</p>
+ </item>
+
+ <tag><c><![CDATA[snmpa:which_aliasnames/0]]></c></tag>
+ <item>
+ <p><seealso marker="snmpa#which_aliasnames">which_aliasnames</seealso> is used to retrieve a list of all alias-names known to the agent. </p>
+ </item>
+
+ <tag><c><![CDATA[snmpa:which_tables/0]]></c></tag>
+ <item>
+ <p><seealso marker="snmpa#which_tables">which_tables</seealso> is used to retrieve a list of all (MIB) tables known to the agent. </p>
+ </item>
+
+ <tag><c><![CDATA[snmpa:which_variables/0]]></c></tag>
+ <item>
+ <p><seealso marker="snmpa#which_variables">which_variables</seealso> is used to retrieve a list of all (MIB) variables known to the agent. </p>
+ </item>
+
+ <tag><c><![CDATA[snmpa:which_notifications/0]]></c></tag>
+ <item>
+ <p><seealso marker="snmpa#which_notifications">which_notifications</seealso> is used to retrieve a list of all (MIB) notifications/traps known to the agent. </p>
+ </item>
+
+ <tag><c><![CDATA[snmpa:restart_worker/0,1]]></c></tag>
+ <item>
+ <p><seealso marker="snmpa#restart_worker">restart_worker</seealso> is used to restart the worker process of a multi-threaded agent. </p>
+ </item>
+
+ <tag><c><![CDATA[snmpa:restart_set_worker/0,1]]></c></tag>
+ <item>
+ <p><seealso marker="snmpa#restart_set_worker">restart_set_worker</seealso> is used to restart the set-worker process of a multi-threaded agent. </p>
+ </item>
+
+ <tag><c><![CDATA[snmpa_local_db:print/0,1,2]]></c></tag>
+ <item>
+ <p>For example, this function can show the counters
+ <c>snmpInPkts</c> and <c>snmpOutPkts</c>.</p>
+ </item>
+ </taglist>
+
+ <p>Another usefull way to debug the agent is to pretty-print the content of
+ some of the (MIB-) tables handled directly by the agent. This can be done
+ for the following tables: </p>
+ <taglist>
+ <tag><c><![CDATA[snmpCommunityTable]]></c></tag>
+ <item>
+ <p><c><![CDATA[snmp_community_mib:snmpCommunityTable(print).]]></c></p>
+ </item>
+
+ <tag><c><![CDATA[snmpNotifyTable]]></c></tag>
+ <item>
+ <p><c><![CDATA[snmp_notification_mib:snmpNotifyTable(print).]]></c></p>
+ </item>
+
+ <tag><c><![CDATA[snmpTargetAddrTable]]></c></tag>
+ <item>
+ <p><c><![CDATA[snmp_target_mib:snmpTargetAddrTable(print).]]></c></p>
+ </item>
+
+ <tag><c><![CDATA[snmpTargetParamsTable]]></c></tag>
+ <item>
+ <p><c><![CDATA[snmp_target_mib:snmpTargetParamsTable(print).]]></c></p>
+ </item>
+
+ <tag><c><![CDATA[usmUserTable]]></c></tag>
+ <item>
+ <p><c><![CDATA[snmp_user_based_sm_mib:usmUserTable(print).]]></c></p>
+ </item>
+
+ </taglist>
+
+ </section>
+</chapter>
+
diff --git a/lib/snmp/doc/src/snmp_def_instr_functions.xml b/lib/snmp/doc/src/snmp_def_instr_functions.xml
new file mode 100644
index 0000000000..f88469aeae
--- /dev/null
+++ b/lib/snmp/doc/src/snmp_def_instr_functions.xml
@@ -0,0 +1,477 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE chapter SYSTEM "chapter.dtd">
+
+<chapter>
+ <header>
+ <copyright>
+ <year>1997</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ 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.
+
+ </legalnotice>
+
+ <title>Definition of Instrumentation Functions</title>
+ <prepared></prepared>
+ <responsible></responsible>
+ <docno></docno>
+ <approved></approved>
+ <checked></checked>
+ <date></date>
+ <rev></rev>
+ <file>snmp_def_instr_functions.xml</file>
+ </header>
+ <p>The section <em>Definition of Instrumentation Functions</em> describes
+ the user defined functions, which the agent calls at different times.
+ </p>
+
+ <section>
+ <title>Variable Instrumentation</title>
+ <p>For scalar variables, a function <c>f(Operation, ...)</c> must
+ be defined.
+ </p>
+ <p>The <c>Operation</c> can be <c>new</c>, <c>delete</c>,
+ <c>get</c>, <c>is_set_ok</c>, <c>set</c>, or <c>undo</c>.
+ </p>
+ <p>In case of an error, all instrumentation functions may return
+ either an SNMPv1 or an SNMPv2 error code. If it returns an SNMPv2
+ code, it is converted into an SNMPv1 code before it is sent to a
+ SNMPv1 manager. It is recommended to use the SNMPv2 error codes
+ for all instrumentation functions, as these provide more
+ details. See <seealso marker="snmp_app_a">Appendix A</seealso> for a
+ description of error code conversions.
+ </p>
+
+ <section>
+ <title>f(new [, ExtraArgs])</title>
+ <p>The function <c>f(new [, ExtraArgs])</c> is called for each
+ variable in the MIB when the
+ MIB is loaded into the agent. This makes it possible to perform
+ necessary initialization.
+ </p>
+ <p>This function is optional. The return value is discarded.</p>
+ </section>
+
+ <section>
+ <title>f(delete [, ExtraArgs])</title>
+ <p>The function <c>f(delete [, ExtraArgs])</c> is called
+ for each object in an MIB when the
+ MIB is unloaded from the agent. This makes it possible to
+ perform necessary clean-up.
+ </p>
+ <p>This function is optional. The return value is discarded.</p>
+ </section>
+
+ <section>
+ <title>f(get [, ExtraArgs])</title>
+ <p>The function <c>f(get [, ExtraArgs])</c> is called when a
+ get-request or a get-next
+ request refers to the variable.
+ </p>
+ <p>This function is mandatory.
+ </p>
+
+ <section>
+ <title>Valid Return Values</title>
+ <list type="bulleted">
+ <item><c>{value, Value}</c>. The <c>Value</c> must be of
+ correct type, length and within ranges, otherwise
+ <c>genErr</c> is returned in the response PDU. If the
+ object is an enumerated integer, the symbolic enum value
+ may be used as an atom. If the object is of type BITS, the
+ return value shall be an integer or a list of bits that
+ are set.
+ </item>
+ <item><c>{noValue, noSuchName}</c>(SNMPv1)
+ </item>
+ <item><c>{noValue, noSuchObject | noSuchInstance} </c>(SNMPv2)
+ </item>
+ <item><c>genErr</c>. Used if an error occurred. Note,
+ this should be an internal processing error, e.g. a caused
+ by a programing fault somewhere. If the variable does not
+ exist, use <c>{noValue, noSuchName}</c> or
+ <c>{noValue, noSuchInstance}</c>.
+ </item>
+ </list>
+ </section>
+ </section>
+
+ <section>
+ <title>f(is_set_ok, NewValue [, ExtraArgs])</title>
+ <p>The function <c>f(is_set_ok, NewValue [, ExtraArgs])</c> is
+ called in phase one of the set-request
+ processing so that the new value can be checked for
+ inconsistencies.
+ </p>
+ <p><c>NewValue</c> is guaranteed to be of the correct type,
+ length and within ranges, as specified in the MIB. If the
+ object is an enumerated integer or of type BITS, the integer
+ value is used.
+ </p>
+ <p>This function is optional.
+ </p>
+ <p>If this function is called, it will be called again, either
+ with <c>undo</c> or with <c>set</c> as first argument.
+ </p>
+
+ <section>
+ <title>Valid return values</title>
+ <list type="bulleted">
+ <item><c>noError</c></item>
+ <item><c>badValue | noSuchName | genErr</c>(SNMPv1)
+ </item>
+ <item><c>noAccess | noCreation | inconsistentValue | resourceUnavailable | inconsistentName | genErr</c>(SNMPv2)</item>
+ </list>
+ </section>
+ </section>
+
+ <section>
+ <title>f(undo, NewValue [, ExtraArgs])</title>
+ <p>If an error occurred, this function is called after the
+ <c>is_set_ok</c> function is called. If <c>set</c> is called for
+ this object, <c>undo</c> is not called.
+ </p>
+ <p><c>NewValue</c> is guaranteed to be of the correct type,
+ length and within ranges, as specified in the MIB. If the
+ object is an enumerated integer or of type BITS, the integer
+ value is used.
+ </p>
+ <p>This function is optional.
+ </p>
+
+ <section>
+ <title>Valid return values</title>
+ <list type="bulleted">
+ <item><c>noError</c></item>
+ <item><c>genErr</c>(SNMPv1)
+ </item>
+ <item><c>undoFailed | genErr</c>(SNMPv2)</item>
+ </list>
+ </section>
+ </section>
+
+ <section>
+ <title>f(set, NewValue [, ExtraArgs])</title>
+ <p>This function is called to perform the set in phase two of
+ the set-request processing. It is only called if the
+ corresponding <c>is_set_ok</c> function is present and returns
+ <c>noError</c>.
+ </p>
+ <p><c>NewValue</c> is guaranteed to be of the correct type,
+ length and within ranges, as specified in the MIB. If the
+ object is an enumerated integer or of type BITS, the integer
+ value is used.
+ </p>
+ <p>This function is mandatory.
+ </p>
+
+ <section>
+ <title>Valid return values</title>
+ <list type="bulleted">
+ <item><c>noError</c></item>
+ <item><c>genErr</c>(SNMPv1)
+ </item>
+ <item><c>commitFailed | undoFailed | genErr</c>(SNMPv2)</item>
+ </list>
+ </section>
+ </section>
+ </section>
+
+ <section>
+ <title>Table Instrumentation</title>
+ <p>For tables, a <c>f(Operation, ...)</c> function should be
+ defined (the function shown is exemplified with <c>f</c>).
+ </p>
+ <p>The <c>Operation</c> can be <c>new</c>, <c>delete</c>,
+ <c>get</c>, <c>next</c>, <c>is_set_ok</c>, <c>undo</c> or
+ <c>set</c>.
+ </p>
+ <p>In case of an error, all instrumentation functions may return
+ either an SNMPv1 or an SNMPv2 error code. If it returns an SNMPv2
+ code, it is converted into an SNMPv1 code before it is sent to a
+ SNMPv1 manager. It is recommended to use the SNMPv2 error codes
+ for all instrumentation functions, as these provide more
+ details. See <seealso marker="snmp_app_a">Appendix A</seealso> for a
+ description of error code conversions.</p>
+
+ <section>
+ <title>f(new [, ExtraArgs])</title>
+ <p>The function <c>f(new [, ExtraArgs])</c> is called for each object in an MIB when the
+ MIB is loaded into the agent. This makes it possible to perform
+ the necessary initialization.
+ </p>
+ <p>This function is optional. The return value is discarded.</p>
+ </section>
+
+ <section>
+ <title>f(delete [, ExtraArgs])</title>
+ <p>The function <c>f(delete [, ExtraArgs])</c> is called for each object in an MIB when the
+ MIB is unloaded from the agent. This makes it possible to
+ perform any necessary clean-up.
+ </p>
+ <p>This function is optional. The return value is discarded.</p>
+ </section>
+
+ <section>
+ <title>f(get, RowIndex, Cols [, ExtraArgs])</title>
+ <p>The function <c>f(get, RowIndex, Cols [, ExtraArgs])</c> is
+ called when a get-request refers to a table.
+ </p>
+ <p>This function is mandatory.
+ </p>
+
+ <section>
+ <title>Arguments</title>
+ <list type="bulleted">
+ <item><c>RowIndex</c> is a list of integers which define the
+ key values for the row. The <c>RowIndex</c> is the list
+ representation (list of integers) which follow the
+ <c>Cols</c> integer in the OBJECT IDENTIFIER.
+ </item>
+ <item><c>Cols</c> is a list of integers which represent the
+ column numbers. The <c>Cols</c> are sorted by increasing
+ value and are guaranteed to be valid column numbers.</item>
+ </list>
+ </section>
+
+ <section>
+ <title>Valid Return Values</title>
+ <list type="bulleted">
+ <item>
+ <p>A list with as many elements as the <c>Cols</c> list,
+ where each element is the value of the corresponding
+ column. Each element can be:</p>
+ <list type="bulleted">
+ <item><c>{value, Value}</c>. The <c>Value</c> must be of
+ correct type, length and within ranges, otherwise
+ <c>genErr</c> is returned in the response PDU. If the
+ object is an enumerated integer, the symbolic enum
+ value may be used (as an atom). If the object is of
+ type BITS, the return value shall be an integer or a
+ list of bits that are set.
+ </item>
+ <item><c>{noValue, noSuchName}</c>(SNMPv1)
+ </item>
+ <item><c>{noValue, noSuchObject | noSuchInstance}</c>(SNMPv2)
+ </item>
+ </list>
+ </item>
+ <item><c>{noValue, Error}</c>. If the row does not exist,
+ because all columns have <c>{noValue, Error}</c>), the
+ single tuple <c>{noValue, Error}</c> can be returned.
+ This is a shorthand for a list with all elements
+ <c>{noValue, Error}</c>.
+ </item>
+ <item><c>genErr</c>. Used if an error occurred. Note that
+ this should be an internal processing error, e.g. a caused
+ by a programing fault somewhere. If some column does not
+ exist, use <c>{noValue, noSuchName}</c> or
+ <c>{noValue, noSuchInstance}</c>.
+ </item>
+ </list>
+ </section>
+ </section>
+
+ <section>
+ <title>f(get_next, RowIndex, Cols [, ExtraArgs])</title>
+ <p>The function <c>f(get_next, RowIndex, Cols [, ExtraArgs])</c> is
+ called when a get-next- or a
+ get-bulk-request refers to the table.
+ </p>
+ <p>The <c>RowIndex</c> argument may refer to an existing row or a
+ non-existing row, or it may be unspecified. The <c>Cols</c> list
+ may refer to inaccessible columns or non-existing columns. For
+ each column in the <c>Cols</c> list, the corresponding next
+ instance is determined, and the last part of its OBJECT
+ IDENTIFIER and its value is returned.
+ </p>
+ <p>This function is mandatory.
+ </p>
+
+ <section>
+ <title>Arguments</title>
+ <list type="bulleted">
+ <item><c>RowIndex</c> is a list of integers (possibly empty)
+ that defines the key values for a row. The <c>RowIndex</c>
+ is the list representation (list of integers), which follow
+ the <c>Cols</c> integer in the OBJECT IDENTIFIER.
+ </item>
+ <item><c>Cols</c> is a list of integers, greater than or
+ equal to zero, which represents the column numbers.</item>
+ </list>
+ </section>
+
+ <section>
+ <title>Valid Return Values</title>
+ <list type="bulleted">
+ <item>
+ <p>A list with as many elements as the <c>Cols</c> list
+ Each element can be:</p>
+ <list type="bulleted">
+ <item><c>{NextOid, NextValue}</c>, where <c>NextOid</c>
+ is the lexicographic next OBJECT IDENTIFIER for the
+ corresponding column. This should be specified as the
+ OBJECT IDENTIFER part following the table entry. This
+ means that the first integer is the column number and
+ the rest is a specification of the keys.
+ <c>NextValue</c> is the value of this element.
+ </item>
+ <item><c>endOfTable</c> if there are no accessible
+ elements after this one.
+ </item>
+ </list>
+ </item>
+ <item><c>{genErr, Column}</c> where <c>Column</c> denotes
+ the column that caused the error. <c>Column</c> must be
+ one of the columns in the <c>Cols</c> list. Note that
+ this should be an internal processing error, e.g. a caused
+ by a programing fault somewhere. If some column does not
+ exist, you must return the next accessible element (or
+ <c>endOfTable</c>).
+ </item>
+ </list>
+ </section>
+ </section>
+
+ <section>
+ <title>f(is_set_ok, RowIndex, Cols [, ExtraArgs])</title>
+ <p>The function <c>f(is_set_ok, RowIndex, Cols [, ExtraArgs])</c>
+ is called in phase one of the set-request
+ processing so that new values can be checked for
+ inconsistencies.
+ </p>
+ <p>If the function is called, it will be called again with
+ <c>undo</c>, or with <c>set</c> as first argument.
+ </p>
+ <p>This function is optional.
+ </p>
+
+ <section>
+ <title>Arguments</title>
+ <list type="bulleted">
+ <item><c>RowIndex</c> is a list of integers which define the
+ key values for the row. The <c>RowIndex</c> is the list
+ representation (list of integers) which follow the
+ <c>Cols</c> integer in the OBJECT IDENTIFIER.
+ </item>
+ <item><c>Cols</c> is a list of <c>{Column, NewValue}</c>,
+ where <c>Column</c> is an integer, and <c>NewValue</c> is
+ guaranteed to be of the correct type, length and within
+ ranges, as specified in the MIB. If the object is an
+ enumerated integer or of type BITS, the integer value is
+ used. The list is sorted by <c>Column</c> (increasing) and
+ each <c>Column</c> is guaranteed to be a valid column
+ number.</item>
+ </list>
+ </section>
+
+ <section>
+ <title>Valid Return Values</title>
+ <list type="bulleted">
+ <item><c>{noError, 0}</c></item>
+ <item><c>{Error, Column}</c>, where <c>Error</c> is the same
+ as for <c>is_set_ok</c> for variables, and <c>Column</c>
+ denotes the faulty column. <c>Column</c> must be one of the
+ columns in the <c>Cols</c> list.</item>
+ </list>
+ </section>
+ </section>
+
+ <section>
+ <title>f(undo, RowIndex, Cols [, ExtraArgs])</title>
+ <p>If an error occurs, The function
+ <c>f(undo, RowIndex, Cols [, ExtraArgs])</c> is called after the
+ <c>is_set_ok</c> function. If <c>set</c> is called for this
+ object, <c>undo</c> is not called.
+ </p>
+ <p>This function is optional.
+ </p>
+
+ <section>
+ <title>Arguments</title>
+ <list type="bulleted">
+ <item><c>RowIndex</c> is a list of integers which define the
+ key values for the row. The <c>RowIndex</c> is the list
+ representation (list of integers) which follow the
+ <c>Cols</c> integer in the OBJECT IDENTIFIER.
+ </item>
+ <item><c>Cols</c> is a list of <c>{Column, NewValue}</c>,
+ where <c>Column</c> is an integer, and <c>NewValue</c> is
+ guaranteed to be of the correct type, length and within
+ ranges, as specified in the MIB. If the object is an
+ enumerated integer or of type BITS, the integer value is
+ used. The list is sorted by <c>Column</c> (increasing) and
+ each <c>Column</c> is guaranteed to be a valid column
+ number.
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Valid Return Values</title>
+ <list type="bulleted">
+ <item><c>{noError, 0}</c></item>
+ <item><c>{Error, Column}</c> where <c>Error</c> is the same
+ as for <c>undo</c> for variables, and <c>Column</c> denotes
+ the faulty column. <c>Column</c> must be one of the columns
+ in the <c>Cols</c> list.
+ </item>
+ </list>
+ </section>
+ </section>
+
+ <section>
+ <title>f(set, RowIndex, Cols [, ExtraArgs])</title>
+ <p>The function <c>f(set, RowIndex, Cols [, ExtraArgs])</c> is
+ called to perform the set in phase two of
+ the set-request processing. It is only called if the
+ corresponding <c>is_set_ok</c> function did not exist, or
+ returned <c>{noError, 0}</c>.
+ </p>
+ <p>This function is mandatory.
+ </p>
+
+ <section>
+ <title>Arguments</title>
+ <list type="bulleted">
+ <item><c>RowIndex</c> is a list of integers that define the
+ key values for the row. The <c>RowIndex</c> is the list
+ representation (list of integers) which follow the
+ <c>Cols</c> integer in the OBJECT IDENTIFIER.
+ </item>
+ <item><c>Cols</c> is a list of <c>{Column, NewValue}</c>,
+ where <c>Column</c> is an integer, and <c>NewValue</c> is
+ guaranteed to be of the correct type, length and within
+ ranges, as specified in the MIB. If the object is an
+ enumerated integer or of type BITS, the integer value is
+ used. The list is sorted by <c>Column</c> (increasing) and
+ each <c>Column</c> is guaranteed to be a valid column
+ number.
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Valid Return Values</title>
+ <list type="bulleted">
+ <item><c>{noError, 0}</c></item>
+ <item><c>{Error, Column}</c> where <c>Error</c> is the same
+ as <c>set</c> for variables, and <c>Column</c> denotes
+ the faulty column. <c>Column</c> must be one of the columns
+ in the <c>Cols</c> list.</item>
+ </list>
+ </section>
+ </section>
+ </section>
+</chapter>
+
diff --git a/lib/snmp/doc/src/snmp_framework_mib.xml b/lib/snmp/doc/src/snmp_framework_mib.xml
new file mode 100644
index 0000000000..38fb531d3e
--- /dev/null
+++ b/lib/snmp/doc/src/snmp_framework_mib.xml
@@ -0,0 +1,119 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE erlref SYSTEM "erlref.dtd">
+
+<erlref>
+ <header>
+ <copyright>
+ <year>1999</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ 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.
+
+ </legalnotice>
+
+ <title>snmp_framework_mib</title>
+ <prepared></prepared>
+ <responsible></responsible>
+ <docno></docno>
+ <approved></approved>
+ <checked></checked>
+ <date></date>
+ <rev></rev>
+ <file>snmp_framework_mib.xml</file>
+ </header>
+ <module>snmp_framework_mib</module>
+ <modulesummary>Instrumentation Functions for SNMP-FRAMEWORK-MIB</modulesummary>
+ <description>
+ <p>The module <c>snmp_framework_mib</c> implements instrumentation
+ functions for the
+ SNMP-FRAMEWORK-MIB, and functions for initializing and configuring the
+ database.
+ </p>
+ <p>The configuration files are described in the SNMP User's Manual.</p>
+ </description>
+ <funcs>
+ <func>
+ <name>configure(ConfDir) -> void()</name>
+ <fsummary>Configure the SNMP-FRAMEWORK-MIB</fsummary>
+ <type>
+ <v>ConfDir = string()</v>
+ </type>
+ <desc>
+ <p>This function is called from the supervisor at system
+ start-up.
+ </p>
+ <p>Inserts all data in the configuration files into the
+ database and destroys all old data.
+ </p>
+ <p>Thus, the data in the SNMP-FRAMEWORK-MIB, after this
+ function has been called, is from the configuration
+ files.
+ </p>
+ <p>All <c>snmp</c> counters are set to zero.
+ </p>
+ <p>If an error is found in the configuration file, it is
+ reported using the function <c>config_err/2</c> of the error
+ report module, and the function fails with reason
+ <c>configuration_error</c>.
+ </p>
+ <p><c>ConfDir</c> is a string which points to the directory
+ where the configuration files are found.
+ </p>
+ <p>The configuration file read is: <c>context.conf</c>.
+ </p>
+ </desc>
+ </func>
+ <func>
+ <name>init() -> void()</name>
+ <fsummary>Initialize the SNMP-FRAMEWORK-MIB</fsummary>
+ <desc>
+ <p>This function is called from the supervisor at system
+ start-up.
+ </p>
+ <p>Creates the necessary objects in the database if they do not
+ exist. It does not destroy any old values.
+ <marker id="add_context"></marker>
+</p>
+ </desc>
+ </func>
+ <func>
+ <name>add_context(Ctx) -> Ret</name>
+ <fsummary>Added one context</fsummary>
+ <type>
+ <v>Ctx = string()</v>
+ <v>Ret = {ok, Key} | {error, Reason}</v>
+ <v>Key = term()</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Adds a context to the agent config.
+ Equivalent to one line in the <c>context.conf</c> file.</p>
+ <marker id="delete_context"></marker>
+ </desc>
+ </func>
+ <func>
+ <name>delete_context(Key) -> Ret</name>
+ <fsummary>Delete one context</fsummary>
+ <type>
+ <v>Key = term()</v>
+ <v>Ret = ok | {error, Reason}</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Delete a context from the agent config.</p>
+ </desc>
+ </func>
+ </funcs>
+
+</erlref>
+
diff --git a/lib/snmp/doc/src/snmp_generic.xml b/lib/snmp/doc/src/snmp_generic.xml
new file mode 100644
index 0000000000..77f3cefaa2
--- /dev/null
+++ b/lib/snmp/doc/src/snmp_generic.xml
@@ -0,0 +1,345 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE erlref SYSTEM "erlref.dtd">
+
+<erlref>
+ <header>
+ <copyright>
+ <year>1996</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ 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.
+
+ </legalnotice>
+
+ <title>snmp_generic</title>
+ <prepared></prepared>
+ <responsible></responsible>
+ <docno></docno>
+ <approved></approved>
+ <checked></checked>
+ <date></date>
+ <rev></rev>
+ <file>snmp_generic.xml</file>
+ </header>
+ <module>snmp_generic</module>
+ <modulesummary>Generic Functions for Implementing SNMP Objects in a Database</modulesummary>
+ <description>
+ <p>The module <c>snmp_generic</c> contains generic functions for implementing tables
+ (and variables) using the SNMP built-in database or Mnesia. These
+ default functions are used if no instrumentation function is
+ provided for a managed object in a MIB. Sometimes, it might be
+ necessary to customize the behaviour of the default functions. For
+ example, in some situations a trap should be sent if a row is
+ deleted or modified, or some hardware is to be informed, when
+ information is changed.
+ </p>
+ <p>The overall structure is shown in the following figure:</p>
+ <pre>
+ +---------------+
+ | SNMP Agent |
+ +- - - - - - - -+
+ | MIB |
+ +---------------+
+ |
+ Association file (associates a MIB object with
+ | snmp_generic:table_funct
+ | snmp_generic:variable_func)
++--------------------------------------+
+| snmp_generic | Support for get-next,
+| | RowStatus operations
++----------------------+---------------+
+| snmpa_local_db | Mnesia | Database
++--------------+-------+---------------+
+| dets | ets |
+| (persistent) | |
++--------------+-------+ </pre>
+ <p>Each function takes the argument <c>NameDb</c>, which is a
+ tuple <c>{Name, Db}</c>, to identify which database the
+ functions should use. <c>Name</c> is the symbolic name of the
+ managed object as defined in the MIB, and <c>Db</c> is either
+ <c>volatile</c>, <c>persistent</c>, or <c>mnesia</c>. If it is
+ <c>mnesia</c>, all variables are stored in the Mnesia table
+ <c>snmp_variables</c> which must be a table with two attributes
+ (not a Mnesia SNMP table). The SNMP tables are stored in Mnesia
+ tables with the same names as the SNMP tables. All functions
+ assume that a Mnesia table exists with the correct name and
+ attributes. It is the programmer's responsibility to ensure
+ this. Specifically, if variables are stored in Mnesia, the table
+ <c>snmp_variables</c> must be created by the programmer. The
+ record definition for this table is defined in the file
+ <c>snmp/include/snmp_types.hrl</c>.
+ </p>
+ <p>If an instrumentation function in the association file for a
+ variable <c>myVar</c> does not have a name when compiling an
+ MIB, the compiler generates an entry.
+ </p>
+ <pre>
+{myVar, {snmp_generic, variable_func, [{myVar, Db]}}.
+ </pre>
+ <p>And for a table:</p>
+ <pre>
+{myTable, {snmp_generic, table_func, [{myTable, Db]}}.
+ </pre>
+ </description>
+
+ <section>
+ <title>DATA TYPES</title>
+ <p>In the functions defined below, the following types are used:</p>
+ <code type="none">
+name_db() = {name(), db()}
+name() = atom()
+db() = volatile | persistent | mnesia
+row_index() = [int()]
+columns() = [column()] | [{column(), value()}]
+column() = int()
+value() = term()
+ </code>
+ <taglist>
+ <tag><c>row_index()</c></tag>
+ <item>
+ <p>Denotes the last part of the OID which specifies the
+ index of the row in the table (see RFC1212, 4.1.6 for
+ more information about INDEX). </p>
+ </item>
+ <tag><c>columns()</c></tag>
+ <item>
+ <p>Is a list of column numbers in the case of a <c>get</c>
+ operation, and a list of column numbers and values in the
+ case of a <c>set</c> operation. </p>
+ </item>
+ </taglist>
+ </section>
+ <funcs>
+ <func>
+ <name>get_status_col(Name, Cols)</name>
+ <name>get_status_col(NameDb, Cols) -> {ok, StatusVal} | false</name>
+ <fsummary>Get the value of the status column from <c>Cols</c></fsummary>
+ <type>
+ <v>Name = name()</v>
+ <v>NameDb = name_db()</v>
+ <v>Cols = columns()</v>
+ <v>StatusVal = term()</v>
+ </type>
+ <desc>
+ <p>Gets the value of the status column from <c>Cols</c>.
+ </p>
+ <p>This function can be used in instrumentation functions for
+ <c>is_set_ok</c>, <c>undo</c> or <c>set</c> to check if the
+ status column of a table is modified.</p>
+ </desc>
+ </func>
+ <func>
+ <name>get_index_types(Name)</name>
+ <fsummary>Get the index types of <c>Name</c></fsummary>
+ <type>
+ <v>Name = name()</v>
+ </type>
+ <desc>
+ <p>Gets the index types of <c>Name</c></p>
+ <p>This function can be used in instrumentation functions to
+ retrieve the index types part of the table info.</p>
+ </desc>
+ </func>
+ <func>
+ <name>table_func(Op1, NameDb)</name>
+ <name>table_func(Op2, RowIndex, Cols, NameDb) -> Ret</name>
+ <fsummary>Default instrumentation function for tables</fsummary>
+ <type>
+ <v>Op1 = new | delete </v>
+ <v>Op2 = get | next | is_set_ok | set | undo</v>
+ <v>NameDb = name_db()</v>
+ <v>RowIndex = row_index()</v>
+ <v>Cols = columns()</v>
+ <v>Ret = term()</v>
+ </type>
+ <desc>
+ <p>This is the default instrumentation function for tables.
+ </p>
+ <list type="bulleted">
+ <item>The <c>new</c> function creates the table if it does
+ not exist, but only if the database is the SNMP internal db.</item>
+ <item>The <c>delete</c> function does not delete the table
+ from the database since unloading an MIB does not
+ necessarily mean that the table should be destroyed.</item>
+ <item>The <c>is_set_ok</c> function checks that a row which
+ is to be modified or deleted exists, and that a row which
+ is to be created does not exist.</item>
+ <item>The <c>undo</c> function does nothing.</item>
+ <item>The <c>set</c> function checks if it has enough
+ information to make the row change its status from
+ <c>notReady</c> to <c>notInService</c> (when a row has
+ been been set to <c>createAndWait</c>). If a row is set to
+ <c>createAndWait</c>, columns without a value are set to
+ <c>noinit</c>. If Mnesia is used, the set functionality is
+ handled within a transaction.</item>
+ </list>
+ <p>If it is possible for a manager to create or delete rows in
+ the table, there must be a <c>RowStatus</c> column for
+ <c>is_set_ok</c>, <c>set</c> and <c>undo</c> to work properly.
+ </p>
+ <p>The function returns according to the specification of an
+ instrumentation function.
+ </p>
+ </desc>
+ </func>
+ <func>
+ <name>table_get_elements(NameDb, RowIndex, Cols) -> Values</name>
+ <fsummary>Get elements in a table row</fsummary>
+ <type>
+ <v>NameDb = name_db()</v>
+ <v>RowIndex = row_index()</v>
+ <v>Cols = columns()</v>
+ <v>Values = [value() | noinit]</v>
+ </type>
+ <desc>
+ <p>Returns a list with values for all columns in <c>Cols</c>.
+ If a column is undefined, its value is <c>noinit</c>.</p>
+ </desc>
+ </func>
+ <func>
+ <name>table_next(NameDb, RestOid) -> RowIndex | endOfTable</name>
+ <fsummary>Find the next row in the table</fsummary>
+ <type>
+ <v>NameDb = name_db()</v>
+ <v>RestOid = [int()]</v>
+ <v>RowIndex = row_index()</v>
+ </type>
+ <desc>
+ <p>Finds the indices of the next row in the table. <c>RestOid</c>
+ does not have to specify an existing row.</p>
+ </desc>
+ </func>
+ <func>
+ <name>table_row_exists(NameDb, RowIndex) -> bool()</name>
+ <fsummary>Check if a row in a table exists</fsummary>
+ <type>
+ <v>NameDb = name_db()</v>
+ <v>RowIndex = row_index()</v>
+ </type>
+ <desc>
+ <p>Checks if a row in a table exists.</p>
+ </desc>
+ </func>
+ <func>
+ <name>table_set_elements(NameDb, RowIndex, Cols) -> bool()</name>
+ <fsummary>Set elements in a table row</fsummary>
+ <type>
+ <v>NameDb = name_db()</v>
+ <v>RowIndex = row_index()</v>
+ <v>Cols = columns()</v>
+ </type>
+ <desc>
+ <p>Sets the elements in <c>Cols</c> to the row specified by
+ <c>RowIndex</c>. No checks are performed on the new values.
+ </p>
+ <p>If the Mnesia database is used, this function calls
+ <c>mnesia:write</c> to store the values. This means that
+ this function must be called from within a transaction
+ (<c>mnesia:transaction/1</c> or <c>mnesia:dirty/1</c>).</p>
+ </desc>
+ </func>
+ <func>
+ <name>variable_func(Op1, NameDb)</name>
+ <name>variable_func(Op2, Val, NameDb) -> Ret</name>
+ <fsummary>Default instrumentation function for tables</fsummary>
+ <type>
+ <v>Op1 = new | delete | get</v>
+ <v>Op2 = is_set_ok | set | undo</v>
+ <v>NameDb = name_db()</v>
+ <v>Val = value()</v>
+ <v>Ret = term()</v>
+ </type>
+ <desc>
+ <p>This is the default instrumentation function for variables.</p>
+ <p>The <c>new</c> function creates a new variable in the
+ database with a default value as defined in the MIB, or a zero
+ value (depending on the type). </p>
+ <p>The <c>delete</c> function does not delete the variable from
+ the database. </p>
+ <p>The function returns according to the specification of an
+ instrumentation function. </p>
+ </desc>
+ </func>
+ <func>
+ <name>variable_get(NameDb) -> {value, Value} | undefined</name>
+ <fsummary>Get the value of a variable</fsummary>
+ <type>
+ <v>NameDb = name_db()</v>
+ <v>Value = value()</v>
+ </type>
+ <desc>
+ <p>Gets the value of a variable.</p>
+ </desc>
+ </func>
+ <func>
+ <name>variable_set(NameDb, NewVal) -> true | false</name>
+ <fsummary>Set a value for a variable</fsummary>
+ <type>
+ <v>NameDb = name_db()</v>
+ <v>NewVal = value()</v>
+ </type>
+ <desc>
+ <p>Sets a new value to a variable. The variable is created if
+ it does not exist. No checks are made on the type of the
+ new value. </p>
+ <p>Returns <c>false</c> if the <c>NameDb</c> argument
+ is incorrectly specified, otherwise <c>true</c>.</p>
+ </desc>
+ </func>
+ </funcs>
+
+ <section>
+ <title>Example</title>
+ <p>The following example shows an implementation of a table which is
+ stored in Mnesia, but with some checks performed at set-request
+ operations.
+ </p>
+ <pre>
+myTable_func(new, NameDb) -> % pass unchanged
+ snmp_generic:table_func(new, NameDb).
+
+myTable_func(delete, NameDb) -> % pass unchanged
+ snmp_generic:table_func(delete, NameDb).
+
+%% change row
+myTable_func(is_set_ok, RowIndex, Cols, NameDb) ->
+ case snmp_generic:table_func(is_set_ok, RowIndex,
+ Cols, NameDb) of
+ {noError, 0} ->
+ myApplication:is_set_ok(RowIndex, Cols);
+ Err ->
+ Err
+ end;
+
+myTable_func(set, RowIndex, Cols, NameDb) ->
+ case snmp_generic:table_func(set, RowIndex, Cols,
+ NameDb),
+ {noError, 0} ->
+ % Now the row is updated, tell the application
+ myApplication:update(RowIndex, Cols);
+ Err ->
+ Err
+ end;
+
+myTable_func(Op, RowIndex, Cols, NameDb) -> % pass unchanged
+ snmp_generic:table_func(Op, RowIndex, Cols, NameDb).
+ </pre>
+ <p>The <c>.funcs</c> file would look like:
+ </p>
+ <pre>
+{myTable, {myModule, myTable_func, [{myTable, mnesia}]}}.
+ </pre>
+ </section>
+
+</erlref>
+
diff --git a/lib/snmp/doc/src/snmp_impl_example_agent.xml b/lib/snmp/doc/src/snmp_impl_example_agent.xml
new file mode 100644
index 0000000000..3bba6467ed
--- /dev/null
+++ b/lib/snmp/doc/src/snmp_impl_example_agent.xml
@@ -0,0 +1,510 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE chapter SYSTEM "chapter.dtd">
+
+<chapter>
+ <header>
+ <copyright>
+ <year>1997</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ 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.
+
+ </legalnotice>
+
+ <title>Agent Implementation Example</title>
+ <prepared></prepared>
+ <responsible></responsible>
+ <docno></docno>
+ <approved></approved>
+ <checked></checked>
+ <date></date>
+ <rev></rev>
+ <file>snmp_impl_example_agent.xml</file>
+ </header>
+ <p>This <em>Implementation Example</em> section describes how an
+ MIB can be implemented with the SNMP Development Toolkit. </p>
+ <p>The example shown can be found in the toolkit distribution. </p>
+ <p>The agent is configured with the configuration tool, using
+ default suggestions for everything but the manager node. </p>
+
+ <section>
+ <title>MIB</title>
+ <p>The MIB used in this example is called EX1-MIB. It contains two
+ objects, a variable with a name and a table with friends.
+ </p>
+ <code type="none">
+EX1-MIB DEFINITIONS ::= BEGIN
+
+ IMPORTS
+ RowStatus FROM STANDARD-MIB
+ DisplayString FROM RFC1213-MIB
+ OBJECT-TYPE FROM RFC-1212
+ ;
+
+ example1 OBJECT IDENTIFIER ::= { experimental 7 }
+
+ myName OBJECT-TYPE
+ SYNTAX DisplayString (SIZE (0..255))
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "My own name"
+ ::= { example1 1 }
+
+ friendsTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF FriendsEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A list of friends."
+ ::= { example1 4 }
+
+ friendsEntry OBJECT-TYPE
+ SYNTAX FriendsEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ ""
+ INDEX { fIndex }
+ ::= { friendsTable 1 }
+
+ FriendsEntry ::=
+ SEQUENCE {
+ fIndex
+ INTEGER,
+ fName
+ DisplayString,
+ fAddress
+ DisplayString,
+ fStatus
+ RowStatus }
+
+ fIndex OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "number of friend"
+ ::= { friendsEntry 1 }
+
+ fName OBJECT-TYPE
+ SYNTAX DisplayString (SIZE (0..255))
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "Name of friend"
+ ::= { friendsEntry 2 }
+ fAddress OBJECT-TYPE
+ SYNTAX DisplayString (SIZE (0..255))
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "Address of friend"
+ ::= { friendsEntry 3 }
+ fStatus OBJECT-TYPE
+ SYNTAX RowStatus
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The status of this conceptual row."
+ ::= { friendsEntry 4 }
+ fTrap TRAP-TYPE
+ ENTERPRISE example1
+ VARIABLES { myName, fIndex }
+ DESCRIPTION
+ "This trap is sent when something happens to
+ the friend specified by fIndex."
+ ::= 1
+END
+ </code>
+ </section>
+
+ <section>
+ <title>Default Implementation</title>
+ <p>Without writing any instrumentation functions, we can compile
+ the MIB and use the default implementation of it. Recall that MIBs
+ imported by "EX1-MIB.mib" must be present and compiled in the
+ current directory ("./STANDARD-MIB.bin","./RFC1213-MIB.bin") when
+ compiling.
+ </p>
+ <pre>
+unix> <input>erl -config ./sys</input>
+1> <input>application:start(snmp).</input>
+ok
+2> <input>snmpc:compile("EX1-MIB").</input>
+No accessfunction for 'friendsTable', using default.
+No accessfunction for 'myName', using default.
+{ok, "EX1-MIB.bin"}
+3> <input>snmpa:load_mibs(snmp_master_agent, ["EX1-MIB"]).</input>
+ok
+ </pre>
+ <p>This MIB is now loaded into the agent, and a manager can ask
+ questions. As an example of this, we start another Erlang system
+ and the simple Erlang manager in the toolkit:
+ </p>
+ <pre>
+1> <input>snmp_test_mgr:start_link([{agent,"dront.ericsson.se"},{community,"all-rights"},</input>
+ %% making it understand symbolic names: {mibs,["EX1-MIB","STANDARD-MIB"]}]).
+{ok, &lt;0.89.0&gt;}
+%% a get-next request with one OID.
+2> <input>snmp_test_mgr:gn([[1,3,6,1,3,7]]).</input>
+ok
+* Got PDU:
+[myName,0] = []
+%% A set-request (now using symbolic names for convenience)
+3> <input>snmp_test_mgr:s([{[myName,0], "Martin"}]).</input>
+ok
+* Got PDU:
+[myName,0] = "Martin"
+%% Try the same get-next request again
+4> <input>snmp_test_mgr:gn([[1,3,6,1,3,7]]).</input>
+ok
+* Got PDU:
+[myName,0] = "Martin"
+%% ... and we got the new value.
+%% you can event do row operations. How to add a row:
+5> <input>snmp_test_mgr:s([{[fName,0], "Martin"}, {[fAddress,0],"home"}, {[fStatus,0],4}]).</input>
+ %% createAndGo
+ok
+* Got PDU:
+[fName,0] = "Martin"
+[fAddress,0] = "home"
+[fStatus,0] = 4
+6> <input>snmp_test_mgr:gn([[myName,0]]).</input>
+ok
+* Got PDU:
+[fName,0] = "Martin"
+7> <input>snmp_test_mgr:gn().</input>
+ok
+* Got PDU:
+[fAddress,0] = "home"
+8> <input>snmp_test_mgr:gn().</input>
+ok
+* Got PDU:
+[fStatus,0] = 1
+9>
+ </pre>
+ </section>
+
+ <section>
+ <title>Manual Implementation</title>
+ <p>The following example shows a "manual" implementation of the
+ EX1-MIB in Erlang. In this example, the values of the objects are
+ stored in an Erlang server. The server has a 2-tuple as loop
+ data, where the first element is the value of variable
+ <c>myName</c>, and the second is a sorted list of rows in the
+ table <c>friendsTable</c>. Each row is a 4-tuple.
+ </p>
+ <note>
+ <p>There are more efficient ways to create tables manually, i.e.
+ to use the module <c>snmp_index</c>.</p>
+ </note>
+
+ <section>
+ <title>Code</title>
+ <code type="none"><![CDATA[
+-module(ex1).
+-author('[email protected]').
+%% External exports
+-export([start/0, my_name/1, my_name/2, friends_table/3]).
+%% Internal exports
+-export([init/0]).
+-define(status_col, 4).
+-define(active, 1).
+-define(notInService, 2).
+-define(notReady, 3).
+-define(createAndGo, 4). % Action; written, not read
+-define(createAndWait, 5). % Action; written, not read
+-define(destroy, 6). % Action; written, not read
+start() ->
+ spawn(ex1, init, []).
+%%----------------------------------------------------------------
+%% Instrumentation function for variable myName.
+%% Returns: (get) {value, Name}
+%% (set) noError
+%%----------------------------------------------------------------
+my_name(get) ->
+ ex1_server ! {self(), get_my_name},
+ Name = wait_answer(),
+ {value, Name}.
+my_name(set, NewName) ->
+ ex1_server ! {self(), {set_my_name, NewName}},
+ noError.
+%%----------------------------------------------------------------
+%% Instrumentation function for table friendsTable.
+%%----------------------------------------------------------------
+friends_table(get, RowIndex, Cols) ->
+ case get_row(RowIndex) of
+ {ok, Row} ->
+ get_cols(Cols, Row);
+ _ ->
+ {noValue, noSuchInstance}
+ end;
+friends_table(get_next, RowIndex, Cols) ->
+ case get_next_row(RowIndex) of
+ {ok, Row} ->
+ get_next_cols(Cols, Row);
+ _ ->
+ case get_next_row([]) of
+ {ok, Row} ->
+ % Get next cols from first row.
+ NewCols = add_one_to_cols(Cols),
+ get_next_cols(NewCols, Row);
+ _ ->
+ end_of_table(Cols)
+ end
+ end;
+%%----------------------------------------------------------------
+%% If RowStatus is set, then:
+%% *) If set to destroy, check that row does exist
+%% *) If set to createAndGo, check that row does not exist AND
+%% that all columns are given values.
+%% *) Otherwise, error (for simplicity).
+%% Otherwise, row is modified; check that row exists.
+%%----------------------------------------------------------------
+friends_table(is_set_ok, RowIndex, Cols) ->
+ RowExists =
+ case get_row(RowIndex) of
+ {ok, _Row} -> true;
+ _ -> false
+ end,
+ case is_row_status_col_changed(Cols) of
+ {true, ?destroy} when RowExists == true ->
+ {noError, 0};
+ {true, ?createAndGo} when RowExists == false,
+ length(Cols) == 3 ->
+ {noError, 0};
+ {true, _} ->
+ {inconsistentValue, ?status_col};
+ false when RowExists == true ->
+ {noError, 0};
+ _ ->
+ [{Col, _NewVal} | _Cols] = Cols,
+ {inconsistentName, Col}
+ end;
+friends_table(set, RowIndex, Cols) ->
+ case is_row_status_col_changed(Cols) of
+ {true, ?destroy} ->
+ ex1_server ! {self(), {delete_row, RowIndex}};
+ {true, ?createAndGo} ->
+ NewRow = make_row(RowIndex, Cols),
+ ex1_server ! {self(), {add_row, NewRow}};
+ false ->
+ {ok, Row} = get_row(RowIndex),
+ NewRow = merge_rows(Row, Cols),
+ ex1_server ! {self(), {delete_row, RowIndex}},
+ ex1_server ! {self(), {add_row, NewRow}}
+ end,
+ {noError, 0}.
+
+%%----------------------------------------------------------------
+%% Make a list of {value, Val} of the Row and Cols list.
+%%----------------------------------------------------------------
+get_cols([Col | Cols], Row) ->
+ [{value, element(Col, Row)} | get_cols(Cols, Row)];
+get_cols([], _Row) ->
+ [].
+%%----------------------------------------------------------------
+%% As get_cols, but the Cols list may contain invalid column
+%% numbers. If it does, we must find the next valid column,
+%% or return endOfTable.
+%%----------------------------------------------------------------
+get_next_cols([Col | Cols], Row) when Col < 2 ->
+ [{[2, element(1, Row)], element(2, Row)} |
+ get_next_cols(Cols, Row)];
+get_next_cols([Col | Cols], Row) when Col > 4 ->
+ [endOfTable |
+ get_next_cols(Cols, Row)];
+get_next_cols([Col | Cols], Row) ->
+ [{[Col, element(1, Row)], element(Col, Row)} |
+ get_next_cols(Cols, Row)];
+get_next_cols([], _Row) ->
+ [].
+%%----------------------------------------------------------------
+%% Make a list of endOfTable with as many elems as Cols list.
+%%----------------------------------------------------------------
+end_of_table([Col | Cols]) ->
+ [endOfTable | end_of_table(Cols)];
+end_of_table([]) ->
+ [].
+add_one_to_cols([Col | Cols]) ->
+ [Col + 1 | add_one_to_cols(Cols)];
+add_one_to_cols([]) ->
+ [].
+is_row_status_col_changed(Cols) ->
+ case lists:keysearch(?status_col, 1, Cols) of
+ {value, {?status_col, StatusVal}} ->
+ {true, StatusVal};
+ _ -> false
+ end.
+get_row(RowIndex) ->
+ ex1_server ! {self(), {get_row, RowIndex}},
+ wait_answer().
+get_next_row(RowIndex) ->
+ ex1_server ! {self(), {get_next_row, RowIndex}},
+ wait_answer().
+wait_answer() ->
+ receive
+ {ex1_server, Answer} ->
+ Answer
+ end.
+%%%---------------------------------------------------------------
+%%% Server code follows
+%%%---------------------------------------------------------------
+init() ->
+ register(ex1_server, self()),
+ loop("", []).
+
+loop(MyName, Table) ->
+ receive
+ {From, get_my_name} ->
+ From ! {ex1_server, MyName},
+ loop(MyName, Table);
+ {From, {set_my_name, NewName}} ->
+ loop(NewName, Table);
+ {From, {get_row, RowIndex}} ->
+ Res = table_get_row(Table, RowIndex),
+ From ! {ex1_server, Res},
+ loop(MyName, Table);
+ {From, {get_next_row, RowIndex}} ->
+ Res = table_get_next_row(Table, RowIndex),
+ From ! {ex1_server, Res},
+ loop(MyName, Table);
+ {From, {delete_row, RowIndex}} ->
+ NewTable = table_delete_row(Table, RowIndex),
+ loop(MyName, NewTable);
+ {From, {add_row, NewRow}} ->
+ NewTable = table_add_row(Table, NewRow),
+ loop(MyName, NewTable)
+ end.
+%%%---------------------------------------------------------------
+%%% Functions for table operations. The table is represented as
+%%% a list of rows.
+%%%---------------------------------------------------------------
+table_get_row([{Index, Name, Address, Status} | _], [Index]) ->
+ {ok, {Index, Name, Address, Status}};
+table_get_row([H | T], RowIndex) ->
+ table_get_row(T, RowIndex);
+table_get_row([], _RowIndex) ->
+ no_such_row.
+table_get_next_row([Row | T], []) ->
+ {ok, Row};
+table_get_next_row([Row | T], [Index | _])
+when element(1, Row) > Index ->
+ {ok, Row};
+table_get_next_row([Row | T], RowIndex) ->
+ table_get_next_row(T, RowIndex);
+table_get_next_row([], RowIndex) ->
+ endOfTable.
+table_delete_row([{Index, _, _, _} | T], [Index]) ->
+ T;
+table_delete_row([H | T], RowIndex) ->
+ [H | table_delete_row(T, RowIndex)];
+table_delete_row([], _RowIndex) ->
+ [].
+table_add_row([Row | T], NewRow)
+ when element(1, Row) > element(1, NewRow) ->
+ [NewRow, Row | T];
+table_add_row([H | T], NewRow) ->
+ [H | table_add_row(T, NewRow)];
+table_add_row([], NewRow) ->
+ [NewRow].
+make_row([Index], [{2, Name}, {3, Address} | _]) ->
+ {Index, Name, Address, ?active}.
+merge_rows(Row, [{Col, NewVal} | T]) ->
+ merge_rows(setelement(Col, Row, NewVal), T);
+merge_rows(Row, []) ->
+ Row.
+ ]]></code>
+ </section>
+
+ <section>
+ <title>Association File</title>
+ <p>The association file <c>EX1-MIB.funcs</c> for the real
+ implementation looks as follows:
+ </p>
+ <code type="none">
+{myName, {ex1, my_name, []}}.
+{friendsTable, {ex1, friends_table, []}}.
+ </code>
+ </section>
+
+ <section>
+ <title>Transcript</title>
+ <p>To use the real implementation, we must recompile the MIB and
+ load it into the agent.
+ </p>
+ <pre>
+1> <input>application:start(snmp).</input>
+ok
+2> <input>snmpc:compile("EX1-MIB").</input>
+{ok,"EX1-MIB.bin"}
+3> <input>snmpa:load_mibs(snmp_master_agent, ["EX1-MIB"]).</input>
+ok
+4> <input>ex1:start().</input>
+&lt;0.115.0&gt;
+%% Now all requests operates on this "real" implementation.
+%% The output from the manager requests will *look* exactly the
+%% same as for the default implementation.
+ </pre>
+ </section>
+
+ <section>
+ <title>Trap Sending</title>
+ <p>How to send a trap by sending the
+ <c>fTrap</c> from the master agent is shown in this section.
+ The master agent has the MIB <c>EX1-MIB</c> loaded, where the
+ trap is defined. This trap specifies that two variables should
+ be sent along with the trap, <c>myName</c> and <c>fIndex</c>.
+ <c>fIndex</c> is a table column, so we must provide its value
+ and the index for the row in the call to <c>snmpa:send_trap/4</c>.
+ In the example below, we assume that the row in question is
+ indexed by 2 (the row with <c>fIndex</c> 2).
+ </p>
+ <p>we use a simple Erlang SNMP manager, which can receive traps.
+ </p>
+ <pre>
+[MANAGER]
+1> <input>snmp_test_mgr:start_link([{agent,"dront.ericsson.se"},{community,"public"}</input>
+ %% does not have write-access
+1><input>{mibs,["EX1-MIB","STANDARD-MIB"]}]).</input>
+{ok, &lt;0.100.0&gt;}
+2> <input>snmp_test_mgr:s([{[myName,0], "Klas"}]).</input>
+ok
+* Got PDU:
+Received a trap:
+ Generic: 4 %% authenticationFailure
+ Enterprise: [iso,2,3]
+ Specific: 0
+ Agent addr: [123,12,12,21]
+ TimeStamp: 42993
+2>
+[AGENT]
+3> <input>snmpa:send_trap(snmp_master_agent, fTrap,"standard trap", [{fIndex,[2],2}]).</input>
+[MANAGER]
+2>
+* Got PDU:
+Received a trap:
+ Generic: 6
+ Enterprise: [example1]
+ Specific: 1
+ Agent addr: [123,12,12,21]
+ TimeStamp: 69649
+[myName,0] = "Martin"
+[fIndex,2] = 2
+2>
+ </pre>
+ </section>
+ </section>
+</chapter>
+
diff --git a/lib/snmp/doc/src/snmp_impl_example_manager.xml b/lib/snmp/doc/src/snmp_impl_example_manager.xml
new file mode 100644
index 0000000000..edc1f3998e
--- /dev/null
+++ b/lib/snmp/doc/src/snmp_impl_example_manager.xml
@@ -0,0 +1,94 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE chapter SYSTEM "chapter.dtd">
+
+<chapter>
+ <header>
+ <copyright>
+ <year>2006</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ 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.
+
+ </legalnotice>
+
+ <title>Manager Implementation Example</title>
+ <prepared></prepared>
+ <responsible></responsible>
+ <docno></docno>
+ <approved></approved>
+ <checked></checked>
+ <date></date>
+ <rev></rev>
+ <file>snmp_impl_example_manager.xml</file>
+ </header>
+ <p>This <em>Implementation Example</em> section describes
+ how a simple manager can be implemented with the
+ SNMP Development Toolkit. </p>
+ <p>The example shown, <em>ex2</em>, can be found in the toolkit
+ distribution. </p>
+ <p>This example has two functions: </p>
+ <list type="bulleted">
+ <item>
+ <p>A simple example of how to use the manager component of
+ the SNMP Development Toolkit.</p>
+ </item>
+ <item>
+ <p>A simple example of how to write agent test cases, using the new
+ manager.</p>
+ </item>
+ </list>
+
+ <section>
+ <title>The example manager</title>
+ <p>The example manager, <c>snmp_ex2_manager</c>, is a simple example of
+ how to implement an snmp manager using the manager component of the
+ SNMP Development Toolkit.</p>
+ <p>The module exports the following functions:</p>
+ <list type="bulleted">
+ <item>
+ <p>start_link/0, start_link/1</p>
+ </item>
+ <item>
+ <p>stop/0</p>
+ </item>
+ <item>
+ <p>agent/2, agent/3</p>
+ </item>
+ <item>
+ <p>sync_get/2, sync_get/3</p>
+ </item>
+ <item>
+ <p>sync_get_next/2, sync_get_next/3</p>
+ </item>
+ <item>
+ <p>sync_get_bulk/4, sync_get_bulk/5</p>
+ </item>
+ <item>
+ <p>sync_set/2, sync_set/3</p>
+ </item>
+ <item>
+ <p>oid_to_name/1</p>
+ </item>
+ </list>
+ <p>This module is also used by the test module described in the
+ next section.</p>
+ </section>
+
+ <section>
+ <title>A simple standard test</title>
+ <p>This simple standard test, <c>snmp_ex2_simple_standard_test</c>,
+ a module which, using the <c>snmp_ex2_manager</c> described in the
+ previous section, implements a simple agent test utility. </p>
+ </section>
+</chapter>
+
diff --git a/lib/snmp/doc/src/snmp_index.xml b/lib/snmp/doc/src/snmp_index.xml
new file mode 100644
index 0000000000..cd241820e8
--- /dev/null
+++ b/lib/snmp/doc/src/snmp_index.xml
@@ -0,0 +1,266 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE erlref SYSTEM "erlref.dtd">
+
+<erlref>
+ <header>
+ <copyright>
+ <year>1997</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ 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.
+
+ </legalnotice>
+
+ <title>snmp_index</title>
+ <prepared></prepared>
+ <responsible></responsible>
+ <docno></docno>
+ <approved></approved>
+ <checked></checked>
+ <date></date>
+ <rev></rev>
+ <file>snmp_index.xml</file>
+ </header>
+ <module>snmp_index</module>
+ <modulesummary>Abstract Data Type for SNMP Indexing</modulesummary>
+ <description>
+ <p>The module <c>snmp_index</c> implements an Abstract
+ Data Type (ADT) for an SNMP
+ index structure for SNMP tables. It is implemented as an ets
+ table of the ordered_set data-type, which means that all operations are
+ O(log n). In the table, the key is an ASN.1 OBJECT
+ IDENTIFIER.
+ </p>
+ <p>This index is used to separate the implementation of the SNMP
+ ordering from the actual implementation of the table. The SNMP
+ ordering, that is implementation of GET NEXT, is implemented in this
+ module.
+ </p>
+ <p>For example, suppose there is an SNMP table, which is best
+ implemented in Erlang as one process per SNMP table row. Suppose
+ further that the INDEX in the SNMP table is an OCTET STRING. The
+ index structure would be created as follows:
+ </p>
+ <code type="none">
+snmp_index:new(string)
+ </code>
+ <p>For each new process we create, we insert an item in an
+ <c>snmp_index</c> structure:
+ </p>
+ <code type="none"><![CDATA[
+new_process(Name, SnmpIndex) ->
+ Pid = start_process(),
+ NewSnmpIndex =
+ snmp_index:insert(SnmpIndex, Name, Pid),
+ <...>
+ ]]></code>
+ <p>With this structure, we can now map an OBJECT IDENTIFIER in
+ e.g. a GET NEXT request, to the correct process:
+ </p>
+ <code type="none">
+get_next_pid(Oid, SnmpIndex) ->
+ {ok, {_, Pid}} = snmp_index:get_next(SnmpIndex, Oid),
+ Pid.
+ </code>
+ </description>
+
+ <section>
+ <title>Common data types</title>
+ <p>The following data types are used in the functions below:
+ </p>
+ <list type="bulleted">
+ <item>
+ <p><c>index()</c></p>
+ </item>
+ <item>
+ <p><c>oid() = [byte()]</c></p>
+ </item>
+ <item>
+ <p><c>key_types = type_spec() | {type_spec(), type_spec(), ...}</c></p>
+ </item>
+ <item>
+ <p><c>type_spec() = fix_string | string | integer</c></p>
+ </item>
+ <item>
+ <p><c>key() = key_spec() | {key_spec(), key_spec(), ...}</c></p>
+ </item>
+ <item>
+ <p><c>key_spec() = string() | integer()</c></p>
+ </item>
+ </list>
+ <p>The <c>index()</c> type denotes an snmp index structure.
+ </p>
+ <p>The <c>oid()</c> type is used to represent an ASN.1 OBJECT
+ IDENTIFIER.
+ </p>
+ <p>The <c>key_types()</c> type is used when creating the
+ index structure, and the <c>key()</c> type is used when inserting
+ and deleting items from the structure.
+ </p>
+ <p>The <c>key_types()</c> type defines the types of the SNMP INDEX
+ columns for the table. If the table has one single INDEX column,
+ this type should be a single atom, but if the table has multiple
+ INDEX columns, it should be a tuple with atoms.
+ </p>
+ <p>If the INDEX column is of type INTEGER, or derived from
+ INTEGER, the corresponding type should be <c>integer</c>. If it
+ is a variable length type (e.g. OBJECT IDENTIFIER, OCTET STRING),
+ the corresponding type should be <c>string</c>. Finally, if the
+ type is of variable length, but with a fixed size restriction
+ (e.g. IpAddress), the corresponding type should be
+ <c>fix_string</c>.
+ </p>
+ <p>For example, if the SNMP table has two INDEX columns, the first
+ one an OCTET STRING with size 2, and the second one an OBJECT
+ IDENTIFER, the corresponding <c>key_types</c> parameter would be
+ <c>{fix_string, string}</c>.
+ </p>
+ <p>The <c>key()</c> type correlates to the <c>key_types()</c>
+ type. If the <c>key_types()</c> is a single atom, the
+ corresponding <c>key()</c> is a single type as well, but if the
+ <c>key_types()</c> is a tuple, <c>key</c> must be a tuple of the
+ same size.
+ </p>
+ <p>In the example above, valid <c>keys</c> could be <c>{"hi", "mom"}</c> and <c>{"no", "thanks"}</c>, whereas <c>"hi"</c>,
+ <c>{"hi", 42}</c> and <c>{"hello", "there"}</c> would be invalid.</p>
+ <warning>
+ <marker id="1"></marker>
+ <p>All API functions that update the index return a <c>NewIndex</c>
+ term. This is for backward compatibility with a previous
+ implementation that used a B+ tree written purely in Erlang for
+ the index. The <c>NewIndex</c> return value can now be ignored.
+ The return value is now the unchanged table identifier for the
+ ets table.</p>
+ <p>The implementation using ets tables introduces a semantic
+ incompatibility with older implementations. In those older
+ implementations, using pure Erlang terms, the index was garbage
+ collected like any other Erlang term and did not have to be
+ deleted when discarded. An ets table is deleted only when the
+ process creating it explicitly deletes it or when the creating
+ process terminates.</p>
+ <p>A new interface <c>delete/1</c> is now added to
+ handle the case when a process wants to discard an index table
+ (i.e. to build a completely new). Any application using
+ transient snmp indexes has to be modified to handle this.</p>
+ <p>As an snmp adaption usually keeps the index for the whole of the
+ systems lifetime, this is rarely a problem.</p>
+ </warning>
+ </section>
+ <funcs>
+ <func>
+ <name>delete(Index) -> true</name>
+ <fsummary>Delete an index table</fsummary>
+ <type>
+ <v>Index = NewIndex = index()</v>
+ <v>Key = key()</v>
+ </type>
+ <desc>
+ <p>Deletes a complete index structure (i.e. the ets table
+ holding the index). The index can no longer be referenced
+ after this call. See the <seealso marker="#1">warning note</seealso>
+ above.</p>
+ </desc>
+ </func>
+ <func>
+ <name>delete(Index, Key) -> NewIndex</name>
+ <fsummary>Delete an item from the index</fsummary>
+ <type>
+ <v>Index = NewIndex = index()</v>
+ <v>Key = key()</v>
+ </type>
+ <desc>
+ <p>Deletes a key and its value from the index structure.
+ Returns a new structure.</p>
+ </desc>
+ </func>
+ <func>
+ <name>get(Index, KeyOid) -> {ok, {KeyOid, Value}} | undefined</name>
+ <fsummary>Get the item with <c>KeyOid</c></fsummary>
+ <type>
+ <v>Index = index()</v>
+ <v>KeyOid = oid()</v>
+ <v>Value = term()</v>
+ </type>
+ <desc>
+ <p>Gets the item with key <c>KeyOid</c>. Could be used from
+ within an SNMP instrumentation function.</p>
+ </desc>
+ </func>
+ <func>
+ <name>get_last(Index) -> {ok, {KeyOid, Value}} | undefined</name>
+ <fsummary>Get the last item in the index structure</fsummary>
+ <type>
+ <v>Index = index()</v>
+ <v>KeyOid = oid()</v>
+ <v>Value = term()</v>
+ </type>
+ <desc>
+ <p>Gets the last item in the index structure.</p>
+ </desc>
+ </func>
+ <func>
+ <name>get_next(Index, KeyOid) -> {ok, {NextKeyOid, Value}} | undefined</name>
+ <fsummary>Get the next item</fsummary>
+ <type>
+ <v>Index = index()</v>
+ <v>KeyOid = NextKeyOid = oid()</v>
+ <v>Value = term()</v>
+ </type>
+ <desc>
+ <p>Gets the next item in the SNMP lexicographic ordering,
+ after <c>KeyOid</c> in the index structure. <c>KeyOid</c>
+ does not have to refer to an existing item in the index.</p>
+ </desc>
+ </func>
+ <func>
+ <name>insert(Index, Key, Value) -> NewIndex</name>
+ <fsummary>Insert an item into the index</fsummary>
+ <type>
+ <v>Index = NewIndex = index()</v>
+ <v>Key = key()</v>
+ <v>Value = term()</v>
+ </type>
+ <desc>
+ <p>Inserts a new key value tuple into the index structure. If
+ an item with the same key already exists, the new <c>Value</c>
+ overwrites the old value.</p>
+ </desc>
+ </func>
+ <func>
+ <name>key_to_oid(Index, Key) -> KeyOid</name>
+ <fsummary>Convert a key to an OBJECT IDENTIFIER</fsummary>
+ <type>
+ <v>Index = index()</v>
+ <v>Key = key()</v>
+ <v>KeyOid = NextKeyOid = oid()</v>
+ </type>
+ <desc>
+ <p>Converts <c>Key</c> to an OBJECT IDENTIFIER.</p>
+ </desc>
+ </func>
+ <func>
+ <name>new(KeyTypes) -> Index</name>
+ <fsummary>Create a new snmp index structure</fsummary>
+ <type>
+ <v>KeyTypes = key_types()</v>
+ <v>Index = index()</v>
+ </type>
+ <desc>
+ <p>Creates a new snmp index structure. The <c>key_types()</c>
+ type is described above.</p>
+ </desc>
+ </func>
+ </funcs>
+
+</erlref>
+
diff --git a/lib/snmp/doc/src/snmp_instr_functions.xml b/lib/snmp/doc/src/snmp_instr_functions.xml
new file mode 100644
index 0000000000..32a1844554
--- /dev/null
+++ b/lib/snmp/doc/src/snmp_instr_functions.xml
@@ -0,0 +1,456 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE chapter SYSTEM "chapter.dtd">
+
+<chapter>
+ <header>
+ <copyright>
+ <year>1997</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ 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.
+
+ </legalnotice>
+
+ <title>Instrumentation Functions</title>
+ <prepared></prepared>
+ <responsible></responsible>
+ <docno></docno>
+ <approved></approved>
+ <checked></checked>
+ <date></date>
+ <rev></rev>
+ <file>snmp_instr_functions.xml</file>
+ </header>
+ <p>A user-defined instrumentation function for each object attaches
+ the managed objects to real resources. This function is called by
+ the agent on a <c>get</c> or <c>set</c> operation. The function
+ could read some hardware register, perform a calculation, or
+ whatever is necessary to implement the semantics associated with the
+ conceptual variable. These functions must be written both for scalar
+ variables and for tables. They are specified in the association
+ file, which is a text file. In this file, the <c>OBJECT IDENTIFIER</c>, or symbolic name for each managed object, is
+ associated with an Erlang tuple <c>{Module,</c><c>Function</c>,
+ <c>ListOfExtraArguments}</c>.
+ </p>
+ <p>When a managed object is referenced in an SNMP operation, the
+ associated <c>{Module, Function, ListOfExtraArguments}</c> is
+ called. The function is applied to some standard arguments (for
+ example, the operation type) and the extra arguments supplied by the
+ user.
+ </p>
+ <p>Instrumentation functions must be written for <c>get</c> and
+ <c>set</c> for scalar variables and tables, and for <c>get-next</c>
+ for tables only. The <c>get-bulk</c> operation is translated into a
+ series of calls to <c>get-next</c>.
+ </p>
+
+ <section>
+ <title>Instrumentation Functions</title>
+ <p>The following sections describe how the instrumentation
+ functions should be defined in Erlang for the different
+ operations. In the following, <c>RowIndex</c> is a list of key
+ values for the table, and <c>Column</c> is a column number.
+ </p>
+ <p>These functions are described in detail in
+ <seealso marker="snmp_def_instr_functions">Definition of Instrumentation Functions</seealso>.
+ </p>
+
+ <section>
+ <title>New / Delete Operations</title>
+ <p>For scalar variables:
+ </p>
+ <code type="none">
+variable_access(new [, ExtraArg1, ...])
+variable_access(delete [, ExtraArg1, ...])
+ </code>
+ <p>For tables:
+ </p>
+ <code type="none">
+table_access(new [, ExtraArg1, ...])
+table_access(delete [, ExtraArg1, ...])
+ </code>
+ <p>These functions are called for each object in an MIB when the
+ MIB is unloaded or loaded, respectively.</p>
+ </section>
+
+ <section>
+ <title>Get Operation</title>
+ <p>For scalar variables:
+ </p>
+ <code type="none">
+variable_access(get [, ExtraArg1, ...])
+ </code>
+ <p>For tables:
+ </p>
+ <code type="none">
+table_access(get,RowIndex,Cols [,ExtraArg1, ...])
+ </code>
+ <p><c>Cols</c> is a list of <c>Column</c>. The agent will sort
+ incoming variables so that all operations on one row (same
+ index) will be supplied at the same time. The reason for this is
+ that a database normally retrieves information row by row.
+ </p>
+ <p>These functions must return the current values of the
+ associated variables.</p>
+ </section>
+
+ <section>
+ <title>Set Operation</title>
+ <p>For scalar variables:
+ </p>
+ <code type="none">
+variable_access(set, NewValue [, ExtraArg1, ...])
+ </code>
+ <p>For tables:
+ </p>
+ <code type="none">
+table_access(set, RowIndex, Cols [, ExtraArg1,..])
+ </code>
+ <p><c>Cols</c> is a list of tuples <c>{Column, NewValue}</c>.
+ </p>
+ <p>These functions returns <c>noError</c> if the assignment was
+ successful, otherwise an error code.</p>
+ </section>
+
+ <section>
+ <title>Is-set-ok Operation</title>
+ <p>As a complement to the <c>set</c> operation, it is possible
+ to specify a test function. This function has the same syntax as
+ the set operation above, except that the first argument is
+ <c>is_set_ok</c> instead of <c>set</c>. This function is called
+ before the variable is set. Its purpose is to ensure that it is
+ permissible to set the variable to the new value.</p>
+ <code type="none">
+variable_access(is_set_ok, NewValue [, ExtraArg1, ...])
+ </code>
+ <p>For tables:
+ </p>
+ <code type="none">
+table_access(set, RowIndex, Cols [, ExtraArg1,..])
+ </code>
+ <p><c>Cols</c> is a list of tuples <c>{Column, NewValue}</c>.
+ </p>
+ </section>
+
+ <section>
+ <title>Undo Operation</title>
+ <p>A function which has been called with <c>is_set_ok</c> will
+ be called again, either with <c>set</c> if there was no error,
+ or with <c>undo</c>, if an error occurred. In this way,
+ resources can be reserved in the <c>is_set_ok</c> operation,
+ released in the <c>undo</c> operation, or made permanent in the
+ <c>set</c> operation.</p>
+ <code type="none">
+variable_access(undo, NewValue [, ExtraArg1, ...])
+ </code>
+ <p>For tables:
+ </p>
+ <code type="none">
+table_access(set, RowIndex, Cols [, ExtraArg1,..])
+ </code>
+ <p><c>Cols</c> is a list of tuples <c>{Column, NewValue}</c>.
+ </p>
+ </section>
+
+ <section>
+ <title>GetNext Operation</title>
+ <p>The GetNext Operation operation should only be defined for
+ tables since the
+ agent can find the next instance of plain variables in the MIB
+ and call the instrumentation with the <c>get</c> operation.
+ </p>
+ <code type="none">
+table_access(get_next, RowIndex, Cols [, ExtraArg1, ...])
+ </code>
+ <p><c>Cols</c> is a list of integers, all greater than or equal
+ to zero. This indicates that the instrumentation should find the
+ next accessible instance. This function returns the tuple
+ <c>{NextOid, NextValue}</c>, or
+ <c>endOfTable</c>. <c>NextOid</c> should be the
+ lexicographically next accessible instance of a managed object
+ in the table. It should be a list of integers, where the first
+ integer is the column, and the rest of the list is the indices
+ for the next row. If <c>endOfTable</c> is returned, the agent
+ continues to search for the next instance among the other
+ variables and tables.
+ </p>
+ <p><c>RowIndex</c> may be an empty list, an incompletely
+ specified row index, or the index for an unspecified row.
+ </p>
+ <p>This operation is best described with an example.
+ </p>
+
+ <section>
+ <title>GetNext Example</title>
+ <p>A table called <c>myTable</c> has five columns. The first
+ two are keys (not accessible), and the table has three
+ rows. The instrumentation function for this table is called
+ <c>my_table</c>.</p>
+ <marker id="getnext1"></marker>
+ <image file="getnext1.gif">
+ <icaption>Contents of my_table</icaption>
+ </image>
+ <note>
+ <p>N/A means not accessible.</p>
+ </note>
+ <p>The manager issues the following <c>getNext</c> request:
+ </p>
+ <code type="none">
+getNext{ myTable.myTableEntry.3.1.1,
+ myTable.myTableEntry.5.1.1 }
+ </code>
+ <p>Since both operations involve the 1.1 index, this is
+ transformed into one call to <c>my_table</c>:
+ </p>
+ <code type="none">
+my_table(get_next, [1, 1], [3, 5])
+ </code>
+ <p>In this call, <c>[1, 1]</c> is the <c>RowIndex</c>, where
+ key 1 has value 1, and key 2 has value 1, and <c>[3, 5]</c> is
+ the list of requested columns. The function should now return
+ the lexicographically next elements:
+ </p>
+ <code type="none">
+[{[3, 1, 2], d}, {[5, 1, 2], f}]
+ </code>
+ <p>This is illustrated in the following table:
+ </p>
+ <p></p>
+ <marker id="getnext2"></marker>
+ <image file="getnext2.gif">
+ <icaption>GetNext from [3,1,1] and [5,1,1].</icaption>
+ </image>
+ <p>The manager now issues the following <c>getNext</c> request:
+ </p>
+ <code type="none">
+getNext{ myTable.myTableEntry.3.2.1,
+ myTable.myTableEntry.5.2.1 }
+ </code>
+ <p>This is transformed into one call to <c>my_table</c>:
+ </p>
+ <code type="none">
+my_table(get_next, [2, 1], [3, 5])
+ </code>
+ <p>The function should now return:
+ </p>
+ <code type="none">
+[{[4, 1, 1], b}, endOfTable]
+ </code>
+ <p>This is illustrated in the following table:
+ </p>
+ <p></p>
+ <marker id="getnext3"></marker>
+ <image file="getnext3.gif">
+ <icaption>GetNext from [3,2,1] and [5,2,1].</icaption>
+ </image>
+ <p>The manager now issues the following <c>getNext</c> request:
+ </p>
+ <code type="none">
+getNext{ myTable.myTableEntry.3.1.2,
+ myTable.myTableEntry.4.1.2 }
+ </code>
+ <p>This will be transform into one call to <c>my_table</c>:
+ </p>
+ <code type="none">
+my_table(get_next, [1, 2], [3, 4])
+ </code>
+ <p>The function should now return:
+ </p>
+ <code type="none">
+[{[3, 2, 1], g}, {[5, 1, 1], c}]
+ </code>
+ <p>This is illustrated in the following table:
+ </p>
+ <p></p>
+ <marker id="getnext4"></marker>
+ <image file="getnext4.gif">
+ <icaption>GetNext from [3,1,2] and [4,1,2].</icaption>
+ </image>
+ <p>The manager now issues the following <c>getNext</c> request:
+ </p>
+ <code type="none">
+getNext{ myTable.myTableEntry,
+ myTable.myTableEntry.1.3.2 }
+ </code>
+ <p>This will be transform into two calls to <c>my_table</c>:
+ </p>
+ <code type="none">
+my_table(get_next, [], [0]) and
+my_table(get_next, [3, 2], [1])
+ </code>
+ <p>The function should now return:
+ </p>
+ <code type="none">
+[{[3, 1, 1], a}] and
+[{[3, 1, 1], a}]
+ </code>
+ <p>In both cases, the first accessible element in the table
+ should be returned. As the key columns are not accessible,
+ this means that the third column is the first row.</p>
+ <note>
+ <p>Normally, the functions described above behave exactly as
+ shown, but they are free to perform other actions. For
+ example, a get-request may have side effects such as setting
+ some other variable, perhaps a global <c>lastAccessed</c>
+ variable.</p>
+ </note>
+ </section>
+ </section>
+ </section>
+
+ <section>
+ <title>Using the ExtraArgument</title>
+ <p>The <c>ListOfExtraArguments</c> can be used to write generic
+ functions. This list is appended to the standard arguments for
+ each function. Consider two read-only variables for a device,
+ <c>ipAdr</c> and <c>name</c> with object identifiers 1.1.23.4 and
+ 1.1.7 respectively. To access these variables, one could implement
+ the two Erlang functions <c>ip_access</c> and <c>name_access</c>,
+ which will be in the MIB. The functions could be specified in a
+ text file as follows:
+ </p>
+ <p></p>
+ <code type="none">
+{ipAdr, {my_module, ip_access, []}}.
+% Or using the oid syntax for 'name'
+{[1,1,7], {my_module, name_access, []}}.
+ </code>
+ <p>The <c>ExtraArgument</c> parameter is the empty list. For
+ example, when the agent receives a get-request for the
+ <c>ipAdr</c> variable, a call will be made to
+ <c>ip_access(get)</c>. The value returned by this function is the
+ answer to the get-request.
+ </p>
+ <p>If <c>ip_access</c> and <c>name_access</c> are implemented
+ similarly, we could write a <c>generic_access</c> function using
+ the <c>ListOfExtraArguments</c>:
+ </p>
+ <code type="none">
+{ipAdr, {my_module, generic_access, ['IPADR']}}.
+% The mnemonic 'name' is more convenient than 1.1.7
+{name, {my_module, generic_access, ['NAME']}}.
+ </code>
+ <p>When the agent receives the same get-request as above, a call
+ will be made to <c>generic_access(get, </c>'<c>IPADR')</c>.
+ </p>
+ <p>Yet another possibility, closer to the hardware, could be:
+ </p>
+ <code type="none">
+{ipAdr, {my_module, generic_access, [16#2543]}}.
+{name, {my_module, generic_access, [16#A2B3]}}.
+ </code>
+ </section>
+
+ <section>
+ <title>Default Instrumentation</title>
+ <marker id="snmp_3"></marker>
+ <p>When the MIB definition work is finished, there are two major
+ issues left.
+ </p>
+ <list type="bulleted">
+ <item>Implementing the MIB
+ </item>
+ <item>Implementing a Manager Application.</item>
+ </list>
+ <p>Implementing an MIB can be a tedious task. Most probably, there
+ is a need to test the agent before all tables and variables are
+ implemented. In this case, the default instrumentation functions
+ are useful. The toolkit can generate default instrumentation
+ functions for variables as well as for tables. Consequently, a
+ running prototype agent, which can handle <c>set</c>, <c>get</c>,
+ <c>get-next</c> and table operations, is generated without any
+ programming.
+ </p>
+ <p>The agent stores the values in an internal volatile database,
+ which is based on the standard module <c>ets</c>. However, it is
+ possible to let the MIB compiler generate functions which use an
+ internal, persistent database, or the Mnesia DBMS. Refer to the
+ Mnesia User Guide and the Reference Manual, section SNMP, module
+ <c>snmp_generic</c> for more information.
+ </p>
+ <p>When parts of the MIB are implemented, you recompile it and
+ continue on by using default functions. With this approach, the
+ SNMP agent can be developed incrementally.
+ </p>
+ <p>The default instrumentation allows the application on the
+ manager side to be developed and tested simultaneously with the
+ agent. As soon as the ASN.1 file is completed, let the MIB
+ compiler generate a default implementation and develop the
+ management application from this.
+ </p>
+
+ <section>
+ <title>Table Operations</title>
+ <p>The generation of default functions for tables works for
+ tables which use the <c>RowStatus</c> textual convention from
+ SNMPv2, defined in STANDARD-MIB and SNMPv2-TC.
+ </p>
+ <note>
+ <p>We strongly encourage the use of the <c>RowStatus</c>
+ convention for every table that can be modified from the
+ manager, even for newly designed SNMPv1 MIBs. In SNMPv1,
+ everybody has invented their own scheme for emulating table
+ operations, which has led to numerous inconsistencies. The
+ convention in SNMPv2 is flexible and powerful and has been
+ tested successfully. If the table is read only, no RowStatus
+ column should be used.
+ </p>
+ </note>
+ </section>
+ </section>
+
+ <section>
+ <title>Atomic Set</title>
+ <p>In SNMP, the <c>set</c> operation is atomic. Either all
+ variables which are specified in a <c>set</c> operation are
+ changed, or none are changed. Therefore, the <c>set</c> operation
+ is divided into two phases. In the first phase, the new value of
+ each variable is checked against the definition of the variable in
+ the MIB. The following definitions are checked:
+ </p>
+ <list type="bulleted">
+ <item>the type</item>
+ <item>the length</item>
+ <item>the range</item>
+ <item>the variable is writable and within the MIB view.
+ </item>
+ </list>
+ <p>At
+ the end of phase one, the user defined <c>is_set_ok</c> functions
+ are called for each scalar variable, and for each group of table
+ operations.
+ </p>
+ <p>If no error occurs, the second phase is performed. This phase
+ calls the user defined <c>set</c> function for all variables.
+ </p>
+ <p>If an error occurs, either in the <c>is_set_ok</c> phase, or in
+ the <c>set</c> phase, all functions which were called with
+ <c>is_set_ok</c> but not <c>set</c>, are called with <c>undo</c>.
+ </p>
+ <p>There are limitations with this transaction mechanism. If
+ complex dependencies exist between variables, for example between
+ <c>month</c> and <c>day</c>, another mechanism is needed. Setting
+ the date to 'Feb 31' can be avoided by a somewhat more generic
+ transaction mechanism. You can continue and find more and more
+ complex situations and construct an N-phase set-mechanism. This
+ toolkit only contains a trivial mechanism.
+ </p>
+ <p>The most common application of transaction mechanisms is to
+ keep row operations together. Since our agent sorts row
+ operations, the mechanism implemented in combination with the
+ RowStatus (particularly 'createAndWait' value) solve most
+ problems elegantly.
+ </p>
+ </section>
+</chapter>
+
diff --git a/lib/snmp/doc/src/snmp_intro.xml b/lib/snmp/doc/src/snmp_intro.xml
new file mode 100644
index 0000000000..b01bfdd88f
--- /dev/null
+++ b/lib/snmp/doc/src/snmp_intro.xml
@@ -0,0 +1,258 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE chapter SYSTEM "chapter.dtd">
+
+<chapter>
+ <header>
+ <copyright>
+ <year>1997</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ 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.
+
+ </legalnotice>
+
+ <title>SNMP Introduction</title>
+ <prepared></prepared>
+ <responsible></responsible>
+ <docno></docno>
+ <approved></approved>
+ <checked></checked>
+ <date></date>
+ <rev></rev>
+ <file>snmp_intro.xml</file>
+ </header>
+ <p>The SNMP development toolkit contains the following parts:
+ </p>
+ <list type="bulleted">
+ <item>An Extensible multi-lingual SNMP agent, which understands SNMPv1
+ (RFC1157), SNMPv2c (RFC1901, 1905, 1906 and 1907), SNMPv3
+ (RFC2271, 2272, 2273, 2274 and 2275), or any combination of
+ these protocols.
+ </item>
+ <item>A multi-lingual SNMP manager.
+ </item>
+ <item>A MIB compiler, which understands SMIv1 (RFC1155, 1212, and
+ 1215) and SMIv2 (RFC1902, 1903, and 1904).
+ </item>
+ </list>
+ <p>The SNMP development tool provides an environment for
+ rapid agent/manager prototyping and construction. With the
+ following information provided, this tool is used to set up a
+ running multi-lingual SNMP agent/manager:
+ </p>
+ <list type="bulleted">
+ <item>a description of a Management Information Base (MIB) in
+ Abstract Syntax Notation One (ASN.1)
+ </item>
+ <item>instrumentation functions for the managed objects in the MIB,
+ written in Erlang.
+ </item>
+ </list>
+ <p>The advantage of using an extensible (agent/manager) toolkit is to
+ remove details such as type-checking, access rights, Protocol Data Unit
+ (PDU), encoding, decoding, and trap distribution from the
+ programmer, who only has to write the instrumentation functions,
+ which implement the MIBs. The <c>get-next</c> function only
+ has to be implemented for tables, and not for every variable in
+ the global naming tree. This information can be deduced from the
+ ASN.1 file.
+ </p>
+
+ <section>
+ <title>Scope and Purpose</title>
+ <p>This manual describes the SNMP development tool,
+ as a component of the Erlang/Open Telecom Platform development
+ environment. It is assumed that the reader is familiar with the
+ Erlang Development Environment, which is described in a separate
+ User's Guide.</p>
+ </section>
+
+ <section>
+ <title>Prerequisites</title>
+ <p>The following prerequisites
+ is required for understanding the material in the SNMP
+ User's Guide:
+ </p>
+ <list type="bulleted">
+ <item>the basics of the Simple Network Management Protocol
+ version 1 (SNMPv1)
+ </item>
+ <item>the basics of the community-based Simple Network
+ Management Protocol version 2 (SNMPv2c)
+ </item>
+ <item>the basics of the Simple Network Management Protocol
+ version 3 (SNMPv3)
+ </item>
+ <item>the knowledge of defining MIBs using SMIv1 and SMIv2
+ </item>
+ <item>familiarity with the Erlang system and Erlang programming
+ </item>
+ </list>
+ <p>The tool requires Erlang release 4.7 or later.
+ </p>
+ </section>
+
+ <section>
+ <title>Definitions</title>
+ <p>The following definitions are used in the SNMP User's Guide.
+ </p>
+ <taglist>
+ <tag>MIB</tag>
+ <item>The conceptual repository for management information is
+ called the Management Information Base (MIB). It does not
+ hold any data, merely a definition of what
+ data can be accessed. A definition of an MIB is a
+ description of a collection of managed objects.
+ </item>
+ <tag>SMI</tag>
+ <item>The MIB is specified in an adapted subset of the Abstract
+ Syntax Notation One (ASN.1) language. This adapted subset is
+ called the Structure of Management Information (SMI).
+ </item>
+ <tag>ASN.1</tag>
+ <item>ASN.1 is used in two different ways in SNMP. The SMI is
+ based on ASN.1, and the messages in the protocol are defined by
+ using ASN.1.
+ </item>
+ <tag>Managed object</tag>
+ <item>
+ <p>A resource to be managed is represented by a managed
+ object, which resides in the MIB. In an SNMP MIB, the managed
+ objects are either:</p>
+ <list type="bulleted">
+ <item><em>scalar variables</em>, which have only one instance
+ per context. They have single values, not multiple values like
+ vectors or structures.
+ </item>
+ <item><em>tables</em>, which can grow dynamically.
+ </item>
+ <item>a <em>table element</em>, which is a special type of
+ scalar variable.</item>
+ </list>
+ </item>
+ <tag>Operations</tag>
+ <item>SNMP relies on the three basic operations: get (object),
+ set (object, value) and get-next (object).
+ </item>
+ <tag>Instrumentation function</tag>
+ <item>An instrumentation function is associated with each
+ managed object. This is the function, which actually implements
+ the operations and will be called by the agent when it receives
+ a request from the management station.</item>
+ <tag>Manager</tag>
+ <item>A manager generates commands and receives notifications
+ from agents. There usually are only a few managers in a system.</item>
+ <tag>Agent</tag>
+ <item>An agent responds to commands from the manager, and sends
+ notification to the manager. There are potentially many agents
+ in a system.</item>
+ </taglist>
+ </section>
+
+ <section>
+ <title>About This Manual</title>
+ <p>In addition to this introductory chapter, the SNMP User's Guide
+ contains the following chapters:
+ </p>
+ <list type="bulleted">
+ <item>Chapter 2: "Functional Description" describes the features
+ and operation of the SNMP development toolkit. It includes
+ topics on Sub-agents and MIB loading, Internal MIBs, and Traps.
+ </item>
+ <item>Chapter 3: "The MIB Compiler" describes the features and the
+ operation of the MIB compiler.
+ </item>
+ <item>Chapter 4: "Running the application" describes how to start and
+ configure the application. Topics on how to debug the application
+ are also included.
+ </item>
+ <item>Chapter 5: "Definition of Agent Configuration Files" is a
+ reference chapter, which contains more detailed information about
+ the agent configuration files.
+ </item>
+ <item>Chapter 6: "Definition of Manager Configuration Files" is a
+ reference chapter, which contains more detailed information about
+ the manager configuration files.
+ </item>
+ <item>Chapter 7: "Agent Implementation Example" describes how an MIB
+ can be implemented with the SNMP Development Toolkit.
+ Implementation examples are included.
+ </item>
+ <item>Chapter 8: "Instrumentation Functions" describes how
+ instrumentation functions should be defined in Erlang for the
+ different operations.
+ </item>
+ <item>Chapter 9: "Definition of Instrumentation Functions" is a
+ reference chapter which contains more detailed information
+ about the instrumentation functions.
+ </item>
+ <item>Chapter 10: "Definition of Agent Net if" is a reference chapter,
+ which describes the Agent Net if function in detail.
+ </item>
+ <item>Chapter 11: "Definition of Manager Net if" is a reference chapter,
+ which describes the Manager Net if function in detail.
+ </item>
+ <item>Chapter 12: "Advanced Agent Topics" describes sub-agents, agent
+ semantics, audit trail logging, and the consideration of
+ distributed tables.
+ </item>
+ <item>Appendix A describes the conversion of SNMPv2 to SNMPv1
+ error messages.
+ </item>
+ <item>Appendix B contains the RFC1903 text on <c>RowStatus</c>.
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>Where to Find More Information</title>
+ <p>Refer to the following documentation for more information about
+ SNMP and about the Erlang/OTP development system:
+ </p>
+ <list type="bulleted">
+ <item>Marshall T. Rose (1991), "The Simple Book - An
+ Introduction to Internet Management", Prentice-Hall
+ </item>
+ <item>Evan McGinnis and David Perkins (1997), "Understanding SNMP
+ MIBs", Prentice-Hall
+ </item>
+ <item>RFC1155, 1157, 1212 and 1215 (SNMPv1)
+ </item>
+ <item>RFC1901-1907 (SNMPv2c)
+ </item>
+ <item>RFC1908, 2089 (coexistence between SNMPv1 and SNMPv2)
+ </item>
+ <item>RFC2271, RFC2273 (SNMP std MIBs)
+ </item>
+ <item>the Mnesia User's Guide
+ </item>
+ <item>the Erlang 4.4 Extensions User's Guide
+ </item>
+ <item>the Reference Manual
+ </item>
+ <item>the Erlang Embedded Systems User's Guide
+ </item>
+ <item>the System Architecture Support Libraries (SASL) User's
+ Guide
+ </item>
+ <item>the Installation Guide
+ </item>
+ <item>the Asn1 User's Guide
+ </item>
+ <item>Concurrent Programming in Erlang, 2nd Edition (1996),
+ Prentice-Hall, ISBN 0-13-508301-X.
+ </item>
+ </list>
+ </section>
+</chapter>
+
diff --git a/lib/snmp/doc/src/snmp_manager_config_files.xml b/lib/snmp/doc/src/snmp_manager_config_files.xml
new file mode 100644
index 0000000000..c2ef3cd2c7
--- /dev/null
+++ b/lib/snmp/doc/src/snmp_manager_config_files.xml
@@ -0,0 +1,249 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE chapter SYSTEM "chapter.dtd">
+
+<chapter>
+ <header>
+ <copyright>
+ <year>2004</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ 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.
+
+ </legalnotice>
+
+ <title>Definition of Manager Configuration Files</title>
+ <prepared></prepared>
+ <responsible></responsible>
+ <docno></docno>
+ <approved></approved>
+ <checked></checked>
+ <date></date>
+ <rev></rev>
+ <file>snmp_manager_config_files.xml</file>
+ </header>
+ <p>Configuration data may be included in configuration files
+ that is located in the configuration directory. The name of this
+ directory is given in the <c>config_dir</c> configuration
+ parameter. These files are read at start-up.
+ </p>
+ <p>The directory where the configuration files are found is given as
+ a parameter to the manager.
+ </p>
+ <p>The entry format in all files are Erlang terms, separated by a
+ '<em>.</em>' and a <em>newline</em>. In the following sections, the
+ formats of these terms are described. Comments may be specified as
+ ordinary Erlang comments.
+ </p>
+ <p>If syntax errors are discovered in these files they are reported with the
+ function <c>config_err/2</c> of the
+ <seealso marker="snmpa_error_report">error report module</seealso>
+ at start-up.
+ </p>
+
+ <section>
+ <marker id="manager"></marker>
+ <marker id="manager_information"></marker>
+ <title>Manager Information</title>
+ <p>The manager information should be stored in a file called
+ <c>manager.conf</c>.
+ </p>
+ <p>Each entry is a tuple of size two:
+ </p>
+ <p><c>{Variable, Value}.</c></p>
+ <list type="bulleted">
+ <item>
+ <p><c>Variable</c> is one of the following:</p>
+ <list type="bulleted">
+ <item>
+ <p><c>address</c> - which defines the IP address of the
+ manager. Default is local host.</p>
+ </item>
+ <item>
+ <p><c>port</c> - which defines which UDP port the manager uses
+ for communicating with agents. <em>Mandatory</em>.</p>
+ </item>
+ <item>
+ <p><c>engine_id</c> - The <c>SnmpEngineID</c> as defined in
+ SNMP-FRAMEWORK-MIB. <em>Mandatory</em>.</p>
+ </item>
+ <item>
+ <p><c>max_message_size</c> - The <c>snmpEngineMaxMessageSize</c> as
+ defined in SNMP-FRAMEWORK-MIB. <em>Mandatory</em>.</p>
+ </item>
+ </list>
+ </item>
+ <item>
+ <p><c>Value</c> is the value for the variable.
+ </p>
+ </item>
+ </list>
+ <p>The following example shows a <c>manager.conf</c> file:
+ </p>
+ <pre>
+{address, [141,213,11,24]}.
+{port, 5000}.
+{engine_id, "mgrEngine"}.
+{max_message_size, 484}.
+ </pre>
+ <p>The value of <c>engine_id</c> is a string, which should have a
+ very specific structure. See RFC 2271/2571 for details.
+ </p>
+ </section>
+
+ <section>
+ <marker id="users"></marker>
+ <title>Users</title>
+ <p>For each <em>manager user</em>, the manager needs some information.
+ This information is either added in the <c>users.conf</c> config
+ file or by calling the
+ <seealso marker="snmpm#register_user">register_user</seealso>
+ function in run-time.
+ </p>
+ <p>Each row defines a <em>manager user</em> of the manager.
+ </p>
+ <p>Each entry is a tuple of size four:
+ </p>
+ <!-- <p><c>{UserId, UserMod, UserData}.</c></p> -->
+ <p><c>{UserId, UserMod, UserData, DefaultAgentConfig}.</c></p>
+ <list type="bulleted">
+ <item>
+ <p><c>UserId</c> is any term (used to uniquely identify the user).</p>
+ </item>
+ <item>
+ <p><c>UserMod</c> is the user callback module (atom).</p>
+ </item>
+ <item>
+ <p><c>UserData</c> is any term (passed on to the user when calling the
+ <c>UserMod</c>.
+ </p>
+ </item>
+ <item>
+ <p><c>DefaultAgentConfig</c> is a list of default agent config's.
+ These values are used as default values when this user registers
+ agents.
+ </p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <marker id="agents"></marker>
+ <title>Agents</title>
+ <p>The information needed to handle agents should be stored in a
+ file called <c>agents.conf</c>. It is also possible to add agents
+ in run-time by calling the
+ <seealso marker="snmpm#register_agent">register_agent</seealso>.
+ </p>
+ <p>Each entry is a tuple:
+ </p>
+ <p><c>{UserId, TargetName, Comm, Ip, Port, EngineID, Timeout, MaxMessageSize, Version, SecModel, SecName, SecLevel}.</c></p>
+ <list type="bulleted">
+ <item>
+ <p><c>UserId</c> is the identity of the <em>manager user</em>
+ responsible for this agent (term).
+ </p>
+ </item>
+ <item>
+ <p><c>TargetName</c> is a <em>unique</em> <em>non-empty</em> string.</p>
+ </item>
+ <item>
+ <p><c>Comm</c> is the community string (string).</p>
+ </item>
+ <item>
+ <p><c>Ip</c> is the ip address of the agent (a list of four integers).</p>
+ </item>
+ <item>
+ <p><c>Port</c> is the port number of the agent (integer).</p>
+ </item>
+ <item>
+ <p><c>EngineID</c> is the engine-id of the agent (string).</p>
+ </item>
+ <item>
+ <p><c>Timeout</c> is re-transmission timeout
+ (<c>infinity</c> | integer).</p>
+ </item>
+ <item>
+ <p><c>MaxMessageSize</c> is the max message size for outgoing messages
+ to this agent (integer).</p>
+ </item>
+ <item>
+ <p><c>Version</c> is the version (v1 | v2 | v3).</p>
+ </item>
+ <item>
+ <p><c>SecModel</c> is the security model (any | v1 | v2c | usm).</p>
+ </item>
+ <item>
+ <p><c>SecName</c> is the security name (string).</p>
+ </item>
+ <item>
+ <p><c>SecLevel</c> is security level (noAuthNoPriv | authNoPriv |
+ authPriv).</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <marker id="usm"></marker>
+ <marker id="usm_user"></marker>
+ <title>Security data for USM</title>
+ <p>The information about Security data for USM should be stored in a
+ file called <c>usm.conf</c>, which must be present if the manager
+ wishes to use SNMPv3 when communicating with agents. It is also
+ possible to add usm data in run-time by calling the
+ <seealso marker="snmpm#register_usm_user">register_usm_user</seealso>.
+ </p>
+ <p>The corresponding table is <c>usmUserTable</c> in the
+ SNMP-USER-BASED-SM-MIB.
+ </p>
+ <p>Each entry is a term:
+ </p>
+ <p><c>{EngineID, UserName, AuthP, AuthKey, PrivP, PrivKey}.</c> <br></br>
+<c>{EngineID, UserName, SecName, AuthP, AuthKey, PrivP, PrivKey}.</c></p>
+ <p>The first case is when we have the identity-function
+ (<c>SecName</c> = <c>UserName</c>).
+ </p>
+ <list type="bulleted">
+ <item>
+ <p><c>EngineID</c> is a string.</p>
+ </item>
+ <item>
+ <p><c>UserName</c> is a string.</p>
+ </item>
+ <item>
+ <p><c>SecName</c> is a string.</p>
+ </item>
+ <item>
+ <p><c>AuthP</c> is a <c>usmNoAuthProtocol</c>,
+ <c>usmHMACMD5AuthProtocol</c> or <c>usmHMACSHAAuthProtocol</c>.</p>
+ </item>
+ <item>
+ <p><c>AuthKey</c> is a list (of integer). This is the User's
+ secret localized authentication key. It is not visible in the MIB.
+ The length of this key needs to be 16 if
+ <c>usmHMACMD5AuthProtocol</c> is used and 20 if
+ <c>usmHMACSHAAuthProtocol</c> is used.</p>
+ </item>
+ <item>
+ <p><c>PrivP</c> is a <c>usmNoPrivProtocol</c>,
+ <c>usmDESPrivProtocol</c> or <c>usmAesCfb128Protocol</c>.</p>
+ </item>
+ <item>
+ <p><c>PrivKey</c> is a list (of integer). This is the User's secret
+ localized encryption key. It is not visible in the MIB. The length
+ of this key needs to be 16 if <c>usmDESPrivProtocol</c>
+ or <c>usmAesCfb128Protocol</c> is used.</p>
+ </item>
+ </list>
+ </section>
+</chapter>
+
diff --git a/lib/snmp/doc/src/snmp_manager_funct_descr.xml b/lib/snmp/doc/src/snmp_manager_funct_descr.xml
new file mode 100644
index 0000000000..db4ab9bf15
--- /dev/null
+++ b/lib/snmp/doc/src/snmp_manager_funct_descr.xml
@@ -0,0 +1,112 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE chapter SYSTEM "chapter.dtd">
+
+<chapter>
+ <header>
+ <copyright>
+ <year>2004</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ 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.
+
+ </legalnotice>
+
+ <title>Manager Functional Description</title>
+ <prepared></prepared>
+ <responsible></responsible>
+ <docno></docno>
+ <approved></approved>
+ <checked></checked>
+ <date></date>
+ <rev></rev>
+ <file>snmp_manager_funct_descr.xml</file>
+ </header>
+
+ <section>
+ <title>Features</title>
+ <marker id="features"></marker>
+ <p>The manager provided with the tool is a lightweight manager
+ that basically provides a means to communicate with agents.</p>
+ <p>It does not really implement any management capabilities by
+ itself. That is up to the <em>user</em>.
+ </p>
+ <p>A <em>user</em> in this context is basically a module implementing
+ the <seealso marker="snmpm_user">snmpm_user</seealso> behaviour.
+ A <em>user</em> can issue snmp requests and receive
+ notification/traps.</p>
+ <p>Agents to be accessed by the manager needs to be registered by
+ a user. Once registered, they can be accessed by all registered
+ users.</p>
+ <p>Notifications/traps from an agent is delivered to the user that
+ did the registration.</p>
+ <p>Any message from an agent that is not registered is delivered to
+ the <em>default user</em>.</p>
+ <p>By default, the <em>default user</em> is set to the
+ <c>snmpm_user_default</c> module, which simply sends an info message
+ to the error_logger. It is however highly recommended that this
+ module be replaced by another that does something useful
+ (see <seealso marker="snmp_config#configuration_params">configuration params</seealso> for more info).</p>
+ <p>When using version 3, then (at least one) <em>usm user</em> has to
+ be registered.</p>
+ <p>Requests can be issued in two different ways. Synchronous (see
+ <seealso marker="snmpm#sync_set">sync_set</seealso>,
+ <seealso marker="snmpm#sync_get">sync_get</seealso>,
+ <seealso marker="snmpm#sync_get_next">sync_get_next</seealso> and
+ <seealso marker="snmpm#sync_get_bulk">sync_get_bulk</seealso>)
+ and asynchronous (see
+ <seealso marker="snmpm#async_set">async_set</seealso>,
+ <seealso marker="snmpm#async_get">async_get</seealso>,
+ <seealso marker="snmpm#async_get_next">async_get_next</seealso> and
+ <seealso marker="snmpm#async_get_bulk">async_get_bulk</seealso>).
+ With synchronous
+ the snmp reply is returned by the function. With asynchronous,
+ the reply will instead be delivered through a call to one of the
+ <c>handle_pdu</c> callback function defined by the
+ <seealso marker="snmpm_user#handle_pdu">handle_pdu</seealso>
+ behaviour.</p>
+ </section>
+
+ <section>
+ <title>Operation</title>
+ <marker id="operation"></marker>
+ <p>The following steps are needed to get the manager running:</p>
+ <list type="ordered">
+ <item>
+ <p>[optional] Implement the default user.</p>
+ </item>
+ <item>
+ <p>Implement the user(s).</p>
+ </item>
+ <item>
+ <p>Configure the application (manager).</p>
+ </item>
+ <item>
+ <p>Start the application (manager).</p>
+ </item>
+ <item>
+ <p>Register the user(s).</p>
+ </item>
+ <item>
+ <p>The user(s) register their agents.</p>
+ </item>
+ </list>
+ </section>
+
+ <section>
+ <title>MIB loading</title>
+ <marker id="mib_loading"></marker>
+ <p>It is possible to load mibs into the manager, but this is not
+ necessary for normal operation, and not recommended.</p>
+ </section>
+</chapter>
+
diff --git a/lib/snmp/doc/src/snmp_manager_netif.xml b/lib/snmp/doc/src/snmp_manager_netif.xml
new file mode 100644
index 0000000000..2738ca76c1
--- /dev/null
+++ b/lib/snmp/doc/src/snmp_manager_netif.xml
@@ -0,0 +1,174 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE chapter SYSTEM "chapter.dtd">
+
+<chapter>
+ <header>
+ <copyright>
+ <year>2004</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ 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.
+
+ </legalnotice>
+
+ <title>Definition of Manager Net if</title>
+ <prepared></prepared>
+ <responsible></responsible>
+ <docno></docno>
+ <approved></approved>
+ <checked></checked>
+ <date></date>
+ <rev></rev>
+ <file>snmp_manager_netif.xml</file>
+ </header>
+ <p></p>
+ <image file="snmp_manager_netif_1.gif">
+ <icaption>The Purpose of Manager Net if</icaption>
+ </image>
+ <p>The Network Interface (Net if) process delivers SNMP PDUs to the
+ manager server, and receives SNMP PDUs from the manager server.
+ The most common behaviour of a Net if process is that is receives
+ request PDU from the manager server, encodes the PDU into bytes
+ and transmits the bytes onto the network to an agent. When the
+ reply from the agent is received by the Net if process, which it
+ decodes into an SNMP PDU, which it sends to the manager server.
+ </p>
+ <p>However, that simple behaviour can be modified in numerous
+ ways. For example, the Net if process can apply some kind of
+ encrypting/decrypting scheme on the bytes.
+ </p>
+ <p>It is also possible to write your own Net if process. The default
+ Net if process is implemented in the module <c>snmpm_net_if</c> and
+ it uses UDP as the transport protocol.
+ </p>
+ <p>This section describes how to write a Net if process.
+ </p>
+
+ <section>
+ <marker id="mandatory_functions"></marker>
+ <title>Mandatory Functions</title>
+ <p>A Net if process must implement the SNMP manager
+ <seealso marker="snmpm_network_interface">network interface behaviour</seealso>.
+ </p>
+ </section>
+
+ <section>
+ <title>Messages</title>
+ <p>The section <em>Messages</em> describes mandatory messages, which
+ Net if must send to the manager server process.
+ </p>
+ <p>Net if must send the following message when it receives an
+ SNMP PDU from the network that is aimed for the MasterAgent:
+ </p>
+ <pre>
+Server ! {snmp_pdu, Pdu, Addr, Port}
+ </pre>
+ <list type="bulleted">
+ <item>
+ <p><c>Pdu</c> is an SNMP PDU record, as defined in
+ <c>snmp_types.hrl</c>, with the SNMP request.</p>
+ </item>
+ <item>
+ <p><c>Addr</c> is the source address. </p>
+ </item>
+ <item>
+ <p><c>Port</c> is port number of the sender.</p>
+ </item>
+ </list>
+ <pre>
+Server ! {snmp_trap, Trap, Addr, Port}
+ </pre>
+ <list type="bulleted">
+ <item>
+ <p><c>Trap</c> is either an SNMP pdu record or an trappdu record,
+ as defined in <c>snmp_types.hrl</c>, with the SNMP request.</p>
+ </item>
+ <item>
+ <p><c>Addr</c> is the source address. </p>
+ </item>
+ <item>
+ <p><c>Port</c> is port number of the sender.</p>
+ </item>
+ </list>
+ <pre>
+Server ! {snmp_inform, Ref, Pdu, PduMS, Addr, Port}
+ </pre>
+ <list type="bulleted">
+ <item>
+ <p><c>Ref</c> is either the atom <c>ignore</c> or something
+ that can be used to identify the inform-request (e.g. request-id).
+ <c>ignore</c> is used if the response (acknowledgment) to the
+ inform-request has already been sent (this means that the server
+ will not make the call to the
+ <seealso marker="snmpm_network_interface#inform_response">inform_response</seealso>
+ function). See the
+ <seealso marker="snmp_app">inform request behaviour</seealso>
+ configuration option for more info.</p>
+ </item>
+ <item>
+ <p><c>Pdu</c> is an SNMP PDU record, as defined in
+ <c>snmp_types.hrl</c>, with the SNMP request.</p>
+ </item>
+ <item>
+ <p><c>Addr</c> is the source address. </p>
+ </item>
+ <item>
+ <p><c>Port</c> is port number of the sender.</p>
+ </item>
+ </list>
+ <pre>
+Server ! {snmp_report, Data, Addr, Port}
+ </pre>
+ <list type="bulleted">
+ <item>
+ <p><c>Data</c> is either <c>{ok, Pdu}</c> or
+ <c>{error, ReqId, ReasonInfo, Pdu}</c>. Which one is used depends
+ on the return value from the MPD
+ <seealso marker="snmpm_mpd#process_msg">process_msg</seealso> function. If the MsgData is <c>ok</c>,
+ the first is used, and if it is <c>{error, ReqId, Reason}</c>
+ the latter is used.</p>
+ </item>
+ <item>
+ <p><c>Pdu</c> is an SNMP PDU record, as defined in
+ <c>snmp_types.hrl</c>, with the SNMP request.</p>
+ </item>
+ <item>
+ <p><c>ReqId</c> is an integer.</p>
+ </item>
+ <item>
+ <p><c>ReasonInfo</c> is a term().</p>
+ </item>
+ <item>
+ <p><c>Addr</c> is the source address. </p>
+ </item>
+ <item>
+ <p><c>Port</c> is port number of the sender.</p>
+ </item>
+ </list>
+
+ <section>
+ <title>Notes</title>
+ <p>Since the Net if process is responsible for encoding and
+ decoding of SNMP messages, it must also update the relevant
+ counters in the SNMP group in MIB-II. It can use the functions
+ in the module <c>snmpm_mpd</c> for this purpose (refer to the
+ Reference Manual, section <c>snmp</c>, module <c>snmpm_mpd</c>
+ for more details).
+ </p>
+ <p>There are also some useful functions for encoding and
+ decoding of SNMP messages in the module <c>snmp_pdus</c>.
+ </p>
+ </section>
+ </section>
+</chapter>
+
diff --git a/lib/snmp/doc/src/snmp_manager_netif_1.gif b/lib/snmp/doc/src/snmp_manager_netif_1.gif
new file mode 100644
index 0000000000..a1f7a6a0c5
--- /dev/null
+++ b/lib/snmp/doc/src/snmp_manager_netif_1.gif
Binary files differ
diff --git a/lib/snmp/doc/src/snmp_manager_netif_1.ps b/lib/snmp/doc/src/snmp_manager_netif_1.ps
new file mode 100644
index 0000000000..913997d0bd
--- /dev/null
+++ b/lib/snmp/doc/src/snmp_manager_netif_1.ps
@@ -0,0 +1,305 @@
+%!PS-Adobe-3.0
+%%Creator: GIMP PostScript file plugin V 1.16 by Peter Kirchgessner
+%%Title: /usr/local/ccase/vws/bmk/bmk_app_dev_snap/clearcase/otp/libraries/snmp/doc/src/snmp_manager_netif_1.ps
+%%CreationDate: Mon Jul 19 16:24:48 2004
+%%DocumentData: Clean7Bit
+%%LanguageLevel: 2
+%%Pages: 1
+%%BoundingBox: 14 14 453 74
+%%EndComments
+%%BeginProlog
+% Use own dictionary to avoid conflicts
+10 dict begin
+%%EndProlog
+%%Page: 1 1
+% Translate for offset
+14.173228346456694 14.173228346456694 translate
+% Translate to begin of first scanline
+0 59 translate
+438 -59 scale
+% Image geometry
+438 59 8
+% Transformation matrix
+[ 438 0 0 59 0 0 ]
+% Strings to hold RGB-samples per scanline
+/rstr 438 string def
+/gstr 438 string def
+/bstr 438 string def
+{currentfile /ASCII85Decode filter /RunLengthDecode filter rstr readstring pop}
+{currentfile /ASCII85Decode filter /RunLengthDecode filter gstr readstring pop}
+{currentfile /ASCII85Decode filter /RunLengthDecode filter bstr readstring pop}
+true 3
+%%BeginData: 13832 ASCII Bytes
+colorimage
+Jc:6"Jc>WIoDm\GJ,~>
+Jc:6"Jc>WIoDm\GJ,~>
+Jc:6"Jc>WIoDm\GJ,~>
+Jc:6"L&UlJo`"XdjSjZ~>
+Jc:6"L&UlJo`"XdjSjZ~>
+Jc:6"L&UlJo`"XdjSjZ~>
+Jc<Iap],mEdf04GjSo,YkPfu~>
+Jc<Iap],mEdf04GjSo,YkPfu~>
+Jc<Iap],mEdf04GjSo,YkPfu~>
+Jc<[gqZ-EjquD<Ig&D!OhZ!NTl2H2~>
+Jc<[gqZ-EjquD<Ig&D!OhZ!NTl2H2~>
+Jc<[gqZ-EjquD<Ig&D!OhZ!NTl2H2~>
+Jc<airrDHcrr@WLhZ!KSgA_'Om/DM~>
+Jc<airrDHcrr@WLhZ!KSgA_'Om/DM~>
+Jc<airrDHcrr@WLhZ!KSgA_'Om/DM~>
+mf*1cJc=U,rrD<_rr@WLir8rXeGfIJmf%_~>
+mf*1cJc=U,rrD<_rr@WLir8rXeGfIJmf%_~>
+mf*1cJc=U,rrD<_rr@WLir8rXeGfIJmf%_~>
+nc&Lfrr2lsJc=d1rrD0[rr@WLjo,5[d/O%FnG[q~>
+nc&Lfrr2lsJc=d1rrD0[rr@WLjo,5[d/O%FnG[q~>
+nc&Lfrr2lsJc=d1rrD0[rr@WLjo,5[d/O%FnG[q~>
+o)8Uhq#:9nJc=p5rrD$Wrr@WLl2L\_c2I\Cnc"%~>
+o)8Uhq#:9nJc=p5rrD$Wrr@WLl2L\_c2I\Cnc"%~>
+o)8Uhq#:9nJc=p5rrD$Wrr@WLl2L\_c2I\Cnc"%~>
+oDS^ip&=skJc>$8!!(jSrr@WLm/?tbb5VD@oDX7~>
+oDS^ip&=skJc>$8!!(jSrr@WLm/?tbb5VD@oDX7~>
+oDS^ip&=skJc>$8!!(jSrr@WLm/?tbb5VD@oDX7~>
+o_ngjo)8UhnG`=cK`1rOgAV'PJc>*:!!((=!!)ZjJ,~>
+o_ngjo)8UhnG`=cK`1rOgAV'PJc>*:!!((=!!)ZjJ,~>
+o_ngjo)8UhnG`=cK`1rOgAV'PJc>*:!!((=!!)ZjJ,~>
+o_ngjnbrLgoD\air;Q]rM#RDSf_tjNJc>3=rrC%;rrDclJ,~>
+o_ngjnbrLgoD\air;Q]rM#RDSf_tjNJc>3=rrC%;rrDclJ,~>
+o_ngjnbrLgoD\air;Q]rM#RDSf_tjNJc>3=rrC%;rrDclJ,~>
+p&4pkn,<:ep&4pkq#:9nMuE\Vec,RKJc><@!!'k7!!)cmJ,~>
+p&4pkn,<:ep&4pkq#:9nMuE\Vec,RKJc><@!!'k7!!)cmJ,~>
+p&4pkn,<:ep&4pkq#:9nMuE\Vec,RKJc><@!!'k7!!)cmJ,~>
+p&4pkmf!1dpAP$lpAP$lNW&nXdf'4HJc>BB!!'e5!!)fnJ,~>
+p&4pkmf!1dpAP$lpAP$lNW&nXdf'4HJc>BB!!'e5!!)fnJ,~>
+p&4pkmf!1dpAP$lpAP$lNW&nXdf'4HJc>BB!!'e5!!)fnJ,~>
+pAP$lm/?tbq#16no_ngjO8]+Zd/F"FJc>EC!!'b4!!)ioJ,~>
+pAP$lm/?tbq#16no_ngjO8]+Zd/F"FJc>EC!!'b4!!)ioJ,~>
+pAP$lm/?tbq#16no_ngjO8]+Zd/F"FJc>EC!!'b4!!)ioJ,~>
+pAP$lli$kaqYgHpo)8UhOT#4[d/F"FJc>HD!!'_3!!)ioJ,~>
+pAP$lli$kaqYgHpo)8UhOT#4[d/F"FJc>HD!!'_3!!)ioJ,~>
+pAP$lli$kaqYgHpo)8UhOT#4[d/F"FJc>HD!!'_3!!)ioJ,~>
+rVlcrrVccslM^b`rVlfsnGWCfP5YF]cMdeDJc>NF!!'Y1!!)lpJ,~>
+rVlcrrVccslM^b`rVlfsnGWCfP5YF]cMdeDJc>NF!!'Y1!!)lpJ,~>
+rVlcrrVccslM^b`rVlfsnGWCfP5YF]cMdeDJc>NF!!'Y1!!)lpJ,~>
+s8N#urr2cplMg_^mJ[(cq>UBoh>RZ=>6&GS>;DuLrW2"He,B=IcMdeDJc>QG!!'S/!!)oqJ,~>
+s8N#urr2cplMg_^mJ[(cq>UBoh>RZ=>6&GS>;DuLrW2"He,B=IcMdeDJc>QG!!'S/!!)oqJ,~>
+s8N#urr2cplMg_^mJ[(cq>UBoh>RZ=>6&GS>;DuLrW2"He,B=IcMdeDJc>QG!!'S/!!)oqJ,~>
+s8DuuqYpKpd/Nh@s8N#uhYmQ)!<2ruUC?tt!TFO;rVurBrVur\rW-4'rG)Boqu-V#'BK,t10[sW
+!*`Y_bPhJA\GcI.r;M3~>
+s8DuuqYpKpd/Nh@s8N#uhYmQ)!<2ruUC?tt!TFO;rVurBrVur\rW-4'rG)Boqu-V#'BK,t10[sW
+!*`Y_bPhJA\GcI.r;M3~>
+s8DuuqYpKpd/Nh@s8N#uhYmQ)!<2ruUC?tt!TFO;rVurBrVur\rW-4'rG)Boqu-V#'BK,t10[sW
+!*`Y_bPhJA\GcI.r;M3~>
+s8Duu]D_d1hu3Z*!<2s9N%=lX)h\,o1<`r&COQ3A>AJ"Qir6enFA6l;rVurBrVur\rW1IJrVce4
+qu-WU'BK,t;uZdF!<2srbl.SB\,H@-r;M3~>
+s8Duu]D_d1hu3Z*!<2s9N%=lX)h\,o1<`r&COQ3A>AJ"Qir6enFA6l;rVurBrVur\rW1IJrVce4
+qu-WU'BK,t;uZdF!<2srbl.SB\,H@-r;M3~>
+s8Duu]D_d1hu3Z*!<2s9N%=lX)h\,o1<`r&COQ3A>AJ"Qir6enFA6l;rVurBrVur\rW1IJrVce4
+qu-WU'BK,t;uZdF!<2srbl.SB\,H@-r;M3~>
+!WE)0rVurVrXdNYCNMs"lMeX#lMcaZrnS7erX16grr/?Ir]7[jr^>iH!!(1@!!)3]!Rh&JrWuO&
+r]1^O3\02'rr*XbFDF:Frr+qlN'nnkrr0M[@WVTcN;EMSdfB@G)rb(;CK'4R'9"t&r]1^O6mK'k
+6mK)<_GbPNFR&i*!4De+!<)nI~>
+!WE)0rVurVrXdNYCNMs"lMeX#lMcaZrnS7erX16grr/?Ir]7[jr^>iH!!(1@!!)3]!Rh&JrWuO&
+r]1^O3\02'rr*XbFDF:Frr+qlN'nnkrr0M[@WVTcN;EMSdfB@G)rb(;CK'4R'9"t&r]1^O6mK'k
+6mK)<_GbPNFR&i*!4De+!<)nI~>
+!WE)0rVurVrXdNYCNMs"lMeX#lMcaZrnS7erX16grr/?Ir]7[jr^>iH!!(1@!!)3]!Rh&JrWuO&
+r]1^O3\02'rr*XbFDF:Frr+qlN'nnkrr0M[@WVTcN;EMSdfB@G)rb(;CK'4R'9"t&r]1^O6mK'k
+6mK)<_GbPNFR&i*!4De+!<)nI~>
+!WE)/rVurWrW1IJrr*dN3r]+HKDngKrnS"^rmLj_CNO#HrerUrbiA[&!6Y9@!9a=kdf<<N;_n@O
+iW.4%:#Zi`rXd:(rr1mW_Z$nerr*S<rhC/%rW1IJrVd`d]Dheu3oU.`r_<CO!5e`B%)W"N/,hTA
+rr,=NrVur+rVursrdX~>
+!WE)/rVurWrW1IJrr*dN3r]+HKDngKrnS"^rmLj_CNO#HrerUrbiA[&!6Y9@!9a=kdf<<N;_n@O
+iW.4%:#Zi`rXd:(rr1mW_Z$nerr*S<rhC/%rW1IJrVd`d]Dheu3oU.`r_<CO!5e`B%)W"N/,hTA
+rr,=NrVur+rVursrdX~>
+!WE)/rVurWrW1IJrr*dN3r]+HKDngKrnS"^rmLj_CNO#HrerUrbiA[&!6Y9@!9a=kdf<<N;_n@O
+iW.4%:#Zi`rXd:(rr1mW_Z$nerr*S<rhC/%rW1IJrVd`d]Dheu3oU.`r_<CO!5e`B%)W"N/,hTA
+rr,=NrVur+rVursrdX~>
+!WE)/rVurWrW1IJrr*J@!;$3,)o@7,ro+@crmLl4qu-]WRQ=C.rVur?rVur^rW1IJrr*%Qrr1mc
+rr)rX'E7tE]3A`K'E8!j%0$7^'E6G\oD[2Iq#1<C!<2s'df=0!FCI;j%/p/8iXGhch$j;^h%TdH
+/!J3ArVur+rVursrdX~>
+!WE)/rVurWrW1IJrr*J@!;$3,)o@7,ro+@crmLl4qu-]WRQ=C.rVur?rVur^rW1IJrr*%Qrr1mc
+rr)rX'E7tE]3A`K'E8!j%0$7^'E6G\oD[2Iq#1<C!<2s'df=0!FCI;j%/p/8iXGhch$j;^h%TdH
+/!J3ArVur+rVursrdX~>
+!WE)/rVurWrW1IJrr*J@!;$3,)o@7,ro+@crmLl4qu-]WRQ=C.rVur?rVur^rW1IJrr*%Qrr1mc
+rr)rX'E7tE]3A`K'E8!j%0$7^'E6G\oD[2Iq#1<C!<2s'df=0!FCI;j%/p/8iXGhch$j;^h%TdH
+/!J3ArVur+rVursrdX~>
+!WE).rVurdrVurlrW1IJrr)qW)ufgO3[<Y`rospk3rUXurr1A@r^?bbdi8#[rrDWh!!(+>!!)6^
+!Rh&GrW2!lrr*bo'E8!r!7Ur,'E8!j'E8!e%0"]UlMfTJq#1<C!<2s!dfA\3rW2!lrVd>e'E8!e%
+0$7^%0$7cUH2?>rVur)rVurtrdX~>
+!WE).rVurdrVurlrW1IJrr)qW)ufgO3[<Y`rospk3rUXurr1A@r^?bbdi8#[rrDWh!!(+>!!)6^
+!Rh&GrW2!lrr*bo'E8!r!7Ur,'E8!j'E8!e%0"]UlMfTJq#1<C!<2s!dfA\3rW2!lrVd>e'E8!e%
+0$7^%0$7cUH2?>rVur)rVurtrdX~>
+!WE).rVurdrVurlrW1IJrr)qW)ufgO3[<Y`rospk3rUXurr1A@r^?bbdi8#[rrDWh!!(+>!!)6^
+!Rh&GrW2!lrr*bo'E8!r!7Ur,'E8!j'E8!e%0"]UlMfTJq#1<C!<2s!dfA\3rW2!lrVd>e'E8!e%
+0$7^%0$7cUH2?>rVur)rVurtrdX~>
+!WE).rVurfrr)olrWhFe!,H@S7*PZ0!P;;/rXV_4N;hg8@WYi>rcCkM9rn!erW)Qh!!)]k!c&Hb
+rr)t7)f,9K!THNErW1J/rr*"8@WZ)QrVurdrVurrrW1IJrVcn7ro+UjrYXW.rr1mWir6e.rr1mj
+rr1mcrr*SCrhBnsrW1IJrVd$PRf<<8:#ZibrX\!%rr1mcrr1^er_<CkbT$KZrrDWh!!'A)!!*#t
+J,~>
+!WE).rVurfrr)olrWhFe!,H@S7*PZ0!P;;/rXV_4N;hg8@WYi>rcCkM9rn!erW)Qh!!)]k!c&Hb
+rr)t7)f,9K!THNErW1J/rr*"8@WZ)QrVurdrVurrrW1IJrVcn7ro+UjrYXW.rr1mWir6e.rr1mj
+rr1mcrr*SCrhBnsrW1IJrVd$PRf<<8:#ZibrX\!%rr1mcrr1^er_<CkbT$KZrrDWh!!'A)!!*#t
+J,~>
+!WE).rVurfrr)olrWhFe!,H@S7*PZ0!P;;/rXV_4N;hg8@WYi>rcCkM9rn!erW)Qh!!)]k!c&Hb
+rr)t7)f,9K!THNErW1J/rr*"8@WZ)QrVurdrVurrrW1IJrVcn7ro+UjrYXW.rr1mWir6e.rr1mj
+rr1mcrr*SCrhBnsrW1IJrVd$PRf<<8:#ZibrX\!%rr1mcrr1^er_<CkbT$KZrrDWh!!'A)!!*#t
+J,~>
+!WE).rVurgrqui`rW/4iir8iUp&4pko_nnQ%&<h$!)<7f!TFOarWM'Vrosp`rVurfrr)oqrW,pt
+rG*K9raH:Oh>UjlC\.OX12C>-IK![aFT,JQFT/m&@Y5?irW?q?!6kHA)rae*FBe$>!,LEiraH:X
+r`]eQraH:OFA6OFX8Mtr!;$0i!;6<mCD0,6rW7]PCWcVV!<2tJ~>
+!WE).rVurgrqui`rW/4iir8iUp&4pko_nnQ%&<h$!)<7f!TFOarWM'Vrosp`rVurfrr)oqrW,pt
+rG*K9raH:Oh>UjlC\.OX12C>-IK![aFT,JQFT/m&@Y5?irW?q?!6kHA)rae*FBe$>!,LEiraH:X
+r`]eQraH:OFA6OFX8Mtr!;$0i!;6<mCD0,6rW7]PCWcVV!<2tJ~>
+!WE).rVurgrqui`rW/4iir8iUp&4pko_nnQ%&<h$!)<7f!TFOarWM'Vrosp`rVurfrr)oqrW,pt
+rG*K9raH:Oh>UjlC\.OX12C>-IK![aFT,JQFT/m&@Y5?irW?q?!6kHA)rae*FBe$>!,LEiraH:X
+r`]eQraH:OFA6OFX8Mtr!;$0i!;6<mCD0,6rW7]PCWcVV!<2tJ~>
+!WE)nrW6jKC]=;7CE%'brW2"HkPbKd'Cbu$!;$3e!:Kgf.q2uHrqc]hrVurjrY&#5%*\_M7/m2F
+>AJ"Qiq$@SCOQ0\#@\AGraH:ON:d)L!:p-f!8RPWl2^,K]2R,VquHEh!!)Zj!]gb,rr)ua1'#Gq
+!!*#tJ,~>
+!WE)nrW6jKC]=;7CE%'brW2"HkPbKd'Cbu$!;$3e!:Kgf.q2uHrqc]hrVurjrY&#5%*\_M7/m2F
+>AJ"Qiq$@SCOQ0\#@\AGraH:ON:d)L!:p-f!8RPWl2^,K]2R,VquHEh!!)Zj!]gb,rr)ua1'#Gq
+!!*#tJ,~>
+!WE)nrW6jKC]=;7CE%'brW2"HkPbKd'Cbu$!;$3e!:Kgf.q2uHrqc]hrVurjrY&#5%*\_M7/m2F
+>AJ"Qiq$@SCOQ0\#@\AGraH:ON:d)L!:p-f!8RPWl2^,K]2R,VquHEh!!)Zj!]gb,rr)ua1'#Gq
+!!*#tJ,~>
+!WE)mrW5+hU]15m:&+\giXG#L!TFd^rVurjrqZW<rqQQirVurirXi*.K-T[\:&b,B]Dheu3r\+P
+qu-cY)ufir'Cu,&!;-9f!8IMQ3WaD=lI#V.!;HHm!;$0k7"$iirX`kG!<2tMFDF:Fr]1^O6mJc3
+rY^?1CIG6&rjs[iF9$*8ro.-tCK'4R'9"t&oDSdkrr.E~>
+!WE)mrW5+hU]15m:&+\giXG#L!TFd^rVurjrqZW<rqQQirVurirXi*.K-T[\:&b,B]Dheu3r\+P
+qu-cY)ufir'Cu,&!;-9f!8IMQ3WaD=lI#V.!;HHm!;$0k7"$iirX`kG!<2tMFDF:Fr]1^O6mJc3
+rY^?1CIG6&rjs[iF9$*8ro.-tCK'4R'9"t&oDSdkrr.E~>
+!WE)mrW5+hU]15m:&+\giXG#L!TFd^rVurjrqZW<rqQQirVurirXi*.K-T[\:&b,B]Dheu3r\+P
+qu-cY)ufir'Cu,&!;-9f!8IMQ3WaD=lI#V.!;HHm!;$0k7"$iirX`kG!<2tMFDF:Fr]1^O6mJc3
+rY^?1CIG6&rjs[iF9$*8ro.-tCK'4R'9"t&oDSdkrr.E~>
+!WE)mr\@3T%*\_M7/m2F>AJ"Qiq$@SCOK+pN;fS-ro-=?rr1nUCMRDN3YRH5/,nNArr,;@PP+nT
+!;?E&!;cZp!;$0r:&b,j:&[Q[dfBA_"CaFkh$j2["mQd#ro+U^rVurkrqZVlrqQQirVurirWl6`
+'=@bfCXW:]rWp^uro*pprj3pIrWp^urr*S<rhC/+rX(0frr/?IiW.4%:%S>c!<2tJ~>
+!WE)mr\@3T%*\_M7/m2F>AJ"Qiq$@SCOK+pN;fS-ro-=?rr1nUCMRDN3YRH5/,nNArr,;@PP+nT
+!;?E&!;cZp!;$0r:&b,j:&[Q[dfBA_"CaFkh$j2["mQd#ro+U^rVurkrqZVlrqQQirVurirWl6`
+'=@bfCXW:]rWp^uro*pprj3pIrWp^urr*S<rhC/+rX(0frr/?IiW.4%:%S>c!<2tJ~>
+!WE)mr\@3T%*\_M7/m2F>AJ"Qiq$@SCOK+pN;fS-ro-=?rr1nUCMRDN3YRH5/,nNArr,;@PP+nT
+!;?E&!;cZp!;$0r:&b,j:&[Q[dfBA_"CaFkh$j2["mQd#ro+U^rVurkrqZVlrqQQirVurirWl6`
+'=@bfCXW:]rWp^uro*pprj3pIrWp^urr*S<rhC/+rX(0frr/?IiW.4%:%S>c!<2tJ~>
+!!)]k0N7t',O58&rr+F[rr/?Iro+UjrppQXr`]f[raPKur[Y&KrdA#1!6kF:ro+UjX((]"!!)Zj
+q>e_<q#L6i!!)Wi$<-s'o.,5WrmLl4r;H`V%/^#-iZ%mriY1n^!!)cmPQ:RZ!!)Wi(.A.S/,ic<
+dfBCH]3A`K'E6u"rr1^err*\F>@LeMrmLl=rmM;TrmLj_CNO#HiXG>U!W`6!J,~>
+!!)]k0N7t',O58&rr+F[rr/?Iro+UjrppQXr`]f[raPKur[Y&KrdA#1!6kF:ro+UjX((]"!!)Zj
+q>e_<q#L6i!!)Wi$<-s'o.,5WrmLl4r;H`V%/^#-iZ%mriY1n^!!)cmPQ:RZ!!)Wi(.A.S/,ic<
+dfBCH]3A`K'E6u"rr1^err*\F>@LeMrmLl=rmM;TrmLj_CNO#HiXG>U!W`6!J,~>
+!!)]k0N7t',O58&rr+F[rr/?Iro+UjrppQXr`]f[raPKur[Y&KrdA#1!6kF:ro+UjX((]"!!)Zj
+q>e_<q#L6i!!)Wi$<-s'o.,5WrmLl4r;H`V%/^#-iZ%mriY1n^!!)cmPQ:RZ!!)Wi(.A.S/,ic<
+dfBCH]3A`K'E6u"rr1^err*\F>@LeMrmLl=rmM;TrmLj_CNO#HiXG>U!W`6!J,~>
+!!)]k#u1Eu;bd6ZrmLlHCBS*-rnS"^rXr.nl>'=Ho4%^udfA\4rk]*'%/p/.iY-_?iq*-L!;$3e
+!6bB=!;?Bl!;-6j:&b,&h%M=<r[XH:rmOU@l4!YQrVcuc'E8!j'Cu,&!;6?f!2fbk!;ZTo!;$1>
+:&a_t@X\7)!<26`e,J>?ro+UjrnS"^rosL4ro+UjdfA\4h$j;^dfA\3rW2!lnGWIhrr.E~>
+!!)]k#u1Eu;bd6ZrmLlHCBS*-rnS"^rXr.nl>'=Ho4%^udfA\4rk]*'%/p/.iY-_?iq*-L!;$3e
+!6bB=!;?Bl!;-6j:&b,&h%M=<r[XH:rmOU@l4!YQrVcuc'E8!j'Cu,&!;6?f!2fbk!;ZTo!;$1>
+:&a_t@X\7)!<26`e,J>?ro+UjrnS"^rosL4ro+UjdfA\4h$j;^dfA\3rW2!lnGWIhrr.E~>
+!!)]k#u1Eu;bd6ZrmLlHCBS*-rnS"^rXr.nl>'=Ho4%^udfA\4rk]*'%/p/.iY-_?iq*-L!;$3e
+!6bB=!;?Bl!;-6j:&b,&h%M=<r[XH:rmOU@l4!YQrVcuc'E8!j'Cu,&!;6?f!2fbk!;ZTo!;$1>
+:&a_t@X\7)!<26`e,J>?ro+UjrnS"^rosL4ro+UjdfA\4h$j;^dfA\3rW2!lnGWIhrr.E~>
+!!)]k$<-s'o.,5WrmLl4r;H`V%0$5=X#cHVX!=[Grr1@HlMge"%,qs!rWM3\_G`5^rVurfrqui?
+rqlchrVurkrW6j[C]=;C]-I=Si_s<.>O)4e9k'([rWcm@C\)!8CVocD!!)WiqZ*MmqZ-Bi!!)Wi
+,t.b3N#VBfdfBC,!94!p'E6u)rr1mcrr1mWir6e.rr*SCrhBo$rWasBrr1A@iY1h\!W`6!J,~>
+!!)]k$<-s'o.,5WrmLl4r;H`V%0$5=X#cHVX!=[Grr1@HlMge"%,qs!rWM3\_G`5^rVurfrqui?
+rqlchrVurkrW6j[C]=;C]-I=Si_s<.>O)4e9k'([rWcm@C\)!8CVocD!!)WiqZ*MmqZ-Bi!!)Wi
+,t.b3N#VBfdfBC,!94!p'E6u)rr1mcrr1mWir6e.rr*SCrhBo$rWasBrr1A@iY1h\!W`6!J,~>
+!!)]k$<-s'o.,5WrmLl4r;H`V%0$5=X#cHVX!=[Grr1@HlMge"%,qs!rWM3\_G`5^rVurfrqui?
+rqlchrVurkrW6j[C]=;C]-I=Si_s<.>O)4e9k'([rWcm@C\)!8CVocD!!)WiqZ*MmqZ-Bi!!)Wi
+,t.b3N#VBfdfBC,!94!p'E6u)rr1mcrr1mWir6e.rr*SCrhBo$rWasBrr1A@iY1h\!W`6!J,~>
+!!)]k!)<Il(u5iUrr+F:rr1A@rospk3r\^Z7/lck1@tME#:lkSrdA#1'E.n6iY2=_13E3g!!)Ke
+rW(.@rW)Qh!!(+>!!)Qgr;`_oquHEh!!)]k!c&a'rVdnU>6&I<K/.4O!/"JaFT,JQFT28l12C>-
+IK$i/@Y5?nrX%R_@WYi>@K:3"oDS^irr.E~>
+!!)]k!)<Il(u5iUrr+F:rr1A@rospk3r\^Z7/lck1@tME#:lkSrdA#1'E.n6iY2=_13E3g!!)Ke
+rW(.@rW)Qh!!(+>!!)Qgr;`_oquHEh!!)]k!c&a'rVdnU>6&I<K/.4O!/"JaFT,JQFT28l12C>-
+IK$i/@Y5?nrX%R_@WYi>@K:3"oDS^irr.E~>
+!!)]k!)<Il(u5iUrr+F:rr1A@rospk3r\^Z7/lck1@tME#:lkSrdA#1'E.n6iY2=_13E3g!!)Ke
+rW(.@rW)Qh!!(+>!!)Qgr;`_oquHEh!!)]k!c&a'rVdnU>6&I<K/.4O!/"JaFT,JQFT28l12C>-
+IK$i/@Y5?nrX%R_@WYi>@K:3"oDS^irr.E~>
+!!)`l!c'#rrr*\F,Q@]%;dsiQlMgcW@Z:<c;euC3@T37)'AZT&CLZm>$u=\uraH:Xr_if+oCr4a
+!:Bac!6bBA!:p*h!6G->!:^!e!2fbp!;$0i!7^uOl2^,K]2Rkk!!*#tJ,~>
+!!)`l!c'#rrr*\F,Q@]%;dsiQlMgcW@Z:<c;euC3@T37)'AZT&CLZm>$u=\uraH:Xr_if+oCr4a
+!:Bac!6bBA!:p*h!6G->!:^!e!2fbp!;$0i!7^uOl2^,K]2Rkk!!*#tJ,~>
+!!)`l!c'#rrr*\F,Q@]%;dsiQlMgcW@Z:<c;euC3@T37)'AZT&CLZm>$u=\uraH:Xr_if+oCr4a
+!:Bac!6bBA!:p*h!6G->!:^!e!2fbp!;$0i!7^uOl2^,K]2Rkk!!*#tJ,~>
+!!'M-!!&ho!!(.?!!)Hd!!&nqrrDWh!!(LIs#L4'@d<+T!!*#tJ,~>
+!!'M-!!&ho!!(.?!!)Hd!!&nqrrDWh!!(LIs#L4'@d<+T!!*#tJ,~>
+!!'M-!!&ho!!(.?!!)Hd!!&nqrrDWh!!(LIs#L4'@d<+T!!*#tJ,~>
+!WE)/rVuqorVur@rVuqLrW2uuZi0q)rr.E~>
+!WE)/rVuqorVur@rVuqLrW2uuZi0q)rr.E~>
+!WE)/rVuqorVur@rVuqLrW2uuZi0q)rr.E~>
+s8Duu\c)R/V#C>ob5MA@Jc>]K!!'G+!!)usJ,~>
+s8Duu\c)R/V#C>ob5MA@Jc>]K!!'G+!!)usJ,~>
+s8Duu\c)R/V#C>ob5MA@Jc>]K!!'G+!!)usJ,~>
+rr2ot]D_d1U](5nbl.SBJc>ZJ!!'G+!!)usJ,~>
+rr2ot]D_d1U](5nbl.SBJc>ZJ!!'G+!!)usJ,~>
+rr2ot]D_d1U](5nbl.SBJc>ZJ!!'G+!!)usJ,~>
+r;QZq^]"35UAb,mbl.SBJc>ZJ!!'G+!!)usJ,~>
+r;QZq^]"35UAb,mbl.SBJc>ZJ!!'G+!!)usJ,~>
+r;QZq^]"35UAb,mbl.SBJc>ZJ!!'G+!!)usJ,~>
+q>L?o_#=<6U&G#lcMdeDJc>TH!!'M-!!)rrJ,~>
+q>L?o_#=<6U&G#lcMdeDJc>TH!!'M-!!)rrJ,~>
+q>L?o_#=<6U&G#lcMdeDJc>TH!!'M-!!)rrJ,~>
+q>L?o_>XE7T`+okcMdeDJc>QG!!'P.!!)rrJ,~>
+q>L?o_>XE7T`+okcMdeDJc>QG!!'P.!!)rrJ,~>
+q>L?o_>XE7T`+okcMdeDJc>QG!!'P.!!)rrJ,~>
+q#16n`;]c:T)J]id/F"FJc>NF!!'S/!!)oqJ,~>
+q#16n`;]c:T)J]id/F"FJc>NF!!'S/!!)oqJ,~>
+q#16n`;]c:T)J]id/F"FJc>NF!!'S/!!)oqJ,~>
+q#16nbPq><SGiKgd/F"FJc>KE!!'Y1!!)lpJ,~>
+q#16nbPq><SGiKgd/F"FJc>KE!!'Y1!!)lpJ,~>
+q#16nbPq><SGiKgd/F"FJc>KE!!'Y1!!)lpJ,~>
+p\k-mc2I\CPl:X_df'4HJc>EC!!'_3!!)ioJ,~>
+p\k-mc2I\CPl:X_df'4HJc>EC!!'_3!!)ioJ,~>
+p\k-mc2I\CPl:X_df'4HJc>EC!!'_3!!)ioJ,~>
+p\k-mc2I\CPPtO^ec,RKJc>?A!!'b4!!)ioJ,~>
+p\k-mc2I\CPPtO^ec,RKJc>?A!!'b4!!)ioJ,~>
+p\k-mc2I\CPPtO^ec,RKJc>?A!!'b4!!)ioJ,~>
+p\k-mcMdeDOo>=\fDYaMJc>9?!!'e5!!)fnJ,~>
+p\k-mcMdeDOo>=\fDYaMJc>9?!!'e5!!)fnJ,~>
+p\k-mcMdeDOo>=\fDYaMJc>9?!!'e5!!)fnJ,~>
+pAP$ld/F"FO8f.ZgAV'PJc>3=!!'k7!!)cmJ,~>
+pAP$ld/F"FO8f.ZgAV'PJc>3=!!'k7!!)cmJ,~>
+pAP$ld/F"FO8f.ZgAV'PJc>3=!!'k7!!)cmJ,~>
+pAP$ld/F"FNW&nXh>[ESJc>-;!!'t:rrDclJ,~>
+pAP$ld/F"FNW&nXh>[ESJc>-;!!'t:rrDclJ,~>
+pAP$ld/F"FNW&nXh>[ESJc>-;!!'t:rrDclJ,~>
+pAP$lkl1;Vo_ngjMuN_Vi;N]VJc>$8rrC+=!!)ZjJ,~>
+pAP$lkl1;Vo_ngjMuN_Vi;N]VJc>$8rrC+=!!)ZjJ,~>
+pAP$lkl1;Vo_ngjMuN_Vi;N]VJc>$8rrC+=!!)ZjJ,~>
+p&4pkli-nap\t!hrVlfsM#RDSjSo/ZJc=p5!!(1@rrDZiJ,~>
+p&4pkli-nap\t!hrVlfsM#RDSjSo/ZJc=p5!!(1@rrDZiJ,~>
+p&4pkli-nap\t!hrVlfsM#RDSjSo/ZJc=p5!!(1@rrDZiJ,~>
+o_ngjmf*4dmf*.bK`:uOkl1S^Jc=g2!!(7B!!)QgJ,~>
+o_ngjmf*4dmf*.bK`:uOkl1S^Jc=g2!!(7B!!)QgJ,~>
+o_ngjmf*4dmf*.bK`:uOkl1S^Jc=g2!!(7B!!)QgJ,~>
+oD\ainbrLgJc=p5rrDEbrr@WLj8T&Yd/O%FnG[q~>
+oD\ainbrLgJc=p5rrDEbrr@WLj8T&Yd/O%FnG[q~>
+oD\ainbrLgJc=p5rrDEbrr@WLj8T&Yd/O%FnG[q~>
+nc&IepAP$lJc=g2qZ-EjqZ)3Hhu<WUeGfIJmf%_~>
+nc&IepAP$lJc=g2qZ-EjqZ)3Hhu<WUeGfIJmf%_~>
+nc&IepAP$lJc=g2qZ-EjqZ)3Hhu<WUeGfIJmf%_~>
+mJd%ar;Q]rJc=R+p],mEfDbaLgA_'Om/DM~>
+mJd%ar;Q]rJc=R+p],mEfDbaLgA_'Om/DM~>
+mJd%ar;Q]rJc=R+p],mEfDbaLgA_'Om/DM~>
+l2LS\Jc:6"VuH\rhZ!NTl2H2~>
+l2LS\Jc:6"VuH\rhZ!NTl2H2~>
+l2LS\Jc:6"VuH\rhZ!NTl2H2~>
+Jc:6"M#RARjSo,YkPfu~>
+Jc:6"M#RARjSo,YkPfu~>
+Jc:6"M#RARjSo,YkPfu~>
+Jc:6"L&UlJo`"XdjSjZ~>
+Jc:6"L&UlJo`"XdjSjZ~>
+Jc:6"L&UlJo`"XdjSjZ~>
+Jc:6"Jc>WIoDm\GJ,~>
+Jc:6"Jc>WIoDm\GJ,~>
+Jc:6"Jc>WIoDm\GJ,~>
+Jc:6"Jc<jlJ,~>
+Jc:6"Jc<jlJ,~>
+Jc:6"Jc<jlJ,~>
+Jc:6"Jc<jlJ,~>
+Jc:6"Jc<jlJ,~>
+Jc:6"Jc<jlJ,~>
+%%EndData
+showpage
+%%Trailer
+end
+%%EOF
diff --git a/lib/snmp/doc/src/snmp_mib_compiler.xml b/lib/snmp/doc/src/snmp_mib_compiler.xml
new file mode 100644
index 0000000000..63af19f479
--- /dev/null
+++ b/lib/snmp/doc/src/snmp_mib_compiler.xml
@@ -0,0 +1,252 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE chapter SYSTEM "chapter.dtd">
+
+<chapter>
+ <header>
+ <copyright>
+ <year>1997</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ 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.
+
+ </legalnotice>
+
+ <title>The MIB Compiler</title>
+ <prepared></prepared>
+ <responsible></responsible>
+ <docno></docno>
+ <approved></approved>
+ <checked></checked>
+ <date></date>
+ <rev></rev>
+ <file>snmp_mib_compiler.xml</file>
+ </header>
+ <p>The chapter <em>The MIB Compiler</em> describes the MIB compiler
+ and contains the following topics:
+ </p>
+ <list type="bulleted">
+ <item>Operation</item>
+ <item>Import</item>
+ <item>Consistency checking between MIBs</item>
+ <item>.hrl file generation</item>
+ <item>Emacs integration</item>
+ <item>Deviations from the standard
+ </item>
+ </list>
+ <note>
+ <p>When importing MIBs, ensure that the imported MIBs as well as the
+ importing MIB are compiled using the same version of the
+ SNMP-compiler.</p>
+ </note>
+
+ <section>
+ <title>Operation</title>
+ <p>The MIB must be written as a text file in SMIv1 or SMIv2 using
+ an ASN.1 notation before
+ it will be compiled. This text file must have the same name as the MIB,
+ but with the suffix <c>.mib</c>. This is necessary for handling
+ the <c>IMPORT</c> statement.
+ </p>
+ <p>The association file, which contains the names of
+ instrumentation functions for the MIB, should have the suffix
+ <c>.funcs</c>. If the compiler does not find the association file,
+ it gives a warning message and uses default instrumentation
+ functions. (See <seealso marker="snmp_instr_functions#snmp_3">Default Instrumentation</seealso> for more details).
+ </p>
+ <p>The MIB compiler is started with a call to
+ <c><![CDATA[snmpc:compile(<mibname>).]]></c> For example:
+ </p>
+ <code type="none">
+snmpc:compile("RFC1213-MIB").
+ </code>
+ <p>The output is a new file which is called <c><![CDATA[<mibname>.bin]]></c>.
+ </p>
+ <p>The MIB compiler understands both SMIv1 and SMIv2 MIBs. It
+ uses the MODULE-IDENTITY statement to determinate if the MIB is
+ written in SMI version 1 or 2.
+ </p>
+ </section>
+
+ <section>
+ <title>Importing MIBs</title>
+ <p>The compiler handles the <c>IMPORT</c> statement. It is important to
+ import the compiled file and not the ASN.1 (source) file. A MIB must
+ be recompiled to make changes visible to other MIBs importing it.
+ </p>
+ <p>The compiled files of the imported MIBs must be present in the
+ current directory, or a directory in the current path. The path is
+ supplied with the <c>{i, Path}</c> option, for example:
+ </p>
+ <code type="none">
+snmpc:compile("MY-MIB",
+ [{i, ["friend_mibs/", "../standard_mibs/"]}]).
+ </code>
+ <p>It is also possible to import MIBs from OTP applications in an
+ <c>"include_lib"</c> like fashion with the <c>il</c>
+ option. Example:
+ </p>
+ <code type="none">
+snmpc:compile("MY-MIB",
+ [{il, ["snmp/priv/mibs/", "myapp/priv/mibs/"]}]).
+ </code>
+ <p>finds the latest version of the <c>snmp</c> and <c>myapp</c>
+ applications in the OTP system and uses the expanded paths as
+ include paths.
+ </p>
+ <p>Note that an SMIv2 MIB can import an SMIv1 MIB and vice versa.
+ </p>
+ <p>The following MIBs are built-ins of the Erlang SNMP compiler:
+ SNMPv2-SMI, RFC-1215, RFC-1212, SNMPv2-TC, SNMPv2-CONF, and
+ RFC1155-SMI. They cannot therefore be compiled separately.
+ </p>
+ </section>
+
+ <section>
+ <title>MIB Consistency Checking</title>
+ <p>When an MIB is compiled, the compiler detects if several
+ managed objects use the same <c>OBJECT IDENTIFIER</c>. If that is
+ the case, it issues an error message. However, the compiler cannot
+ detect Oid conflicts between different MIBs. These kinds of
+ conflicts generate an error at load time. To avoid this, the
+ following function can be used to do consistency checking between
+ MIBs:
+ </p>
+ <pre>
+
+erl><input>snmpc:is_consistent(ListOfMibNames).</input>
+ </pre>
+ <p><c>ListOfMibNames</c> is a list of compiled MIBs, for example
+ <c>["RFC1213-MIB", "MY-MIB"]</c>. The function also performs
+ consistency checking of trap definitions.</p>
+ </section>
+
+ <section>
+ <title>.hrl File Generation</title>
+ <p>It is possible to generate an <c>.hrl</c> file which contains
+ definitions of Erlang constants from a compiled MIB file. This
+ file can then be included in Erlang source code. The file will
+ contain constants for:
+ </p>
+ <list type="bulleted">
+ <item>object Identifiers for tables, table entries and variables</item>
+ <item>column numbers</item>
+ <item>enumerated values</item>
+ <item>default values for variables and table columns.
+ </item>
+ </list>
+ <p>Use the following command to generate a .hrl file from an MIB:
+ </p>
+ <pre>
+erl><input>snmpc:mib_to_hrl(MibName).</input>
+ </pre>
+ </section>
+
+ <section>
+ <title>Emacs Integration</title>
+ <p>With the Emacs editor, the <c>next-error</c> (<c>C-X `</c>)
+ function can be used indicate where a compilation error occurred,
+ provided the error message is described by a line number.
+ </p>
+ <p>Use <c>M-x compile</c> to compile an MIB from inside Emacs, and
+ enter:
+ </p>
+ <pre>
+ <input>erl -s snmpc compile &lt;MibName&gt; -noshell</input>
+ </pre>
+ <p>An example of <c><![CDATA[<MibName>]]></c> is <c>RFC1213-MIB</c>.
+ </p>
+ </section>
+
+ <section>
+ <title>Compiling from a Shell or a Makefile</title>
+ <p>The <c>erlc</c> commands can be used to compile SNMP MIBs. Example:
+ </p>
+ <pre>
+ <input>erlc MY-MIB.mib</input>
+ </pre>
+ <p>All the standard <c>erlc</c> flags are supported, e.g.
+ </p>
+ <pre>
+ <input>erlc -I mymibs -o mymibs -W MY-MIB.mib</input>
+ </pre>
+ <p>The flags specific to the MIB compiler can be specified by
+ using the <c>+</c> syntax:
+ </p>
+ <pre>
+ <input>erlc +'{group_check,false}' MY-MIB.mib</input>
+ </pre>
+ </section>
+
+ <section>
+ <title>Deviations from the Standard</title>
+ <p>In some aspects the Erlang MIB compiler does not follow or
+ implement the SMI fully. Here are the differences:
+ </p>
+ <list type="bulleted">
+ <item>
+ <p>Tables must be written in the following order:
+ <c>tableObject</c>, <c>entryObject</c>, <c>column1</c>, ...,
+ <c>columnN</c> (in order).</p>
+ </item>
+ <item>
+ <p>Integer values, for example in the <c>SIZE</c> expression
+ must be entered in decimal syntax, not in hex or bit syntax.</p>
+ </item>
+ <item>
+ <p>Symbolic names must be unique within a MIB and within a
+ system.</p>
+ </item>
+ <item>
+ <p>Hyphens are allowed in SMIv2 (a pragmatic approach). The
+ reason for this is that according to SMIv2, hyphens are allowed
+ for objects converted from SMIv1, but not for others. This is
+ impossible to check for the compiler.</p>
+ </item>
+ <item>
+ <p>If a word is a keyword in any of SMIv1 or SMIv2, it is a
+ keyword in the compiler (deviates from SMIv1 only).</p>
+ </item>
+ <item>
+ <p>Indexes in a table must be objects, not types (deviates
+ from SMIv1 only).</p>
+ </item>
+ <item>
+ <p>A subset of all semantic checks on types are
+ implemented. For example, strictly the <c>TimeTicks</c> may not
+ be sub-classed but the compiler allows this (standard MIBs must
+ pass through the compiler) (deviates from SMIv2 only).</p>
+ </item>
+ <item>
+ <p>The <c>MIB.Object</c> syntax is not implemented (since all
+ objects must be unique anyway).</p>
+ </item>
+ <item>
+ <p>Two different names cannot define the same OBJECT IDENTIFIER.</p>
+ </item>
+ <item>
+ <p>The type checking in the SEQUENCE construct is non-strict
+ (i.e. subtypes may be specified). The reason for this is
+ that some standard MIBs use this.</p>
+ </item>
+ <item>A definition has normally a status field. When the status field
+ has the value deprecated, then the MIB-compiler will ignore this
+ definition. With the MIB-compiler option <c>{deprecated,true}</c>
+ the MIB-compiler does not ignore the deprecated definitions.</item>
+ <item>An object has a DESCRIPTIONS field. The descriptions-field will
+ not be included in the compiled mib by default. In order to get
+ the description, the mib must be compiled with the option
+ <c>description</c>.</item>
+ </list>
+ </section>
+</chapter>
+
diff --git a/lib/snmp/doc/src/snmp_notification_mib.xml b/lib/snmp/doc/src/snmp_notification_mib.xml
new file mode 100644
index 0000000000..d1d83570d1
--- /dev/null
+++ b/lib/snmp/doc/src/snmp_notification_mib.xml
@@ -0,0 +1,131 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE erlref SYSTEM "erlref.dtd">
+
+<erlref>
+ <header>
+ <copyright>
+ <year>1998</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ 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.
+
+ </legalnotice>
+
+ <title>snmp_notification_mib</title>
+ <prepared></prepared>
+ <responsible></responsible>
+ <docno></docno>
+ <approved></approved>
+ <checked></checked>
+ <date></date>
+ <rev></rev>
+ <file>snmp_notification_mib.xml</file>
+ </header>
+ <module>snmp_notification_mib</module>
+ <modulesummary>Instrumentation Functions for SNMP-NOTIFICATION-MIB</modulesummary>
+ <description>
+ <p>The module <c>snmp_notification_mib</c> implements the
+ instrumentation functions for the
+ SNMP-NOTIFICATION-MIB, and functions for configuring the database.
+ </p>
+ <p>The configuration files are described in the SNMP User's Manual.</p>
+ </description>
+ <funcs>
+ <func>
+ <name>configure(ConfDir) -> void()</name>
+ <fsummary>Configure the SNMP-NOTIFICATION-MIB</fsummary>
+ <type>
+ <v>ConfDir = string()</v>
+ </type>
+ <desc>
+ <p>This function is called from the supervisor at system
+ start-up.
+ </p>
+ <p>Inserts all data in the configuration files into the
+ database and destroys all old rows with StorageType
+ <c>volatile</c>. The rows created from the configuration file
+ will have StorageType <c>nonVolatile</c>.
+ </p>
+ <p>If an error is found in the configuration file, it is
+ reported using the function <c>config_err/2</c> of the
+ error report module,
+ and the function fails with reason <c>configuration_error</c>.
+ </p>
+ <p><c>ConfDir</c> is a string which points to the directory
+ where the configuration files are found.
+ </p>
+ <p>The configuration file read is: <c>notify.conf</c>.
+ </p>
+ </desc>
+ </func>
+ <func>
+ <name>reconfigure(ConfDir) -> void()</name>
+ <fsummary>Configure the SNMP-NOTIFICATION-MIB</fsummary>
+ <type>
+ <v>ConfDir = string()</v>
+ </type>
+ <desc>
+ <p>Inserts all data in the configuration files into the
+ database and destroys all old data, including the rows with
+ StorageType <c>nonVolatile</c>. The rows created from the
+ configuration file will have StorageType <c>nonVolatile</c>.
+ </p>
+ <p>Thus, the data in the SNMP-NOTIFICATION-MIB, after this
+ function has been called, is from the configuration files.
+ </p>
+ <p>If an error is found in the configuration file, it is
+ reported using the function <c>config_err/2</c> of the
+ error report module,
+ and the function fails with reason <c>configuration_error</c>.
+ </p>
+ <p><c>ConfDir</c> is a string which points to the directory
+ where the configuration files are found.
+ </p>
+ <p>The configuration file read is: <c>notify.conf</c>.
+ <marker id="add_notify"></marker>
+</p>
+ </desc>
+ </func>
+ <func>
+ <name>add_notify(Name, Tag, Type) -> Ret</name>
+ <fsummary>Added one notify definition</fsummary>
+ <type>
+ <v>Name = string()</v>
+ <v>Tag = string()</v>
+ <v>Type = trap | inform</v>
+ <v>Ret = {ok, Key} | {error, Reason}</v>
+ <v>Key = term()</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Adds a notify definition to the agent config.
+ Equivalent to one line in the <c>notify.conf</c> file.</p>
+ <marker id="delete_notify"></marker>
+ </desc>
+ </func>
+ <func>
+ <name>delete_notify(Key) -> Ret</name>
+ <fsummary>Delete one notify definition</fsummary>
+ <type>
+ <v>Key = term()</v>
+ <v>Ret = ok | {error, Reason}</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Delete a notify definition from the agent config.</p>
+ </desc>
+ </func>
+ </funcs>
+
+</erlref>
+
diff --git a/lib/snmp/doc/src/snmp_pdus.xml b/lib/snmp/doc/src/snmp_pdus.xml
new file mode 100644
index 0000000000..6c323c3ad9
--- /dev/null
+++ b/lib/snmp/doc/src/snmp_pdus.xml
@@ -0,0 +1,204 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE erlref SYSTEM "erlref.dtd">
+
+<erlref>
+ <header>
+ <copyright>
+ <year>1996</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ 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.
+
+ </legalnotice>
+
+ <title>snmp_pdus</title>
+ <prepared></prepared>
+ <responsible></responsible>
+ <docno></docno>
+ <approved></approved>
+ <checked></checked>
+ <date></date>
+ <rev></rev>
+ <file>snmp_pdus.xml</file>
+ </header>
+ <module>snmp_pdus</module>
+ <modulesummary>Encode and Decode Functions for SNMP PDUs</modulesummary>
+ <description>
+ <p>RFC1157, RFC1905 and/or RFC2272 should be studied carefully
+ before using this module, <c>snmp_pdus</c>.
+ </p>
+ <p>The module <c>snmp_pdus</c> contains functions for encoding
+ and decoding of
+ SNMP protocol data units (PDUs). In short, this module converts a
+ list of bytes to Erlang record representations and vice versa.
+ The record definitions can be found in the file
+ <c>snmp/include/snmp_types.hrl</c>. If snmpv3 is used, the module
+ that includes <c>snmp_types.hrl</c> must define the constant
+ <c>SNMP_USE_V3</c> before the header file is included. Example:</p>
+ <pre>
+-define(SNMP_USE_V3, true).
+-include_lib("snmp/include/snmp_types.hrl"). </pre>
+ <p>Encoding and decoding must be done explicitly when writing your
+ own Net if process.
+ </p>
+ </description>
+ <funcs>
+ <func>
+ <name>dec_message([byte()]) -> Message</name>
+ <fsummary>Decode an SNMP Message</fsummary>
+ <type>
+ <v>Message = #message</v>
+ </type>
+ <desc>
+ <p>Decodes a list of bytes into an SNMP Message. Note, if there
+ is a v3 message, the <c>msgSecurityParameters</c> are not
+ decoded. They must be explicitly decoded by a call to a
+ security model specific decoding function,
+ e.g. <c>dec_usm_security_parameters/1</c>. Also note, if
+ the <c>scopedPDU</c> is encrypted, the OCTET STRING encoded
+ <c>encryptedPDU</c> will be present in the <c>data</c> field.</p>
+ </desc>
+ </func>
+ <func>
+ <name>dec_message_only([byte()]) -> Message</name>
+ <fsummary>Decode an SNMP Message, but not the data part</fsummary>
+ <type>
+ <v>Message = #message</v>
+ </type>
+ <desc>
+ <p>Decodes a list of bytes into an SNMP Message, but does not
+ decode the data part of the Message. That means, data is still
+ a list of bytes, normally an encoded <c>PDU</c> (v1 and V2) or an
+ encoded and possibly encrypted <c>scopedPDU</c> (v3).</p>
+ </desc>
+ </func>
+ <func>
+ <name>dec_pdu([byte()]) -> Pdu</name>
+ <fsummary>Decode an SNMP Pdu</fsummary>
+ <type>
+ <v>Pdu = #pdu</v>
+ </type>
+ <desc>
+ <p>Decodes a list of bytes into an SNMP Pdu.</p>
+ </desc>
+ </func>
+ <func>
+ <name>dec_scoped_pdu([byte()]) -> ScopedPdu</name>
+ <fsummary>Decode an SNMP ScopedPdu</fsummary>
+ <type>
+ <v>ScopedPdu = #scoped_pdu</v>
+ </type>
+ <desc>
+ <p>Decodes a list of bytes into an SNMP ScopedPdu.</p>
+ </desc>
+ </func>
+ <func>
+ <name>dec_scoped_pdu_data([byte()]) -> ScopedPduData</name>
+ <fsummary>Decode an SNMP ScopedPduData</fsummary>
+ <type>
+ <v>ScopedPduData = #scoped_pdu | EncryptedPDU</v>
+ <v>EncryptedPDU = [byte()]</v>
+ </type>
+ <desc>
+ <p>Decodes a list of bytes into either a scoped pdu record, or
+ - if the scoped pdu was encrypted - to a list of bytes.</p>
+ </desc>
+ </func>
+ <func>
+ <name>dec_usm_security_parameters([byte()]) -> UsmSecParams</name>
+ <fsummary>Decode SNMP UsmSecurityParameters</fsummary>
+ <type>
+ <v>UsmSecParams = #usmSecurityParameters</v>
+ </type>
+ <desc>
+ <p>Decodes a list of bytes into an SNMP UsmSecurityParameters</p>
+ </desc>
+ </func>
+ <func>
+ <name>enc_encrypted_scoped_pdu(EncryptedScopedPdu) -> [byte()]</name>
+ <fsummary>Encode an encrypted SNMP scopedPDU</fsummary>
+ <type>
+ <v>EncryptedScopedPdu = [byte()]</v>
+ </type>
+ <desc>
+ <p>Encodes an encrypted SNMP ScopedPdu into an OCTET STRING
+ that can be used as the <c>data</c> field in a
+ <c>message</c> record, that later can be encoded with a call
+ to <c>enc_message_only/1</c>.
+ </p>
+ <p>This function should be used whenever the <c>ScopedPDU</c>
+ is encrypted.</p>
+ </desc>
+ </func>
+ <func>
+ <name>enc_message(Message) -> [byte()]</name>
+ <fsummary>Encode an SNMP Message</fsummary>
+ <type>
+ <v>Message = #message</v>
+ </type>
+ <desc>
+ <p>Encodes a message record to a list of bytes.</p>
+ </desc>
+ </func>
+ <func>
+ <name>enc_message_only(Message) -> [byte()]</name>
+ <fsummary>Encode an SNMP Message, but not the data part</fsummary>
+ <type>
+ <v>Message = #message</v>
+ </type>
+ <desc>
+ <p><c>Message</c> is a record where the <c>data</c> field is
+ assumed to be encoded (a list of bytes). If there is a v1 or v2
+ message, the <c>data</c> field is an encoded <c>PDU</c>, and if
+ there is a v3 message, <c>data</c> is an encoded and possibly
+ encrypted <c>scopedPDU</c>.</p>
+ </desc>
+ </func>
+ <func>
+ <name>enc_pdu(Pd) -> [byte()]</name>
+ <fsummary>Encode an SNMP Pdu</fsummary>
+ <type>
+ <v>Pdu = #pdu</v>
+ </type>
+ <desc>
+ <p>Encodes an SNMP Pdu into a list of bytes.</p>
+ </desc>
+ </func>
+ <func>
+ <name>enc_scoped_pdu(ScopedPdu) -> [byte()]</name>
+ <fsummary>Encode an SNMP scopedPDU</fsummary>
+ <type>
+ <v>ScopedPdu = #scoped_pdu</v>
+ </type>
+ <desc>
+ <p>Encodes an SNMP ScopedPdu into a list of bytes, which can be
+ encrypted, and after encryption, encoded with
+ a call to <c>enc_encrypted_scoped_pdu/1</c>; or it can be
+ used as the <c>data</c> field in a <c>message</c> record, which
+ then can be encoded with <c>enc_message_only/1</c>.</p>
+ </desc>
+ </func>
+ <func>
+ <name>enc_usm_security_parameters(UsmSecParams) -> [byte()]</name>
+ <fsummary>Encode SNMP UsmSecurityParameters</fsummary>
+ <type>
+ <v>UsmSecParams = #usmSecurityParameters</v>
+ </type>
+ <desc>
+ <p>Encodes SNMP UsmSecurityParameters into a list of bytes.</p>
+ </desc>
+ </func>
+ </funcs>
+
+</erlref>
+
diff --git a/lib/snmp/doc/src/snmp_standard_mib.xml b/lib/snmp/doc/src/snmp_standard_mib.xml
new file mode 100644
index 0000000000..e8dea46f32
--- /dev/null
+++ b/lib/snmp/doc/src/snmp_standard_mib.xml
@@ -0,0 +1,135 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE erlref SYSTEM "erlref.dtd">
+
+<erlref>
+ <header>
+ <copyright>
+ <year>1996</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ 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.
+
+ </legalnotice>
+
+ <title>snmp_standard_mib</title>
+ <prepared></prepared>
+ <responsible></responsible>
+ <docno></docno>
+ <approved></approved>
+ <checked></checked>
+ <date></date>
+ <rev></rev>
+ <file>snmp_standard_mib.xml</file>
+ </header>
+ <module>snmp_standard_mib</module>
+ <modulesummary>Instrumentation Functions for STANDARD-MIB and SNMPv2-MIB</modulesummary>
+ <description>
+ <p>The module <c>snmp_standard_mib</c> implements the instrumentation functions for the
+ STANDARD-MIB and SNMPv2-MIB, and functions for configuring the database.
+ </p>
+ <p>The configuration files are described in the SNMP User's Manual.</p>
+ </description>
+ <funcs>
+ <func>
+ <name>configure(ConfDir) -> void()</name>
+ <fsummary>Configure the STANDARD-MIB and SNMPv2-MIB</fsummary>
+ <type>
+ <v>ConfDir = string()</v>
+ </type>
+ <desc>
+ <p>This function is called from the supervisor at system
+ start-up.
+ </p>
+ <p>Inserts all data in the configuration files into the
+ database and destroys all old rows with StorageType
+ <c>volatile</c>. The rows created from the configuration file
+ will have StorageType <c>nonVolatile</c>.
+ </p>
+ <p>All <c>snmp</c> counters are set to zero.
+ </p>
+ <p>If an error is found in the configuration file, it is
+ reported using the function <c>config_err/2</c> of the error
+ report module, and the function fails with the reason
+ <c>configuration_error</c>.
+ </p>
+ <p><c>ConfDir</c> is a string which points to the directory
+ where the configuration files are found.
+ </p>
+ <p>The configuration file read is: <c>standard.conf</c>.
+ </p>
+ </desc>
+ </func>
+ <func>
+ <name>inc(Name) -> void()</name>
+ <name>inc(Name, N) -> void()</name>
+ <fsummary>Increment a variable in the MIB</fsummary>
+ <type>
+ <v>Name = atom()</v>
+ <v>N = integer()</v>
+ </type>
+ <desc>
+ <p>Increments a variable in the MIB with <c>N</c>, or one if
+ <c>N</c> is not specified.</p>
+ </desc>
+ </func>
+ <func>
+ <name>reconfigure(ConfDir) -> void()</name>
+ <fsummary>Configure the STANDARD-MIB and SNMPv2-MIB</fsummary>
+ <type>
+ <v>ConfDir = string()</v>
+ </type>
+ <desc>
+ <p>Inserts all data in the configuration files into the
+ database and destroys all old data, including the rows with
+ StorageType <c>nonVolatile</c>. The rows created from the
+ configuration file will have StorageType <c>nonVolatile</c>.
+ </p>
+ <p>Thus, the data in the SNMP-STANDARD-MIB and SNMPv2-MIB,
+ after this function has been called, is from the
+ configuration files.
+ </p>
+ <p>All <c>snmp</c> counters are set to zero.
+ </p>
+ <p>If an error is found in the configuration file, it is
+ reported using the function <c>config_err/2</c> of the error
+ report module, and the function fails with the reason
+ <c>configuration_error</c>.
+ </p>
+ <p><c>ConfDir</c> is a string which points to the directory
+ where the configuration files are found.
+ </p>
+ <p>The configuration file read is: <c>standard.conf</c>.
+ </p>
+ </desc>
+ </func>
+ <func>
+ <name>reset() -> void()</name>
+ <fsummary>Reset all <c>snmp</c>counters to 0</fsummary>
+ <desc>
+ <p>Resets all <c>snmp</c> counters to 0.</p>
+ </desc>
+ </func>
+ <func>
+ <name>sys_up_time() -> Time</name>
+ <fsummary>Get the system up time</fsummary>
+ <type>
+ <v>Time = int()</v>
+ </type>
+ <desc>
+ <p>Gets the system up time in hundredth of a second.</p>
+ </desc>
+ </func>
+ </funcs>
+
+</erlref>
+
diff --git a/lib/snmp/doc/src/snmp_target_mib.xml b/lib/snmp/doc/src/snmp_target_mib.xml
new file mode 100644
index 0000000000..4a36be19a3
--- /dev/null
+++ b/lib/snmp/doc/src/snmp_target_mib.xml
@@ -0,0 +1,195 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE erlref SYSTEM "erlref.dtd">
+
+<erlref>
+ <header>
+ <copyright>
+ <year>1998</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ 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.
+
+ </legalnotice>
+
+ <title>snmp_target_mib</title>
+ <prepared></prepared>
+ <responsible></responsible>
+ <docno></docno>
+ <approved></approved>
+ <checked></checked>
+ <date></date>
+ <rev></rev>
+ <file>snmp_target_mib.xml</file>
+ </header>
+ <module>snmp_target_mib</module>
+ <modulesummary>Instrumentation Functions for SNMP-TARGET-MIB</modulesummary>
+ <description>
+ <p>The module <c>snmp_target_mib</c> implements the instrumentation
+ functions for the SNMP-TARGET-MIB,
+ and functions for configuring the database. </p>
+ <p>The configuration files are described in the SNMP User's Manual.</p>
+
+ <marker id="configure"></marker>
+ </description>
+
+ <funcs>
+ <func>
+ <name>configure(ConfDir) -> void()</name>
+ <fsummary>Configure the SNMP-TARGET-MIB</fsummary>
+ <type>
+ <v>ConfDir = string()</v>
+ </type>
+ <desc>
+ <p>This function is called from the supervisor at system
+ start-up.
+ </p>
+ <p>Inserts all data in the configuration files into the
+ database and destroys all old rows with StorageType
+ <c>volatile</c>. The rows created from the configuration file
+ will have StorageType <c>nonVolatile</c>. </p>
+ <p>All <c>snmp</c> counters are set to zero. </p>
+ <p>If an error is found in the configuration file, it is
+ reported using the function <c>config_err/2</c> of the error
+ report module, and the function fails with the reason
+ <c>configuration_error</c>. </p>
+ <p><c>ConfDir</c> is a string which points to the directory
+ where the configuration files are found. </p>
+ <p>The configuration files read are: <c>target_addr.conf</c>
+ and <c>target_params.conf</c>. </p>
+
+ <marker id="reconfigure"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>reconfigure(ConfDir) -> void()</name>
+ <fsummary>Configure the SNMP-TARGET-MIB</fsummary>
+ <type>
+ <v>ConfDir = string()</v>
+ </type>
+ <desc>
+ <p>Inserts all data in the configuration files into the
+ database and destroys all old data, including the rows with
+ StorageType <c>nonVolatile</c>. The rows created from the
+ configuration file will have StorageType <c>nonVolatile</c>. </p>
+ <p>Thus, the data in the SNMP-TARGET-MIB, after this
+ function has been called, is the data from the configuration
+ files. </p>
+ <p>All <c>snmp</c> counters are set to zero.</p>
+ <p>If an error is found in the configuration file, it is
+ reported using the function <c>config_err/2</c> of the ,
+ and the function fails with the reason
+ <c>configuration_error</c>.</p>
+ <p><c>ConfDir</c> is a string which points to the directory
+ where the configuration files are found. </p>
+ <p>The configuration files read are: <c>target_addr.conf</c>
+ and <c>target_params.conf</c>. </p>
+
+ <marker id="set_target_engine_id"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>set_target_engine_id(TargetAddrName, EngineId) -> boolean()</name>
+ <fsummary>Set the engine id for a targetAddr row.</fsummary>
+ <type>
+ <v>TargetAddrName = string()</v>
+ <v>EngineId = string()</v>
+ </type>
+ <desc>
+ <p>Changes the engine id for a target in the
+ <c>snmpTargetAddrTable</c>.
+ If notifications are sent as Inform requests to a target, its
+ engine id must be set. </p>
+
+ <marker id="add_addr"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>add_addr(Name, Ip, Port, Timeout, Retry, TagList, Params, EngineId, TMask, MMS) -> Ret</name>
+ <fsummary>Add one target address definition</fsummary>
+ <type>
+ <v>Name = string()</v>
+ <v>Ip = [integer()], length 4</v>
+ <v>Port = integer()</v>
+ <v>Timeout = integer()</v>
+ <v>Retry = integer()</v>
+ <v>TagList = string()</v>
+ <v>ParamsName = string()</v>
+ <v>EngineId = string()</v>
+ <v>TMask = string(), length 0 or 6</v>
+ <v>MMS = integer()</v>
+ <v>Ret = {ok, Key} | {error, Reason}</v>
+ <v>Key = term()</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Adds a target address definition to the agent config.
+ Equivalent to one line in the <c>target_addr.conf</c> file.</p>
+
+ <marker id="delete_addr"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>delete_addr(Key) -> Ret</name>
+ <fsummary>Delete one target address definition</fsummary>
+ <type>
+ <v>Key = term()</v>
+ <v>Ret = ok | {error, Reason}</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Delete a target address definition from the agent config.</p>
+
+ <marker id="add_params"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>add_params(Name, MPModel, SecModel, SecName, SecLevel) -> Ret</name>
+ <fsummary>Add one target parameter definition</fsummary>
+ <type>
+ <v>Name = string()</v>
+ <v>MPModel = v1 | v2c | v3</v>
+ <v>SecModel = v1 | v2c | usm</v>
+ <v>SecName = string()</v>
+ <v>SecLevel = noAuthNoPriv | authNoPriv | authPriv</v>
+ <v>Ret = {ok, Key} | {error, Reason}</v>
+ <v>Key = term()</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Adds a target parameter definition to the agent config.
+ Equivalent to one line in the <c>target_params.conf</c> file.</p>
+
+ <marker id="delete_params"></marker>
+ </desc>
+ </func>
+ <func>
+ <name>delete_params(Key) -> Ret</name>
+ <fsummary>Delete one target parameter definition</fsummary>
+ <type>
+ <v>Key = term()</v>
+ <v>Ret = ok | {error, Reason}</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Delete a target parameter definition from the agent config.</p>
+ </desc>
+ </func>
+ </funcs>
+
+</erlref>
+
diff --git a/lib/snmp/doc/src/snmp_user_based_sm_mib.xml b/lib/snmp/doc/src/snmp_user_based_sm_mib.xml
new file mode 100644
index 0000000000..7485e5af57
--- /dev/null
+++ b/lib/snmp/doc/src/snmp_user_based_sm_mib.xml
@@ -0,0 +1,146 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE erlref SYSTEM "erlref.dtd">
+
+<erlref>
+ <header>
+ <copyright>
+ <year>1999</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ 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.
+
+ </legalnotice>
+
+ <title>snmp_user_based_sm_mib</title>
+ <prepared></prepared>
+ <responsible></responsible>
+ <docno></docno>
+ <approved></approved>
+ <checked></checked>
+ <date></date>
+ <rev></rev>
+ <file>snmp_user_based_sm_mib.xml</file>
+ </header>
+ <module>snmp_user_based_sm_mib</module>
+ <modulesummary>Instrumentation Functions for SNMP-USER-BASED-SM-MIB</modulesummary>
+ <description>
+ <p>The module <c>snmp_user_based_sm_mib</c> implements the instrumentation
+ functions for the SNMP-USER-BASED-SM-MIB, and functions for configuring
+ the database.
+ </p>
+ <p>The configuration files are described in the SNMP User's Manual.</p>
+ </description>
+ <funcs>
+ <func>
+ <name>configure(ConfDir) -> void()</name>
+ <fsummary>Configure the SNMP-USER-BASED-SM-MIB</fsummary>
+ <type>
+ <v>ConfDir = string()</v>
+ </type>
+ <desc>
+ <p>This function is called from the supervisor at system
+ start-up.
+ </p>
+ <p>Inserts all data in the configuration files into the
+ database and destroys all old rows with StorageType
+ <c>volatile</c>. The rows created from the configuration file
+ will have StorageType <c>nonVolatile</c>.
+ </p>
+ <p>All <c>snmp</c> counters are set to zero.
+ </p>
+ <p>If an error is found in the configuration file, it is
+ reported using the function <c>config_err/2</c> of the error
+ report module, and the function fails with the reason
+ <c>configuration_error</c>.
+ </p>
+ <p><c>ConfDir</c> is a string which points to the directory
+ where the configuration files are found.
+ </p>
+ <p>The configuration file read is: <c>usm.conf</c>.
+ </p>
+ </desc>
+ </func>
+ <func>
+ <name>reconfigure(ConfDir) -> void()</name>
+ <fsummary>Configure the SNMP-USER-BASED-SM-MIB</fsummary>
+ <type>
+ <v>ConfDir = string()</v>
+ </type>
+ <desc>
+ <p>Inserts all data in the configuration files into the
+ database and destroys all old data, including the rows with
+ StorageType <c>nonVolatile</c>. The rows created from the
+ configuration file will have StorageType <c>nonVolatile</c>.
+ </p>
+ <p>Thus, the data in the SNMP-USER-BASED-SM-MIB, after this
+ function has been called, is the data from the configuration
+ files.
+ </p>
+ <p>All <c>snmp</c> counters are set to zero.
+ </p>
+ <p>If an error is found in the configuration file, it is
+ reported using the function <c>config_err/2</c> of the error
+ report module, and the function fails with the reason
+ <c>configuration_error</c>.
+ </p>
+ <p><c>ConfDir</c> is a string which points to the directory
+ where the configuration files are found.
+ </p>
+ <p>The configuration file read is: <c>usm.conf</c>.
+ <marker id="add_user"></marker>
+</p>
+ </desc>
+ </func>
+ <func>
+ <name>add_user(EngineID, Name, SecName, Clone, AuthP, AuthKeyC, OwnAuthKeyC, PrivP, PrivKeyC, OwnPrivKeyC, Public, AuthKey, PrivKey) -> Ret</name>
+ <fsummary>Add one user</fsummary>
+ <type>
+ <v>EngineID = string()</v>
+ <v>Name = string()</v>
+ <v>SecName = string()</v>
+ <v>Clone = zeroDotZero | [integer()]</v>
+ <v>AuthP = usmNoAuthProtocol | usmHMACMD5AuthProtocol | usmHMACSHAAuthProtocol</v>
+ <v>AuthKeyC = string()</v>
+ <v>OwnAuthKeyC = string()</v>
+ <v>PrivP = usmNoPrivProtocol | usmDESPrivProtocol</v>
+ <v>PrivKeyC = string()</v>
+ <v>OwnPrivKeyC = string()</v>
+ <v>Public = string()</v>
+ <v>AuthKey = string()</v>
+ <v>PrivKey = string()</v>
+ <v>Ret = {ok, Key} | {error, Reason}</v>
+ <v>Key = term()</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Adds a USM security data (user) to the agent config.
+ Equivalent to one line in the <c>usm.conf</c> file.</p>
+ <marker id="delete_user"></marker>
+ </desc>
+ </func>
+ <func>
+ <name>delete_user(Key) -> Ret</name>
+ <fsummary>Delete one user</fsummary>
+ <type>
+ <v>Key = term()</v>
+ <v>Ret = ok | {error, Reason}</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Delete a USM security data (user) from the agent config.</p>
+ </desc>
+ </func>
+ </funcs>
+
+</erlref>
+
diff --git a/lib/snmp/doc/src/snmp_view_based_acm_mib.xml b/lib/snmp/doc/src/snmp_view_based_acm_mib.xml
new file mode 100644
index 0000000000..ffea256608
--- /dev/null
+++ b/lib/snmp/doc/src/snmp_view_based_acm_mib.xml
@@ -0,0 +1,201 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE erlref SYSTEM "erlref.dtd">
+
+<erlref>
+ <header>
+ <copyright>
+ <year>1999</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ 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.
+
+ </legalnotice>
+
+ <title>snmp_view_based_acm_mib</title>
+ <prepared></prepared>
+ <responsible></responsible>
+ <docno></docno>
+ <approved></approved>
+ <checked></checked>
+ <date></date>
+ <rev></rev>
+ <file>snmp_view_based_acm_mib.xml</file>
+ </header>
+ <module>snmp_view_based_acm_mib</module>
+ <modulesummary>Instrumentation Functions for SNMP-VIEW-BASED-ACM-MIB</modulesummary>
+ <description>
+ <p>The module <c>snmp_view_based_acm_mib</c> implements the instrumentation functions for the
+ SNMP-VIEW-BASED-ACM-MIB, and functions for configuring the database.
+ </p>
+ <p>The configuration files are described in the SNMP User's Manual.</p>
+ </description>
+ <funcs>
+ <func>
+ <name>configure(ConfDir) -> void()</name>
+ <fsummary>Configure the SNMP-VIEW-BASED-ACM-MIB</fsummary>
+ <type>
+ <v>ConfDir = string()</v>
+ </type>
+ <desc>
+ <p>This function is called from the supervisor at system
+ start-up.
+ </p>
+ <p>Inserts all data in the configuration files into the
+ database and destroys all old rows with StorageType
+ <c>volatile</c>. The rows created from the configuration file
+ will have StorageType <c>nonVolatile</c>.
+ </p>
+ <p>All <c>snmp</c> counters are set to zero.
+ </p>
+ <p>If an error is found in the configuration file, it is
+ reported using the function <c>config_err/2</c> of the error
+ report module, and the function fails with the reason
+ <c>configuration_error</c>.
+ </p>
+ <p><c>ConfDir</c> is a string which points to the directory
+ where the configuration files are found.
+ </p>
+ <p>The configuration file read is: <c>vacm.conf</c>.
+ </p>
+ </desc>
+ </func>
+ <func>
+ <name>reconfigure(ConfDir) -> void()</name>
+ <fsummary>Configure the SNMP-VIEW-BASED-ACM-MIB</fsummary>
+ <type>
+ <v>ConfDir = string()</v>
+ </type>
+ <desc>
+ <p>Inserts all data in the configuration files into the
+ database and destroys all old data, including the rows with
+ StorageType <c>nonVolatile</c>. The rows created from the
+ configuration file will have StorageType <c>nonVolatile</c>.
+ </p>
+ <p>Thus, the data in the SNMP-VIEW-BASED-ACM-MIB, after this
+ function has been called, is the data from the configuration
+ files.
+ </p>
+ <p>All <c>snmp</c> counters are set to zero.
+ </p>
+ <p>If an error is found in the configuration file, it is
+ reported using the function <c>config_err/2</c> of the error
+ report module, and the function fails with the reason
+ <c>configuration_error</c>.
+ </p>
+ <p><c>ConfDir</c> is a string which points to the directory
+ where the configuration files are found.
+ </p>
+ <p>The configuration file read is: <c>vacm.conf</c>.
+ <marker id="add_sec2group"></marker>
+</p>
+ </desc>
+ </func>
+ <func>
+ <name>add_sec2group(SecModel, SecName, GroupName) -> Ret</name>
+ <fsummary>Add one security to group definition</fsummary>
+ <type>
+ <v>SecModel = v1 | v2c | usm</v>
+ <v>SecName = string()</v>
+ <v>GroupName = string()</v>
+ <v>Ret = {ok, Key} | {error, Reason}</v>
+ <v>Key = term()</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Adds a security to group definition to the agent config.
+ Equivalent to one vacmSecurityToGroup-line in the <c>vacm.conf</c> file.</p>
+ <marker id="delete_sec2group"></marker>
+ </desc>
+ </func>
+ <func>
+ <name>delete_sec2group(Key) -> Ret</name>
+ <fsummary>Delete one security to group definition</fsummary>
+ <type>
+ <v>Key = term()</v>
+ <v>Ret = ok | {error, Reason}</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Delete a security to group definition from the agent config.</p>
+ <marker id="add_access"></marker>
+ </desc>
+ </func>
+ <func>
+ <name>add_access(GroupName, Prefix, SecModel, SecLevel, Match, RV, WV, NV) -> Ret</name>
+ <fsummary>Add one access definition</fsummary>
+ <type>
+ <v>GroupName = string()</v>
+ <v>Prefix = string()</v>
+ <v>SecModel = v1 | v2c | usm</v>
+ <v>SecLevel = string()</v>
+ <v>Match = prefix | exact</v>
+ <v>RV = string()</v>
+ <v>WV = string()</v>
+ <v>NV = string()</v>
+ <v>Ret = {ok, Key} | {error, Reason}</v>
+ <v>Key = term()</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Adds a access definition to the agent config.
+ Equivalent to one vacmAccess-line in the <c>vacm.conf</c> file.</p>
+ <marker id="delete_access"></marker>
+ </desc>
+ </func>
+ <func>
+ <name>delete_access(Key) -> Ret</name>
+ <fsummary>Delete one access definition</fsummary>
+ <type>
+ <v>Key = term()</v>
+ <v>Ret = ok | {error, Reason}</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Delete a access definition from the agent config.</p>
+ <marker id="add_view_tree_fam"></marker>
+ </desc>
+ </func>
+ <func>
+ <name>add_view_tree_fam(ViewIndex, SubTree, Status, Mask) -> Ret</name>
+ <fsummary>Add one view tree family definition</fsummary>
+ <type>
+ <v>ViewIndex = integer()</v>
+ <v>SubTree = oid()</v>
+ <v>Status = included | excluded</v>
+ <v>Mask = null | [integer()], where all values are either 0 or 1</v>
+ <v>Ret = {ok, Key} | {error, Reason}</v>
+ <v>Key = term()</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Adds a view tree family definition to the agent config.
+ Equivalent to one vacmViewTreeFamily-line in the <c>vacm.conf</c> file.</p>
+ <marker id="delete_view_tree_fam"></marker>
+ </desc>
+ </func>
+ <func>
+ <name>delete_view_tree_fam(Key) -> Ret</name>
+ <fsummary>Delete one view tree family definition</fsummary>
+ <type>
+ <v>Key = term()</v>
+ <v>Ret = ok | {error, Reason}</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Delete a view tree family definition from the agent config.</p>
+ </desc>
+ </func>
+ </funcs>
+
+</erlref>
+
diff --git a/lib/snmp/doc/src/snmpa.xml b/lib/snmp/doc/src/snmpa.xml
new file mode 100644
index 0000000000..b3661ae9b0
--- /dev/null
+++ b/lib/snmp/doc/src/snmpa.xml
@@ -0,0 +1,1252 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE erlref SYSTEM "erlref.dtd">
+
+<erlref>
+ <header>
+ <copyright>
+ <year>2004</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ 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.
+
+ </legalnotice>
+
+ <title>snmpa</title>
+ <prepared></prepared>
+ <responsible></responsible>
+ <docno></docno>
+ <approved></approved>
+ <checked></checked>
+ <date></date>
+ <rev></rev>
+ <file>snmpa.xml</file>
+ </header>
+ <module>snmpa</module>
+ <modulesummary>Interface Functions to the SNMP toolkit agent</modulesummary>
+ <description>
+ <p>The module <c>snmpa</c> contains interface functions to the
+ SNMP agent.</p>
+
+ <marker id="data_types"></marker>
+ </description>
+
+ <section>
+ <title>DATA TYPES</title>
+ <code type="none"><![CDATA[
+oid() = [byte()]
+atl_type() = read | write | read_write
+notification_delivery_info() = #snmpa_notification_delivery_info{}
+ ]]></code>
+
+ <p>The <c>oid()</c> type is used to represent an ASN.1 OBJECT IDENTIFIER. </p>
+
+ <p>The record <c><![CDATA[snmpa_notification_delivery_info]]></c> contains the following fields: </p>
+ <taglist>
+ <tag><c><![CDATA[tag = term()]]></c></tag>
+ <item>
+ <p>A user defined identity representing this notification send
+ operation.</p>
+ </item>
+ <tag><c><![CDATA[mod = module()]]></c></tag>
+ <item>
+ <p>A module implementing the
+ <seealso marker="snmpa_notification_delivery_info_receiver">snmpa_notification_delivery_info_receiver</seealso>
+ behaviour. The info functions of this module will be called at
+ various stages of delivery. </p>
+ </item>
+ <tag><c><![CDATA[extra = term()]]></c></tag>
+ <item>
+ <p>This is any extra info the user wants to have supplied
+ when the functions in the callback module is called. </p>
+ </item>
+ </taglist>
+
+ <marker id="add_agent_caps"></marker>
+ </section>
+
+ <funcs>
+ <func>
+ <name>add_agent_caps(SysORID, SysORDescr) -> SysORIndex</name>
+ <fsummary>Add an AGENT-CAPABILITY definition to the agent</fsummary>
+ <type>
+ <v>SysORID = oid()</v>
+ <v>SysORDescr = string()</v>
+ <v>SysORIndex = integer()</v>
+ </type>
+ <desc>
+ <p>This function can be used to add an AGENT-CAPABILITY
+ statement to the sysORTable in the agent. The table is
+ defined in the SNMPv2-MIB.</p>
+ <marker id="del_agent_caps"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>del_agent_caps(SysORIndex) -> void()</name>
+ <fsummary>Delete an AGENT-CAPABILITY definition from the agent</fsummary>
+ <type>
+ <v>SysORIndex = integer()</v>
+ </type>
+ <desc>
+ <p>This function can be used to delete an AGENT-CAPABILITY
+ statement to the sysORTable in the agent. This table is
+ defined in the SNMPv2-MIB. </p>
+
+ <marker id="get_agent_caps"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>get_agent_caps() -> [[SysORIndex, SysORID, SysORDescr, SysORUpTime]]</name>
+ <fsummary>Return all AGENT-CAPABILITY definitions in the agent</fsummary>
+ <type>
+ <v>SysORIndex = integer()</v>
+ <v>SysORId = oid()</v>
+ <v>SysORDescr = string()</v>
+ <v>SysORUpTime = integer()</v>
+ </type>
+ <desc>
+ <p>Returns all AGENT-CAPABILITY statements in the sysORTable
+ in the agent. This table is defined in the SNMPv2-MIB. </p>
+
+ <marker id="get"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>get(Agent, Vars) -> Values | {error, Reason}</name>
+ <name>get(Agent, Vars, Context) -> Values | {error, Reason}</name>
+ <fsummary>Perform a get operation on the agent</fsummary>
+ <type>
+ <v>Agent = pid() | atom()</v>
+ <v>Vars = [oid()]</v>
+ <v>Context = string()</v>
+ <v>Values = [term()]</v>
+ <v>Reason = {atom(), oid()}</v>
+ </type>
+ <desc>
+ <p>Performs a GET operation on the agent. All loaded MIB
+ objects are visible in this operation. The agent calls the
+ corresponding instrumentation functions just as if it was a
+ GET request coming from a manager. </p>
+ <p>Note that the request specific parameters (such as
+ <seealso marker="#current_request_id">current_request_id</seealso>)
+ are not accessible for the instrumentation functions if this
+ function is used. </p>
+
+ <marker id="get_next"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>get_next(Agent, Vars) -> Values | {error, Reason}</name>
+ <name>get_next(Agent, Vars, Context) -> Values | {error, Reason}</name>
+ <fsummary>Perform a get-next operation on the agent</fsummary>
+ <type>
+ <v>Agent = pid() | atom()</v>
+ <v>Vars = [oid()]</v>
+ <v>Context = string()</v>
+ <v>Values = [{oid(), term()}]</v>
+ <v>Reason = {atom(), oid()}</v>
+ </type>
+ <desc>
+ <p>Performs a GET-NEXT operation on the agent. All loaded MIB
+ objects are visible in this operation. The agent calls the
+ corresponding instrumentation functions just as if it was a
+ GET request coming from a manager. </p>
+ <p>Note that the request specific parameters (such as
+ <c>snmpa:current_request_id/0</c> are not accessible for the
+ instrumentation functions if this function is used. </p>
+
+ <marker id="backup"></marker>
+ <!-- <marker id="get_symbolic_store_db"></marker> -->
+ </desc>
+ </func>
+
+<!--
+ <func>
+ <name>get_symbolic_store_db() -> Db</name>
+ <fsummary>Retrieve the symbolic store database reference</fsummary>
+ <type>
+ <v>Db = term()</v>
+ </type>
+ <desc>
+ <p>Retrieve the symbolic store database reference. This is used
+ for faster access to the database using the functions:
+ <c>int_to_enum/3</c>, <c>enum_to_int/3</c>, <c>name_to_oid/2</c>,
+ <c>oid_to_name/2</c>. </p>
+
+ <marker id="backup"></marker>
+ </desc>
+ </func>
+
+-->
+ <func>
+ <name>backup(BackupDir) -> ok | {error, Reason}</name>
+ <name>backup(Agent, BackupDir) -> ok | {error, Reason}</name>
+ <fsummary>Backup agent data</fsummary>
+ <type>
+ <v>BackupDir = string()</v>
+ <v>Agent = pid() | atom()</v>
+ </type>
+ <desc>
+ <p>Backup persistent/permanent data handled by the agent
+ (such as local-db, mib-data and vacm). </p>
+ <p>Data stored by mnesia is not handled. </p>
+ <p>BackupDir cannot be identical to DbDir. </p>
+
+ <marker id="info"></marker>
+ </desc>
+ </func>
+ <func>
+ <name>info() -> [{Key, Value}]</name>
+ <name>info(Agent) -> [{Key, Value}]</name>
+ <fsummary>Return information about the agent</fsummary>
+ <type>
+ <v>Agent = pid() | atom()</v>
+ </type>
+ <desc>
+ <p>Returns a list (a dictionary) containing information about
+ the agent. Information includes loaded MIBs, registered
+ sub-agents, some information about the memory allocation. </p>
+ <p>As of version 4.4 the format of the info has been changed.
+ To convert the info to the old format, call the
+ <seealso marker="#old_info_format">old_info_format</seealso>
+ function. </p>
+
+ <marker id="old_info_format"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>old_info_format(NewInfo) -> OldInfo</name>
+ <fsummary>Return information about the agent</fsummary>
+ <type>
+ <v>OldInfo = NewInfo = [{Key, Value}]</v>
+ </type>
+ <desc>
+ <p>As of version 4.4 the format of the info has been changed.
+ This function is used to convert to the old (pre-4.4) info
+ format. </p>
+
+ <marker id="load_mibs"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>load_mibs(Mibs) -> ok | {error, Reason}</name>
+ <name>load_mibs(Agent,Mibs) -> ok | {error, Reason}</name>
+ <fsummary>Load MIBs into the agent</fsummary>
+ <type>
+ <v>Agent = pid() | atom()</v>
+ <v>Mibs = [MibName]</v>
+ <v>MibName = string()</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Loads <c>Mibs</c> into an agent. If the agent cannot load
+ all MIBs, it will indicate where loading was aborted. The
+ <c>MibName</c> is the name of the Mib, including the path to
+ where the compiled mib is found. For example,</p>
+ <code type="none">
+ Dir = code:priv_dir(my_app) ++ "/mibs/",
+ snmpa:load_mibs(snmp_master_agent, [Dir ++ "MY-MIB"]).
+ </code>
+
+ <marker id="unload_mibs"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>unload_mibs(Mibs) -> ok | {error, Reason}</name>
+ <name>unload_mibs(Agent,Mibs) -> ok | {error, Reason}</name>
+ <fsummary>Unload MIBs from the agent</fsummary>
+ <type>
+ <v>Agent = pid() | atom()</v>
+ <v>Mibs = [MibName]</v>
+ <v>MibName = string()</v>
+ </type>
+ <desc>
+ <p>Unloads MIBs into an agent. If it cannot unload all MIBs,
+ it will indicate where unloading was aborted. </p>
+
+ <marker id="which_mibs"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>which_mibs() -> Mibs</name>
+ <name>which_mibs(Agent) -> Mibs</name>
+ <fsummary>Get a list of all the loaded mibs</fsummary>
+ <type>
+ <v>Agent = pid() | atom()</v>
+ <v>Mibs = [{MibName, MibFile}]</v>
+ <v>MibName = atom()</v>
+ <v>MibFile = string()</v>
+ </type>
+ <desc>
+ <p>Retrieve the list of all the mibs loaded into this agent. Default
+ is the master agent. </p>
+
+ <marker id="whereis_mib"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>whereis_mib(MibName) -> {ok, MibFile} | {error, Reason}</name>
+ <name>whereis_mib(Agent, MibName) -> {ok, MibFile} | {error, Reason}</name>
+ <fsummary>Get the path to the mib file</fsummary>
+ <type>
+ <v>Agent = pid() | atom()</v>
+ <v>MibName = atom()</v>
+ <v>MibFile = string()</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Get the full path to the (compiled) mib-file. </p>
+
+ <marker id="current_request_id"></marker>
+ <marker id="current_context"></marker>
+ <marker id="current_community"></marker>
+ <marker id="current_address"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>current_request_id() -> {value, RequestId} | false</name>
+ <name>current_context() -> {value, Context} | false</name>
+ <name>current_community() -> {value, Community} | false</name>
+ <name>current_address() -> {value, Address} | false</name>
+ <fsummary>Get the request-id, context, community and address of the current request</fsummary>
+ <type>
+ <v>RequestId = integer()</v>
+ <v>Context = string()</v>
+ <v>Community = string()</v>
+ <v>Address = term()</v>
+ </type>
+ <desc>
+ <p>Get the request-id, context, community and address of the
+ request currently being processed by the agent. </p>
+ <p>Note that these functions is intended to be called by the
+ instrumentation functions and <em>only</em> if they are
+ executed in the context of the agent process (e.g. it does
+ not work if called from a spawned process).</p>
+
+ <marker id="enum_to_int"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>enum_to_int(Name, Enum) -> {value, Int} | false</name>
+ <name>enum_to_int(Db, Name, Enum) -> {value, Int} | false</name>
+ <fsummary>Convert an enum value to an integer</fsummary>
+ <type>
+ <v>Db = term()</v>
+ <v>Name = atom()</v>
+ <v>Enum = atom()</v>
+ <v>Int = int()</v>
+ </type>
+ <desc>
+ <p>Converts the symbolic value <c>Enum</c> to the
+ corresponding integer of the enumerated object or type
+ <c>Name</c> in a MIB. The MIB must be loaded.
+ </p>
+ <p><c>false</c> is returned if the object or type is not
+ defined in any loaded MIB, or if it does not define the
+ symbolic value as enumerated.
+ </p>
+ <p><c>Db</c> is a reference to the symbolic store database
+ (retrieved by a call to <c>get_symbolic_store_db/0</c>). </p>
+
+ <marker id="int_to_enum"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>int_to_enum(Name, Int) -> {value, Enum} | false</name>
+ <name>int_to_enum(Db, Name, Int) -> {value, Enum} | false</name>
+ <fsummary>Convert an integer to an enum value</fsummary>
+ <type>
+ <v>Db = term()</v>
+ <v>Name = atom()</v>
+ <v>Int = int()</v>
+ <v>Enum = atom()</v>
+ </type>
+ <desc>
+ <p>Converts the integer <c>Int</c> to the corresponding
+ symbolic value of the enumerated object or type <c>Name</c> in
+ a MIB. The MIB must be loaded.
+ </p>
+ <p><c>false</c> is returned if the object or type is not
+ defined in any loaded MIB, or if it does not define the
+ symbolic value as enumerated.
+ </p>
+ <p><c>Db</c> is a reference to the symbolic store database
+ (retrieved by a call to <c>get_symbolic_store_db/0</c>). </p>
+
+ <marker id="name_to_oid"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>name_to_oid(Name) -> {value, oid()} | false</name>
+ <name>name_to_oid(Db, Name) -> {value, oid()} | false</name>
+ <fsummary>Convert a symbolic name to an OID</fsummary>
+ <type>
+ <v>Db = term()</v>
+ <v>Name = atom()</v>
+ </type>
+ <desc>
+ <p>Looks up the OBJECT IDENTIFIER of a MIB object, given the
+ symbolic name. Note, the OBJECT IDENTIFIER is given for the
+ object, not for an instance. </p>
+ <p><c>false</c> is returned if the object is not defined in any
+ loaded MIB. </p>
+ <p><c>Db</c> is a reference to the symbolic store database
+ (retrieved by a call to <c>get_symbolic_store_db/0</c>). </p>
+
+ <marker id="oid_to_name"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>oid_to_name(OID) -> {value, Name} | false</name>
+ <name>oid_to_name(Db, OID) -> {value, Name} | false</name>
+ <fsummary>Convert an OID to a symbolic name</fsummary>
+ <type>
+ <v>Db = term()</v>
+ <v>OID = oid()</v>
+ <v>Name = atom()</v>
+ </type>
+ <desc>
+ <p>Looks up the symbolic name of a MIB object, given OBJECT
+ IDENTIFIER. </p>
+ <p><c>false</c> is returned if the object is not defined in any
+ loaded MIB. </p>
+ <p><c>Db</c> is a reference to the symbolic store database
+ (retrieved by a call to <c>get_symbolic_store_db/0</c>). </p>
+
+ <marker id="which_aliasnames"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>which_aliasnames() -> Result</name>
+ <fsummary>Get all alias-names known to the agent</fsummary>
+ <type>
+ <v>Result = [atom()]</v>
+ </type>
+ <desc>
+ <p>Retrieve all alias-names known to the agent.</p>
+ <marker id="which_tables"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>which_tables() -> Result</name>
+ <fsummary>Get all tables known to the agent</fsummary>
+ <type>
+ <v>Result = [atom()]</v>
+ </type>
+ <desc>
+ <p>Retrieve all tables known to the agent.</p>
+
+ <marker id="which_variables"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>which_variables() -> Result</name>
+ <fsummary>Get all variables known to the agent</fsummary>
+ <type>
+ <v>Result = [atom()]</v>
+ </type>
+ <desc>
+ <p>Retrieve all variables known to the agent.</p>
+
+ <marker id="which_notifications"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>which_notifications() -> Result</name>
+ <fsummary>Get all notifications known to the agent</fsummary>
+ <type>
+ <v>Result = [{Name, MibName, Info}]</v>
+ <v>Name = atom()</v>
+ <v>MibName = atom()</v>
+ <v>Info = term()</v>
+ </type>
+ <desc>
+ <p>Retrieve all notifications (and traps) known to the agent.</p>
+
+ <marker id="log_to_txt"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>log_to_txt(LogDir, Mibs)</name>
+ <name>log_to_txt(LogDir, Mibs, OutFile) -> ok | {error, Reason}</name>
+ <name>log_to_txt(LogDir, Mibs, OutFile, LogName) -> ok | {error, Reason}</name>
+ <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile) -> ok | {error, Reason}</name>
+ <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Start) -> ok | {error, Reason}</name>
+ <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Start, Stop) -> ok | {error, Reason}</name>
+ <fsummary>Convert an Audit Trail Log to text format</fsummary>
+ <type>
+ <v>LogDir = string()</v>
+ <v>Mibs = [MibName]</v>
+ <v>MibName = string()</v>
+ <v>OutFile = string()</v>
+ <v>LogName = string()</v>
+ <v>LogFile = string()</v>
+ <v>Start = Stop = null | datetime() | {local_time,datetime()} | {universal_time,datetime()} </v>
+ <v>Reason = disk_log_open_error() | file_open_error() | term()</v>
+ <v>disk_log_open_error() = {LogName, term()}</v>
+ <v>file_open_error() = {OutFile, term()}</v>
+ </type>
+ <desc>
+ <p>Converts an Audit Trail Log to a readable text file.
+ <c>OutFile</c> defaults to "./snmpa_log.txt".
+ <c>LogName</c> defaults to "snmpa_log".
+ <c>LogFile</c> defaults to "snmpa.log".
+ See <seealso marker="snmp#log_to_txt">snmp:log_to_txt</seealso>
+ for more info.</p>
+
+ <marker id="change_log_size"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>change_log_size(NewSize) -> ok | {error, Reason}</name>
+ <fsummary>Change the size of the Audit Trail Log</fsummary>
+ <type>
+ <v>NewSize = {MaxBytes, MaxFiles}</v>
+ <v>MaxBytes = integer()</v>
+ <v>MaxFiles = integer()</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Changes the log size of the Audit Trail Log. The application must
+ be configured to use the audit trail log function. Please refer to
+ disk_log(3) in Kernel Reference Manual for a description of how to
+ change the log size. </p>
+ <p>The change is permanent, as long as the log is not deleted.
+ That means, the log size is remembered across reboots. </p>
+
+ <marker id="set_log_type"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>set_log_type(NewType) -> {ok, OldType} | {error, Reason}</name>
+ <name>set_log_type(Agent, NewType) -> {ok, OldType} | {error, Reason}</name>
+ <fsummary>Change the type of the Audit Trail Log</fsummary>
+ <type>
+ <v>NewType = OldType = atl_type()</v>
+ <v>Agent = pid() | atom()</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Changes the run-time Audit Trail log type. </p>
+ <p>Note that this has no effect on the application configuration as
+ defined by configuration files, so a node restart will revert the
+ config to whatever is in those files. </p>
+ <p>This function is primarily useful in testing/debugging
+ scenarios. </p>
+
+ <marker id="mib_of"></marker>
+ </desc>
+
+ </func>
+
+ <func>
+ <name>mib_of(Oid) -> {ok, MibName} | {error, Reason}</name>
+ <name>mib_of(Agent, Oid) -> {ok, MibName} | {error, Reason}</name>
+ <fsummary>Which mib an Oid belongs to</fsummary>
+ <type>
+ <v>Agent = pid() | atom()</v>
+ <v>Oid = oid()</v>
+ <v>MibName = atom()</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Finds the mib corresponding to the <c>Oid</c>. If it is a
+ variable, the Oid must be
+ &lt;Oid for var&gt;.0 and if it is a table, Oid must be
+ &lt;table&gt;.&lt;entry&gt;.&lt;col&gt;.&lt;any&gt;</p>
+
+ <marker id="me_of"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>me_of(Oid) -> {ok, Me} | {error, Reason}</name>
+ <name>me_of(Agent, Oid) -> {ok, Me} | {error, Reason}</name>
+ <fsummary>Retrieve the mib-entry of an Oid</fsummary>
+ <type>
+ <v>Agent = pid() | atom()</v>
+ <v>Oid = oid()</v>
+ <v>Me = #me{}</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Finds the mib entry corresponding to the <c>Oid</c>. If it is a
+ variable, the Oid must be
+ &lt;Oid for var&gt;.0 and if it is a table, Oid must be
+ &lt;table&gt;.&lt;entry&gt;.&lt;col&gt;.&lt;any&gt;</p>
+
+ <marker id="invalidate_mibs_cache"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>invalidate_mibs_cache() -> void()</name>
+ <name>invalidate_mibs_cache(Agent) -> void()</name>
+ <fsummary>Invalidate the mib server cache</fsummary>
+ <type>
+ <v>Agent = pid() | atom()</v>
+ </type>
+ <desc>
+ <p>Invalidate the mib server cache. </p>
+ <p>The entire contents of the cache will be deleted. </p>
+
+ <marker id="enable_mibs_cache"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>enable_mibs_cache() -> void()</name>
+ <name>enable_mibs_cache(Agent) -> void()</name>
+ <fsummary>Enable the mib server cache</fsummary>
+ <type>
+ <v>Agent = pid() | atom()</v>
+ </type>
+ <desc>
+ <p>Enable the mib server cache. </p>
+
+ <marker id="disable_mibs_cache"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>disable_mibs_cache() -> void()</name>
+ <name>disable_mibs_cache(Agent) -> void()</name>
+ <fsummary>Disable the mib server cache</fsummary>
+ <type>
+ <v>Agent = pid() | atom()</v>
+ </type>
+ <desc>
+ <p>Disable the mib server cache. </p>
+
+ <marker id="gc_mibs_cache"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>gc_mibs_cache() -> {ok, NumElementsGCed} | {error, Reason}</name>
+ <name>gc_mibs_cache(Agent) -> {ok, NumElementsGCed} | {error, Reason}</name>
+ <name>gc_mibs_cache(Age) -> {ok, NumElementsGCed} | {error, Reason}</name>
+ <name>gc_mibs_cache(Agent, Age) -> {ok, NumElementsGCed} | {error, Reason}</name>
+ <name>gc_mibs_cache(Age, GcLimit) -> {ok, NumElementsGCed} | {error, Reason}</name>
+ <name>gc_mibs_cache(Agent, Age, GcLimit) -> {ok, NumElementsGCed} | {error, Reason}</name>
+ <fsummary>Perform mib server cache gc</fsummary>
+ <type>
+ <v>Agent = pid() | atom()</v>
+ <v>Age = integer() > 0</v>
+ <v>GcLimit = integer() > 0 | infinity</v>
+ <v>NumElementsGCed = integer() >= 0</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Perform mib server cache gc. </p>
+ <p>Manually performs a mib server cache gc.
+ This can be done regardless of the value of the
+ <c>autogc</c> option.
+ The <c>NumElementsGCed</c> value indicates how many
+ elements where actually removed from the cache. </p>
+
+ <marker id="enable_mibs_cache_autogc"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>enable_mibs_cache_autogc() -> void()</name>
+ <name>enable_mibs_cache_autogc(Agent) -> void()</name>
+ <fsummary>Enable automatic gc of the mib server cache</fsummary>
+ <type>
+ <v>Agent = pid() | atom()</v>
+ </type>
+ <desc>
+ <p>Enable automatic gc of the mib server cache. </p>
+
+ <marker id="disable_mibs_cache_autogc"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>disable_mibs_cache_autogc() -> void()</name>
+ <name>disable_mibs_cache_autogc(Agent) -> void()</name>
+ <fsummary>Disable automatic gc of the mib server cache</fsummary>
+ <type>
+ <v>Agent = pid() | atom()</v>
+ </type>
+ <desc>
+ <p>Disable automatic gc of the mib server cache. </p>
+
+ <marker id="update_mibs_cache_age"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>update_mibs_cache_age(NewAge) -> ok | {error, Reason}</name>
+ <name>update_mibs_cache_age(Agent, NewAge) -> ok | {error, Reason}</name>
+ <fsummary>Change the mib server cache age property</fsummary>
+ <type>
+ <v>Agent = pid() | atom()</v>
+ <v>NewAge = integer() > 0</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Change the mib server cache <c>age</c> property. </p>
+
+ <marker id="update_mibs_cache_gclimit"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>update_mibs_cache_gclimit(NewGcLimit) -> ok | {error, Reason}</name>
+ <name>update_mibs_cache_gclimit(Agent, NewGCLimit) -> ok | {error, Reason}</name>
+ <fsummary>Change the mib server cache gclimit property</fsummary>
+ <type>
+ <v>Agent = pid() | atom()</v>
+ <v>NewGcLimit = integer() > 0 | infinity</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Change the mib server cache <c>gclimit</c> property. </p>
+
+ <marker id="register_notification_filter"></marker>
+ </desc>
+ </func>
+
+
+ <func>
+ <name>register_notification_filter(Id, Mod, Data) -> ok | {error, Reason}</name>
+ <name>register_notification_filter(Agent, Id, Mod, Data) -> ok | {error, Reason}</name>
+ <name>register_notification_filter(Id, Mod, Data, Where) -> ok | {error, Reason}</name>
+ <name>register_notification_filter(Agent, Id, Mod, Data, Where) -> ok | {error, Reason}</name>
+ <fsummary>Register a notification filter</fsummary>
+ <type>
+ <v>Agent = pid() | atom()</v>
+ <v>Id = filter_id()</v>
+ <v>filter_id() = term()</v>
+ <v>Mod = atom()</v>
+ <v>Data = term()</v>
+ <v>Where = filter_position()</v>
+ <v>Reason = term()</v>
+ <v>filter_position() = first | last | {insert_before, filter_id()} | {insert_after, filter_id()} </v>
+ </type>
+ <desc>
+ <p>Registers a notification filter.
+ </p>
+ <p><c>Mod</c> is a module implementing the
+ <c>snmpa_notification_filter</c> behaviour.</p>
+ <p><c>Data</c> will be passed on to the filter when calling the
+ functions of the behaviour.</p>
+
+ <marker id="unregister_notification_filter"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>unregister_notification_filter(Id) -> ok | {error, Reason}</name>
+ <name>unregister_notification_filter(Agent, Id) -> ok | {error, Reason}</name>
+ <fsummary>Unregister a notification filter</fsummary>
+ <type>
+ <v>Agent = pid() | atom()</v>
+ <v>Id = filter_id()</v>
+ <v>filter_id() = term()</v>
+ </type>
+ <desc>
+ <p>Unregister a notification filter. </p>
+
+ <marker id="which_notification_filter"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>which_notification_filter() -> Filters</name>
+ <name>which_notification_filter(Agent) -> Filters</name>
+ <fsummary>Which notification filter</fsummary>
+ <type>
+ <v>Agent = pid() | atom()</v>
+ <v>Filters = [filter_id()]</v>
+ <v>filter_id() = term()</v>
+ </type>
+ <desc>
+ <p>List all notification filters in an agent.</p>
+
+ <marker id="set_request_limit"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>set_request_limit(NewLimit) -> {ok, OldLimit} | {error, Reason}</name>
+ <name>set_request_limit(Agent, NewLimit) -> {ok, OldLimit} | {error, Reason}</name>
+ <fsummary>Change the request limit</fsummary>
+ <type>
+ <v>NewLimit = OldLimit = infinity | integer() >= 0</v>
+ <v>Agent = pid() | atom()</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Changes the request limit. </p>
+ <p>Note that this has no effect on the application configuration as
+ defined by configuration files, so a node restart will revert the
+ config to whatever is in those files. </p>
+ <p>This function is primarily useful in load regulation
+ scenarios. </p>
+
+ <marker id="register_subagent"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>register_subagent(Agent, SubTreeOid, Subagent) -> ok | {error, Reason}</name>
+ <fsummary>Register a sub-agent under a sub-tree</fsummary>
+ <type>
+ <v>Agent = pid() | atom()</v>
+ <v>SubTreeOid = oid()</v>
+ <v>SubAgent = pid()</v>
+ </type>
+ <desc>
+ <p>Registers a sub-agent under a sub-tree of another agent. </p>
+ <p>It is easy to make mistakes when registering sub-agents and
+ this activity should be done carefully. For example, a
+ strange behaviour would result from the following
+ configuration:</p>
+ <pre>
+snmp_agent:register_subagent(MAPid,[1,2,3,4],SA1),
+snmp_agent:register_subagent(SA1,[1,2,3], SA2).
+ </pre>
+ <p><c>SA2</c> will not get requests starting with object
+ identifier <c>[1,2,3]</c> since <c>SA1</c> does not. </p>
+
+ <marker id="unregister_subagent"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>unregister_subagent(Agent, SubagentOidOrPid) -> ok | {ok, SubAgentPid} | {error, Reason}</name>
+ <fsummary>Unregister a sub-agent</fsummary>
+ <type>
+ <v>Agent = pid() | atom()</v>
+ <v>SubTreeOidorPid = oid() | pid()</v>
+ </type>
+ <desc>
+ <p>Unregister a sub-agent. If the second argument is a pid,
+ then that sub-agent will be unregistered from all trees in
+ <c>Agent</c>. </p>
+
+ <marker id="send_notification"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>send_notification(Agent, Notification, Receiver)</name>
+ <name>send_notification(Agent, Notification, Receiver, Varbinds)</name>
+ <name>send_notification(Agent, Notification, Receiver, NotifyName, Varbinds)</name>
+ <name>send_notification(Agent, Notification, Receiver, NotifyName, ContextName, Varbinds) -> void() </name>
+ <fsummary>Send a notification</fsummary>
+ <type>
+ <v>Agent = pid() | atom()</v>
+ <v>Notification = atom()</v>
+ <v>Receiver = no_receiver | {Tag, Recv} | notification_delivery_info()</v>
+ <v>Tag = term()</v>
+ <v>Recv = receiver()</v>
+ <v>receiver() = pid() | atom() | {Mod, Func, Args}</v>
+ <v>Mod = atom()</v>
+ <v>Func = atom()</v>
+ <v>Args = list()</v>
+ <v>NotifyName = string()</v>
+ <v>ContextName = string()</v>
+ <v>Varbinds = varbinds()</v>
+ <v>varbinds() = [varbind()]</v>
+ <v>varbind() = {Variable, Value} | {Column, RowIndex, Value} | {OID, Value}</v>
+ <v>Variable = atom()</v>
+ <v>Column = atom()</v>
+ <v>OID = oid()</v>
+ <v>Value = term()</v>
+ <v>RowIndex = [int()]</v>
+ </type>
+ <desc>
+ <p>Sends the notification <c>Notification</c> to the
+ management targets defined for <c>NotifyName</c> in the
+ <c>snmpNotifyTable</c> in SNMP-NOTIFICATION-MIB from the
+ specified context. If no <c>NotifyName</c> is specified (or
+ if it is <c>""</c>), the notification is sent to all
+ management targets (<c>Addresses</c> below). If no <c>ContextName</c>
+ is specified, the default <c>""</c> context is used.
+ </p>
+
+ <p>The parameter <c>Receiver</c> specifies where information
+ about delivery of Inform-Requests should be sent. The agent
+ sends Inform-Requests and waits for acknowledgments from the
+ managers. <c>Receiver</c> can have three values: </p>
+
+ <list type="bulleted">
+ <item>
+ <p><c>no_receiver</c> - No information is delivered. </p>
+ </item>
+
+ <item>
+ <p><c>{Tag, Recv}</c> - The information is delivered either via messages
+ or via a function call according to the value of <c>Recv</c>. </p>
+ </item>
+
+ <item>
+ <p><c>notification_delivery_info()</c> - The information is
+ delivered via a function call according to this data. See the
+ <seealso marker="#data_types">DATA TYPES</seealso> section
+ above for details. </p>
+ </item>
+
+ </list>
+
+
+ <p>If <c>Receiver</c> has the value <c>{Tag, Recv}</c>, the delivery is
+ done according to <c>Recv</c>: </p>
+
+ <list>
+ <item>
+ <p><c>pid() | atom()</c> - The info will be delivered in
+ the following messages: </p>
+ <list>
+ <item>
+ <p><c>{snmp_targets, Tag, Addresses}</c></p>
+ <p>This inform the user which target addresses the
+ notification was sent to. </p>
+ </item>
+ <item>
+ <p><c>{snmp_notification, Tag, {got_response, Address}}</c></p>
+ <p>This informs the user that this target address
+ acknowledged the notification. </p>
+ </item>
+ <item>
+ <p><c>{snmp_notification, Tag, {no_response, Address}}</c></p>
+ <p>This informs the user that this target address
+ did not acknowledge notification. </p>
+ </item>
+ </list>
+ <p>The notification is sent as an Inform-Request to each
+ target address in <c>Addresses</c> and if there are no
+ targets for which an Inform-Request is sent, <c>Addresses</c>
+ is the empty list <c>[]</c>. </p>
+ <p>The <c>receiver</c> will first be sent the <c>snmp_targets</c>
+ message, and then for each address in <c>Addresses</c> list,
+ one of the two <c>snmp_notification</c> messages. </p>
+ </item>
+ <item>
+ <p><c>{Mod, Func, Args}</c> - The info will be delivered via
+ the function call: </p>
+ <p><c>Mod:Func([Msg | Args])</c></p>
+ <p>where <c>Msg</c> has the same content and purpose as the
+ messages descrived above.</p>
+ </item>
+ </list>
+
+ <p><c>Address</c> is a management target address and <c>Addresses</c> is a
+ list of management target addresses. They are defined as followes: </p>
+
+<pre>
+ Addresses = [address()]
+ Address = address()
+ address() = v1_address() | v3_address()
+ v1_address() = {TDomain, TAddress}
+ v3_address() = {{TDomain, TAddress}, V3MsgData}
+ TDomain = tdoamin()
+ TAddress = taddress()
+ tdomain() = The oid of snmpUDPDomain
+ This is the only supported transport domain.
+ taddress() = [A1, A2, A3, A4, P1, P3]
+ The 4 first bytes makes up the IP-address and the last 2,
+ the UDP-port number.
+ V3MsgData = v3_msg_data()
+ v3_msg_data() = term()
+</pre>
+
+ <p>If <c>Receiver</c> is a <c>notification_delivery_info()</c> record,
+ then the information about the notification delivery will be delivered
+ to the <c>receiver</c> via the callback functions defined by the
+ <seealso marker="snmpa_notification_delivery_info_receiver">snmpa_notification_delivery_info_receiver</seealso>
+ behaviour according to the content of the <c>notification_delivery_info()</c>
+ record. </p>
+
+ <p>The optional argument <c>Varbinds</c> defines
+ values for the objects in the notification. If no value is
+ given for an object, the <c>Agent</c> performs a get-operation
+ to retrieve the value.
+ </p>
+ <p><c>Varbinds</c> is a list of <c>Varbind</c>, where each
+ <c>Varbind</c> is one of:
+ </p>
+ <list type="bulleted">
+ <item><c>{Variable, Value}</c>, where <c>Variable</c> is the
+ symbolic name of a scalar variable referred to in the notification
+ specification.
+ </item>
+ <item><c>{Column, RowIndex, Value}</c>, where <c>Column</c>
+ is the symbolic name of a column variable.
+ <c>RowIndex</c> is a list of indices for the specified
+ element. If this is the case, the OBJECT IDENTIFIER sent
+ in the notification is the <c>RowIndex</c> appended to the OBJECT
+ IDENTIFIER for the table column. This is the OBJECT
+ IDENTIFIER which specifies the element.
+ </item>
+ <item><c>{OID, Value}</c>, where <c>OID</c> is the OBJECT
+ IDENTIFIER for an instance of an object, scalar variable,
+ or column variable.
+ </item>
+ </list>
+ <p>For example, to specify that <c>sysLocation</c> should have the
+ value <c>"upstairs"</c> in the notification, we could use one of:
+ </p>
+ <list type="bulleted">
+ <item><c>{sysLocation, "upstairs"}</c> or</item>
+ <item><c>{[1,3,6,1,2,1,1,6,0], "upstairs"}</c> or</item>
+ <item><c>{?sysLocation_instance, "upstairs"}</c> (provided
+ that the generated <c>.hrl</c> file is included)</item>
+ </list>
+ <p>If a variable in the notification is a table element, the
+ <c>RowIndex</c> for the element must be given in the
+ <c>Varbinds</c> list. In this case, the OBJECT IDENTIFIER sent
+ in the notification is the OBJECT IDENTIFIER that identifies this
+ element. This OBJECT IDENTIFIER could be used in a get
+ operation later.
+ </p>
+ <p>This function is asynchronous, and does not return any
+ information. If an error occurs, <c>user_err/2</c> of the error
+ report module is called and the notification is discarded.
+ </p>
+
+ <marker id="send_trap"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>send_trap(Agent,Trap,Community)</name>
+ <name>send_trap(Agent,Trap,Community,Varbinds) -> void()</name>
+ <fsummary>Send a trap</fsummary>
+ <type>
+ <v>Agent = pid() | atom()</v>
+ <v>Trap = atom()</v>
+ <v>Community = string()</v>
+ <v>Varbinds = [Varbind]</v>
+ <v>Varbind = {Variable, Value} | {Column, RowIndex, Value} | {OID, Value}</v>
+ <v>Variable = atom()</v>
+ <v>Column = atom()</v>
+ <v>OID = oid()</v>
+ <v>Value = term()</v>
+ <v>RowIndex = [int()]</v>
+ </type>
+ <desc>
+ <p>Note! This function is only kept for backwards
+ compatibility reasons. Use <c>send_notification</c> instead.
+ </p>
+ <p>Sends the trap <c>Trap</c> to the managers defined for
+ <c>Community</c> in the <c>intTrapDestTable</c> in
+ OTP-SNMPEA-MIB. The optional argument <c>Varbinds</c> defines
+ values for the objects in the trap. If no value is given for
+ an object, the <c>Agent</c> performs a get-operation to
+ retrieve the value.
+ </p>
+ <p><c>Varbinds</c> is a list of <c>Varbind</c>, where each
+ <c>Varbind</c> is one of:
+ </p>
+ <list type="bulleted">
+ <item><c>{Variable, Value}</c>, where <c>Variable</c> is the
+ symbolic name of a scalar variable referred to in the trap
+ specification.
+ </item>
+ <item><c>{Column, RowIndex, Value}</c>, where <c>Column</c>
+ is the symbolic name of a column variable.
+ <c>RowIndex</c> is a list of indices for the specified
+ element. If this is the case, the OBJECT IDENTIFIER sent
+ in the trap is the <c>RowIndex</c> appended to the OBJECT
+ IDENTIFIER for the table column. This is the OBJECT
+ IDENTIFIER which specifies the element.
+ </item>
+ <item><c>{OID, Value}</c>, where <c>OID</c> is the OBJECT
+ IDENTIFIER for an instance of an object, scalar variable,
+ or column variable.
+ </item>
+ </list>
+ <p>For example, to specify that <c>sysLocation</c> should have the
+ value <c>"upstairs"</c> in the trap, we could use one of:
+ </p>
+ <list type="bulleted">
+ <item><c>{sysLocation, "upstairs"}</c> or</item>
+ <item><c>{[1,3,6,1,2,1,1,6,0], "upstairs"}</c> or</item>
+ <item><c>{?sysLocation_instance, "upstairs"}</c> (provided
+ that the generated <c>.hrl</c> file is included)</item>
+ </list>
+ <p>If a variable in the trap is a table element, the
+ <c>RowIndex</c> for the element must be given in the
+ <c>Varbinds</c> list. In this case, the OBJECT IDENTIFIER sent
+ in the trap is the OBJECT IDENTIFIER that identifies this
+ element. This OBJECT IDENTIFIER could be used in a get
+ operation later.
+ </p>
+ <p>This function is asynchronous, and does not return any
+ information. If an error occurs, <c>snmp_error:user_err/2</c>
+ is called and the trap is discarded. </p>
+
+ <marker id="discovery"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>discovery(TargetName, Notification) -> {ok, ManagerEngineID} | {error, Reason}</name>
+ <name>discovery(TargetName, Notification, Varbinds) -> {ok, ManagerEngineID} | {error, Reason}</name>
+ <name>discovery(TargetName, Notification, DiscoHandler) -> {ok, ManagerEngineID} | {error, Reason}</name>
+ <name>discovery(TargetName, Notification, ContextName, Varbinds) -> {ok, ManagerEngineID} | {error, Reason}</name>
+ <name>discovery(TargetName, Notification, Varbinds, DiscoHandler) -> {ok, ManagerEngineID} | {error, Reason}</name>
+ <name>discovery(TargetName, Notification, ContextName, Varbinds, DiscoHandler) -> {ok, ManagerEngineID} | {error, Reason}</name>
+ <name>discovery(TargetName, Notification, ContextName, Varbinds, DiscoHandler, ExtraInfo) -> {ok, ManagerEngineID} | {error, Reason}</name>
+ <fsummary>Initiate the discovery process with a manager</fsummary>
+ <type>
+ <v>TargetName = string()</v>
+ <v>Notification = atom()</v>
+ <v>ContextName = string() (defaults to "")</v>
+ <v>Varbinds = varbinds()</v>
+ <v>varbinds() = [varbind()]</v>
+ <v>DiscoHandler = snmpa_discovery_handler()</v>
+ <v>ExtraInfo = term()</v>
+ <v>snmpa_discovery_handler() = Module implementing the snmpa_discovery_handler behaviour</v>
+ <v>ManagerEngineID = string()</v>
+ <v>varbind() = {Variable, Value} | {Column, RowIndex, Value} | {OID, Value}</v>
+ <v>Variable = atom()</v>
+ <v>Column = atom()</v>
+ <v>OID = oid()</v>
+ <v>Value = term()</v>
+ <v>RowIndex = [int()]</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Initiate the discovery process with the manager identified by
+ <c>TargetName</c> using the notification <c>Notification</c>. </p>
+
+ <p>This function is synchronous, which means that it will return when
+ the discovery process has been completed or failed. </p>
+
+ <p>The <c>DiscoHandler</c> module is used during the discovery
+ process. See
+ <seealso marker="snmpa_discovery_handler">discovery handler</seealso>
+ for more info. </p>
+
+ <p>The <c>ExtraInfo</c> argument is passed on to the callback functions
+ of the <c>DiscoHandler</c>. </p>
+
+ <note><p>If we are not at security-level <c>noAuthNoPriv</c>,
+ this could be complicated, since the agent will then continue
+ with stage 2, before which the usm-related updates must be
+ done. </p></note>
+
+ <note><p>The default discovery handler will require
+ additional actions by the caller and the discovery will not work
+ if the security-level is higher then <c>noAuthNoPriv</c>. </p></note>
+
+ <marker id="convert_config"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>convert_config(OldConfig) -> AgentConfig</name>
+ <fsummary>Convert old snmp config to new agent config</fsummary>
+ <type>
+ <v>OldConfig = list()</v>
+ <v>AgentConfig = list()</v>
+ </type>
+ <desc>
+ <p>This off-line utility function can be used to convert
+ the old snmp application config (pre snmp-4.0) to the
+ new snmp agent config (as of snmp-4.0).</p>
+ <p>For information about the old config (<c>OldConfig</c>)
+ see the OTP R9C documentation.</p>
+ <p>For information about the current agent config
+ (<c>AgentConfig</c>), see either
+ the <seealso marker="snmp_app">SNMP application</seealso>
+ part of the reference manual or the
+ <seealso marker="snmp_config">Configuring the application</seealso>
+ chapter of the SNMP user's guide.</p>
+
+ <marker id="restart_worker"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>restart_worker() -> void()</name>
+ <name>restart_worker(Agent) -> void()</name>
+ <fsummary>Restart the worker process of a multi-threaded agent</fsummary>
+ <type>
+ <v>Agent = pid() | atom()</v>
+ </type>
+ <desc>
+ <p>Restart the worker process of a multi-threaded agent.</p>
+ <p>This is a utility function, that can be usefull when
+ e.g. debugging instrumentation functions.</p>
+
+ <marker id="restart_set_worker"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>restart_set_worker() -> void()</name>
+ <name>restart_set_worker(Agent) -> void()</name>
+ <fsummary>Restart the set worker process of a multi-threaded agent</fsummary>
+ <type>
+ <v>Agent = pid() | atom()</v>
+ </type>
+ <desc>
+ <p>Restart the set worker process of a multi-threaded agent.</p>
+ <p>This is a utility function, that can be usefull when
+ e.g. debugging instrumentation functions.</p>
+
+ <marker id="verbosity"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>verbosity(Ref,Verbosity) -> void()</name>
+ <fsummary>Assign a new verbosity for the process</fsummary>
+ <type>
+ <v>Ref = pid() | sub_agents | master_agent | net_if | mib_server | symbolic_store | note_store | local_db</v>
+ <v>Verbosity = verbosity() | {subagents, verbosity()}</v>
+ <v>verbosity() = silence | info | log | debug | trace </v>
+ </type>
+ <desc>
+ <p>Sets verbosity for the designated process. For the lowest
+ verbosity <c>silence</c>, nothing is printed. The higher the
+ verbosity, the more is printed. </p>
+ </desc>
+ </func>
+ </funcs>
+
+ <section>
+ <title>See Also</title>
+ <p>calendar(3), erlc(1) </p>
+ </section>
+
+
+</erlref>
+
diff --git a/lib/snmp/doc/src/snmpa_conf.xml b/lib/snmp/doc/src/snmpa_conf.xml
new file mode 100644
index 0000000000..f383394b7a
--- /dev/null
+++ b/lib/snmp/doc/src/snmpa_conf.xml
@@ -0,0 +1,861 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE erlref SYSTEM "erlref.dtd">
+
+<erlref>
+ <header>
+ <copyright>
+ <year>2006</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ 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.
+
+ </legalnotice>
+
+ <title>snmpa_conf</title>
+ <prepared></prepared>
+ <responsible></responsible>
+ <docno></docno>
+ <approved></approved>
+ <checked></checked>
+ <date></date>
+ <rev></rev>
+ <file>snmpa_conf.xml</file>
+ </header>
+ <module>snmpa_conf</module>
+ <modulesummary>Utility functions for handling the agent config files.</modulesummary>
+ <description>
+ <p>The module <c>snmpa_conf</c> contains various utility functions to
+ used for manipulating (write/append/read) the config files of the
+ SNMP agent. </p>
+
+ <marker id="agent_entry"></marker>
+ </description>
+ <funcs>
+ <func>
+ <name>agent_entry(Tag, Val) -> agent_entry()</name>
+ <fsummary>Create an agent entry</fsummary>
+ <type>
+ <v>Tag = intAgentIpAddress | intAgentUDPPort | intAgentMaxPacketSize | snmpEngineMaxMessageSize | snmpEngineID</v>
+ <v>Val = term()</v>
+ <v>agent_entry() = term()</v>
+ </type>
+ <desc>
+ <p>Create an entry for the agent config file, <c>agent.conf</c>. </p>
+ <p>The type of <c>Val</c> depends on the value of <c>Tag</c>,
+ see
+ <seealso marker="snmp_agent_config_files#agent_information">Agent Information</seealso>
+ for more info. </p>
+
+ <marker id="write_agent_config"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>write_agent_config(Dir, Conf) -> ok</name>
+ <name>write_agent_config(Dir, Hdr, Conf) -> ok</name>
+ <fsummary>Write the agent config to the config file</fsummary>
+ <type>
+ <v>Dir = string()</v>
+ <v>Hdr = string()</v>
+ <v>Conf = [agent_entry()]</v>
+ </type>
+ <desc>
+ <p>Write the agent config to the agent config file. </p>
+ <p><c>Dir</c> is the path to the directory where to store the
+ config file. </p>
+ <p><c>Hdr</c> is an optional file header (note that this text is
+ written to the file as is). </p>
+ <p>See
+ <seealso marker="snmp_agent_config_files#agent_information">Agent Information</seealso>
+ for more info. </p>
+
+ <marker id="append_agent_config"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>append_agent_config(Dir, Conf) -> ok</name>
+ <fsummary>Append the agent config to the config file</fsummary>
+ <type>
+ <v>Dir = string()</v>
+ <v>Conf = [agent_entry()]</v>
+ </type>
+ <desc>
+ <p>Append the config to the current agent config file. </p>
+ <p><c>Dir</c> is the path to the directory where to store the
+ config file. </p>
+ <p>See
+ <seealso marker="snmp_agent_config_files#agent_information">Agent Information</seealso>
+ for more info. </p>
+
+ <marker id="read_agent_config"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>read_agent_config(Dir) -> Conf</name>
+ <fsummary>Read the agent config from the config file</fsummary>
+ <type>
+ <v>Dir = string()</v>
+ <v>Conf = [agent_entry()]</v>
+ </type>
+ <desc>
+ <p>Read the current agent config file. </p>
+ <p><c>Dir</c> is the path to the directory where to store the
+ config file. </p>
+ <p>See
+ <seealso marker="snmp_agent_config_files#agent_information">Agent Information</seealso>
+ for more info. </p>
+
+ <marker id="standard_entry"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>standard_entry(Tag, Val) -> standard_entry()</name>
+ <fsummary>Create an standard entry</fsummary>
+ <type>
+ <v>Tag = sysDescr | sysObjectID | sysContact | sysName | sysLocation | sysServices | snmpEnableAuthenTraps</v>
+ <v>Val = term()</v>
+ <v>standard_entry() = term()</v>
+ </type>
+ <desc>
+ <p>Create an entry for the agent standard config file,
+ <c>standard.conf</c>. </p>
+ <p>The type of <c>Val</c> depends on the value of <c>Tag</c>,
+ see
+ <seealso marker="snmp_agent_config_files#system_information">System Information</seealso>
+ for more info. </p>
+
+ <marker id="write_standard_config"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>write_standard_config(Dir, Conf) -> ok</name>
+ <name>write_standard_config(Dir, Hdr, Conf) -> ok</name>
+ <fsummary>Write the agent standard config to the config file</fsummary>
+ <type>
+ <v>Dir = string()</v>
+ <v>Hdr = string()</v>
+ <v>Conf = [standard_entry()]</v>
+ </type>
+ <desc>
+ <p>Write the agent standard config to the agent standard
+ config file. </p>
+ <p><c>Dir</c> is the path to the directory where to store the
+ config file. </p>
+ <p><c>Hdr</c> is an optional file header (note that this text is
+ written to the file as is). </p>
+ <p>See
+ <seealso marker="snmp_agent_config_files#system_information">System Information</seealso>
+ for more info. </p>
+
+ <marker id="append_standard_config"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>append_standard_config(Dir, Conf) -> ok</name>
+ <fsummary>Append the agent standard config to the config file</fsummary>
+ <type>
+ <v>Dir = string()</v>
+ <v>Conf = [standard_entry()]</v>
+ </type>
+ <desc>
+ <p>Append the standard config to the current agent standard
+ config file. </p>
+ <p><c>Dir</c> is the path to the directory where to store the
+ config file. </p>
+ <p>See
+ <seealso marker="snmp_agent_config_files#system_information">System Information</seealso>
+ for more info. </p>
+
+ <marker id="read_standard_config"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>read_standard_config(Dir) -> Conf</name>
+ <fsummary>Read the agent standard config from the config file</fsummary>
+ <type>
+ <v>Dir = string()</v>
+ <v>Conf = [standard_entry()]</v>
+ </type>
+ <desc>
+ <p>Read the current agent standard config file. </p>
+ <p><c>Dir</c> is the path to the directory where to store the
+ config file. </p>
+ <p>See
+ <seealso marker="snmp_agent_config_files#system_information">System Information</seealso>
+ for more info. </p>
+
+ <marker id="context_entry"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>context_entry(Context) -> context_entry()</name>
+ <fsummary>Create an context entry</fsummary>
+ <type>
+ <v>Context = string()</v>
+ <v>context_entry() = term()</v>
+ </type>
+ <desc>
+ <p>Create an entry for the agent context config file,
+ <c>context.conf</c>. </p>
+ <p>See
+ <seealso marker="snmp_agent_config_files#context">Contexts</seealso>
+ for more info. </p>
+
+ <marker id="write_context_config"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>write_context_config(Dir, Conf) -> ok</name>
+ <name>write_context_config(Dir, Hdr, Conf) -> ok</name>
+ <fsummary>Write the agent context(s) to the config file</fsummary>
+ <type>
+ <v>Dir = string()</v>
+ <v>Hdr = string()</v>
+ <v>Conf = [context_entry()]</v>
+ </type>
+ <desc>
+ <p>Write the agent context config to the agent context
+ config file. </p>
+ <p><c>Dir</c> is the path to the directory where to store the
+ config file. </p>
+ <p><c>Hdr</c> is an optional file header (note that this text is
+ written to the file as is). </p>
+ <p>See
+ <seealso marker="snmp_agent_config_files#context">Contexts</seealso>
+ for more info. </p>
+
+ <marker id="append_context_config"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>append_context_config(Dir, Conf) -> ok</name>
+ <fsummary>Append the agent context(s) to the config file</fsummary>
+ <type>
+ <v>Dir = string()</v>
+ <v>Conf = [context_entry()]</v>
+ </type>
+ <desc>
+ <p>Append the context config to the current agent context
+ config file. </p>
+ <p><c>Dir</c> is the path to the directory where to store the
+ config file. </p>
+ <p>See
+ <seealso marker="snmp_agent_config_files#context">Contexts</seealso>
+ for more info. </p>
+
+ <marker id="read_context_config"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>read_context_config(Dir) -> Conf</name>
+ <fsummary>Read the agent context config from the config file</fsummary>
+ <type>
+ <v>Dir = string()</v>
+ <v>Conf = [context_entry()]</v>
+ </type>
+ <desc>
+ <p>Read the current agent context config file. </p>
+ <p><c>Dir</c> is the path to the directory where to store the
+ config file. </p>
+ <p>See
+ <seealso marker="snmp_agent_config_files#context">Contexts</seealso>
+ for more info. </p>
+
+ <marker id="community_entry"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>community_entry(CommunityIndex) -> community_entry()</name>
+ <name>community_entry(CommunityIndex, CommunityName, SecName, ContextName, TransportTag) -> community_entry()</name>
+ <fsummary>Create an community entry</fsummary>
+ <type>
+ <v>CommunityIndex = string()</v>
+ <v>CommunityName = string()</v>
+ <v>SecName = string()</v>
+ <v>CtxName = string()</v>
+ <v>TransportTag = string()</v>
+ <v>community_entry() = term()</v>
+ </type>
+ <desc>
+ <p>Create an entry for the agent community config file,
+ <c>community.conf</c>. </p>
+ <p><c>CommunityIndex</c> must be a <em>non-empty</em> string. </p>
+ <p><c>community_entry("public")</c> translates to the following call:
+ <c>community_entry(CommunityIndex, CommunityIndex, "initial", "", "")</c>. </p>
+ <p><c>community_entry("all-rights")</c> translates to the following
+ call: <c>community_entry(CommunityIndex, CommunityIndex, CommunityIndex, "", "")</c>. </p>
+ <p>See
+ <seealso marker="snmp_agent_config_files#community">Community</seealso>
+ for more info. </p>
+
+ <marker id="write_community_config"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>write_community_config(Dir, Conf) -> ok</name>
+ <name>write_community_config(Dir, Hdr, Conf) -> ok</name>
+ <fsummary>Write the agent community config to the config file</fsummary>
+ <type>
+ <v>Dir = string()</v>
+ <v>Hdr = string()</v>
+ <v>Conf = [community_entry()]</v>
+ </type>
+ <desc>
+ <p>Write the agent community config to the agent community
+ config file. </p>
+ <p><c>Dir</c> is the path to the directory where to store the
+ config file. </p>
+ <p><c>Hdr</c> is an optional file header (note that this text is
+ written to the file as is). </p>
+ <p>See
+ <seealso marker="snmp_agent_config_files#community">Community</seealso>
+ for more info. </p>
+
+ <marker id="append_community_config"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>append_community_config(Dir, Conf) -> ok</name>
+ <fsummary>Append the agent community config to the config file</fsummary>
+ <type>
+ <v>Dir = string()</v>
+ <v>Conf = [community_entry()]</v>
+ </type>
+ <desc>
+ <p>Append the community config to the current agent community
+ config file. </p>
+ <p><c>Dir</c> is the path to the directory where to store the
+ config file. </p>
+ <p>See
+ <seealso marker="snmp_agent_config_files#community">Community</seealso>
+ for more info. </p>
+
+ <marker id="read_community_config"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>read_community_config(Dir) -> Conf</name>
+ <fsummary>Read the agent community config from the config file</fsummary>
+ <type>
+ <v>Dir = string()</v>
+ <v>Conf = [community_entry()]</v>
+ </type>
+ <desc>
+ <p>Read the current agent community config file. </p>
+ <p><c>Dir</c> is the path to the directory where to store the
+ config file. </p>
+ <p>See
+ <seealso marker="snmp_agent_config_files#community">Communities</seealso>
+ for more info. </p>
+
+ <marker id="target_addr_entry"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>target_addr_entry(Name, Ip, TagList, ParamsName, EngineId) -> target_addr_entry()</name>
+ <name>target_addr_entry(Name, Ip, TagList, ParamsName, EngineId, TMask) -> target_addr_entry()</name>
+ <name>target_addr_entry(Name, Ip, Udp, TagList, ParamsName, EngineId, TMask, MaxMessageSize) -> target_addr_entry()</name>
+ <name>target_addr_entry(Name, Ip, Udp, Timeout, RetryCount, TagList, ParamsName, EngineId, TMask, MaxMessageSize) -> target_addr_entry()</name>
+ <fsummary>Create an target_addr entry</fsummary>
+ <type>
+ <v>Name = string()</v>
+ <v>Ip = string()</v>
+ <v>Udp = integer()</v>
+ <v>Timeout = integer()</v>
+ <v>RetryCount = integer()</v>
+ <v>TagList = string()</v>
+ <v>ParamsName = string()</v>
+ <v>EngineId = string()</v>
+ <v>TMask = string()</v>
+ <v>MaxMessageSize = integer()</v>
+ <v>target_addr_entry() = term()</v>
+ </type>
+ <desc>
+ <p>Create an entry for the agent target_addr config file,
+ <c>target_addr.conf</c>. </p>
+ <p><c>Name</c> must be a <em>non-empty</em> string. </p>
+ <p><c>target_addr_entry/5</c> translates to the following call:
+ <c>target_addr_entry(Name, Ip, TagList, ParamsName, EngineId)</c>. </p>
+ <p><c>target_addr_entry/6</c> translates to the following call:
+ <c>target_addr_entry(Name, Ip, 162, TagList, ParamsName, EngineId, TMask, 2048)</c>. </p>
+ <p><c>target_addr_entry/8</c> translates to the following call:
+ <c>target_addr_entry(Name, Ip, Udp, 1500, 3, TagList, ParamsName, EngineId, TMask, MaxMessageSize)</c>. </p>
+ <p>See
+ <seealso marker="snmp_agent_config_files#target_addr">Target Address Definitions</seealso>
+ for more info. </p>
+
+ <marker id="write_target_addr_config"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>write_target_addr_config(Dir, Conf) -> ok</name>
+ <name>write_target_addr_config(Dir, Hdr, Conf) -> ok</name>
+ <fsummary>Write the agent target_addr config to the config file</fsummary>
+ <type>
+ <v>Dir = string()</v>
+ <v>Hdr = string()</v>
+ <v>Conf = [target_addr_entry()]</v>
+ </type>
+ <desc>
+ <p>Write the agent target_addr config to the agent target_addr
+ config file. </p>
+ <p><c>Dir</c> is the path to the directory where to store the
+ config file. </p>
+ <p><c>Hdr</c> is an optional file header (note that this text is
+ written to the file as is). </p>
+ <p>See
+ <seealso marker="snmp_agent_config_files#target_addr">Target Address Definitions</seealso>
+ for more info. </p>
+
+ <marker id="append_target_addr_config"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>append_target_addr_config(Dir, Conf) -> ok</name>
+ <fsummary>Append the agent target_addr config to the config file</fsummary>
+ <type>
+ <v>Dir = string()</v>
+ <v>Conf = [target_addr_entry()]</v>
+ </type>
+ <desc>
+ <p>Append the target_addr config to the current agent target_addr
+ config file. </p>
+ <p><c>Dir</c> is the path to the directory where to store the
+ config file. </p>
+ <p>See
+ <seealso marker="snmp_agent_config_files#target_addr">Target Address Definitions</seealso>
+ for more info. </p>
+
+ <marker id="read_target_addr_config"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>read_target_addr_config(Dir) -> Conf</name>
+ <fsummary>Read the agent target_addr config from the config file</fsummary>
+ <type>
+ <v>Dir = string()</v>
+ <v>Conf = [target_addr_entry()]</v>
+ </type>
+ <desc>
+ <p>Read the current agent target_addr config file. </p>
+ <p><c>Dir</c> is the path to the directory where to store the
+ config file. </p>
+ <p>See
+ <seealso marker="snmp_agent_config_files#target_addr">Target Address Definitions</seealso>
+ for more info. </p>
+
+ <marker id="target_params_entry"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>target_params_entry(Name, Vsn) -> target_params_entry()</name>
+ <name>target_params_entry(Name, Vsn, SecName, SecLevel) -> target_params_entry()</name>
+ <name>target_params_entry(Name, MPModel, SecModel, SecName, SecLevel) -> target_params_entry()</name>
+ <fsummary>Create an target_params entry</fsummary>
+ <type>
+ <v>Name = string()</v>
+ <v>Vsn = v1 | v2 | v3</v>
+ <v>MPModel = v1 | v2c | v3</v>
+ <v>SecModel = v1 | v2c | usm</v>
+ <v>SecName = string()</v>
+ <v>SecLevel = noAuthNoPriv | authNoPriv | authPriv</v>
+ <v>target_params_entry() = term()</v>
+ </type>
+ <desc>
+ <p>Create an entry for the agent target_params config file,
+ <c>target_params.conf</c>. </p>
+ <p><c>Name</c> must be a <em>non-empty</em> string. </p>
+ <p><c>Vsn</c> translates into <c>MPModel</c> and <c>SecModel</c> as follows:</p>
+ <pre>
+\011 Vsn = v1 => MPModel = v1, SecModel = v1
+\011 Vsn = v2 => MPModel = v2c, SecModel = v2c
+\011 Vsn = v3 => MPModel = v3, SecModel = usm
+ </pre>
+ <p><c>target_params_entry/2</c> translates to the following call:
+ <c>target_params_entry(Name, Vsn, "initial", noAuthNoPriv)</c>. </p>
+ <p><c>target_params_entry/4</c> translates to the following
+ call: <c>target_params_entry(Name, MPModel, SecModel, SecName, SecLevel)</c> where <c>MPModel</c> and
+ <c>SecModel</c> is mapped from <c>Vsn</c>, see above. </p>
+ <p>See
+ <seealso marker="snmp_agent_config_files#target_params">Target Parameters Definitions</seealso>
+ for more info. </p>
+
+ <marker id="write_target_params_config"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>write_target_params_config(Dir, Conf) -> ok</name>
+ <name>write_target_params_config(Dir, Hdr, Conf) -> ok</name>
+ <fsummary>Write the agent target_params config to the config file</fsummary>
+ <type>
+ <v>Dir = string()</v>
+ <v>Hdr = string()</v>
+ <v>Conf = [target_params_entry()]</v>
+ </type>
+ <desc>
+ <p>Write the agent target_params config to the agent target_params
+ config file. </p>
+ <p><c>Dir</c> is the path to the directory where to store the
+ config file. </p>
+ <p><c>Hdr</c> is an optional file header (note that this text is
+ written to the file as is). </p>
+ <p>See
+ <seealso marker="snmp_agent_config_files#target_params">Target Parameters Definitions</seealso>
+ for more info. </p>
+
+ <marker id="append_target_params_config"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>append_target_params_config(Dir, Conf) -> ok</name>
+ <fsummary>Append the agent target_params config to the config file</fsummary>
+ <type>
+ <v>Dir = string()</v>
+ <v>Conf = [target_params_entry()]</v>
+ </type>
+ <desc>
+ <p>Append the target_params config to the current agent target_params
+ config file. </p>
+ <p><c>Dir</c> is the path to the directory where to store the
+ config file. </p>
+ <p>See
+ <seealso marker="snmp_agent_config_files#target_params">Target Parameters Definitions</seealso>
+ for more info. </p>
+
+ <marker id="read_target_params_config"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>read_target_params_config(Dir) -> Conf</name>
+ <fsummary>Read the agent target_params config from the config file</fsummary>
+ <type>
+ <v>Dir = string()</v>
+ <v>Conf = [target_params_entry()]</v>
+ </type>
+ <desc>
+ <p>Read the current agent target_params config file. </p>
+ <p><c>Dir</c> is the path to the directory where to store the
+ config file. </p>
+ <p>See
+ <seealso marker="snmp_agent_config_files#target_params">Target Parameters Definitions</seealso>
+ for more info. </p>
+
+ <marker id="vacm_entry"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>vacm_s2g_entry(SecModel, SecName, GroupName) -> vacm_s2g_entry()</name>
+ <name>vacm_acc_entry(GroupName, Prefix, SecModel, SecLevel, Match, ReadView, WriteView, NotifyView) -> vacm_acc_entry()</name>
+ <name>vacm_vtf_entry(ViewIndex, ViewSubtree) -> vacm_vtf_entry()</name>
+ <name>vacm_vtf_entry(ViewIndex, ViewSubtree, ViewStatus, ViewMask) -> vacm_vtf_entry()</name>
+ <fsummary>Create an vacm entry</fsummary>
+ <type>
+ <v>SecModel = v1 | v2c | usm</v>
+ <v>SecName = string()</v>
+ <v>GroupName = string()</v>
+ <v>Prefix = string()</v>
+ <v>SecLevel = noAuthNoPriv | authNoPriv | authPriv</v>
+ <v>Match = prefix | exact</v>
+ <v>ReadView = string()</v>
+ <v>WriteView = string()</v>
+ <v>NotifyView = string()</v>
+ <v>ViewIndex = integer()</v>
+ <v>ViewSubtree = [integer()]</v>
+ <v>ViewStatus = included | excluded</v>
+ <v>ViewMask = null | [zero_or_one()]</v>
+ <v>zero_or_one() = 0 | 1</v>
+ <v>vacm_s2g_entry() = term()</v>
+ <v>vacm_acc_entry() = term()</v>
+ <v>vacm_vtf_entry() = term()</v>
+ </type>
+ <desc>
+ <p>Create an entry for the agent vacm config file,
+ <c>vacm.conf</c>. </p>
+ <p><c>vacm_vtf_entry/2</c> translates to the following call:
+ <c>vacm_vtf_entry(ViewIndex, ViewSubtree, included, null)</c>. </p>
+ <p>See
+ <seealso marker="snmp_agent_config_files#vacm">MIB Views for VACM</seealso>
+ for more info. </p>
+
+ <marker id="write_vacm_config"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>write_vacm_config(Dir, Conf) -> ok</name>
+ <name>write_vacm_config(Dir, Hdr, Conf) -> ok</name>
+ <fsummary>Write the agent vacm config to the config file</fsummary>
+ <type>
+ <v>Dir = string()</v>
+ <v>Hdr = string()</v>
+ <v>Conf = [vacm_entry()]</v>
+ <v>vacm_entry() = vacm_sg2_entry() | vacm_acc_entry() | vacm_vtf_entry()</v>
+ </type>
+ <desc>
+ <p>Write the agent vacm config to the agent vacm
+ config file. </p>
+ <p><c>Dir</c> is the path to the directory where to store the
+ config file. </p>
+ <p><c>Hdr</c> is an optional file header (note that this text is
+ written to the file as is). </p>
+ <p>See
+ <seealso marker="snmp_agent_config_files#vacm">MIB Views for VACM</seealso>
+ for more info. </p>
+
+ <marker id="append_vacm_config"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>append_vacm_config(Dir, Conf) -> ok</name>
+ <fsummary>Append the agent vacm config to the config file</fsummary>
+ <type>
+ <v>Dir = string()</v>
+ <v>Conf = [vacm_entry()]</v>
+ </type>
+ <desc>
+ <p>Append the vacm config to the current agent vacm
+ config file. </p>
+ <p><c>Dir</c> is the path to the directory where to store the
+ config file. </p>
+ <p>See
+ <seealso marker="snmp_agent_config_files#vacm">MIB Views for VACM</seealso>
+ for more info. </p>
+
+ <marker id="read_vacm_config"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>read_vacm_config(Dir) -> Conf</name>
+ <fsummary>Read the agent vacm config from the config file</fsummary>
+ <type>
+ <v>Dir = string()</v>
+ <v>Conf = [vacm_entry()]</v>
+ </type>
+ <desc>
+ <p>Read the current agent vacm config file. </p>
+ <p><c>Dir</c> is the path to the directory where to store the
+ config file. </p>
+ <p>See
+ <seealso marker="snmp_agent_config_files#vacm">MIB Views for VACM</seealso>
+ for more info. </p>
+
+ <marker id="usm_entry"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>usm_entry(EngineId) -> usm_entry()</name>
+ <name>usm_entry(EngineID, UserName, SecName, Clone, AuthP, AuthKeyC, OwnAuthKeyC, PrivP, PrivKeyC, OwnPrivKeyC, Public, AuthKey, PrivKey) -> usm_entry()</name>
+ <fsummary>Create an usm entry</fsummary>
+ <type>
+ <v>EngineId = string()</v>
+ <v>UserName = string()</v>
+ <v>SecName = string()</v>
+ <v>Clone = zeroDotZero | [integer()]</v>
+ <v>AuthP = usmNoAuthProtocol | usmHMACMD5AuthProtocol, | usmHMACSHAAuthProtocol</v>
+ <v>AuthKeyC = string()</v>
+ <v>OwnAuthKeyC = string()</v>
+ <v>PrivP = usmNoPrivProtocol | usmDESPrivProtocol | usmAesCfb128Protocol</v>
+ <v>PrivKeyC = string()</v>
+ <v>OwnPrivKeyC = string()</v>
+ <v>Public = string()</v>
+ <v>AuthKey = [integer()]</v>
+ <v>PrivKey = [integer()]</v>
+ <v>usm_entry() = term()</v>
+ </type>
+ <desc>
+ <p>Create an entry for the agent vacm config file,
+ <c>vacm.conf</c>. </p>
+ <p><c>usm_entry/1</c> translates to the following call:
+ <c>usm_entry("initial", "initial", zeroDotZero, usmNoAuthProtocol, "", "", usmNoPrivProtocol, "", "", "", "", "")</c>. </p>
+ <p>See
+ <seealso marker="snmp_agent_config_files#usm">Security data for USM</seealso>
+ for more info. </p>
+
+ <marker id="write_usm_config"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>write_usm_config(Dir, Conf) -> ok</name>
+ <name>write_usm_config(Dir, Hdr, Conf) -> ok</name>
+ <fsummary>Write the agent usm config to the config file</fsummary>
+ <type>
+ <v>Dir = string()</v>
+ <v>Hdr = string()</v>
+ <v>Conf = [usm_entry()]</v>
+ </type>
+ <desc>
+ <p>Write the agent usm config to the agent usm
+ config file. </p>
+ <p><c>Dir</c> is the path to the directory where to store the
+ config file. </p>
+ <p><c>Hdr</c> is an optional file header (note that this text is
+ written to the file as is). </p>
+ <p>See
+ <seealso marker="snmp_agent_config_files#usm">Security data for USM</seealso>
+ for more info. </p>
+
+ <marker id="append_usm_config"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>append_usm_config(Dir, Conf) -> ok</name>
+ <fsummary>Append the agent usm config to the config file</fsummary>
+ <type>
+ <v>Dir = string()</v>
+ <v>Conf = [usm_entry()]</v>
+ </type>
+ <desc>
+ <p>Append the usm config to the current agent vacm
+ config file. </p>
+ <p><c>Dir</c> is the path to the directory where to store the
+ config file. </p>
+ <p>See
+ <seealso marker="snmp_agent_config_files#usm">Security data for USM</seealso>
+ for more info. </p>
+ <marker id="read_usm_config"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>read_usm_config(Dir) -> Conf</name>
+ <fsummary>Read the agent usm config from the config file</fsummary>
+ <type>
+ <v>Dir = string()</v>
+ <v>Conf = [usm_entry()]</v>
+ </type>
+ <desc>
+ <p>Read the current agent usm config file. </p>
+ <p><c>Dir</c> is the path to the directory where to store the
+ config file. </p>
+ <p>See
+ <seealso marker="snmp_agent_config_files#usm">Security data for USM</seealso>
+ for more info. </p>
+
+ <marker id="notify_entry"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>notify_entry(Name, Tag, Type) -> notify_entry()</name>
+ <fsummary>Create an notify entry</fsummary>
+ <type>
+ <v>Name = string()</v>
+ <v>Tag = string()</v>
+ <v>Type = trap | inform</v>
+ <v>community_entry() = term()</v>
+ </type>
+ <desc>
+ <p>Create an entry for the agent notify config file,
+ <c>notify.conf</c>. </p>
+ <p><c>Name</c> must be a <em>non-empty</em> string. </p>
+ <p>See
+ <seealso marker="snmp_agent_config_files#notify">Notify Definitions</seealso>
+ for more info. </p>
+
+ <marker id="write_notify_config"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>write_notify_config(Dir, Conf) -> ok</name>
+ <name>write_notify_config(Dir, Hdr, Conf) -> ok</name>
+ <fsummary>Write the agent notify config to the config file</fsummary>
+ <type>
+ <v>Dir = string()</v>
+ <v>Hdr = string()</v>
+ <v>Conf = [notify_entry()]</v>
+ </type>
+ <desc>
+ <p>Write the agent notify config to the agent notify
+ config file. </p>
+ <p><c>Dir</c> is the path to the directory where to store the
+ config file. </p>
+ <p><c>Hdr</c> is an optional file header (note that this text is
+ written to the file as is). </p>
+ <p>See
+ <seealso marker="snmp_agent_config_files#notify">Notify Definitions</seealso>
+ for more info. </p>
+
+ <marker id="append_notify_config"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>append_notify_config(Dir, Conf) -> ok</name>
+ <fsummary>Append the agent notify config to the config file</fsummary>
+ <type>
+ <v>Dir = string()</v>
+ <v>Conf = [notify_entry()]</v>
+ </type>
+ <desc>
+ <p>Append the notify config to the current agent notify
+ config file. </p>
+ <p><c>Dir</c> is the path to the directory where to store the
+ config file. </p>
+ <p>See
+ <seealso marker="snmp_agent_config_files#notify">Notify Definitions</seealso>
+ for more info. </p>
+
+ <marker id="read_notify_config"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>read_notify_config(Dir) -> Conf</name>
+ <fsummary>Read the agent notify config from the config file</fsummary>
+ <type>
+ <v>Dir = string()</v>
+ <v>Conf = [community_entry()]</v>
+ </type>
+ <desc>
+ <p>Read the current agent notify config file. </p>
+ <p><c>Dir</c> is the path to the directory where to store the
+ config file. </p>
+ <p>See
+ <seealso marker="snmp_agent_config_files#notify">Notify Definitions</seealso>
+ for more info. </p>
+ <marker id="end"></marker>
+ </desc>
+ </func>
+ </funcs>
+
+</erlref>
+
diff --git a/lib/snmp/doc/src/snmpa_discovery_handler.xml b/lib/snmp/doc/src/snmpa_discovery_handler.xml
new file mode 100644
index 0000000000..47814221aa
--- /dev/null
+++ b/lib/snmp/doc/src/snmpa_discovery_handler.xml
@@ -0,0 +1,118 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE erlref SYSTEM "erlref.dtd">
+
+<erlref>
+ <header>
+ <copyright>
+ <year>2004</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ 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.
+
+ </legalnotice>
+
+ <title>snmpa_discovery_handler</title>
+ <prepared></prepared>
+ <responsible></responsible>
+ <docno></docno>
+ <approved></approved>
+ <checked></checked>
+ <date></date>
+ <rev></rev>
+ <file>snmpa_discovery_handler.xml</file>
+ </header>
+ <module>snmpa_discovery_handler</module>
+ <modulesummary>Behaviour module for the SNMP agent discovery handler.</modulesummary>
+ <description>
+ <p>This module defines the behaviour of the agent discovery
+ handler. A <c>snmpa_discovery_handler</c> compliant module
+ must export the following functions: </p>
+ <list type="bulleted">
+ <item>
+ <p><seealso marker="#stage1_finish">stage1_finish/2</seealso></p>
+ </item>
+ </list>
+ <p>The semantics of them and their exact signatures are explained
+ below. </p>
+
+ <marker id="stage1_finish"></marker>
+ </description>
+
+ <funcs>
+ <func>
+ <name>stage1_finish(TargetName, ManagerEngineID, ExtraInfo) -> ignore | {ok, usm_entry() | [usm_entry()]} | {ok, usm_entry() | [usm_entry()], NewExtraInfo}</name>
+ <fsummary>Discovery stage 1 finish</fsummary>
+ <type>
+ <v>TargetName = string()</v>
+ <v>ManagerEngineID = string()</v>
+ <v>ExtraInfo = term()</v>
+ <v>usm_entry() = tuple() compatible with usm.conf</v>
+ <v>NewExtraInfo = term()</v>
+ </type>
+ <desc>
+ <p>This function is called at the end of stage 1 of the
+ discovery process. It should return either the atom
+ <c>ignore</c> or <c>{ok, usm_entry() | [usm_entry()]}</c>. See
+ <seealso marker="snmp_agent_config_files#usm">usm_entry()</seealso>
+ and
+ <seealso marker="snmpa_conf#usm_entry">usm_entry/13</seealso>
+ for more info. </p>
+
+ <p>If the function returns <c>ignore</c>, then it is assumed that
+ either: </p>
+
+ <list type="bulleted">
+ <item>The caller (of the discovery function) will make the
+ needed updates later. </item>
+ <item>The callback function itself did the updates. </item>
+ </list>
+
+ <p>In either case, the agent will do nothing, but return
+ the retrieved ManagerEngineID (see
+ <seealso marker="snmpa#discovery">discovery</seealso>
+ for more info) and possible continue with stage 2 of
+ the discovery process. </p>
+
+ <p>The <c>ExtraInfo</c> argument is passed on from the
+ <seealso marker="snmpa#discovery">discovery</seealso>
+ function. </p>
+
+ <p>This function may return an updated <c>NewExtraInfo</c>
+ that will be used in subsequent calls to the callback
+ functions. Intended for future use. </p>
+
+ <p>The purpose of this function is to generate the usm-
+ related security data needed for usm processing in the
+ agent. Specifically, updating the usmUserTable. </p>
+
+ <p>When an <c>usm_entry()</c> tuple (or a list of such
+ tuples) is returned, this data is then added to the
+ <c>usmUserTable</c> by the (master-) agent. </p>
+
+ <p>When an <c>usm_entry()</c> tuple (or a list of such
+ tuples) is returned, this data is then added to the
+ <c>usmUserTable</c> by the (master-) agent. </p>
+
+ <note><p>Note that the function does not check if this entry
+ already exists. </p></note>
+
+ <note><p>Note that this function is executed in the context of
+ the master-agent process. </p></note>
+
+ </desc>
+ </func>
+
+ </funcs>
+
+</erlref>
+
diff --git a/lib/snmp/doc/src/snmpa_error.xml b/lib/snmp/doc/src/snmpa_error.xml
new file mode 100644
index 0000000000..a7312e8b24
--- /dev/null
+++ b/lib/snmp/doc/src/snmpa_error.xml
@@ -0,0 +1,91 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE erlref SYSTEM "erlref.dtd">
+
+<erlref>
+ <header>
+ <copyright>
+ <year>2002</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ 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.
+
+ </legalnotice>
+
+ <title>snmpa_error</title>
+ <prepared></prepared>
+ <responsible></responsible>
+ <docno></docno>
+ <approved></approved>
+ <checked></checked>
+ <date></date>
+ <rev></rev>
+ <file>snmpa_error.xml</file>
+ </header>
+ <module>snmpa_error</module>
+ <modulesummary>Functions for Reporting SNMP Errors</modulesummary>
+ <description>
+ <marker id="desc"></marker>
+ <p>The module <c>snmpa_error</c> contains two callback functions
+ which are called if an error occurs at different times during agent
+ operation. These functions in turn calls the corresponding function
+ in the configured error report module, which implements the actual
+ report functionality.
+ </p>
+ <p>Two simple implementation(s) is provided with the
+ toolkit; the modules
+ <seealso marker="snmpa_error_logger">snmpa_error_logger</seealso>
+ which is the default and
+ <seealso marker="snmpa_error_io">snmpa_error_io</seealso>.
+ </p>
+ <p>The error report module is configured using the directive
+ <c>error_report_mod</c>, see
+ <seealso marker="snmp_config#configuration_params">configuration parameters</seealso>.
+ </p>
+ </description>
+ <funcs>
+ <func>
+ <name>config_err(Format, Args) -> void()</name>
+ <fsummary>Called if a configuration error occurs</fsummary>
+ <type>
+ <v>Format = string()</v>
+ <v>Args = list()</v>
+ </type>
+ <desc>
+ <p>The function is called if an error occurs during the
+ configuration phase, for example if a syntax error is found in
+ a configuration file.
+ </p>
+ <p><c>Format</c> and <c>Args</c> are as in
+ <c>io:format(Format, Args)</c>.</p>
+ </desc>
+ </func>
+ <func>
+ <name>user_err(Format, Args) -> void()</name>
+ <fsummary>Called if a user related error occurs</fsummary>
+ <type>
+ <v>Format = string()</v>
+ <v>Args = list()</v>
+ </type>
+ <desc>
+ <p>The function is called if a user related error occurs at
+ run-time, for example if a user defined instrumentation
+ function returns erroneous.
+ </p>
+ <p><c>Format</c> and <c>Args</c> are as in
+ <c>io:format(Format, Args)</c>.</p>
+ </desc>
+ </func>
+ </funcs>
+
+</erlref>
+
diff --git a/lib/snmp/doc/src/snmpa_error_io.xml b/lib/snmp/doc/src/snmpa_error_io.xml
new file mode 100644
index 0000000000..33fbfac20c
--- /dev/null
+++ b/lib/snmp/doc/src/snmpa_error_io.xml
@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE erlref SYSTEM "erlref.dtd">
+
+<erlref>
+ <header>
+ <copyright>
+ <year>2002</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ 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.
+
+ </legalnotice>
+
+ <title>snmpa_error_io</title>
+ <prepared></prepared>
+ <responsible></responsible>
+ <docno></docno>
+ <approved></approved>
+ <checked></checked>
+ <date></date>
+ <rev></rev>
+ <file>snmpa_error_io.xml</file>
+ </header>
+ <module>snmpa_error_io</module>
+ <modulesummary>Functions for Reporting SNMP Errors on stdio</modulesummary>
+ <description>
+ <p>The module <c>snmpa_error_io</c> implements the
+ <c>snmp_error_report</c> behaviour
+ (see <seealso marker="snmpa_error_report">snmpa_error_report</seealso>)
+ containing two callback functions which are called in order to
+ report SNMP errors.
+ </p>
+ <p>This module provides a simple mechanism for reporting SNMP
+ errors. Errors are written to stdout using the <c>io</c> module.
+ It is provided as an simple example.
+ </p>
+ <p>This module needs to be explicitly configured, see
+ <seealso marker="snmpa_error#desc">snmpa_error</seealso> and
+ <seealso marker="snmp_config#configuration_params">configuration parameters</seealso>.
+ </p>
+ </description>
+ <funcs>
+ <func>
+ <name>config_err(Format, Args) -> void()</name>
+ <fsummary>Called if a configuration error occurs</fsummary>
+ <type>
+ <v>Format = string()</v>
+ <v>Args = list()</v>
+ </type>
+ <desc>
+ <p>The function is called if an error occurs during the
+ configuration phase, for example if a syntax error is found in
+ a configuration file.
+ </p>
+ <p><c>Format</c> and <c>Args</c> are as in
+ <c>io:format(Format, Args)</c>.</p>
+ </desc>
+ </func>
+ <func>
+ <name>user_err(Format, Args) -> void()</name>
+ <fsummary>Called if a user related error occurs</fsummary>
+ <type>
+ <v>Format = string()</v>
+ <v>Args = list()</v>
+ </type>
+ <desc>
+ <p>The function is called if a user related error occurs at
+ run-time, for example if a user defined instrumentation
+ function returns erroneous.
+ </p>
+ <p><c>Format</c> and <c>Args</c> are as in
+ <c>io:format(Format, Args)</c>.</p>
+ </desc>
+ </func>
+ </funcs>
+
+</erlref>
+
diff --git a/lib/snmp/doc/src/snmpa_error_logger.xml b/lib/snmp/doc/src/snmpa_error_logger.xml
new file mode 100644
index 0000000000..06382a6057
--- /dev/null
+++ b/lib/snmp/doc/src/snmpa_error_logger.xml
@@ -0,0 +1,95 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE erlref SYSTEM "erlref.dtd">
+
+<erlref>
+ <header>
+ <copyright>
+ <year>1996</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ 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.
+
+ </legalnotice>
+
+ <title>snmpa_error_logger</title>
+ <prepared></prepared>
+ <responsible></responsible>
+ <docno></docno>
+ <approved></approved>
+ <checked></checked>
+ <date></date>
+ <rev></rev>
+ <file>snmpa_error_logger.xml</file>
+ </header>
+ <module>snmpa_error_logger</module>
+ <modulesummary>Functions for Reporting SNMP Errors through the error_logger</modulesummary>
+ <description>
+ <p>The module <c>snmpa_error_logger</c> implements the
+ <c>snmpa_error_report</c> behaviour
+ (see <seealso marker="snmpa_error_report">snmpa_error_report</seealso>)
+ containing two callback functions which are called in order to
+ report SNMP errors.
+ </p>
+ <p>This module provides a simple mechanism for reporting SNMP
+ errors. Errors are sent to the <c>error_logger</c> after a
+ size check. Messages are truncated after 1024 chars.
+ It is provided as an example.
+ </p>
+ <p>This module is the default error report module, but can be
+ explicitly configured, see
+ <seealso marker="snmpa_error#desc">snmpa_error</seealso> and
+ <seealso marker="snmp_config#configuration_params">configuration parameters</seealso>.
+ </p>
+ </description>
+ <funcs>
+ <func>
+ <name>config_err(Format, Args) -> void()</name>
+ <fsummary>Called if a configuration error occurs</fsummary>
+ <type>
+ <v>Format = string()</v>
+ <v>Args = list()</v>
+ </type>
+ <desc>
+ <p>The function is called if an error occurs during the
+ configuration phase, for example if a syntax error is found in
+ a configuration file.
+ </p>
+ <p><c>Format</c> and <c>Args</c> are as in
+ <c>io:format(Format, Args)</c>.</p>
+ </desc>
+ </func>
+ <func>
+ <name>user_err(Format, Args) -> void()</name>
+ <fsummary>Called if a user related error occurs</fsummary>
+ <type>
+ <v>Format = string()</v>
+ <v>Args = list()</v>
+ </type>
+ <desc>
+ <p>The function is called if a user related error occurs at
+ run-time, for example if a user defined instrumentation
+ function returns erroneous.
+ </p>
+ <p><c>Format</c> and <c>Args</c> are as in
+ <c>io:format(Format, Args)</c>.</p>
+ </desc>
+ </func>
+ </funcs>
+
+ <section>
+ <title>See Also</title>
+ <p>error_logger(3)</p>
+ </section>
+
+</erlref>
+
diff --git a/lib/snmp/doc/src/snmpa_error_report.xml b/lib/snmp/doc/src/snmpa_error_report.xml
new file mode 100644
index 0000000000..421202bade
--- /dev/null
+++ b/lib/snmp/doc/src/snmpa_error_report.xml
@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE erlref SYSTEM "erlref.dtd">
+
+<erlref>
+ <header>
+ <copyright>
+ <year>2004</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ 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.
+
+ </legalnotice>
+
+ <title>snmpa_error_report</title>
+ <prepared></prepared>
+ <responsible></responsible>
+ <docno></docno>
+ <approved></approved>
+ <checked></checked>
+ <date></date>
+ <rev></rev>
+ <file>snmpa_error_report.xml</file>
+ </header>
+ <module>snmpa_error_report</module>
+ <modulesummary>Behaviour module for reporting SNMP agent errors</modulesummary>
+ <description>
+ <marker id="desc"></marker>
+ <p>This module defines the behaviour of the agent error reporting.
+ A <c>snmpa_error_report</c> compliant module
+ must export the following functions: </p>
+ <list type="bulleted">
+ <item>
+ <p>config_err/2</p>
+ </item>
+ <item>
+ <p>user_err/2</p>
+ </item>
+ </list>
+ <p>The semantics of them and their exact signatures are explained
+ below. </p>
+ </description>
+ <funcs>
+ <func>
+ <name>config_err(Format, Args) -> void()</name>
+ <fsummary>Called if a configuration error occurs</fsummary>
+ <type>
+ <v>Format = string()</v>
+ <v>Args = list()</v>
+ </type>
+ <desc>
+ <p>The function is called if an error occurs during the
+ configuration phase, for example if a syntax error is found in
+ a configuration file.
+ </p>
+ <p><c>Format</c> and <c>Args</c> are as in
+ <c>io:format(Format, Args)</c>.</p>
+ </desc>
+ </func>
+ <func>
+ <name>user_err(Format, Args) -> void()</name>
+ <fsummary>Called if a user related error occurs</fsummary>
+ <type>
+ <v>Format = string()</v>
+ <v>Args = list()</v>
+ </type>
+ <desc>
+ <p>The function is called if a user related error occurs at
+ run-time, for example if a user defined instrumentation
+ function returns erroneous.
+ </p>
+ <p><c>Format</c> and <c>Args</c> are as in
+ <c>io:format(Format, Args)</c>.</p>
+ </desc>
+ </func>
+ </funcs>
+
+</erlref>
+
diff --git a/lib/snmp/doc/src/snmpa_local_db.xml b/lib/snmp/doc/src/snmpa_local_db.xml
new file mode 100644
index 0000000000..c077bc96d8
--- /dev/null
+++ b/lib/snmp/doc/src/snmpa_local_db.xml
@@ -0,0 +1,190 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE erlref SYSTEM "erlref.dtd">
+
+<erlref>
+ <header>
+ <copyright>
+ <year>1996</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ 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.
+
+ </legalnotice>
+
+ <title>snmpa_local_db</title>
+ <prepared></prepared>
+ <responsible></responsible>
+ <docno></docno>
+ <approved></approved>
+ <checked></checked>
+ <date></date>
+ <rev></rev>
+ <file>snmpa_local_db.xml</file>
+ </header>
+ <module>snmpa_local_db</module>
+ <modulesummary>The SNMP built-in database</modulesummary>
+ <description>
+ <p>The module <c>snmpa_local_db</c> contains functions for
+ implementing tables (and variables) using the SNMP built-in
+ database. The database exists in two instances, one volatile
+ and one persistent. The volatile database is implemented with
+ ets. The persistent database is implemented with dets.
+ </p>
+ <p>There is a scaling problem with this database.
+ </p>
+ <list type="bulleted">
+ <item>Insertions and deletions are inefficient for large tables.
+ </item>
+ </list>
+ <p>This problem is best solved by using Mnesia instead.
+ </p>
+ <p>The following functions describe the interface to
+ <c>snmpa_local_db</c>. Each function has a Mnesia equivalent.
+ The argument <c>NameDb</c> is a tuple <c>{Name, Db}</c> where
+ <c>Name</c> is the symbolic name of the managed object (as defined
+ in the MIB), and <c>Db</c> is either <c>volatile</c> or
+ <c>persistent</c>. <c>mnesia</c> is not possible since all these
+ functions are <c>snmpa_local_db</c> specific.
+ </p>
+ </description>
+
+ <section>
+ <title>Common Data Types</title>
+ <p>In the functions defined below, the following types are
+ used:
+ </p>
+ <list type="bulleted">
+ <item>
+ <p><c>NameDb = {Name, Db}</c></p>
+ </item>
+ <item>
+ <p><c>Name = atom(), Db = volatile | persistent</c></p>
+ </item>
+ <item>
+ <p><c>RowIndex = [int()]</c></p>
+ </item>
+ <item>
+ <p><c>Cols = [Col] | [{Col, Value}], Col = int(), Value = term()</c></p>
+ </item>
+ </list>
+ <p>where <c>RowIndex</c> denotes the last part of the OID, that
+ specifies the index of the row in the table. <c>Cols</c> is a
+ list of column numbers in case of a get operation, and a list of
+ column numbers and values in case of a set operation.
+ </p>
+ </section>
+ <funcs>
+ <func>
+ <name>dump() -> ok | {error, Reason}</name>
+ <fsummary>Dump the database to disk</fsummary>
+ <type>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>This function can be used to manually dump the database
+ to file.</p>
+ </desc>
+ </func>
+ <func>
+ <name>match(NameDb, Pattern)</name>
+ <fsummary>Perform a match on the table</fsummary>
+ <desc>
+ <p>Performs an ets/dets matching on the table.
+ See Stdlib documentation, module ets, for a description of
+ <c>Pattern</c> and the return values.</p>
+ </desc>
+ </func>
+ <func>
+ <name>print()</name>
+ <name>print(TableName)</name>
+ <name>print(TableName, Db)</name>
+ <fsummary>Print the database to screen</fsummary>
+ <type>
+ <v>TableName = atom()</v>
+ </type>
+ <desc>
+ <p>Prints the contents of the database on
+ screen. This is useful for debugging since the
+ <c>STANDARD-MIB</c> and <c>OTP-SNMPEA-MIB</c>
+ (and maybe your own MIBs) are stored in <c>snmpa_local_db</c>.
+ </p>
+ <p><c>TableName</c> is an atom for a table in the database.
+ When no name is supplied, the whole database is shown.</p>
+ </desc>
+ </func>
+ <func>
+ <name>table_create(NameDb) -> bool()</name>
+ <fsummary>Create a table</fsummary>
+ <desc>
+ <p>Creates a table. If the table already exist, the old copy
+ is destroyed.
+ </p>
+ <p>Returns <c>false</c> if the <c>NameDb</c> argument is
+ incorrectly specified, <c>true</c> otherwise.</p>
+ </desc>
+ </func>
+ <func>
+ <name>table_create_row(NameDb, RowIndex, Row) -> bool()</name>
+ <fsummary>Create a row in a table</fsummary>
+ <type>
+ <v>Row = {Val1, Val2, ..., ValN}</v>
+ <v>Val1 = Val2 = ... = ValN = term()</v>
+ </type>
+ <desc>
+ <p>Creates a row in a table. <c>Row</c> is a tuple with
+ values for all columns, including the index columns.</p>
+ </desc>
+ </func>
+ <func>
+ <name>table_delete(NameDb) -> void()</name>
+ <fsummary>Delete a table</fsummary>
+ <desc>
+ <p>Deletes a table.</p>
+ </desc>
+ </func>
+ <func>
+ <name>table_delete_row(NameDb, RowIndex) -> bool()</name>
+ <fsummary>Delete the row in the table</fsummary>
+ <desc>
+ <p>Deletes the row in the table.</p>
+ </desc>
+ </func>
+ <func>
+ <name>table_exists(NameDb) -> bool()</name>
+ <fsummary>Check if a table exists</fsummary>
+ <desc>
+ <p>Checks if a table exists.</p>
+ </desc>
+ </func>
+ <func>
+ <name>table_get_row(NameDb, RowIndex) -> Row | undefined</name>
+ <fsummary>Get a row from the table</fsummary>
+ <type>
+ <v>Row = {Val1, Val2, ..., ValN}</v>
+ <v>Val1 = Val2 = ... = ValN = term()</v>
+ </type>
+ <desc>
+ <p><c>Row</c> is a tuple with values for all columns,
+ including the index columns.</p>
+ </desc>
+ </func>
+ </funcs>
+
+ <section>
+ <title>See Also</title>
+ <p>ets(3), dets(3), snmp_generic(3)
+ </p>
+ </section>
+
+</erlref>
+
diff --git a/lib/snmp/doc/src/snmpa_mpd.xml b/lib/snmp/doc/src/snmpa_mpd.xml
new file mode 100644
index 0000000000..ea5bde8956
--- /dev/null
+++ b/lib/snmp/doc/src/snmpa_mpd.xml
@@ -0,0 +1,159 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE erlref SYSTEM "erlref.dtd">
+
+<erlref>
+ <header>
+ <copyright>
+ <year>1999</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ 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.
+
+ </legalnotice>
+
+ <title>snmpa_mpd</title>
+ <prepared></prepared>
+ <responsible></responsible>
+ <docno></docno>
+ <approved></approved>
+ <checked></checked>
+ <date></date>
+ <rev></rev>
+ <file>snmpa_mpd.xml</file>
+ </header>
+ <module>snmpa_mpd</module>
+ <modulesummary>Message Processing and Dispatch module for the SNMP agent</modulesummary>
+ <description>
+ <p>The module <c>snmpa_mpd</c> implements the version independent
+ Message Processing and Dispatch functionality in SNMP for the agent.
+ It is supposed to be used from a Network Interface process
+ (<seealso marker="snmp_agent_netif">Definition of Agent Net if</seealso>).
+ </p>
+
+ <marker id="init"></marker>
+ </description>
+
+ <funcs>
+ <func>
+ <name>init(Vsns) -> mpd_state()</name>
+ <fsummary>Initialize the MPD module</fsummary>
+ <type>
+ <v>Vsns = [Vsn]</v>
+ <v>Vsn = v1 | v2 | v3</v>
+ </type>
+ <desc>
+ <p>This function can be called from the net_if process at start-up.
+ The options list defines which versions to use.
+ </p>
+ <p>It also initializes some SNMP counters.
+ </p>
+
+ <marker id="process_packet"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>process_packet(Packet, TDomain, TAddress, State) -> {ok, Vsn, Pdu, PduMS, ACMData} | {discarded, Reason} | {discovery, DiscoPacket}</name>
+ <fsummary>Process a packet received from the network</fsummary>
+ <type>
+ <v>Packet = binary()</v>
+ <v>TDomain = snmpUDPDomain</v>
+ <v>TAddress = {Ip, Udp}</v>
+ <v>Ip = {integer(), integer(), integer(), integer()}</v>
+ <v>Udp = integer()</v>
+ <v>State = mpd_state()</v>
+ <v>Vsn = 'version-1' | 'version-2' | 'version-3'</v>
+ <v>Pdu = #pdu</v>
+ <v>PduMs = integer()</v>
+ <v>ACMData = acm_data()</v>
+ <v>Reason = term()</v>
+ <v>DiscoPacket = binary()</v>
+ </type>
+ <desc>
+ <p>Processes an incoming packet. Performs authentication and
+ decryption as necessary. The return values should be passed the
+ agent.</p>
+
+ <marker id="generate_response_msg"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>generate_response_msg(Vsn, RePdu, Type, ACMData) -> {ok, Packet} | {discarded, Reason}</name>
+ <fsummary>Generate a response packet to be sent to the network</fsummary>
+ <type>
+ <v>Vsn = 'version-1' | 'version-2' | 'version-3'</v>
+ <v>RePdu = #pdu</v>
+ <v>Type = atom()</v>
+ <v>ACMData = acm_data()</v>
+ <v>Packet = binary()</v>
+ </type>
+ <desc>
+ <p>Generates a possibly encrypted response packet to be sent to the
+ network. <c>Type</c> is the <c>#pdu.type</c> of the original
+ request.</p>
+
+ <marker id="generate_msg"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>generate_msg(Vsn, Pdu, MsgData, To) -> {ok, PacketsAndAddresses} | {discarded, Reason}</name>
+ <fsummary>Generate a request message to be sent to the network</fsummary>
+ <type>
+ <v>Vsn = 'version-1' | 'version-2' | 'version-3'</v>
+ <v>Pdu = #pdu</v>
+ <v>MsgData = msg_data()</v>
+ <v>To = [dest_addrs()]</v>
+ <v>PacketsAndAddresses = [{TDomain, TAddress, Packet}]</v>
+ <v>TDomain = snmpUDPDomain</v>
+ <v>TAddress = {Ip, Udp}</v>
+ <v>Ip = {integer(), integer(), integer(), integer()}</v>
+ <v>Udp = integer()</v>
+ <v>Packet = binary()</v>
+ </type>
+ <desc>
+ <p>Generates a possibly encrypted request packet to be sent to the
+ network.
+ </p>
+ <p><c>MsgData</c> is the message specific data used in
+ the SNMP message. This value is received in a <c>send_pdu</c>
+ or <c>send_pdu_req</c> message from the agent. In SNMPv1 and
+ SNMPv2c, this message data is the community string. In
+ SNMPv3, it is the context information.
+ <c>To</c> is a list of the destination addresses and
+ their corresponding security parameters. This value is
+ also received from the requests mentioned above.
+ </p>
+
+ <marker id="discarded_pdu"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>discarded_pdu(Variable) -> void()</name>
+ <fsummary>Increment the variable associated with a discarded pdu</fsummary>
+ <type>
+ <v>Variable = atom()</v>
+ </type>
+ <desc>
+ <p>Increments the variable associated with a discarded pdu.
+ This function can be used when the net_if process receives a
+ <c>discarded_pdu</c> message from the agent.
+ </p>
+ </desc>
+ </func>
+ </funcs>
+
+</erlref>
+
diff --git a/lib/snmp/doc/src/snmpa_network_interface.xml b/lib/snmp/doc/src/snmpa_network_interface.xml
new file mode 100644
index 0000000000..a986343a4f
--- /dev/null
+++ b/lib/snmp/doc/src/snmpa_network_interface.xml
@@ -0,0 +1,170 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE erlref SYSTEM "erlref.dtd">
+
+<erlref>
+ <header>
+ <copyright>
+ <year>2004</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ 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.
+
+ </legalnotice>
+
+ <title>snmpa_network_interface</title>
+ <prepared></prepared>
+ <responsible></responsible>
+ <docno></docno>
+ <approved></approved>
+ <checked></checked>
+ <date></date>
+ <rev></rev>
+ <file>snmpa_network_interface.xml</file>
+ </header>
+ <module>snmpa_network_interface</module>
+ <modulesummary>Behaviour module for the SNMP agent network interface.</modulesummary>
+ <description>
+ <p>This module defines the behaviour of the agent network
+ interface. A <c>snmpa_network_interface</c> compliant module
+ must export the following functions: </p>
+ <list type="bulleted">
+ <item>
+ <p><seealso marker="#start_link">start_link/4</seealso></p>
+ </item>
+ <item>
+ <p><seealso marker="#info">info/1</seealso></p>
+ </item>
+ <item>
+ <p><seealso marker="#get_log_type">get_log_type/1</seealso></p>
+ </item>
+ <item>
+ <p><seealso marker="#set_log_type">set_log_type/2</seealso></p>
+ </item>
+ <item>
+ <p><seealso marker="#verbosity">verbosity/2</seealso></p>
+ </item>
+ </list>
+ <p>The semantics of them and their exact signatures are explained
+ below. </p>
+ <p>But this is not enough. There is also a set of <em>mandatory</em>
+ messages which the network interface entity must be able to
+ receive and be able to send. This is described in chapter
+ <seealso marker="snmp_agent_netif">snmp_agent_netif</seealso>.
+ </p>
+
+ <marker id="start_link"></marker>
+ </description>
+
+ <funcs>
+ <func>
+ <name>start_link(Prio, NoteStore, MasterAgent, Opts) -> {ok, Pid} | {error, Reason}</name>
+ <fsummary>Start-link the network interface process</fsummary>
+ <type>
+ <v>Prio = priority()</v>
+ <v>NoteStore = pid()</v>
+ <v>MasterAgent = pid()</v>
+ <v>Opts = [opt()]</v>
+ <v>opt() = {verbosity, verbosity()} | {versions, versions()} | term()</v>
+ <v>versions() = [version()]</v>
+ <v>version() = v1 | v2 | v3</v>
+ </type>
+ <desc>
+ <p>Start-link the network interface process.</p>
+ <p><c>NoteStore</c> is the pid of the note-store process and
+ <c>MasterAgent</c> is the pid of the master-agent process.</p>
+ <p><c>Opts</c> is an (basically) implementation dependent list of
+ options to the network interface process. There are however
+ a number of options which <em>must</em> be handled:
+ <c>versions</c> and <c>verbosity</c>.</p>
+
+ <marker id="info"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>info(Pid) -> [{Key, Value}]</name>
+ <fsummary>Return information about the running network interface process</fsummary>
+ <type>
+ <v>Pid = pid()</v>
+ </type>
+ <desc>
+ <p>The info returned is basically up to the implementer to decide.
+ This implementation provided by the application provides info about
+ memory allocation and various socket information.</p>
+ <p>The info returned by this function is returned together with other
+ info collected by the agent when the
+ <seealso marker="snmpa#info">info</seealso> function is called
+ (tagged with with the key <c>net_if</c>).</p>
+
+ <marker id="verbosity"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>verbosity(Pid, Verbosity) -> void()</name>
+ <fsummary>Change the verbosity of a running network interface process</fsummary>
+ <type>
+ <v>Pid = pid()</v>
+ <v>Verbosity = verbosity()</v>
+ </type>
+ <desc>
+ <p>Change the verbosity of a running network interface process.</p>
+
+ <marker id="get_log_type"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>get_log_type(Pid) -> {ok, LogType} | {error, Reason}</name>
+ <fsummary>Get the Audit Trail Log type</fsummary>
+ <type>
+ <v>Pid = pid()</v>
+ <v>LogType = atl_type()</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>The Audit Trail Log is managed by the network interface process.
+ So, it is this process that has to retrieve the actual log-type. </p>
+<!--
+ <p>See
+ <seealso marker="snmpa#get_log_type">get_log_type</seealso>
+ for more info. </p>
+-->
+
+ <marker id="set_log_type"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>set_log_type(Pid, NewType) -> {ok, OldType} | {error, Reason}</name>
+ <fsummary>Change the Audit Trail Log type</fsummary>
+ <type>
+ <v>Pid = pid()</v>
+ <v>NewType = OldType = atl_type()</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>The Audit Trail Log is managed by the network interface process.
+ So, it is this process that has to do the actual changing of the
+ type. </p>
+ <p>See
+ <seealso marker="snmpa#set_log_type">set_log_type</seealso>
+ for more info. </p>
+ </desc>
+ </func>
+
+ </funcs>
+
+
+</erlref>
+
diff --git a/lib/snmp/doc/src/snmpa_network_interface_filter.xml b/lib/snmp/doc/src/snmpa_network_interface_filter.xml
new file mode 100644
index 0000000000..d625fd3e4a
--- /dev/null
+++ b/lib/snmp/doc/src/snmpa_network_interface_filter.xml
@@ -0,0 +1,163 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE erlref SYSTEM "erlref.dtd">
+
+<erlref>
+ <header>
+ <copyright>
+ <year>2007</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ 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.
+
+ </legalnotice>
+
+ <title>snmpa_network_interface_filter</title>
+ <prepared></prepared>
+ <responsible></responsible>
+ <docno></docno>
+ <approved></approved>
+ <checked></checked>
+ <date></date>
+ <rev></rev>
+ <file>snmpa_network_interface_filter.xml</file>
+ </header>
+ <module>snmpa_network_interface_filter</module>
+ <modulesummary>Behaviour module for the SNMP agent network-interface filter.</modulesummary>
+ <description>
+ <p>This module defines the behaviour of the agent network interface
+ filter. A <c>snmpa_network_interface_filter</c> compliant module
+ must export the following functions: </p>
+ <list type="bulleted">
+ <item>
+ <p><seealso marker="#accept_recv">accept_recv/2</seealso></p>
+ </item>
+ <item>
+ <p><seealso marker="#accept_send">accept_send/2</seealso></p>
+ </item>
+ <item>
+ <p><seealso marker="#accept_recv_pdu">accept_recv_pdu/3</seealso></p>
+ </item>
+ <item>
+ <p><seealso marker="#accept_send_pdu">accept_send_pdu/2</seealso></p>
+ </item>
+ </list>
+ <p>The semantics of them and their exact signatures are explained
+ below. </p>
+ <p>The purpose of the network interface filter is to allow for filtering
+ of messages (accept or reject) receive and send. This is done
+ on two levels: </p>
+ <list type="bulleted">
+ <item>
+ <p>The first level is at the UDP entry / exit point, i.e.
+ immediately after the receipt of the message, before any message
+ processing is done (accept_recv) and
+ immediately before sending the message, after all message
+ processing is done (accept_send).</p>
+ </item>
+ <item>
+ <p>The second level is at the MPD entry / exit point, i.e.
+ immediately after the basic message processing (accept_recv_pdu) /
+ immediately before the basic message processing (accept_send_pdu).</p>
+ </item>
+ </list>
+ <p>Note that the network interface filter is something which is used
+ by the network interface implementation provided by the application
+ (<c>snmpa_net_if</c>). The default filter accepts all messages.</p>
+ <p>A network interface filter can e.g. be used during testing or for load
+ regulation. If the intended use is load regulation, see also
+ <seealso marker="snmp_app#configuration_params">req_limit</seealso> and
+ the function
+ <seealso marker="snmpa#register_notification_filter">register_notification_filter</seealso>. </p>
+ </description>
+
+ <section>
+ <title>DATA TYPES</title>
+ <code type="none">
+port() = integer() > 0
+pdu_type() = 'get-request' | 'get-next-request' | 'get-response' | 'set-request' | trap | 'get-bulk-request' | 'inform-request' | report
+ </code>
+ <marker id="accept_recv"></marker>
+ </section>
+ <funcs>
+ <func>
+ <name>accept_recv(Ip, Port) -> boolean()</name>
+ <fsummary>Shall the received message be accepted</fsummary>
+ <type>
+ <v>Ip = ip_address()</v>
+ <v>Port = port()</v>
+ </type>
+ <desc>
+ <p>Called at the reception of a message (before <em>any</em> processing
+ has been done).</p>
+ <p>For the message to be discarded, the function <em>must</em> return
+ <em>false</em>. </p>
+ <marker id="accept_send"></marker>
+ </desc>
+ </func>
+ <func>
+ <name>accept_send(Ip, Port) -> boolean()</name>
+ <fsummary>Shall the message be sent</fsummary>
+ <type>
+ <v>Ip = ip_address()</v>
+ <v>Port = port()</v>
+ </type>
+ <desc>
+ <p>Called before the sending of a message (after <em>all</em> processing
+ has been done).</p>
+ <p>For the message to be discarded, the function <em>must</em> return
+ <em>false</em>. </p>
+ <marker id="accept_recv_pdu"></marker>
+ </desc>
+ </func>
+ <func>
+ <name>accept_recv_pdu(Ip, Port, PduType) -> boolean()</name>
+ <fsummary>Shall the received pdu be accepted</fsummary>
+ <type>
+ <v>Ip = ip_address()</v>
+ <v>Port = port()</v>
+ <v>PduType = pdu_type()</v>
+ </type>
+ <desc>
+ <p>Called after the basic message processing (MPD) has been done,
+ but before the pdu is handed over to the master-agent for
+ primary processing.</p>
+ <p>For the pdu to be discarded, the function <em>must</em> return
+ <em>false</em>. </p>
+ <marker id="accept_send_pdu"></marker>
+ </desc>
+ </func>
+ <func>
+ <name>accept_send_pdu(Targets, PduType) -> Reply</name>
+ <fsummary>Shall the pdu be sent</fsummary>
+ <type>
+ <v>Targets = targets()</v>
+ <v>targets() = [target()]</v>
+ <v>target() = {ip_address(), port()}</v>
+ <v>PduType = pdu_type() > 0</v>
+ <v>Reply = boolean() | NewTargets</v>
+ <v>NewTargets = targets()</v>
+ </type>
+ <desc>
+ <p>Called before the basic message processing (MPD) is done,
+ when a pdu has been received from the master-agent.</p>
+ <p>For the message to be discarded all together, the function
+ <em>must</em> return <em>false</em>. </p>
+ <p>Note that it is possible for this function to filter out targets
+ (but <em>not</em> add it's own) by returning an updated
+ <c>Targets</c> list (<c>NewTargets</c>). </p>
+ </desc>
+ </func>
+ </funcs>
+
+</erlref>
+
diff --git a/lib/snmp/doc/src/snmpa_notification_delivery_info_receiver.xml b/lib/snmp/doc/src/snmpa_notification_delivery_info_receiver.xml
new file mode 100644
index 0000000000..c52479f76a
--- /dev/null
+++ b/lib/snmp/doc/src/snmpa_notification_delivery_info_receiver.xml
@@ -0,0 +1,120 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE erlref SYSTEM "erlref.dtd">
+
+<erlref>
+ <header>
+ <copyright>
+ <year>2008</year>
+ <year>2009</year>
+ <holder>Ericsson AB, All Rights Reserved</holder>
+ </copyright>
+ <legalnotice>
+ 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.
+
+ The Initial Developer of the Original Code is Ericsson AB.
+ </legalnotice>
+
+ <title>snmpa_notification_delivery_info_receiver</title>
+ <prepared></prepared>
+ <responsible></responsible>
+ <docno></docno>
+ <approved></approved>
+ <checked></checked>
+ <date></date>
+ <rev></rev>
+ <file>snmpa_notification_delivery_info_receiver.xml</file>
+ </header>
+ <module>snmpa_notification_delivery_info_receiver</module>
+ <modulesummary>
+ Behaviour module for the SNMP agent notification delivery
+ information receiver.
+ </modulesummary>
+ <description>
+ <p>This module defines the behaviour of the notification
+ delivery information receiver. </p>
+ <p>A <c>snmpa_notification_delivery_info_receiver</c> compliant module
+ must export the following functions: </p>
+ <list type="bulleted">
+ <item>
+ <p><seealso marker="#delivery_targets">delivery_targets/3</seealso></p>
+ </item>
+ <item>
+ <p><seealso marker="#delivery_info">delivery_info/4</seealso></p>
+ </item>
+ </list>
+ <p>The semantics of them and their exact signatures are explained
+ below. </p>
+
+ </description>
+
+ <section>
+ <title>DATA TYPES</title>
+ <code type="none"><![CDATA[
+address() = A 4-tuple
+ ]]></code>
+
+ <marker id="delivery_targets"></marker>
+ </section>
+
+ <funcs>
+ <func>
+ <name>delivery_targets(Tag, Targets, Extra) -> void()</name>
+ <fsummary>Inform about target addresses</fsummary>
+ <type>
+ <v>Tag = term()</v>
+ <v>Targets = [target()]</v>
+ <v>target() = {Address, Port}</v>
+ <v>Address = address()</v>
+ <v>Port = integer()</v>
+ <v>Extra = term()</v>
+ </type>
+ <desc>
+ <p>Inform about target addresses. </p>
+ <p>This is the first function called when a notification delivery is
+ in progress. It informs the <c>receiver</c> which targets will
+ get the notification. The result of the delivery will be
+ provided via successive calls to <c>delivery_info/4</c> function,
+ see below.</p>
+
+ <marker id="delivery_info"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>delivery_info(Tag, Target, DeliveryResult, Extra) -> void()</name>
+ <fsummary>Inform about delivery result</fsummary>
+ <type>
+ <v>Tag = term()</v>
+ <v>Target = target()</v>
+ <v>target() = {Address, Port}</v>
+ <v>Address = address()</v>
+ <v>Port = integer()</v>
+ <v>DeliveryResult = delivery_result()</v>
+ <v>delivery_result() = no_response | got_response</v>
+ <v>Extra = term()</v>
+ </type>
+ <desc>
+ <p>Inform about delivery result.</p>
+ <p>This function is called for each target in the <c>Targets</c>
+ argument of the <c>delivery_targets/3</c> function, see above. </p>
+ <p>The purpose is to inform the <c>receiver</c> of the
+ result of the delivery (was the notification acknowledged or
+ not) for each target.</p>
+
+ </desc>
+ </func>
+
+ </funcs>
+
+
+</erlref>
+
diff --git a/lib/snmp/doc/src/snmpa_notification_filter.xml b/lib/snmp/doc/src/snmpa_notification_filter.xml
new file mode 100644
index 0000000000..c3b300ecab
--- /dev/null
+++ b/lib/snmp/doc/src/snmpa_notification_filter.xml
@@ -0,0 +1,73 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE erlref SYSTEM "erlref.dtd">
+
+<erlref>
+ <header>
+ <copyright>
+ <year>2004</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ 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.
+
+ </legalnotice>
+
+ <title>snmpa_notification_filter</title>
+ <prepared></prepared>
+ <responsible></responsible>
+ <docno></docno>
+ <approved></approved>
+ <checked></checked>
+ <date></date>
+ <rev></rev>
+ <file>snmpa_notification_filter.xml</file>
+ </header>
+ <module>snmpa_notification_filter</module>
+ <modulesummary>Behaviour module for the SNMP agent notification filters.</modulesummary>
+ <description>
+ <p>This module defines the behaviour of the agent notification
+ filters. A <c>snmpa_notification_filter</c> compliant module
+ must export the following functions: </p>
+ <list type="bulleted">
+ <item>
+ <p>handle_notification/2</p>
+ </item>
+ </list>
+ <p>The semantics of them and their exact signatures are explained
+ below. </p>
+ <p>The purpose of notification filters is to allow for modification
+ and/or suppression of a notification.</p>
+ <p>A misbehaving filter will be removed.</p>
+ </description>
+ <funcs>
+ <func>
+ <name>handle_notification(Notif, Data) -> Reply</name>
+ <fsummary>Handle a notification</fsummary>
+ <type>
+ <v>Reply = send | {send, NewNotif} | dont_send</v>
+ <v>Notif = NewNotif = notification() | trap()</v>
+ <v>Data = term()</v>
+ </type>
+ <desc>
+ <p>Handle a notification to be sent. The filter can either
+ accept the notification as is, return <c>send</c>, modify
+ the notification, return <c>{send, NewNotif}</c> or
+ suppress the notification, return <c>dont_send</c>.</p>
+ <p><c>Data</c> is supplied at filter registration time,
+ see <seealso marker="snmpa#register_notification_filter">register_notification_filter</seealso>.
+ </p>
+ </desc>
+ </func>
+ </funcs>
+
+</erlref>
+
diff --git a/lib/snmp/doc/src/snmpa_supervisor.xml b/lib/snmp/doc/src/snmpa_supervisor.xml
new file mode 100644
index 0000000000..89b4eb8d54
--- /dev/null
+++ b/lib/snmp/doc/src/snmpa_supervisor.xml
@@ -0,0 +1,117 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE erlref SYSTEM "erlref.dtd">
+
+<erlref>
+ <header>
+ <copyright>
+ <year>2004</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ 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.
+
+ </legalnotice>
+
+ <title>snmpa_supervisor</title>
+ <prepared></prepared>
+ <responsible></responsible>
+ <docno></docno>
+ <approved></approved>
+ <checked></checked>
+ <date></date>
+ <rev></rev>
+ <file>snmpa_supervisor.xml</file>
+ </header>
+ <module>snmpa_supervisor</module>
+ <modulesummary>A supervisor for the SNMP agent Processes</modulesummary>
+ <description>
+ <p>This is the top supervisor for the agent part of the SNMP
+ application. There is always one supervisor at each node with
+ an SNMP agent (master agent or sub-agent).
+ </p>
+ </description>
+ <funcs>
+ <func>
+ <name>start_sub_sup(Opts) -> {ok, pid()} | {error, {already_started, pid()}} | {error, Reason}</name>
+ <fsummary>Start the SNMP supervisor for sub-agents only</fsummary>
+ <type>
+ <v>Opts = [opt()]</v>
+ <v>opt() = {db_dir, string()} | ...</v>
+ </type>
+ <desc>
+ <p>Starts a supervisor for the SNMP agent system without a
+ master agent. The supervisor starts all involved SNMP
+ processes, but no agent processes. Sub-agents should be
+ started by calling <c>start_sub_agent/3</c>.
+ </p>
+ <p><c>db_dir</c> is mandatory.</p>
+ <p>See <seealso marker="snmp_config#configuration_params">configuration parameters</seealso> for
+ a description of the options.</p>
+ </desc>
+ </func>
+ <func>
+ <name>start_master_sup(Opts) -> {ok, pid()} | {error, {already_started, pid()}} | {error, Reason}</name>
+ <fsummary>Start the SNMP supervisor for all agents</fsummary>
+ <type>
+ <v>Opts = [opt()]</v>
+ <v>opt() = {db_dir, string()} | {config, ConfOpts()} | ...</v>
+ <v>ConfOpts = [conf_opts()]</v>
+ <v>conf_opts() = {dir, string()} | ...</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Starts a supervisor for the SNMP agent system. The
+ supervisor starts all involved SNMP processes, including the
+ master agent. Sub-agents should be started by calling
+ <c>start_subagent/3</c>.
+ </p>
+ <p><c>db_dir</c> is mandatory.</p>
+ <p><c>dir</c> in config is mandatory.</p>
+ <p>See <seealso marker="snmp_config">snmp config</seealso> for
+ a description of the options.</p>
+ </desc>
+ </func>
+ <func>
+ <name>start_sub_agent(ParentAgent,Subtree,Mibs) -> {ok, pid()} | {error, Reason}</name>
+ <fsummary>Start a sub-agent</fsummary>
+ <type>
+ <v>ParentAgent = pid()</v>
+ <v>SubTree = oid()</v>
+ <v>Mibs = [MibName]</v>
+ <v>MibName = [string()]</v>
+ </type>
+ <desc>
+ <p>Starts a sub-agent on the node where the function is
+ called. The <c>snmpa_supervisor</c> must be running.
+ </p>
+ <p>If the supervisor is not running, the function fails with the
+ reason <c>badarg</c>.</p>
+ </desc>
+ </func>
+ <func>
+ <name>stop_sub_agent(SubAgent) -> ok | no_such_child</name>
+ <fsummary>Stop a sub-agent</fsummary>
+ <type>
+ <v>SubAgent = pid()</v>
+ </type>
+ <desc>
+ <p>Stops the sub-agent on the node where the function is
+ called. The <c>snmpa_supervisor</c> must be running.
+ </p>
+ <p>If the supervisor is not running, the function fails with the
+ reason <c>badarg</c>.</p>
+ </desc>
+ </func>
+ </funcs>
+
+</erlref>
+
diff --git a/lib/snmp/doc/src/snmpc.xml b/lib/snmp/doc/src/snmpc.xml
new file mode 100644
index 0000000000..48d63d6c91
--- /dev/null
+++ b/lib/snmp/doc/src/snmpc.xml
@@ -0,0 +1,201 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE erlref SYSTEM "erlref.dtd">
+
+<erlref>
+ <header>
+ <copyright>
+ <year>2004</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ 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.
+
+ </legalnotice>
+
+ <title>snmpc</title>
+ <prepared></prepared>
+ <responsible></responsible>
+ <docno></docno>
+ <approved></approved>
+ <checked></checked>
+ <date></date>
+ <rev></rev>
+ <file>snmpc.xml</file>
+ </header>
+ <module>snmpc</module>
+ <modulesummary>Interface Functions to the SNMP toolkit MIB compiler</modulesummary>
+ <description>
+ <p>The module <c>snmpc</c> contains interface functions to the
+ SNMP toolkit MIB compiler.</p>
+
+ </description>
+
+ <funcs>
+ <func>
+ <name>compile(File)</name>
+ <name>compile(File, Options) -> {ok, BinFileName} | {error, Reason}</name>
+ <fsummary>Compile the specified MIB</fsummary>
+ <type>
+ <v>File = string()</v>
+ <v>Options = [opt()]</v>
+ <v>opt() = db() | deprecated() | description() | reference() | group_check() | i() | il() | imports() | module() | module_identity() | outdir() | no_defs() | verbosity() | warnings()</v>
+ <v>db() = {db, volatile|persistent|mnesia}</v>
+ <v>deprecated() = {deprecated, bool()}</v>
+ <v>description() = description</v>
+ <v>reference() = reference</v>
+ <v>group_check() = {group_check, bool()}</v>
+ <v>i() = {i, [dir()]}</v>
+ <v>il() = {il, [dir()]}</v>
+ <v>imports() = imports</v>
+ <v>module() = {module, atom()}</v>
+ <v>module_identity() = module_identity</v>
+ <v>no_defs() = no_defs</v>
+ <v>outdir() = {outdir, dir()}</v>
+ <v>verbosity() = {verbosity, silence|warning|info|log|debug|trace}</v>
+ <v>warnings() = {warnings, bool()}</v>
+ <v>dir() = string()</v>
+ <v>BinFileName = string()</v>
+ </type>
+ <desc>
+ <marker id="compiler_opts"></marker>
+ <p>Compiles the specified MIB file <c><![CDATA[<File>.mib]]></c>. The
+ compiled file <c>BinFileName</c> is called
+ <c><![CDATA[<File>.bin]]></c>. </p>
+ <list type="bulleted">
+ <item>The option <c>db</c> specifies which database should
+ be used for the default instrumentation. Default is
+ <c>volatile</c>.
+ </item>
+ <item>The option <c>deprecated</c> specifies if a deprecated
+ definition should be kept or not. If the option is
+ false the MIB compiler will ignore all deprecated
+ definitions. Default is <c>true</c>.
+ </item>
+ <item>The option <c>description</c> specifies if the text
+ of the DESCRIPTION field will be included or not. By default
+ it is not included, but if this option is present it will
+ be.
+ </item>
+ <item>The option <c>reference</c> specifies if the text
+ of the REFERENCE field, when found in a table definition,
+ will be included or not. By default
+ it is not included, but if this option is present it will
+ be. The reference text will be placed in the allocList field
+ of the mib-entry record (#me{}) for the table.
+ </item>
+ <item>The option <c>group_check</c> specifies whether the
+ mib compiler should check the OBJECT-GROUP macro and
+ the NOTIFICATION-GROUP macro for correctness or not.
+ Default is <c>true</c>.
+ </item>
+ <item>The option <c>i</c> specifies the path to search for
+ imported (compiled) MIB files. The directories should be
+ strings with a trailing directory delimiter. Default is
+ <c>["./"]</c>.
+ </item>
+ <item>The option <c>il</c> (include_lib) also specifies a
+ list of directories to search for imported MIBs. It
+ assumes that the first element in the directory name
+ corresponds to an OTP application. The compiler will find
+ the current installed version. For example, the value
+ ["snmp/mibs/"] will be replaced by ["snmp-3.1.1/mibs/"]
+ (or what the current version may be in the system). The
+ current directory and the <c><![CDATA[<snmp-home>/priv/mibs/]]></c>
+ are always listed last in the include path.
+ </item>
+ <item>The option <c>imports</c>, if present, specifies that the
+ IMPORT statement of the MIB shall be included in the compiled mib.
+ </item>
+ <item>The option <c>module</c>, if present, specifies the
+ name of a module which implements all instrumentation
+ functions for the MIB. The name of all instrumentation
+ functions must be the same as the corresponding managed
+ object it implements.
+ </item>
+ <item>The option <c>module_identity</c>, if present, specifies
+ that the info part of the MODULE-IDENTITY statement of the MIB
+ shall be included in the compiled mib.
+ </item>
+ <item>The option <c>no_defs</c>, if present, specifies
+ that if a managed object does not have an instrumentation
+ function, the default instrumentation function should NOT
+ be used, instead this is reported as an error, and the
+ compilation aborts.
+ </item>
+ <item>The option <c>verbosity</c> specifies the verbosity of
+ the SNMP mib compiler. I.e. if warning, info, log, debug
+ and trace messages shall be shown. Default is <c>silence</c>.
+ Note that if the option <c>warnings</c> is <c>true</c> and the
+ option <c>verbosity</c> is <c>silence</c>, warning messages will
+ still be shown.
+ </item>
+ <item>The option <c>warnings</c> specifies whether warning
+ messages should be shown. Default is <c>true</c>.
+ </item>
+ </list>
+ <p>The MIB compiler understands both SMIv1 and SMIv2 MIBs. It
+ uses the <c>MODULE-IDENTITY</c> statement to determine if the MIB is
+ version 1 or 2.
+ </p>
+ <p>The MIB compiler can be invoked from the OS command line by
+ using the command <c>erlc</c>. <c>erlc</c> recognizes the
+ extension <c>.mib</c>, and invokes the SNMP MIB compiler for
+ files with that extension. The options <c>db</c>,
+ <c>group_check</c>, <c>deprecated</c>, <c>description</c>,
+ <c>verbosity</c>, <c>imports</c> and <c>module_identity</c>
+ have to be specified to <c>erlc</c> using the syntax
+ <c>+term</c>. See <c>erlc(1)</c> for details.
+ </p>
+ </desc>
+ </func>
+ <func>
+ <name>is_consistent(Mibs) -> ok | {error, Reason}</name>
+ <fsummary>Check for OID conflicts between MIBs</fsummary>
+ <type>
+ <v>Mibs = [MibName]</v>
+ <v>MibName = string()</v>
+ </type>
+ <desc>
+ <p>Checks for multiple usage of object identifiers and traps
+ between MIBs.
+ </p>
+ </desc>
+ </func>
+ <func>
+ <name>mib_to_hrl(MibName) -> ok | {error, Reason}</name>
+ <fsummary>Generate constants for the objects in the MIB</fsummary>
+ <type>
+ <v>MibName = string()</v>
+ </type>
+ <desc>
+ <p>Generates a <c>.hrl</c> file with definitions of Erlang
+ constants for the objects in the MIB. The <c>.hrl</c> file is
+ called <c><![CDATA[<MibName>.hrl]]></c>. The MIB must be compiled, and
+ present in the current directory.
+ </p>
+ <p>The <c>mib_to_hrl</c> generator can be invoked from the OS
+ command line by using the command <c>erlc</c>. <c>erlc</c>
+ recognizes the extension <c>.bin</c>, and invokes this function
+ for files with that extension.
+ </p>
+ </desc>
+ </func>
+ </funcs>
+
+ <section>
+ <title>See Also</title>
+ <p>erlc(1)
+ </p>
+ </section>
+
+</erlref>
+
diff --git a/lib/snmp/doc/src/snmpm.xml b/lib/snmp/doc/src/snmpm.xml
new file mode 100644
index 0000000000..9e7ac75daf
--- /dev/null
+++ b/lib/snmp/doc/src/snmpm.xml
@@ -0,0 +1,1043 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE erlref SYSTEM "erlref.dtd">
+
+<erlref>
+ <header>
+ <copyright>
+ <year>2004</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ 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.
+
+ </legalnotice>
+
+ <title>snmpm</title>
+ <prepared></prepared>
+ <responsible></responsible>
+ <docno></docno>
+ <approved></approved>
+ <checked></checked>
+ <date></date>
+ <rev></rev>
+ <file>snmpm.xml</file>
+ </header>
+ <module>snmpm</module>
+ <modulesummary>Interface functions to the SNMP toolkit manager</modulesummary>
+ <description>
+ <p>The module <c>snmpm</c> contains interface functions to the
+ SNMP manager. </p>
+ </description>
+
+ <section>
+ <title>Common Data Types</title>
+ <p>The following data types are used in the functions below:</p>
+<code type="none"><![CDATA[
+oid() = [byte()] - The oid() type is used to represent an ASN.1 OBJECT IDENTIFIER
+snmp_reply() = {error_status(), error_index(), varbinds()}
+error_status() = noError | atom()
+error_index() = integer()
+varbinds() = [varbind()]
+atl_type() = read | write | read_write
+target_name() = string() - Is a unique *non-empty* string
+vars_and_vals() = [var_and_val()]
+var_and_val() = {oid(), value_type(), value()} | {oid(), value()}
+value_type() = o ('OBJECT IDENTIFIER') |
+ i ('INTEGER') |
+ u ('Unsigned32') |
+ g ('Unsigned32') |
+ s ('OCTET SRING') |
+ b ('BITS') |
+ ip ('IpAddress') |
+ op ('Opaque') |
+ c32 ('Counter32') |
+ c64 ('Counter64') |
+ tt ('TimeTicks')
+value() = term()
+]]></code>
+
+ <marker id="monitor"></marker>
+ </section>
+ <funcs>
+ <func>
+ <name>monitor() -> Ref</name>
+ <fsummary>Monitor the snmp manager</fsummary>
+ <type>
+ <v>Ref = reference()</v>
+ </type>
+ <desc>
+ <p>Monitor the SNMP manager. In case of a crash, the calling
+ (monitoring) process will get a 'DOWN' message (see the erlang
+ module for more info). </p>
+
+ <marker id="demonitor"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>demonitor(Ref) -> void()</name>
+ <fsummary>Turn off monitoring of the snmp manager</fsummary>
+ <type>
+ <v>Ref = reference()</v>
+ </type>
+ <desc>
+ <p>Turn off monitoring of the SNMP manager. </p>
+
+ <marker id="notify_started"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>notify_started(Timeout) -> Pid</name>
+ <fsummary>Request to be notified when manager started</fsummary>
+ <type>
+ <v>Timeout = integer()</v>
+ <v>Pid = pid()</v>
+ </type>
+ <desc>
+ <p>Request a notification (message) when the SNMP manager has
+ started. </p>
+ <p>The <c>Timeout</c> is the time the request is valid. The
+ value has to be greater then zero. </p>
+ <p>The <c>Pid</c> is the process handling the supervision of the
+ SNMP manager start. When the manager has started a completion
+ message will be sent to the client from this process:
+ <c>{snmpm_started, Pid}</c>. If the SNMP manager was not started
+ in time, a timeout message will be sent to the client:
+ <c>{snmpm_start_timeout, Pid}</c>. </p>
+ <p>A client application that is dependent on the SNMP manager
+ will use this function in order to be notified of when the
+ manager has started. There are two situations when this
+ is useful:</p>
+ <list type="bulleted">
+ <item>
+ <p>During the start of a system, when a client application
+ <em>could</em> start prior to the SNMP manager but is dependent
+ upon it, and therefor has to wait for it to start.</p>
+ </item>
+ <item>
+ <p>When the SNMP manager has crashed, the dependent client
+ application has to wait for the SNMP manager to be restarted
+ before it can <em>reconnect</em>.</p>
+ </item>
+ </list>
+ <p>The function returns the pid() of a handler process, that does
+ the supervision on behalf of the client application. Note that the
+ client application is linked to this handler. </p>
+ <p>This function is used in conjunction with the monitor function.</p>
+
+ <marker id="cancel_notify_started"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>cancel_notify_started(Pid) -> void()</name>
+ <fsummary>Cancel request to be notified when manager started</fsummary>
+ <type>
+ <v>Pid = pid()</v>
+ </type>
+ <desc>
+ <p>Cancel a previous request to be notified of SNMP manager start.</p>
+
+ <marker id="register_user"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>register_user(Id, Module, Data) -> ok | {error, Reason}</name>
+ <name>register_user(Id, Module, Data, DefaultAgentConfig) -> ok | {error, Reason}</name>
+ <fsummary>Register a user of the manager</fsummary>
+ <type>
+ <v>Id = term()</v>
+ <v>Module = snmpm_user()</v>
+ <v>Data = term()</v>
+ <v>DefaultAgentConfig = [default_agent_config()]</v>
+ <v>default_agent_config() = {Item, Val}</v>
+ <v>Item = community | timeout | max_message_size | version | sec_model | sec_name | sec_level</v>
+ <v>Val = term()</v>
+ <v>Reason = term()</v>
+ <v>snmpm_user() = Module implementing the snmpm_user behaviour</v>
+ </type>
+ <desc>
+ <p>Register the manager entity (=user) responsible for specific
+ agent(s). </p>
+
+ <p><c>Module</c> is the callback module (snmpm_user behaviour) which
+ will be called whenever something happens (detected
+ agent, incoming reply or incoming trap/notification).
+ Note that this could have already been done as a
+ consequence of the node config. (see users.conf).</p>
+
+ <p>The argument <c>DefaultAgentConfig</c> is used as default values when
+ this user register agents.</p>
+
+ <p>The type of <c>Val</c> depends on <c>Item</c>: </p>
+<code type="none"><![CDATA[
+community = string()
+timeout = integer() | snmp_timer()
+max_message_size = integer()
+version = v1 | v2 | v3
+sec_model = any | v1 | v2c | usm
+sec_name = string()
+sec_level = noAuthNoPriv | authNoPriv | authPriv
+ ]]></code>
+
+ <marker id="register_user_monitor"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>register_user_monitor(Id, Module, Data) -> ok | {error, Reason}</name>
+ <name>register_user_monitor(Id, Module, Data, DefaultAgentConfig) -> ok | {error, Reason}</name>
+ <fsummary>Register a monitored user of the manager</fsummary>
+ <type>
+ <v>Id = term()</v>
+ <v>Module = snmpm_user()</v>
+ <v>DefaultAgentConfig = [default_agent_config()]</v>
+ <v>default_agent_config() = {Item, Val}</v>
+ <v>Item = community | timeout | max_message_size | version | sec_model | sec_name | sec_level</v>
+ <v>Val = term()</v>
+ <v>Data = term()</v>
+ <v>Reason = term()</v>
+ <v>snmpm_user() = Module implementing the snmpm_user behaviour</v>
+ </type>
+ <desc>
+ <p>Register the monitored manager entity (=user) responsible
+ for specific agent(s). </p>
+
+ <p>The process performing the registration will be monitored.
+ Which means that if that process should die, all agents
+ registered by that user process will be unregistered. All
+ outstanding requests will be canceled. </p>
+
+ <p><c>Module</c> is the callback module (snmpm_user behaviour) which
+ will be called whenever something happens (detected
+ agent, incoming reply or incoming trap/notification).
+ Note that this could have already been done as a
+ consequence of the node config. (see users.conf).</p>
+
+ <p>The argument <c>DefaultAgentConfig</c> is used as default values when
+ this user register agents.</p>
+
+ <p>The type of <c>Val</c> depends on <c>Item</c>: </p>
+<code type="none"><![CDATA[
+community = string()
+timeout = integer() | snmp_timer()
+max_message_size = integer()
+version = v1 | v2 | v3
+sec_model = any | v1 | v2c | usm
+sec_name = string()
+sec_level = noAuthNoPriv | authNoPriv | authPriv
+ ]]></code>
+
+ <marker id="unregister_user"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>unregister_user(Id) -> ok | {error, Reason}</name>
+ <fsummary>Unregister the user</fsummary>
+ <type>
+ <v>Id = term()</v>
+ </type>
+ <desc>
+ <p>Unregister the user.</p>
+
+ <marker id="which_users"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>which_users() -> Users</name>
+ <fsummary>Get a list of all users</fsummary>
+ <type>
+ <v>Users = [UserId]</v>
+ <v>UserId = term()</v>
+ </type>
+ <desc>
+ <p>Get a list of the identities of all registered users.</p>
+
+ <marker id="register_agent"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>register_agent(UserId, TargetName, Config) -> ok | {error, Reason}</name>
+ <fsummary>Register this agent</fsummary>
+ <type>
+ <v>UserId = term()</v>
+ <v>Addr = ip_address()</v>
+ <v>TargetName = target_name()</v>
+ <v>Config = [agent_config()]</v>
+ <v>agent_config() = {Item, Val}</v>
+ <v>Item = engine_id | address | port | community | timeout | max_message_size | version | sec_model | sec_name | sec_level</v>
+ <v>Val = term()</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Explicitly instruct the manager to handle this agent, with
+ <c>UserId</c> as the responsible user. </p>
+ <p>Called to instruct the manager that this agent
+ shall be handled. This function is used when
+ the user knows in advance which agents the
+ manager shall handle.
+ Note that there is an alternate way to do the same thing:
+ Add the agent to the manager config files (see
+ <seealso marker="snmp_manager_config_files#agents">agents.conf</seealso>).</p>
+ <p><c>TargetName</c> is a non-empty string,
+ uniquely identifying the agent. </p>
+ <p>The type of <c>Val</c> depends on <c>Item</c>: </p>
+<code type="none"><![CDATA[
+[mandatory] engine_id = string()
+[mandatory] address = ip_address()
+[optional] port = integer()
+[optional] community = string()
+[optional] timeout = integer() | snmp_timer()
+[optional] max_message_size = integer()
+[optional] version = v1 | v2 | v3
+[optional] sec_model = any | v1 | v2c | usm
+[optional] sec_name = string()
+[optional] sec_level = noAuthNoPriv | authNoPriv | authPriv
+]]></code>
+ <p>Note that if no <c>Port</c> is given, the default value is used.</p>
+
+ <marker id="unregister_agent"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>unregister_agent(UserId, TargetName) -> ok | {error, Reason}</name>
+ <fsummary>Unregister the user</fsummary>
+ <type>
+ <v>UserId = term()</v>
+ <v>TargetName = target_name()</v>
+ </type>
+ <desc>
+ <p>Unregister the agent.</p>
+
+ <marker id="agent_info"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>agent_info(TargetName, Item) -> {ok, Val} | {error, Reason}</name>
+ <fsummary>Retrieve agent config</fsummary>
+ <type>
+ <v>TargetName = target_name()</v>
+ <v>Item = atom()</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Retrieve agent config.</p>
+
+ <marker id="update_agent_info"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>update_agent_info(UserId, TargetName, Item, Val) -> ok | {error, Reason}</name>
+ <fsummary>Update agent config</fsummary>
+ <type>
+ <v>UserId = term()</v>
+ <v>TargetName = target_name()</v>
+ <v>Item = atom()</v>
+ <v>Val = term()</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Update agent config.</p>
+
+ <marker id="which_agents"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>which_agents() -> Agents</name>
+ <name>which_agents(UserId) -> Agents</name>
+ <fsummary>List the registered agents</fsummary>
+ <type>
+ <v>UserId = term()</v>
+ <v>Agents = [TargetName]</v>
+ <v>TargetName = target_name()</v>
+ </type>
+ <desc>
+ <p>Get a list of all registered agents or all agents registered
+ by a specific user.</p>
+
+ <marker id="register_usm_user"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>register_usm_user(EngineID, UserName, Conf) -> ok | {error, Reason}</name>
+ <fsummary>Register this USM user</fsummary>
+ <type>
+ <v>EngineID = string()</v>
+ <v>UserName = string()</v>
+ <v>Conf = [usm_config()]</v>
+ <v>usm_config() = {Item, Val}</v>
+ <v>Item = sec_name | auth | auth_key | priv | priv_key</v>
+ <v>Val = term()</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Explicitly instruct the manager to handle this USM user.
+ Note that there is an alternate way to do the same thing:
+ Add the usm user to the manager config files (see
+ <seealso marker="snmp_manager_config_files#usm_user">usm.conf</seealso>).</p>
+ <p>The type of <c>Val</c> depends on <c>Item</c>: </p>
+<code type="none"><![CDATA[
+sec_name = string()
+auth = usmNoAuthProtocol | usmHMACMD5AuthProtocol | usmHMACSHAAuthProtocoltimeout
+auth_key = [integer()] (length 16 if auth = usmHMACMD5AuthProtocol,
+ length 20 if auth = usmHMACSHAAuthProtocol)
+priv = usmNoPrivProtocol | usmDESPrivProtocol | usmAesCfb128Protocol
+priv_key = [integer()] (length is 16 if priv = usmDESPrivProtocol | usmAesCfb128Protocol).
+]]></code>
+
+ <marker id="unregister_usm_user"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>unregister_usm_user(EngineID, UserName) -> ok | {error, Reason}</name>
+ <fsummary>Unregister this USM user</fsummary>
+ <type>
+ <v>EngineID = string()</v>
+ <v>UserName = string()</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Unregister this USM user.</p>
+
+ <marker id="which_usm_users1"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>usm_user_info(EngineID, UserName, Item) -> {ok, Val} | {error, Reason}</name>
+ <fsummary>Retrieve usm user config</fsummary>
+ <type>
+ <v>EngineID = string()</v>
+ <v>UsmName = string()</v>
+ <v>Item = sec_name | auth | auth_key | priv | priv_key</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Retrieve usm user config.</p>
+
+ <marker id="update_usm_user_info"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>update_usm_user_info(EngineID, UserName, Item, Val) -> ok | {error, Reason}</name>
+ <fsummary>Update agent config</fsummary>
+ <type>
+ <v>EngineID = string()</v>
+ <v>UsmName = string()</v>
+ <v>Item = sec_name | auth | auth_key | priv | priv_key</v>
+ <v>Val = term()</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Update usm user config.</p>
+
+ <marker id="which_usm_users"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>which_usm_users() -> UsmUsers</name>
+ <fsummary>List all the registered usm users</fsummary>
+ <type>
+ <v>UsmUsers = [{EngineID,UserName}]</v>
+ <v>EngineID = string()</v>
+ <v>UsmName = string()</v>
+ </type>
+ <desc>
+ <p>Get a list of all registered usm users.</p>
+
+ <marker id="which_usm_users2"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>which_usm_users(EngineID) -> UsmUsers</name>
+ <fsummary>List the registered usm users</fsummary>
+ <type>
+ <v>UsmUsers = [UserName]</v>
+ <v>UserName = string()</v>
+ </type>
+ <desc>
+ <p>Get a list of all registered usm users with engine-id
+ <c>EngineID</c>.</p>
+
+ <marker id="sync_get"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>sync_get(UserId, TargetName, Oids) -> {ok, SnmpReply, Remaining} | {error, Reason}</name>
+ <name>sync_get(UserId, TargetName, ContextName, Oids) -> {ok, SnmpReply, Remaining} | {error, Reason}</name>
+ <name>sync_get(UserId, TargetName, Oids, Timeout) -> {ok, SnmpReply, Remaining} | {error, Reason}</name>
+ <name>sync_get(UserId, TargetName, ContextName, Oids, Timeout) -> {ok, SnmpReply, Remaining} | {error, Reason}</name>
+ <name>sync_get(UserId, TargetName, ContextName, Oids, Timeout, ExtraInfo) -> {ok, SnmpReply, Remaining} | {error, Reason}</name>
+ <fsummary>Synchronous <c>get-request</c></fsummary>
+ <type>
+ <v>UserId = term()</v>
+ <v>TargetName = target_name()</v>
+ <v>ContextName = string()</v>
+ <v>Oids = [oid()]</v>
+ <v>Timeout = integer()</v>
+ <v>ExtraInfo = term()</v>
+ <v>SnmpReply = snmp_reply()</v>
+ <v>Remaining = integer()</v>
+ <v>Reason = {send_failed, ReqId, R} | {invalid_sec_info, SecInfo, SnmpInfo} | term()</v>
+ <v>R = term()</v>
+ <v>SecInfo = [sec_info()]</v>
+ <v>sec_info() = {sec_tag(), ExpectedValue, ReceivedValue}</v>
+ <v>sec_tag() = atom()</v>
+ <v>ExpectedValue = ReceivedValue = term()</v>
+ <v>SnmpInfo = term()</v>
+ </type>
+ <desc>
+ <p>Synchronous <c>get-request</c>. </p>
+ <p><c>Remaining</c> is the remaining time of the given or
+ default timeout time.</p>
+ <p>When <em>Reason</em> is <em>{send_failed, ...}</em> it means that
+ the net_if process failed to send the message. This could happen
+ because of any number of reasons, i.e. encoding error. <em>R</em>
+ is the actual reason in this case. </p>
+ <p><c>ExtraInfo</c> is an opaque data structure passed on to
+ the net-if process. The net-if process included in this
+ application makes no use of this info, so the only use for it
+ in such a configuration (when using the built in net-if) would
+ be tracing.</p>
+ <p>For <c>SnmpInfo</c>, see the user callback function
+ <seealso marker="snmpm_user#handle_report">handle_report</seealso>.</p>
+
+ <marker id="async_get"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>async_get(UserId, TargetName, Oids) -> {ok, ReqId} | {error, Reason}</name>
+ <name>async_get(UserId, TargetName, ContextName, Oids) -> {ok, ReqId} | {error, Reason}</name>
+ <name>async_get(UserId, TargetName, Oids, Expire) -> {ok, ReqId} | {error, Reason}</name>
+ <name>async_get(UserId, TargetName, ContextName, Oids, Expire) -> {ok, ReqId} | {error, Reason}</name>
+ <name>async_get(UserId, TargetName, ContextName, Oids, Expire, ExtraInfo) -> {ok, ReqId} | {error, Reason}</name>
+ <fsummary>Asynchronous <c>get-request</c></fsummary>
+ <type>
+ <v>UserId = term()</v>
+ <v>TargetName = target_name()</v>
+ <v>ContextName = string()</v>
+ <v>Oids = [oid()]</v>
+ <v>Expire = integer()</v>
+ <v>ExtraInfo = term()</v>
+ <v>ReqId = term()</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Asynchronous <c>get-request</c>.</p>
+ <p>The reply, if it arrives, will be delivered to the user
+ through a call to the snmpm_user callback function
+ <c>handle_pdu</c>.</p>
+ <p>The <c>Expire</c> time indicates for how long the request is
+ valid (after which the manager is free to delete it).</p>
+ <p><c>ExtraInfo</c> is an opaque data structure passed on to
+ the net-if process. The net-if process included in this
+ application makes no use of this info, so the only use for it
+ in such a configuration (when using the built in net-if) would
+ be tracing.</p>
+
+ <marker id="sync_get_next"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>sync_get_next(UserId, TargetName, Oids) -> {ok, SnmpReply, Remaining} | {error, Reason}</name>
+ <name>sync_get_next(UserId, TargetName, ContextName, Oids) -> {ok, SnmpReply, Remaining} | {error, Reason}</name>
+ <name>sync_get_next(UserId, TargetName, Oids, Timeout) -> {ok, SnmpReply, Remaining} | {error, Reason}</name>
+ <name>sync_get_next(UserId, TargetName, ContextName, Oids, Timeout) -> {ok, SnmpReply, Remaining} | {error, Reason}</name>
+ <name>sync_get_next(UserId, TargetName, ContextName, Oids, Timeout, ExtraInfo) -> {ok, SnmpReply, Remaining} | {error, Reason}</name>
+ <fsummary>Synchronous <c>get-next-request</c></fsummary>
+ <type>
+ <v>UserId = term()</v>
+ <v>TargetName = target_name()</v>
+ <v>ContextName = string()</v>
+ <v>Oids = [oid()]</v>
+ <v>Timeout = integer()</v>
+ <v>ExtraInfo = term()</v>
+ <v>SnmpReply = snmp_reply()</v>
+ <v>Remaining = integer()</v>
+ <v>Reason = {send_failed, ReqId, R} | {invalid_sec_info, SecInfo, SnmpInfo} | term()</v>
+ <v>R = term()</v>
+ </type>
+ <desc>
+ <p>Synchronous <c>get-next-request</c>. </p>
+ <p><c>Remaining</c> time of the given or default timeout time.</p>
+ <p>When <em>Reason</em> is <em>{send_failed, ...}</em> it means that
+ the net_if process failed to send the message. This could happen
+ because of any number of reasons, i.e. encoding error. <em>R</em>
+ is the actual reason in this case. </p>
+ <p><c>ExtraInfo</c> is an opaque data structure passed on to
+ the net-if process. The net-if process included in this
+ application makes no use of this info, so the only use for it
+ in such a configuration (when using the built in net-if) would
+ be tracing.</p>
+
+ <marker id="async_get_next"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>async_get_next(UserId, TargetName, Oids) -> {ok, ReqId} | {error, Reason}</name>
+ <name>async_get_next(UserId, TargetName, ContextName, Oids) -> {ok, ReqId} | {error, Reason}</name>
+ <name>async_get_next(UserId, TargetName, Oids, Expire) -> {ok, ReqId} | {error, Reason}</name>
+ <name>async_get_next(UserId, TargetName, ContextName, Oids, Expire) -> {ok, ReqId} | {error, Reason}</name>
+ <name>async_get_next(UserId, TargetName, ContextName, Oids, Expire, ExtraInfo) -> {ok, ReqId} | {error, Reason}</name>
+ <fsummary>Asynchronous <c>get-next-request</c></fsummary>
+ <type>
+ <v>UserId = term()</v>
+ <v>TargetName = target_name()</v>
+ <v>ContextName = string()</v>
+ <v>Oids = [oid()]</v>
+ <v>Expire = integer()</v>
+ <v>ExtraInfo = term()</v>
+ <v>ReqId = integer()</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Asynchronous <c>get-next-request</c>. </p>
+ <p>The reply will be delivered to the user through a call
+ to the snmpm_user callback function <c>handle_pdu</c>.</p>
+ <p>The <c>Expire</c> time indicates for how long the request is
+ valid (after which the manager is free to delete it).</p>
+
+ <marker id="sync_set"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>sync_set(UserId, TargetName, VarsAndVals) -> {ok, SnmpReply, Remaining} | {error, Reason}</name>
+ <name>sync_set(UserId, TargetName, ContextName, VarsAndVals) -> {ok, SnmpReply, Remaining} | {error, Reason}</name>
+ <name>sync_set(UserId, TargetName, VarsAndVals, Timeout) -> {ok, SnmpReply, Remaining} | {error, Reason}</name>
+ <name>sync_set(UserId, TargetName, ContextName, VarsAndVals, Timeout) -> {ok, SnmpReply, Remaining} | {error, Reason}</name>
+ <name>sync_set(UserId, TargetName, ContextName, VarsAndVals, Timeout, ExtraInfo) -> {ok, SnmpReply, Remaining} | {error, Reason}</name>
+ <fsummary>Synchronous <c>set-request</c></fsummary>
+ <type>
+ <v>UserId = term()</v>
+ <v>TargetName = target_name()</v>
+ <v>ContextName = string()</v>
+ <v>VarsAndVals = vars_and_vals()</v>
+ <v>Timeout = integer()</v>
+ <v>ExtraInfo = term()</v>
+ <v>SnmpReply = snmp_reply()</v>
+ <v>Remaining = integer()</v>
+ <v>Reason = {send_failed, ReqId, ActualReason} | {invalid_sec_info, SecInfo, SnmpInfo} | term()</v>
+ <v>ActualReason = term()</v>
+ </type>
+ <desc>
+ <p>Synchronous <c>set-request</c>. </p>
+ <p><c>Remaining</c> time of the given or default timeout time.</p>
+ <p>When <em>Reason</em> is <em>{send_failed, ...}</em> it means that
+ the net_if process failed to send the message. This could happen
+ because of any number of reasons, i.e. encoding error. <em>R</em>
+ is the actual reason in this case. </p>
+ <p>When <em>var_and_val()</em> is <em>{oid(), value()}</em>, the
+ manager makes an educated guess based on the loaded mibs. </p>
+ <p><c>ExtraInfo</c> is an opaque data structure passed on to
+ the net-if process. The net-if process included in this
+ application makes no use of this info, so the only use for it
+ in such a configuration (when using the built in net-if) would
+ be tracing.</p>
+
+ <marker id="async_set"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>async_set(UserId, TargetName, VarsAndVals) -> {ok, ReqId} | {error, Reason}</name>
+ <name>async_set(UserId, TargetName, ContextName, VarsAndVals) -> {ok, ReqId} | {error, Reason}</name>
+ <name>async_set(UserId, TargetName, VarsAndVals, Expire) -> {ok, ReqId} | {error, Reason}</name>
+ <name>async_set(UserId, TargetName, ContextName, VarsAndVals, Expire) -> {ok, ReqId} | {error, Reason}</name>
+ <name>async_set(UserId, TargetName, ContextName, VarsAndVals, Expire, ExtraInfo) -> {ok, ReqId} | {error, Reason}</name>
+ <fsummary>Asynchronous <c>set-request</c></fsummary>
+ <type>
+ <v>UserId = term()</v>
+ <v>TargetName = target_name()</v>
+ <v>VarsAndVals = vars_and_vals()</v>
+ <v>Expire = integer()</v>
+ <v>ExtraInfo = term()</v>
+ <v>ReqId = term()</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Asynchronous <c>set-request</c>. </p>
+ <p>The reply will be delivered to the user through a call
+ to the snmpm_user callback function <c>handle_pdu</c>.</p>
+ <p>The <c>Expire</c> time indicates for how long the request is
+ valid (after which the manager is free to delete it).</p>
+ <p>When <em>var_and_val()</em> is <em>{oid(), value()}</em>, the
+ manager makes an educated guess based on the loaded mibs. </p>
+ <p><c>ExtraInfo</c> is an opaque data structure passed on to
+ the net-if process. The net-if process included in this
+ application makes no use of this info, so the only use for it
+ in such a configuration (when using the built in net-if) would
+ be tracing.</p>
+
+ <marker id="sync_get_bulk"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>sync_get_bulk(UserId, TragetName, NonRep, MaxRep, Oids) -> {ok, SnmpReply, Remaining} | {error, Reason}</name>
+ <name>sync_get_bulk(UserId, TragetName, NonRep, MaxRep, ContextName, Oids) -> {ok, SnmpReply, Remaining} | {error, Reason}</name>
+ <name>sync_get_bulk(UserId, TragetName, NonRep, MaxRep, Oids, Timeout) -> {ok, SnmpReply, Remaining} | {error, Reason}</name>
+ <name>sync_get_bulk(UserId, TragetName, NonRep, MaxRep, ContextName, Oids, Timeout) -> {ok, SnmpReply, Remaining} | {error, Reason}</name>
+ <name>sync_get_bulk(UserId, TragetName, NonRep, MaxRep, ContextName, Oids, Timeout, ExtraInfo) -> {ok, SnmpReply, Remaining} | {error, Reason}</name>
+ <fsummary>Synchronous <c>get-bulk-request</c></fsummary>
+ <type>
+ <v>UserId = term()</v>
+ <v>TargetName = target_name()</v>
+ <v>NonRep = integer()</v>
+ <v>MaxRep = integer()</v>
+ <v>ContextName = string()</v>
+ <v>Oids = [oid()]</v>
+ <v>Timeout = integer()</v>
+ <v>ExtraInfo = term()</v>
+ <v>SnmpReply = snmp_reply()</v>
+ <v>Remaining = integer()</v>
+ <v>Reason = {send_failed, ReqId, R} | {invalid_sec_info, SecInfo, SnmpInfo} | term()</v>
+ </type>
+ <desc>
+ <p>Synchronous <c>get-bulk-request</c> (See RFC1905).</p>
+ <p><c>Remaining</c> time of the given or default timeout time.</p>
+ <p>When <em>Reason</em> is <em>{send_failed, ...}</em> it means that
+ the net_if process failed to send the message. This could happen
+ because of any number of reasons, i.e. encoding error. <em>R</em>
+ is the actual reason in this case. </p>
+ <p><c>ExtraInfo</c> is an opaque data structure passed on to
+ the net-if process. The net-if process included in this
+ application makes no use of this info, so the only use for it
+ in such a configuration (when using the built in net-if) would
+ be tracing.</p>
+
+ <marker id="async_get_bulk"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>async_get_bulk(UserId, TargetName, NonRep, MaxRep, Oids) -> {ok, ReqId} | {error, Reason}</name>
+ <name>async_get_bulk(UserId, TargetName, NonRep, MaxRep, ContextName, Oids) -> {ok, ReqId} | {error, Reason}</name>
+ <name>async_get_bulk(UserId, TargetName, NonRep, MaxRep, Oids, Expire) -> {ok, ReqId} | {error, Reason}</name>
+ <name>async_get_bulk(UserId, TargetName, NonRep, MaxRep, ContextName, Oids, Expire) -> {ok, ReqId} | {error, Reason}</name>
+ <name>async_get_bulk(UserId, TargetName, NonRep, MaxRep, ContextName, Oids, Expire, ExtraInfo) -> {ok, ReqId} | {error, Reason}</name>
+ <fsummary>Asynchronous <c>get-bulk-request</c></fsummary>
+ <type>
+ <v>UserId = term()</v>
+ <v>TargetName = target_name()</v>
+ <v>NonRep = integer()</v>
+ <v>MaxRep = integer()</v>
+ <v>ContextName = string()</v>
+ <v>Oids = [oid()]</v>
+ <v>Expire = integer()</v>
+ <v>ExtraInfo = term()</v>
+ <v>ReqId = integer()</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Asynchronous <c>get-bulk-request</c> (See RFC1905).</p>
+ <p>The reply will be delivered to the user through a call
+ to the snmpm_user callback function <c>handle_pdu</c>.</p>
+ <p>The <c>Expire</c> time indicates for how long the request is
+ valid (after which the manager is free to delete it).</p>
+
+ <marker id="cancel_async_request"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>cancel_async_request(UserId, ReqId) -> ok | {error, Reason}</name>
+ <fsummary>Cancel a asynchronous request</fsummary>
+ <type>
+ <v>UserId = term()</v>
+ <v>ReqId = term()</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Cancel a previous asynchronous request.</p>
+
+ <marker id="log_to_txt"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>log_to_txt(LogDir, Mibs)</name>
+ <name>log_to_txt(LogDir, Mibs, OutFile) -> ok | {error, Reason}</name>
+ <name>log_to_txt(LogDir, Mibs, OutFile, LogName) -> ok | {error, Reason}</name>
+ <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile) -> ok | {error, Reason}</name>
+ <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Start) -> ok | {error, Reason}</name>
+ <name>log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Start, Stop) -> ok | {error, Reason}</name>
+ <fsummary>Convert an Audit Trail Log to text format</fsummary>
+ <type>
+ <v>LogDir = string()</v>
+ <v>Mibs = [MibName]</v>
+ <v>MibName = string()</v>
+ <v>OutFile = string()</v>
+ <v>LogName = string()</v>
+ <v>LogFile = string()</v>
+ <v>Start = Stop = null | datetime() | {local_time,datetime()} | {universal_time,datetime()} </v>
+ <v>Reason = disk_log_open_error() | file_open_error() | term()</v>
+ <v>disk_log_open_error() = {LogName, term()}</v>
+ <v>file_open_error() = {OutFile, term()}</v>
+ </type>
+ <desc>
+ <p>Converts an Audit Trail Log to a readable text file.
+ <c>OutFile</c> defaults to "./snmpm_log.txt".
+ <c>LogName</c> defaults to "snmpm_log".
+ <c>LogFile</c> defaults to "snmpm.log".
+ See <seealso marker="snmp#log_to_txt">snmp:log_to_txt</seealso>
+ for more info.</p>
+
+ <marker id="change_log_size"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>change_log_size(NewSize) -> ok | {error, Reason}</name>
+ <fsummary>Change the size of the Audit Trail Log</fsummary>
+ <type>
+ <v>NewSize = {MaxBytes, MaxFiles}</v>
+ <v>MaxBytes = integer()</v>
+ <v>MaxFiles = integer()</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Changes the log size of the Audit Trail Log. The application must
+ be configured to use the audit trail log function. Please refer to
+ disk_log(3) in Kernel Reference Manual for a description of how to
+ change the log size.
+ </p>
+ <p>The change is permanent, as long as the log is not deleted.
+ That means, the log size is remembered across reboots.</p>
+
+ <marker id="set_log_type"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>set_log_type(NewType) -> {ok, OldType} | {error, Reason}</name>
+ <fsummary>Change the Audit Trail Log type</fsummary>
+ <type>
+ <v>NewType = OldType = atl_type()</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Changes the run-time Audit Trail log type. </p>
+ <p>Note that this has no effect on the application configuration as
+ defined by configuration files, so a node restart will revert the
+ config to whatever is in those files. </p>
+ <p>This function is primarily useful in testing/debugging
+ scenarios. </p>
+
+ <marker id="load_mib"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>load_mib(Mib) -> ok | {error, Reason}</name>
+ <fsummary>Load a MIB into the manager</fsummary>
+ <type>
+ <v>Mib = MibName</v>
+ <v>MibName = string()</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Load a <c>Mib</c> into the manager. The <c>MibName</c> is the
+ name of the Mib, including the path to where the compiled mib is
+ found. For example,</p>
+ <code type="none">
+ Dir = code:priv_dir(my_app) ++ "/mibs/",
+ snmpm:load_mib(Dir ++ "MY-MIB").
+ </code>
+
+ <marker id="unload_mib"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>unload_mib(Mib) -> ok | {error, Reason}</name>
+ <fsummary>Unload a MIB from the manager</fsummary>
+ <type>
+ <v>Mib = MibName</v>
+ <v>MibName = string()</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Unload a <c>Mib</c> from the manager. The <c>MibName</c> is the
+ name of the Mib, including the path to where the compiled mib is
+ found. For example,</p>
+ <code type="none">
+ Dir = code:priv_dir(my_app) ++ "/mibs/",
+ snmpm:unload_mib(Dir ++ "MY-MIB").
+ </code>
+
+ <marker id="which_mibs"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>which_mibs() -> Mibs</name>
+ <fsummary>Which mibs are loaded into the manager</fsummary>
+ <type>
+ <v>Mibs = [{MibName, MibFile}]</v>
+ <v>MibName = atom()</v>
+ <v>MibFile = string()</v>
+ </type>
+ <desc>
+ <p>Get a list of all the mib's loaded into the manager.</p>
+
+ <marker id="name_to_oid"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>name_to_oid(Name) -> {ok, Oids} | {error, Reason}</name>
+ <fsummary>Get all the possible oid's for an alias-name</fsummary>
+ <type>
+ <v>Name = atom()</v>
+ <v>Oids = [oid()]</v>
+ </type>
+ <desc>
+ <p>Transform a alias-name to it's oid.</p>
+ <p>Note that an alias-name is only unique within the mib, so
+ when loading several mib's into a manager, there might be
+ several instances of the same aliasname.</p>
+
+ <marker id="oid_to_name"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>oid_to_name(Oid) -> {ok, Name} | {error, Reason}</name>
+ <fsummary>Get the alias-name of the oid </fsummary>
+ <type>
+ <v>Oid = oid()</v>
+ <v>Name = atom()</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Transform a oid to it's aliasname.</p>
+
+ <marker id="oid_to_type"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>oid_to_type(Oid) -> {ok, Type} | {error, Reason}</name>
+ <fsummary>Get the type of the the oid</fsummary>
+ <type>
+ <v>Oid = oid()</v>
+ <v>Type = atom()</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Retreive the type (asn1 bertype) of an oid.</p>
+
+ <marker id="backup"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>backup(BackupDir) -> ok | {error, Reason}</name>
+ <fsummary>Backup manager data</fsummary>
+ <type>
+ <v>BackupDir = string()</v>
+ </type>
+ <desc>
+ <p>Backup persistent data handled by the manager. </p>
+ <p>BackupDir cannot be identical to DbDir. </p>
+
+ <marker id="info"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>info() -> [{Key, Value}]</name>
+ <fsummary>Return information about the manager</fsummary>
+ <type>
+ <v>Key = atom()</v>
+ <v>Value = term()</v>
+ </type>
+ <desc>
+ <p>Returns a list (a dictionary) containing information about
+ the manager. Information includes statistics counters,
+ miscellaneous info about each process (e.g. memory allocation),
+ and so on.</p>
+
+ <marker id="verbosity"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>verbosity(Ref, Verbosity) -> void()</name>
+ <fsummary>Assign a new verbosity for the process</fsummary>
+ <type>
+ <v>Ref = server | config | net_if | note_store | all</v>
+ <v>Verbosity = verbosity()</v>
+ <v>verbosity() = silence | info | log | debug | trace </v>
+ </type>
+ <desc>
+ <p>Sets verbosity for the designated process. For the lowest
+ verbosity <c>silence</c>, nothing is printed. The higher the
+ verbosity, the more is printed.</p>
+
+ <marker id="format_reason"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>format_reason(Reason) -> string()</name>
+ <name>format_reason(Prefix, Reason) -> string()</name>
+ <fsummary>Assign a new verbosity for the process</fsummary>
+ <type>
+ <v>Reason = term()</v>
+ <v>Prefix = integer() | string()</v>
+ </type>
+ <desc>
+ <p>This utility function is used to create a formatted
+ (pretty printable) string of the error reason received
+ from either:
+ </p>
+ <list type="bulleted">
+ <item>
+ <p>The <c>Reason</c> returned value if any of the
+ sync/async get/get-next/set/get-bulk
+ functions returns <c>{error, Reason}</c></p>
+ </item>
+ <item>
+ <p>The <c>Reason</c> parameter in the
+ <seealso marker="snmpm_user#handle_error">handle_error</seealso> user callback function.</p>
+ </item>
+ </list>
+ <p><c>Prefix</c> should either be an indention string
+ (e.g. a list of spaces) or a positive integer (which will be used
+ to create the indention string of that length).</p>
+ </desc>
+ </func>
+ </funcs>
+
+
+</erlref>
+
diff --git a/lib/snmp/doc/src/snmpm_conf.xml b/lib/snmp/doc/src/snmpm_conf.xml
new file mode 100644
index 0000000000..177e29faa3
--- /dev/null
+++ b/lib/snmp/doc/src/snmpm_conf.xml
@@ -0,0 +1,364 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE erlref SYSTEM "erlref.dtd">
+
+<erlref>
+ <header>
+ <copyright>
+ <year>2006</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ 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.
+
+ </legalnotice>
+
+ <title>snmpm_conf</title>
+ <prepared></prepared>
+ <responsible></responsible>
+ <docno></docno>
+ <approved></approved>
+ <checked></checked>
+ <date></date>
+ <rev></rev>
+ <file>snmpm_conf.xml</file>
+ </header>
+ <module>snmpm_conf</module>
+ <modulesummary>Utility functions for handling the manager config files.</modulesummary>
+ <description>
+ <p>The module <c>snmpm_conf</c> contains various utility functions to
+ used for manipulating (write/append/read) the config files of the
+ SNMP manager. </p>
+ <marker id="manager_entry"></marker>
+ </description>
+ <funcs>
+ <func>
+ <name>manager_entry(Tag, Val) -> manager_entry()</name>
+ <fsummary>Create an manager entry</fsummary>
+ <type>
+ <v>Tag = address | port | engine_id | max_message_size</v>
+ <v>Val = term()</v>
+ <v>manager_entry() = term()</v>
+ </type>
+ <desc>
+ <p>Create an entry for the manager config file,
+ <c>manager.conf</c>. </p>
+ <p>The type of <c>Val</c> depends on the value of <c>Tag</c>,
+ see
+ <seealso marker="snmp_manager_config_files#manager_information">Manager Information</seealso>
+ for more info. </p>
+ <marker id="write_manager_config"></marker>
+ </desc>
+ </func>
+ <func>
+ <name>write_manager_config(Dir, Conf) -> ok</name>
+ <name>write_manager_config(Dir, Hdr, Conf) -> ok</name>
+ <fsummary>Write the manager config to the config file</fsummary>
+ <type>
+ <v>Dir = string()</v>
+ <v>Hdr = string()</v>
+ <v>Conf = [manager_entry()]</v>
+ </type>
+ <desc>
+ <p>Write the manager config to the manager config file. </p>
+ <p><c>Dir</c> is the path to the directory where to store the
+ config file. </p>
+ <p><c>Hdr</c> is an optional file header (note that this text is
+ written to the file as is). </p>
+ <p>See
+ <seealso marker="snmp_manager_config_files#manager_information">Manager Information</seealso>
+ for more info. </p>
+ <marker id="append_manager_config"></marker>
+ </desc>
+ </func>
+ <func>
+ <name>append_manager_config(Dir, Conf) -> ok</name>
+ <fsummary>Append the manager config to the config file</fsummary>
+ <type>
+ <v>Dir = string()</v>
+ <v>Conf = [manager_entry()]</v>
+ </type>
+ <desc>
+ <p>Append the config to the current manager config file. </p>
+ <p><c>Dir</c> is the path to the directory where to store the
+ config file. </p>
+ <p>See
+ <seealso marker="snmp_manager_config_files#manager_information">Manager Information</seealso>
+ for more info. </p>
+ <marker id="read_manager_config"></marker>
+ </desc>
+ </func>
+ <func>
+ <name>read_manager_config(Dir) -> Conf</name>
+ <fsummary>Read the manager config from the config file</fsummary>
+ <type>
+ <v>Dir = string()</v>
+ <v>Conf = [manager_entry()]</v>
+ </type>
+ <desc>
+ <p>Read the current manager config file. </p>
+ <p><c>Dir</c> is the path to the directory where to store the
+ config file. </p>
+ <p>See
+ <seealso marker="snmp_manager_config_files#manager_information">Manager Information</seealso>
+ for more info. </p>
+ <marker id="users_entry"></marker>
+ </desc>
+ </func>
+ <func>
+ <name>users_entry(UserId) -> users_entry()</name>
+ <name>users_entry(UserId, UserMod) -> users_entry()</name>
+ <name>users_entry(UserId, UserMod, UserData) -> users_entry()</name>
+ <fsummary>Create an users entry</fsummary>
+ <type>
+ <v>UserId = term()</v>
+ <v>UserMod = atom()</v>
+ <v>UserData = term()</v>
+ <v>standard_entry() = term()</v>
+ </type>
+ <desc>
+ <p>Create an entry for the manager users config file,
+ <c>users.conf</c>. </p>
+ <p><c>users_entry(UserId)</c> translates to the following call:
+ <c>users_entry(UserId, snmpm_user_default)</c>. </p>
+ <p><c>users_entry(UserId, UserMod)</c> translates to the following
+ call: <c>users_entry(UserId, UserMod, undefined)</c>. </p>
+ <p>See
+ <seealso marker="snmp_manager_config_files#users">Users</seealso>
+ for more info. </p>
+ <marker id="write_users_config"></marker>
+ </desc>
+ </func>
+ <func>
+ <name>write_users_config(Dir, Conf) -> ok</name>
+ <name>write_users_config(Dir, Hdr, Conf) -> ok</name>
+ <fsummary>Write the manager users config to the config file</fsummary>
+ <type>
+ <v>Dir = string()</v>
+ <v>Hdr = string()</v>
+ <v>Conf = [users_entry()]</v>
+ </type>
+ <desc>
+ <p>Write the manager users config to the manager users
+ config file. </p>
+ <p><c>Dir</c> is the path to the directory where to store the
+ config file. </p>
+ <p><c>Hdr</c> is an optional file header (note that this text is
+ written to the file as is). </p>
+ <p>See
+ <seealso marker="snmp_manager_config_files#users">Users</seealso>
+ for more info. </p>
+ <marker id="append_users_config"></marker>
+ </desc>
+ </func>
+ <func>
+ <name>append_users_config(Dir, Conf) -> ok</name>
+ <fsummary>Append the manager users config to the config file</fsummary>
+ <type>
+ <v>Dir = string()</v>
+ <v>Conf = [users_entry()]</v>
+ </type>
+ <desc>
+ <p>Append the users config to the current manager users
+ config file. </p>
+ <p><c>Dir</c> is the path to the directory where to store the
+ config file. </p>
+ <p>See
+ <seealso marker="snmp_manager_config_files#users">Users</seealso>
+ for more info. </p>
+ <marker id="read_users_config"></marker>
+ </desc>
+ </func>
+ <func>
+ <name>read_users_config(Dir) -> Conf</name>
+ <fsummary>Read the manager users config from the config file</fsummary>
+ <type>
+ <v>Dir = string()</v>
+ <v>Conf = [users_entry()]</v>
+ </type>
+ <desc>
+ <p>Read the current manager users config file. </p>
+ <p><c>Dir</c> is the path to the directory where to store the
+ config file. </p>
+ <p>See
+ <seealso marker="snmp_manager_config_files#users">Users</seealso>
+ for more info. </p>
+ <marker id="agents_entry"></marker>
+ </desc>
+ </func>
+ <func>
+ <name>agents_entry(UserId, TargetName, Comm, Ip, Port, EngineID, Timeout, MaxMessageSize, Version, SecModel, SecName, SecLevel) -> agents_entry()</name>
+ <fsummary>Create an agents entry</fsummary>
+ <type>
+ <v>UserId = term()</v>
+ <v>TargetName = string()</v>
+ <v>Comm = string()</v>
+ <v>Ip = string()</v>
+ <v>Port = integer()</v>
+ <v>EngineID = string()</v>
+ <v>Timeout = integer()</v>
+ <v>MaxMessageSize = integer()</v>
+ <v>Version = v1 | v2 | v3</v>
+ <v>SecModel = v1 | v2c | usm</v>
+ <v>SecName = string()</v>
+ <v>SecLevel = noAuthNoPriv | authNoPriv | authPriv</v>
+ <v>agents_entry() = term()</v>
+ </type>
+ <desc>
+ <p>Create an entry for the manager agents config file,
+ <c>agents.conf</c>. </p>
+ <p>See
+ <seealso marker="snmp_manager_config_files#agents">Agents</seealso>
+ for more info. </p>
+ <marker id="write_agents_config"></marker>
+ </desc>
+ </func>
+ <func>
+ <name>write_agents_config(Dir, Conf) -> ok</name>
+ <name>write_agents_config(Dir, Hdr, Conf) -> ok</name>
+ <fsummary>Write the manager agents to the config file</fsummary>
+ <type>
+ <v>Dir = string()</v>
+ <v>Hdr = string()</v>
+ <v>Conf = [_entry()]</v>
+ </type>
+ <desc>
+ <p>Write the manager agents config to the manager agents
+ config file. </p>
+ <p><c>Dir</c> is the path to the directory where to store the
+ config file. </p>
+ <p><c>Hdr</c> is an optional file header (note that this text is
+ written to the file as is). </p>
+ <p>See
+ <seealso marker="snmp_manager_config_files#agents">Agents</seealso>
+ for more info. </p>
+ <marker id="append_agents_config"></marker>
+ </desc>
+ </func>
+ <func>
+ <name>append_agents_config(Dir, Conf) -> ok</name>
+ <fsummary>Append the manager agents to the config file</fsummary>
+ <type>
+ <v>Dir = string()</v>
+ <v>Conf = [agents_entry()]</v>
+ </type>
+ <desc>
+ <p>Append the agents config to the current manager agents
+ config file. </p>
+ <p><c>Dir</c> is the path to the directory where to store the
+ config file. </p>
+ <p>See
+ <seealso marker="snmp_manager_config_files#agents">Agents</seealso>
+ for more info. </p>
+ <marker id="read_agents_config"></marker>
+ </desc>
+ </func>
+ <func>
+ <name>read_agents_config(Dir) -> Conf</name>
+ <fsummary>Read the manager agents config from the config file</fsummary>
+ <type>
+ <v>Dir = string()</v>
+ <v>Conf = [agents_entry()]</v>
+ </type>
+ <desc>
+ <p>Read the current manager agents config file. </p>
+ <p><c>Dir</c> is the path to the directory where to store the
+ config file. </p>
+ <p>See
+ <seealso marker="snmp_manager_config_files#agents">Agents</seealso>
+ for more info. </p>
+ <marker id="usm_entry"></marker>
+ </desc>
+ </func>
+ <func>
+ <name>usm_entry(EngineID, UserName, AuthP, AuthKey, PrivP, PrivKey) -> usm_entry()</name>
+ <name>usm_entry(EngineID, UserName, SecName, AuthP, AuthKey, PrivP, PrivKey) -> usm_entry()</name>
+ <fsummary>Create an usm entry</fsummary>
+ <type>
+ <v>EngineID = string()</v>
+ <v>UserName = string()</v>
+ <v>SecName = string()</v>
+ <v>AuthP = usmNoAuthProtocol | usmHMACMD5AuthProtocol | usmHMACSHAAuthProtocol</v>
+ <v>AuthKey = [integer()]</v>
+ <v>PrivP = usmNoPrivProtocol | usmDESPrivProtocol | usmAesCfb128Protocol</v>
+ <v>PrivKey = [integer()]</v>
+ <v>usm_entry() = term()</v>
+ </type>
+ <desc>
+ <p>Create an entry for the agent community config file,
+ <c>community.conf</c>. </p>
+ <p>See
+ <seealso marker="snmp_manager_config_files#usm">Security data for USM</seealso>
+ for more info. </p>
+ <marker id="write_usm_config"></marker>
+ </desc>
+ </func>
+ <func>
+ <name>write_usm_config(Dir, Conf) -> ok</name>
+ <name>write_usm_config(Dir, Hdr, Conf) -> ok</name>
+ <fsummary>Write the manager usm config to the config file</fsummary>
+ <type>
+ <v>Dir = string()</v>
+ <v>Hdr = string()</v>
+ <v>Conf = [usm_entry()]</v>
+ </type>
+ <desc>
+ <p>Write the manager usm config to the manager usm
+ config file. </p>
+ <p><c>Dir</c> is the path to the directory where to store the
+ config file. </p>
+ <p><c>Hdr</c> is an optional file header (note that this text is
+ written to the file as is). </p>
+ <p>See
+ <seealso marker="snmp_manager_config_files#usm">Security data for USM</seealso>
+ for more info. </p>
+ <marker id="append_usm_config"></marker>
+ </desc>
+ </func>
+ <func>
+ <name>append_usm_config(Dir, Conf) -> ok</name>
+ <fsummary>Append the manager usm config to the config file</fsummary>
+ <type>
+ <v>Dir = string()</v>
+ <v>Conf = [usm_entry()]</v>
+ </type>
+ <desc>
+ <p>Append the usm config to the current manager usm
+ config file. </p>
+ <p><c>Dir</c> is the path to the directory where to store the
+ config file. </p>
+ <p>See
+ <seealso marker="snmp_manager_config_files#usm">Security data for USM</seealso>
+ for more info. </p>
+ <marker id="read_usm_config"></marker>
+ </desc>
+ </func>
+ <func>
+ <name>read_usm_config(Dir) -> Conf</name>
+ <fsummary>Read the manager usm config from the config file</fsummary>
+ <type>
+ <v>Dir = string()</v>
+ <v>Conf = [usm_entry()]</v>
+ </type>
+ <desc>
+ <p>Read the current manager usm config file. </p>
+ <p><c>Dir</c> is the path to the directory where to store the
+ config file. </p>
+ <p>See
+ <seealso marker="snmp_manager_config_files#usm">Security data for USM</seealso>
+ for more info. </p>
+ <marker id="end"></marker>
+ </desc>
+ </func>
+ </funcs>
+
+</erlref>
+
diff --git a/lib/snmp/doc/src/snmpm_mpd.xml b/lib/snmp/doc/src/snmpm_mpd.xml
new file mode 100644
index 0000000000..030c79e0e6
--- /dev/null
+++ b/lib/snmp/doc/src/snmpm_mpd.xml
@@ -0,0 +1,139 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE erlref SYSTEM "erlref.dtd">
+
+<erlref>
+ <header>
+ <copyright>
+ <year>2004</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ 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.
+
+ </legalnotice>
+
+ <title>snmpm_mpd</title>
+ <prepared></prepared>
+ <responsible></responsible>
+ <docno></docno>
+ <approved></approved>
+ <checked></checked>
+ <date></date>
+ <rev></rev>
+ <file>snmpm_mpd.xml</file>
+ </header>
+ <module>snmpm_mpd</module>
+ <modulesummary>Message Processing and Dispatch module for the SNMP manager</modulesummary>
+ <description>
+ <p>The module <c>snmpm_mpd</c> implements the version independent
+ Message Processing and Dispatch functionality in SNMP for the manager.
+ It is supposed to be used from a Network Interface process
+ (<seealso marker="snmp_manager_netif">Definition of Manager Net if</seealso>).
+ </p>
+ </description>
+ <funcs>
+ <func>
+ <name>init_mpd(Vsns) -> mpd_state()</name>
+ <fsummary>Initialize the MPD module</fsummary>
+ <type>
+ <v>Vsns = [Vsn]</v>
+ <v>Vsn = v1 | v2 | v3</v>
+ </type>
+ <desc>
+ <p>This function can be called from the net_if process at start-up.
+ The options list defines which versions to use.
+ </p>
+ <p>It also initializes some SNMP counters.
+ <marker id="process_msg"></marker>
+</p>
+ </desc>
+ </func>
+ <func>
+ <name>process_msg(Msg, TDomain, Addr, Port, State, NoteStore, Logger) -> {ok, Vsn, Pdu, PduMS, MsgData} | {discarded, Reason}</name>
+ <fsummary>Process a message received from the network</fsummary>
+ <type>
+ <v>Msg = binary()</v>
+ <v>TDomain = snmpUDPDomain</v>
+ <v>Addr = {integer(), integer(), integer(), integer()}</v>
+ <v>Port = integer()</v>
+ <v>State = mpd_state()</v>
+ <v>NoteStore = pid()</v>
+ <v>Logger = function()</v>
+ <v>Vsn = 'version-1' | 'version-2' | 'version-3'</v>
+ <v>Pdu = #pdu</v>
+ <v>PduMs = integer()</v>
+ <v>MsgData = term()</v>
+ </type>
+ <desc>
+ <p>Processes an incoming message. Performs authentication and
+ decryption as necessary. The return values should be passed the
+ manager server.
+ </p>
+ <p><c>NoteStore</c> is the <c>pid()</c> of the note-store process.</p>
+ <p><c>Logger</c> is the function used for audit trail logging.
+ </p>
+ <p>In the case when the pdu type is <c>report</c>, <c>MsgData</c> is
+ either <c>ok</c> or <c>{error, ReqId, Reason}</c>.
+ </p>
+ </desc>
+ </func>
+ <func>
+ <name>generate_msg(Vsn, NoteStore, Pdu, MsgData, Logger) -> {ok, Packet} | {discarded, Reason}</name>
+ <fsummary>Generate a request message to be sent to the network</fsummary>
+ <type>
+ <v>Vsn = 'version-1' | 'version-2' | 'version-3'</v>
+ <v>NoteStore = pid()</v>
+ <v>Pdu = #pdu</v>
+ <v>MsgData = term()</v>
+ <v>Logger = function()</v>
+ <v>Packet = binary()</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Generates a possibly encrypted packet to be sent to the network.
+ </p>
+ <p><c>NoteStore</c> is the <c>pid()</c> of the note-store process.
+ </p>
+ <p><c>MsgData</c> is the message specific data used in the SNMP
+ message. In SNMPv1 and SNMPv2c, this message data is the community
+ string. In SNMPv3, it is the context information.
+ </p>
+ <p><c>Logger</c> is the function used for audit trail logging.
+ </p>
+ </desc>
+ </func>
+ <func>
+ <name>generate_response_msg(Vsn, Pdu, MsgData, Logger) -> {ok, Packet} | {discarded, Reason}</name>
+ <fsummary>Generate a response packet to be sent to the network</fsummary>
+ <type>
+ <v>Vsn = 'version-1' | 'version-2' | 'version-3'</v>
+ <v>Pdu = #pdu</v>
+ <v>MsgData = term()</v>
+ <v>Logger = function()</v>
+ <v>Packet = binary()</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>Generates a possibly encrypted response packet to be sent to the
+ network.
+ </p>
+ <p><c>MsgData</c> is the message specific data used in the SNMP
+ message. This value is received from the
+ <seealso marker="snmpm_mpd#process_msg">process_msg</seealso>
+ function.
+ </p>
+ </desc>
+ </func>
+ </funcs>
+
+</erlref>
+
diff --git a/lib/snmp/doc/src/snmpm_network_interface.xml b/lib/snmp/doc/src/snmpm_network_interface.xml
new file mode 100644
index 0000000000..33eb736b8f
--- /dev/null
+++ b/lib/snmp/doc/src/snmpm_network_interface.xml
@@ -0,0 +1,252 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE erlref SYSTEM "erlref.dtd">
+
+<erlref>
+ <header>
+ <copyright>
+ <year>2004</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ 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.
+
+ </legalnotice>
+
+ <title>snmpm_network_interface</title>
+ <prepared></prepared>
+ <responsible></responsible>
+ <docno></docno>
+ <approved></approved>
+ <checked></checked>
+ <date></date>
+ <rev></rev>
+ <file>snmpm_network_interface.xml</file>
+ </header>
+ <module>snmpm_network_interface</module>
+ <modulesummary>Behaviour module for the SNMP manager network interface.</modulesummary>
+ <description>
+ <p>This module defines the behaviour of the manager network
+ interface. A <c>snmpm_network_interface</c> compliant module
+ must export the following functions: </p>
+ <list type="bulleted">
+ <item>
+ <p><seealso marker="#start_link">start_link/2</seealso></p>
+ </item>
+ <item>
+ <p><seealso marker="#stop">stop/1</seealso></p>
+ </item>
+ <item>
+ <p><seealso marker="#send_pdu">send_pdu/7</seealso></p>
+ </item>
+ <item>
+ <p><seealso marker="#inform_response">inform_response/4</seealso></p>
+ </item>
+ <item>
+ <p><seealso marker="#note_store">note_store/2</seealso></p>
+ </item>
+ <item>
+ <p><seealso marker="#info">info/1</seealso></p>
+ </item>
+ <item>
+ <p><seealso marker="#get_log_type">get_log_type/1</seealso></p>
+ </item>
+ <item>
+ <p><seealso marker="#set_log_type">set_log_type/2</seealso></p>
+ </item>
+ <item>
+ <p><seealso marker="#verbosity">verbosity/2</seealso></p>
+ </item>
+ </list>
+ <p>The semantics of them and their exact signatures are explained
+ below. </p>
+
+ <marker id="start_link"></marker>
+ </description>
+
+ <funcs>
+ <func>
+ <name>start_link(Server, NoteStore) -> {ok, Pid} | {error, Reason}</name>
+ <fsummary>Start-link the network interface process</fsummary>
+ <type>
+ <v>Server = pid()</v>
+ <v>NoteStore = pid()</v>
+ </type>
+ <desc>
+ <p>Start-link the network interface process.</p>
+ <p><c>Server</c> is the pid of the managing process.</p>
+ <p><c>NoteStore</c> is the pid of the note-store process.</p>
+
+ <marker id="stop"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>stop(Pid) -> void()</name>
+ <fsummary>Stop the network interface process</fsummary>
+ <type>
+ <v>Pid = pid()</v>
+ </type>
+ <desc>
+ <p>Stop the network interface process.</p>
+
+ <marker id="send_pdu"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>send_pdu(Pid, Pdu, Vsn, MsgData, Addr, Port, ExtraInfo) -> void()</name>
+ <fsummary>Request the network interface process to send this pdu</fsummary>
+ <type>
+ <v>Pid = pid()</v>
+ <v>Pdu = pdu()</v>
+ <v>Vsn = 'version-1' | 'version-2' | 'version-3'</v>
+ <v>MsgData = term()</v>
+ <v>Addr = address()</v>
+ <v>Port = integer()</v>
+ <v>ExtraInfo = term()</v>
+ </type>
+ <desc>
+ <p>Request the network interface process (<c>Pid</c>) to send
+ this pdu (<c>Pdu</c>).</p>
+ <p><c>ExtraInfo</c> is some opaque data that is passed to the
+ net-if process. It originates from the <c>ExtraInfo</c>
+ parameter in the calls to the
+ <seealso marker="snmpm#sync_get">synchronous get-request</seealso>,
+ <seealso marker="snmpm#async_get">asynchronous get-request</seealso>,
+ <seealso marker="snmpm#sync_get_next">synchronous get-next-request</seealso>,
+ <seealso marker="snmpm#async_get_next">asynchronous get-next-request</seealso>,
+ <seealso marker="snmpm#sync_set">synchronous set-request</seealso>
+ and
+ <seealso marker="snmpm#async_set">asynchronous set-request</seealso>
+ functions.
+ Whether the net-if process chooses
+ to use this is implementation dependent. The net-if process
+ included in this application ignores it. </p>
+
+ <marker id="inform_response"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>inform_response(Pid, Ref, Addr, Port) -> void()</name>
+ <fsummary>Send the inform-request ack</fsummary>
+ <type>
+ <v>Pid = pid()</v>
+ <v>Ref = term()</v>
+ <v>Addr = address()</v>
+ <v>Port = integer()</v>
+ </type>
+ <desc>
+ <p>Instruct the network interface process to send the response
+ (acknowledgment) to an inform-request.</p>
+ <p><c>Ref</c> is something that can be used to identify the
+ inform-request, e.g. request-id of the inform-request.</p>
+ <p><c>Addr</c> and <c>Port</c> identifies the agent, from
+ which the inform-request originated.</p>
+
+ <marker id="note_store"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>note_store(Pid, NoteStore) -> void()</name>
+ <fsummary>Change the verbosity of the network interface process</fsummary>
+ <type>
+ <v>Pid = pid()</v>
+ <v>NoteStore = pid()</v>
+ </type>
+ <desc>
+ <p>Change the pid of the note-store process.
+ This is used when the server re-starts the note_store
+ (e.g. after a crach).</p>
+
+ <marker id="info"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>info(Pid) -> [{Key, Value}]</name>
+ <fsummary>Return information about the running network interface process</fsummary>
+ <type>
+ <v>Pid = pid()</v>
+ </type>
+ <desc>
+ <p>The info returned is basically up to the implementer to decide.
+ The implementation provided by this application provides info about
+ memory allocation and various socket information.</p>
+ <p>The info returned by this function is returned together with other
+ info collected by the manager when the
+ <seealso marker="snmpm#info">info</seealso> function is called
+ (tagged with the key <c>net_if</c>).</p>
+
+ <marker id="verbosity"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>verbosity(Pid, Verbosity) -> void()</name>
+ <fsummary>Change the verbosity of the network interface process</fsummary>
+ <type>
+ <v>Pid = pid()</v>
+ <v>Verbosity = verbosity()</v>
+ </type>
+ <desc>
+ <p>Change the verbosity of the network interface process.</p>
+
+ <marker id="get_log_type"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>get_log_type(Pid) -> {ok, LogType} | {error, Reason}</name>
+ <fsummary>Get the Audit Trail Log type</fsummary>
+ <type>
+ <v>Pid = pid()</v>
+ <v>LogType = atl_type()</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>The Audit Trail Log is managed by the network interface process.
+ So, it is this process that has to return the actual log-type. </p>
+<!--
+ <p>See
+ <seealso marker="snmpm#get_log_type">get_log_type</seealso>
+ for more info. </p>
+-->
+
+ <marker id="set_log_type"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>set_log_type(Pid, NewType) -> {ok, OldType} | {error, Reason}</name>
+ <fsummary>Change the Audit Trail Log type</fsummary>
+ <type>
+ <v>Pid = pid()</v>
+ <v>NewType = OldType = atl_type()</v>
+ <v>Reason = term()</v>
+ </type>
+ <desc>
+ <p>The Audit Trail Log is managed by the network interface process.
+ So, it is this process that has to do the actual changing of the
+ type. </p>
+ <p>See
+ <seealso marker="snmpm#set_log_type">set_log_type</seealso>
+ for more info. </p>
+ </desc>
+ </func>
+
+ </funcs>
+
+
+</erlref>
+
diff --git a/lib/snmp/doc/src/snmpm_network_interface_filter.xml b/lib/snmp/doc/src/snmpm_network_interface_filter.xml
new file mode 100644
index 0000000000..ea1e183848
--- /dev/null
+++ b/lib/snmp/doc/src/snmpm_network_interface_filter.xml
@@ -0,0 +1,158 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE erlref SYSTEM "erlref.dtd">
+
+<erlref>
+ <header>
+ <copyright>
+ <year>2007</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ 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.
+
+ </legalnotice>
+
+ <title>snmpm_network_interface_filter</title>
+ <prepared></prepared>
+ <responsible></responsible>
+ <docno></docno>
+ <approved></approved>
+ <checked></checked>
+ <date></date>
+ <rev></rev>
+ <file>snmpm_network_interface_filter.xml</file>
+ </header>
+ <module>snmpm_network_interface_filter</module>
+ <modulesummary>Behaviour module for the SNMP manager network-interface filter.</modulesummary>
+ <description>
+ <p>This module defines the behaviour of the manager network interface
+ filter. A <c>snmpm_network_interface_filter</c> compliant module
+ must export the following functions: </p>
+ <list type="bulleted">
+ <item>
+ <p><seealso marker="#accept_recv">accept_recv/2</seealso></p>
+ </item>
+ <item>
+ <p><seealso marker="#accept_send">accept_send/2</seealso></p>
+ </item>
+ <item>
+ <p><seealso marker="#accept_recv_pdu">accept_recv_pdu/3</seealso></p>
+ </item>
+ <item>
+ <p><seealso marker="#accept_send_pdu">accept_send_pdu/2</seealso></p>
+ </item>
+ </list>
+ <p>The semantics of them and their exact signatures are explained
+ below. </p>
+ <p>The purpose of the network interface filter is to allow for filtering
+ of messages (accept or reject) receive and send. This is done
+ on two levels: </p>
+ <list type="bulleted">
+ <item>
+ <p>The first level is at the UDP entry / exit point, i.e.
+ immediately after the receipt of the message, before any message
+ processing is done (accept_recv) and
+ immediately before sending the message, after all message
+ processing is done (accept_send).</p>
+ </item>
+ <item>
+ <p>The second level is at the MPD entry / exit point, i.e.
+ immediately after the basic message processing (accept_recv_pdu) /
+ immediately before the basic message processing (accept_send_pdu).</p>
+ </item>
+ </list>
+ <p>Note that the network interface filter is something which is used
+ by the network interface implementation provided by the application
+ (<c>snmpm_net_if</c>). The default filter accepts all messages.</p>
+ <p>A network interface filter can e.g. be used during testing or for load
+ regulation. </p>
+ </description>
+
+ <section>
+ <title>DATA TYPES</title>
+ <code type="none">
+port() = integer() > 0
+pdu_type() = 'get-request' | 'get-next-request' | 'get-response' | 'set-request' | trap | 'get-bulk-request' | 'inform-request' | report | trappdu
+ </code>
+ <marker id="accept_recv"></marker>
+ </section>
+
+ <funcs>
+ <func>
+ <name>accept_recv(Addr, Port) -> boolean()</name>
+ <fsummary>Shall the received message be accepted</fsummary>
+ <type>
+ <v>Addr = ip_address()</v>
+ <v>Port = port()</v>
+ </type>
+ <desc>
+ <p>Called at the reception of a message (before <em>any</em> processing
+ has been done).</p>
+ <p>For the message to be rejected, the function <em>must</em> return
+ <em>false</em>. </p>
+ <marker id="accept_send"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>accept_send(Addr, Port) -> boolean()</name>
+ <fsummary>Shall the message be sent</fsummary>
+ <type>
+ <v>Addr = ip_address()</v>
+ <v>Port = port()</v>
+ </type>
+ <desc>
+ <p>Called before the sending of a message (after <em>all</em> processing
+ has been done).</p>
+ <p>For the message to be rejected, the function <em>must</em> return
+ <em>false</em>. </p>
+ <marker id="accept_recv_pdu"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>accept_recv_pdu(Addr, Port, PduType) -> boolean()</name>
+ <fsummary>Shall the received pdu be accepted</fsummary>
+ <type>
+ <v>Addr = ip_address()</v>
+ <v>Port = port()</v>
+ <v>PduType = pdu_type()</v>
+ </type>
+ <desc>
+ <p>Called after the basic message processing (MPD) has been done,
+ but before the pdu is handed over to the server for primary
+ processing.</p>
+ <p>For the pdu to be rejected, the function <em>must</em> return
+ <em>false</em>. </p>
+ <marker id="accept_send_pdu"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>accept_send_pdu(Addr, Port, PduType) -> boolean()</name>
+ <fsummary>Shall the pdu be sent</fsummary>
+ <type>
+ <v>Addr = ip_address()</v>
+ <v>Port = port()</v>
+ <v>PduType = pdu_type() > 0</v>
+ </type>
+ <desc>
+ <p>Called before the basic message processing (MPD) is done,
+ when a pdu has been received from the master-agent.</p>
+ <p>For the message to be rejected, the function <em>must</em> return
+ <em>false</em>. </p>
+ </desc>
+ </func>
+ </funcs>
+
+</erlref>
+
diff --git a/lib/snmp/doc/src/snmpm_user.xml b/lib/snmp/doc/src/snmpm_user.xml
new file mode 100644
index 0000000000..1823e0c815
--- /dev/null
+++ b/lib/snmp/doc/src/snmpm_user.xml
@@ -0,0 +1,276 @@
+<?xml version="1.0" encoding="latin1" ?>
+<!DOCTYPE erlref SYSTEM "erlref.dtd">
+
+<erlref>
+ <header>
+ <copyright>
+ <year>2004</year><year>2009</year>
+ <holder>Ericsson AB. All Rights Reserved.</holder>
+ </copyright>
+ <legalnotice>
+ 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.
+
+ </legalnotice>
+
+ <title>snmpm_user</title>
+ <prepared></prepared>
+ <responsible></responsible>
+ <docno></docno>
+ <approved></approved>
+ <checked></checked>
+ <date></date>
+ <rev></rev>
+ <file>snmpm_user.xml</file>
+ </header>
+ <module>snmpm_user</module>
+ <modulesummary>Behaviour module for the SNMP manager user.</modulesummary>
+ <description>
+ <p>This module defines the behaviour of the manager user.
+ A <c>snmpm_user</c> compliant module
+ must export the following functions: </p>
+ <list type="bulleted">
+ <item>
+ <p>handle_error/3</p>
+ </item>
+ <item>
+ <p>handle_agent/4</p>
+ </item>
+ <item>
+ <p>handle_pdu/4</p>
+ </item>
+ <item>
+ <p>handle_trap/3</p>
+ </item>
+ <item>
+ <p>handle_inform/3</p>
+ </item>
+ <item>
+ <p>handle_report/3</p>
+ </item>
+ </list>
+ <p>The semantics of them and their exact signatures are explained
+ below. </p>
+ <p>Note that if an agent is registered using the old, no longer
+ documented, functions (using Addr and Port), the old variant of the
+ callback functions, handle_pdu, handle_trap, handle_inform and
+ handle_report, will be called. </p>
+
+ <marker id="handle_error"></marker>
+ </description>
+ <funcs>
+ <func>
+ <name>handle_error(ReqId, Reason, UserData) -> Reply</name>
+ <fsummary>Handle error</fsummary>
+ <type>
+ <v>ReqId = integer()</v>
+ <v>Reason = {unexpected_pdu, SnmpInfo} | {invalid_sec_info, SecInfo, SnmpInfo} | {empty_message, Addr, Port} | term()</v>
+ <v>Addr = ip_address()</v>
+ <v>Port = integer()</v>
+ <v>UserData = term()</v>
+ <v>Reply = ignore</v>
+ </type>
+ <desc>
+ <p>This function is called when the manager needs to
+ communicate an "asynchronous" error, to the user:
+ e.g. failure to send an asynchronous message (i.e. encoding
+ error), a received message was discarded due to security
+ error, the manager failed to generate a response message to
+ a received inform-request, or when receiving an unexpected
+ PDU from an agent (could be an expired async request). </p>
+ <p>If <c>ReqId</c> is less then 0, it means that this
+ information was not available to the manager (that info was
+ never retrieved before the message was discarded).
+ </p>
+ <p>For <c>SnmpInfo</c> see handle_agent below.</p>
+
+ <marker id="handle_agent"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>handle_agent(Addr, Port, Type, SnmpInfo, UserData) -> Reply</name>
+ <fsummary>Handle agent</fsummary>
+ <type>
+ <v>Addr = ip_address()</v>
+ <v>Port = integer()</v>
+ <v>Type = pdu | trap | report | inform</v>
+ <v>SnmpInfo = SnmpPduInfo | SnmpTrapInfo | SnmpReportInfo | SnmpInformInfo</v>
+ <v>ErrorStatus = atom()</v>
+ <v>ErrorIndex = integer()</v>
+ <v>Varbinds = [varbind()]</v>
+ <v>varbind() = #varbind</v>
+ <v>UserData = term()</v>
+ <v>Reply = ignore | {register, UserId, TargetName, agent_info()}</v>
+ <v>UserId = term()</v>
+ <v>TargetName = target_name()</v>
+ <v>agent_info() = [{agent_info_item(), agent_info_value()}]</v>
+ </type>
+ <desc>
+ <p>This function is called when a message is received from an
+ unknown agent.</p>
+ <p>Note that this will always be the default user that is called.</p>
+ <p>For more info about the <c>agent_info()</c>, see
+ <seealso marker="snmpm#register_agent">register_agent</seealso>.</p>
+
+ <p>The arguments <c>Type</c> and <c>SnmpInfo</c> relates in the
+ following way: </p>
+
+ <list type="bulleted">
+ <item>
+ <p><c>pdu</c> - <c>SnmpPduInfo</c>
+ (see <seealso marker="#handle_pdu">handle_pdu</seealso>
+ for more info).</p>
+ </item>
+ <item>
+ <p><c>trap</c> - <c>SnmpTrapInfo</c>
+ (see <seealso marker="#handle_trap">handle_trap</seealso>
+ for more info).</p>
+ </item>
+ <item>
+ <p><c>report</c> - <c>SnmpReportInfo</c>
+ (see <seealso marker="#handle_report">handle_report</seealso>
+ for more info).</p>
+ </item>
+ <item>
+ <p><c>inform</c> - <c>SnmpInformInfo</c>
+ (see <seealso marker="#handle_inform">handle_inform</seealso>
+ for more info).</p>
+ </item>
+ </list>
+
+ <p>The only user which would return
+ <c>{register, UserId, TargetName, agent_info()}</c> is the
+ <em>default user</em>.</p>
+
+ <marker id="handle_pdu"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>handle_pdu(TargetName, ReqId, SnmpPduInfo, UserData) -> Reply</name>
+ <fsummary>Handle the reply to an asynchronous request</fsummary>
+ <type>
+ <v>TargetName = target_name()</v>
+ <v>ReqId = term()</v>
+ <v>SnmpPduInfo = {ErrorStatus, ErrorIndex, Varbinds}</v>
+ <v>ErrorStatus = atom()</v>
+ <v>ErrorIndex = integer()</v>
+ <v>Varbinds = [varbind()]</v>
+ <v>varbind() = #varbind</v>
+ <v>UserData = term()</v>
+ <v>Reply = ignore</v>
+ </type>
+ <desc>
+ <p>Handle the reply to an asynchronous request, such as
+ <seealso marker="snmpm#async_get">async_get</seealso>,
+ <seealso marker="snmpm#async_get_next">async_get_next</seealso> or
+ <seealso marker="snmpm#async_set">async_set</seealso>.</p>
+ <p>It could also be a late reply to a synchronous request.</p>
+ <p><c>ReqId</c> is returned by the asynchronous request function.</p>
+
+ <marker id="handle_trap"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>handle_trap(TargetName, SnmpTrapInfo, UserData) -> Reply</name>
+ <fsummary>Handle a trap/notification message</fsummary>
+ <type>
+ <v>TargetName = TargetName2 = target_name()</v>
+ <v>SnmpTrapInfo = {Enteprise, Generic, Spec, Timestamp, Varbinds} | {ErrorStatus, ErrorIndex, Varbinds}</v>
+ <v>Enterprise = oid()</v>
+ <v>Generic = integer()</v>
+ <v>Spec = integer()</v>
+ <v>Timestamp = integer()</v>
+ <v>ErrorStatus = atom()</v>
+ <v>ErrorIndex = integer()</v>
+ <v>Varbinds = [varbind()]</v>
+ <v>varbind() = #varbind</v>
+ <v>UserData = term()</v>
+ <v>Reply = ignore | unregister | {register, UserId, TargetName2, agent_info()}</v>
+ <v>UserId = term()</v>
+ <v>agent_info() = [{agent_info_item(), agent_info_value()}]</v>
+ </type>
+ <desc>
+ <p>Handle a trap/notification message from an agent.</p>
+ <p>For more info about the <c>agent_info()</c>, see
+ <seealso marker="snmpm#register_agent">register_agent</seealso></p>
+ <p>The only user which would return
+ <c>{register, UserId, TargetName2, agent_info()}</c> is the
+ <em>default user</em>.</p>
+
+ <marker id="handle_inform"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>handle_inform(TargetName, SnmpInformInfo, UserData) -> Reply</name>
+ <fsummary>Handle a inform message</fsummary>
+ <type>
+ <v>TargetName = TargetName2 = target_name()</v>
+ <v>SnmpInformInfo = {ErrorStatus, ErrorIndex, Varbinds}</v>
+ <v>ErrorStatus = atom()</v>
+ <v>ErrorIndex = integer()</v>
+ <v>Varbinds = [varbind()]</v>
+ <v>varbind() = #varbind</v>
+ <v>UserData = term()</v>
+ <v>Reply = ignore | unregister | {register, UserId, TargetName2, agent_info()}</v>
+ <v>UserId = term()</v>
+ <v>agent_info() = [{agent_info_item(), agent_info_value()}]</v>
+ </type>
+ <desc>
+ <p>Handle a inform message.</p>
+ <p>For more info about the <c>agent_info()</c>, see
+ <seealso marker="snmpm#register_agent">register_agent</seealso></p>
+ <p>The only user which would return
+ <c>{register, UserId, TargetName2, agent_info()}</c> is the
+ <em>default user</em>.</p>
+ <p>If the
+ <seealso marker="snmp_app">inform request behaviour</seealso>
+ configuration option is set to <c>user</c> or
+ <c>{user, integer()}</c>, the response (acknowledgment) to this
+ inform-request will be sent when this function returns.</p>
+
+ <marker id="handle_report"></marker>
+ </desc>
+ </func>
+
+ <func>
+ <name>handle_report(TargetName, SnmpReportInfo, UserData) -> Reply</name>
+ <fsummary>Handle a report message</fsummary>
+ <type>
+ <v>TargetName = TargetName2 = target_name()</v>
+ <v>Addr = ip_address()</v>
+ <v>Port = integer()</v>
+ <v>SnmpReportInfo = {ErrorStatus, ErrorIndex, Varbinds}</v>
+ <v>ErrorStatus = atom()</v>
+ <v>ErrorIndex = integer()</v>
+ <v>Varbinds = [varbind()]</v>
+ <v>varbind() = #varbind</v>
+ <v>UserData = term()</v>
+ <v>Reply = ignore | unregister | {register, UserId, TargetName2, agent_info()}</v>
+ <v>UserId = term()</v>
+ <v>agent_info() = [{agent_info_item(), agent_info_value()}]</v>
+ </type>
+ <desc>
+ <p>Handle a report message.</p>
+ <p>For more info about the <c>agent_info()</c>, see
+ <seealso marker="snmpm#register_agent">register_agent</seealso></p>
+ <p>The only user which would return
+ <c>{register, UserId, TargetName2, agent_info()}</c> is the
+ <em>default user</em>.</p>
+ </desc>
+ </func>
+ </funcs>
+
+</erlref>
+
diff --git a/lib/snmp/doc/src/structure.fig b/lib/snmp/doc/src/structure.fig
new file mode 100644
index 0000000000..c7feff6f47
--- /dev/null
+++ b/lib/snmp/doc/src/structure.fig
@@ -0,0 +1,46 @@
+#FIG 3.1
+Landscape
+Center
+Inches
+1200 2
+6 5850 2400 8100 3075
+4 0 -1 0 0 0 12 0.0000 4 180 2025 5850 2550 (associate a MIB object with\001
+4 0 -1 0 0 0 12 0.0000 4 180 1815 5850 2775 snmp_generic:table_funct\001
+4 0 -1 0 0 0 12 0.0000 4 180 2055 5850 3000 snmp_generic:variable_func)\001
+-6
+2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2
+ 4200 3150 4200 3450
+2 2 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 5
+ 3600 1275 4800 1275 4800 1725 3600 1725 3600 1275
+2 2 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 5
+ 3600 1725 4800 1725 4800 2100 3600 2100 3600 1725
+2 1 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 2
+ 4200 2100 4200 2775
+2 2 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 5
+ 3000 3450 5400 3450 5400 3975 3000 3975 3000 3450
+2 2 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 5
+ 4200 3975 5400 3975 5400 4500 4200 4500 4200 3975
+2 2 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 5
+ 3000 5025 4200 5025 4200 5550 3000 5550 3000 5025
+2 2 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 5
+ 3000 3975 4200 3975 4200 4500 3000 4500 3000 3975
+2 2 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 5
+ 3000 4500 4200 4500 4200 5025 3000 5025 3000 4500
+2 2 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 5
+ 2400 900 8625 900 8625 6000 2400 6000 2400 900
+2 2 0 1 -1 7 0 0 -1 0.000 0 0 -1 0 0 5
+ 8625 6000 8625 6000 8625 6000 8625 6000 8625 6000
+4 0 -1 0 0 0 12 0.0000 4 135 1230 3525 3000 Assosiacition file\001
+4 0 -1 0 0 0 12 0.0000 4 180 990 3750 1575 SNMP Agent\001
+4 0 -1 0 0 0 12 0.0000 4 135 345 4050 1950 MIB\001
+4 0 -1 0 0 0 12 0.0000 4 180 1080 3075 4275 snmp_local_db\001
+4 0 -1 0 0 0 12 0.0000 4 135 525 4500 4275 Mnesia\001
+4 0 -1 0 0 0 12 0.0000 4 165 285 3450 4800 pets\001
+4 0 -1 0 0 0 12 0.0000 4 120 195 3450 5325 ets\001
+4 0 -1 0 0 0 12 0.0000 4 180 990 3600 3825 snmp_generic\001
+4 0 -1 0 0 0 12 0.0000 4 180 1530 5925 3600 Support for get-next,\001
+4 0 -1 0 0 0 12 0.0000 4 180 1560 5925 3825 RowStatus operations\001
+4 0 -1 0 0 0 12 0.0000 4 135 645 6000 4275 Database\001
+4 0 -1 0 0 0 12 0.0000 4 180 1860 6000 4800 Adds persistent properties\001
+4 0 -1 0 0 0 12 0.0000 4 120 375 6000 5025 to ets\001
+4 0 -1 0 0 0 12 0.0000 4 180 1995 6000 5475 The standard Erlang module\001
diff --git a/lib/snmp/doc/src/structure.gif b/lib/snmp/doc/src/structure.gif
new file mode 100644
index 0000000000..69ce000357
--- /dev/null
+++ b/lib/snmp/doc/src/structure.gif
Binary files differ
diff --git a/lib/snmp/doc/src/structure.ps b/lib/snmp/doc/src/structure.ps
new file mode 100644
index 0000000000..ffb345eb6a
--- /dev/null
+++ b/lib/snmp/doc/src/structure.ps
@@ -0,0 +1,170 @@
+%!PS-Adobe-2.0 EPSF-2.0
+%%Title: bild2.fig
+%%Creator: fig2dev Version 3.1 Patchlevel 2
+%%CreationDate: Mon Jan 3 10:34:34 2000
+%%For: nibe@gundor (Bengt Nilsson, ETX/DN/SP)
+%Magnification: 1.00
+%%Orientation: Portrait
+%%BoundingBox: 0 0 376 308
+%%Pages: 0
+%%BeginSetup
+%%IncludeFeature: *PageSize Letter
+%%EndSetup
+%%EndComments
+/$F2psDict 200 dict def
+$F2psDict begin
+$F2psDict /mtrx matrix put
+/col-1 {0 setgray} bind def
+/col0 {0.000 0.000 0.000 srgb} bind def
+/col1 {0.000 0.000 1.000 srgb} bind def
+/col2 {0.000 1.000 0.000 srgb} bind def
+/col3 {0.000 1.000 1.000 srgb} bind def
+/col4 {1.000 0.000 0.000 srgb} bind def
+/col5 {1.000 0.000 1.000 srgb} bind def
+/col6 {1.000 1.000 0.000 srgb} bind def
+/col7 {1.000 1.000 1.000 srgb} bind def
+/col8 {0.000 0.000 0.560 srgb} bind def
+/col9 {0.000 0.000 0.690 srgb} bind def
+/col10 {0.000 0.000 0.820 srgb} bind def
+/col11 {0.530 0.810 1.000 srgb} bind def
+/col12 {0.000 0.560 0.000 srgb} bind def
+/col13 {0.000 0.690 0.000 srgb} bind def
+/col14 {0.000 0.820 0.000 srgb} bind def
+/col15 {0.000 0.560 0.560 srgb} bind def
+/col16 {0.000 0.690 0.690 srgb} bind def
+/col17 {0.000 0.820 0.820 srgb} bind def
+/col18 {0.560 0.000 0.000 srgb} bind def
+/col19 {0.690 0.000 0.000 srgb} bind def
+/col20 {0.820 0.000 0.000 srgb} bind def
+/col21 {0.560 0.000 0.560 srgb} bind def
+/col22 {0.690 0.000 0.690 srgb} bind def
+/col23 {0.820 0.000 0.820 srgb} bind def
+/col24 {0.500 0.190 0.000 srgb} bind def
+/col25 {0.630 0.250 0.000 srgb} bind def
+/col26 {0.750 0.380 0.000 srgb} bind def
+/col27 {1.000 0.500 0.500 srgb} bind def
+/col28 {1.000 0.630 0.630 srgb} bind def
+/col29 {1.000 0.750 0.750 srgb} bind def
+/col30 {1.000 0.880 0.880 srgb} bind def
+/col31 {1.000 0.840 0.000 srgb} bind def
+
+end
+save
+-143.0 361.0 translate
+1 -1 scale
+
+/cp {closepath} bind def
+/ef {eofill} bind def
+/gr {grestore} bind def
+/gs {gsave} bind def
+/sa {save} bind def
+/rs {restore} bind def
+/l {lineto} bind def
+/m {moveto} bind def
+/rm {rmoveto} bind def
+/n {newpath} bind def
+/s {stroke} bind def
+/sh {show} bind def
+/slc {setlinecap} bind def
+/slj {setlinejoin} bind def
+/slw {setlinewidth} bind def
+/srgb {setrgbcolor} bind def
+/rot {rotate} bind def
+/sc {scale} bind def
+/sd {setdash} bind def
+/ff {findfont} bind def
+/sf {setfont} bind def
+/scf {scalefont} bind def
+/sw {stringwidth} bind def
+/tr {translate} bind def
+/tnt {dup dup currentrgbcolor
+ 4 -2 roll dup 1 exch sub 3 -1 roll mul add
+ 4 -2 roll dup 1 exch sub 3 -1 roll mul add
+ 4 -2 roll dup 1 exch sub 3 -1 roll mul add srgb}
+ bind def
+/shd {dup dup currentrgbcolor 4 -2 roll mul 4 -2 roll mul
+ 4 -2 roll mul srgb} bind def
+/$F2psBegin {$F2psDict begin /$F2psEnteredState save def} def
+/$F2psEnd {$F2psEnteredState restore end} def
+%%EndProlog
+
+$F2psBegin
+10 setmiterlimit
+n 0 792 m 0 0 l 612 0 l 612 792 l cp clip
+ 0.06000 0.06000 sc
+/Times-Roman ff 180.00 scf sf
+5850 2550 m
+gs 1 -1 sc (\(associate a MIB object with) col-1 sh gr
+/Times-Roman ff 180.00 scf sf
+5850 2775 m
+gs 1 -1 sc (snmp_generic:table_funct) col-1 sh gr
+/Times-Roman ff 180.00 scf sf
+5850 3000 m
+gs 1 -1 sc (snmp_generic:variable_func\)) col-1 sh gr
+7.500 slw
+% Polyline
+n 4200 3150 m 4200 3450 l gs col-1 s gr
+% Polyline
+n 3600 1275 m 4800 1275 l 4800 1725 l 3600 1725 l cp gs col-1 s gr
+% Polyline
+n 3600 1725 m 4800 1725 l 4800 2100 l 3600 2100 l cp gs col-1 s gr
+% Polyline
+n 4200 2100 m 4200 2775 l gs col-1 s gr
+% Polyline
+n 3000 3450 m 5400 3450 l 5400 3975 l 3000 3975 l cp gs col-1 s gr
+% Polyline
+n 4200 3975 m 5400 3975 l 5400 4500 l 4200 4500 l cp gs col-1 s gr
+% Polyline
+n 3000 5025 m 4200 5025 l 4200 5550 l 3000 5550 l cp gs col-1 s gr
+% Polyline
+n 3000 3975 m 4200 3975 l 4200 4500 l 3000 4500 l cp gs col-1 s gr
+% Polyline
+n 3000 4500 m 4200 4500 l 4200 5025 l 3000 5025 l cp gs col-1 s gr
+% Polyline
+n 2400 900 m 8625 900 l 8625 6000 l 2400 6000 l cp gs col-1 s gr
+% Polyline
+n 8625 6000 m 8625 6000 l 8625 6000 l 8625 6000 l cp gs col-1 s gr
+/Times-Roman ff 180.00 scf sf
+3525 3000 m
+gs 1 -1 sc (Assosiacition file) col-1 sh gr
+/Times-Roman ff 180.00 scf sf
+3750 1575 m
+gs 1 -1 sc (SNMP Agent) col-1 sh gr
+/Times-Roman ff 180.00 scf sf
+4050 1950 m
+gs 1 -1 sc (MIB) col-1 sh gr
+/Times-Roman ff 180.00 scf sf
+3075 4275 m
+gs 1 -1 sc (snmp_local_db) col-1 sh gr
+/Times-Roman ff 180.00 scf sf
+4500 4275 m
+gs 1 -1 sc (Mnesia) col-1 sh gr
+/Times-Roman ff 180.00 scf sf
+3450 4800 m
+gs 1 -1 sc (pets) col-1 sh gr
+/Times-Roman ff 180.00 scf sf
+3450 5325 m
+gs 1 -1 sc (ets) col-1 sh gr
+/Times-Roman ff 180.00 scf sf
+3600 3825 m
+gs 1 -1 sc (snmp_generic) col-1 sh gr
+/Times-Roman ff 180.00 scf sf
+5925 3600 m
+gs 1 -1 sc (Support for get-next,) col-1 sh gr
+/Times-Roman ff 180.00 scf sf
+5925 3825 m
+gs 1 -1 sc (RowStatus operations) col-1 sh gr
+/Times-Roman ff 180.00 scf sf
+6000 4275 m
+gs 1 -1 sc (Database) col-1 sh gr
+/Times-Roman ff 180.00 scf sf
+6000 4800 m
+gs 1 -1 sc (Adds persistent properties) col-1 sh gr
+/Times-Roman ff 180.00 scf sf
+6000 5025 m
+gs 1 -1 sc (to ets) col-1 sh gr
+/Times-Roman ff 180.00 scf sf
+6000 5475 m
+gs 1 -1 sc (The standard Erlang module) col-1 sh gr
+$F2psEnd
+rs
diff --git a/lib/snmp/doc/src/summary.html.src b/lib/snmp/doc/src/summary.html.src
new file mode 100644
index 0000000000..9bad4adbeb
--- /dev/null
+++ b/lib/snmp/doc/src/summary.html.src
@@ -0,0 +1 @@
+Simple Network Management Protocol (SNMP) support including a MIB compiler, a simple SNMP manager and tools for creating SNMP agents
diff --git a/lib/snmp/doc/src/user_guide.gif b/lib/snmp/doc/src/user_guide.gif
new file mode 100644
index 0000000000..e6275a803d
--- /dev/null
+++ b/lib/snmp/doc/src/user_guide.gif
Binary files differ
diff --git a/lib/snmp/doc/src/warning.gif b/lib/snmp/doc/src/warning.gif
new file mode 100644
index 0000000000..96af52360e
--- /dev/null
+++ b/lib/snmp/doc/src/warning.gif
Binary files differ
diff --git a/lib/snmp/ebin/.gitignore b/lib/snmp/ebin/.gitignore
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/lib/snmp/ebin/.gitignore
diff --git a/lib/snmp/examples/Makefile b/lib/snmp/examples/Makefile
new file mode 100644
index 0000000000..341107ce30
--- /dev/null
+++ b/lib/snmp/examples/Makefile
@@ -0,0 +1,35 @@
+#-*-makefile-*- ; force emacs to enter makefile-mode
+
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2004-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%
+
+include $(ERL_TOP)/make/target.mk
+include $(ERL_TOP)/make/$(TARGET)/otp.mk
+
+# ----------------------------------------------------
+# Common Macros
+# ----------------------------------------------------
+
+include subdirs.mk
+
+SPECIAL_TARGETS =
+
+# ----------------------------------------------------
+# Default Subdir Targets
+# ----------------------------------------------------
+include $(ERL_TOP)/make/otp_subdir.mk
+
diff --git a/lib/snmp/examples/ex1/EX1-MIB.funcs b/lib/snmp/examples/ex1/EX1-MIB.funcs
new file mode 100644
index 0000000000..0ae1db6541
--- /dev/null
+++ b/lib/snmp/examples/ex1/EX1-MIB.funcs
@@ -0,0 +1,2 @@
+{myName, {ex1, my_name, []}}.
+{friendsTable, {ex1, friends_table, []}}.
diff --git a/lib/snmp/examples/ex1/EX1-MIB.mib b/lib/snmp/examples/ex1/EX1-MIB.mib
new file mode 100644
index 0000000000..5d9979d0b4
--- /dev/null
+++ b/lib/snmp/examples/ex1/EX1-MIB.mib
@@ -0,0 +1,90 @@
+ EX1-MIB DEFINITIONS ::= BEGIN
+
+ IMPORTS
+ experimental FROM RFC1155-SMI
+ RowStatus FROM STANDARD-MIB
+ DisplayString FROM RFC1213-MIB
+ OBJECT-TYPE FROM RFC-1212
+ ;
+
+ example1 OBJECT IDENTIFIER ::= { experimental 7 }
+
+
+ myName OBJECT-TYPE
+ SYNTAX DisplayString (SIZE (0..255))
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "My own name"
+ ::= { example1 1 }
+
+ friendsTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF FriendsEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A list of friends."
+ ::= { example1 4 }
+
+ friendsEntry OBJECT-TYPE
+ SYNTAX FriendsEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ ""
+ INDEX { fIndex }
+ ::= { friendsTable 1 }
+
+ FriendsEntry ::=
+ SEQUENCE {
+ fIndex
+ INTEGER,
+ fName
+ DisplayString,
+ fAddress
+ DisplayString,
+ fStatus
+ RowStatus }
+
+ fIndex OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "number of friend"
+ ::= { friendsEntry 1 }
+
+ fName OBJECT-TYPE
+ SYNTAX DisplayString (SIZE (0..255))
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "Name of friend"
+ ::= { friendsEntry 2 }
+
+ fAddress OBJECT-TYPE
+ SYNTAX DisplayString (SIZE (0..255))
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "Address of friend"
+ ::= { friendsEntry 3 }
+
+ fStatus OBJECT-TYPE
+ SYNTAX RowStatus
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The status of this conceptual row."
+ ::= { friendsEntry 4 }
+
+
+ fTrap TRAP-TYPE
+ ENTERPRISE example1
+ VARIABLES { myName, fIndex }
+ DESCRIPTION
+ "This trap is sent something happens to
+ the friend specified by fIndex."
+ ::= 1
+
+ END
diff --git a/lib/snmp/examples/ex1/EX1-MIBv2.funcs b/lib/snmp/examples/ex1/EX1-MIBv2.funcs
new file mode 100644
index 0000000000..0ae1db6541
--- /dev/null
+++ b/lib/snmp/examples/ex1/EX1-MIBv2.funcs
@@ -0,0 +1,2 @@
+{myName, {ex1, my_name, []}}.
+{friendsTable, {ex1, friends_table, []}}.
diff --git a/lib/snmp/examples/ex1/EX1-MIBv2.mib b/lib/snmp/examples/ex1/EX1-MIBv2.mib
new file mode 100644
index 0000000000..e7250c4a63
--- /dev/null
+++ b/lib/snmp/examples/ex1/EX1-MIBv2.mib
@@ -0,0 +1,104 @@
+EX1-MIBv2 DEFINITIONS ::= BEGIN
+
+IMPORTS
+ MODULE-IDENTITY, OBJECT-TYPE, NOTIFICATION-TYPE,
+ Integer32, snmpModules ,experimental
+ FROM SNMPv2-SMI
+ MODULE-COMPLIANCE, OBJECT-GROUP, NOTIFICATION-GROUP
+ FROM SNMPv2-CONF
+ DisplayString
+ FROM SNMPv2-TC
+ RowStatus
+ FROM STANDARD-MIB;
+
+
+exampleModule MODULE-IDENTITY
+ LAST-UPDATED "0005290000Z"
+ ORGANIZATION "Erlang"
+ CONTACT-INFO " test mib
+ Ericsson Utvecklings AB
+ Open System
+ Box 1505
+ SE-125 25 �LVSJ�"
+
+ DESCRIPTION
+ " Objects for management "
+ REVISION "0005290000Z"
+ DESCRIPTION
+ "The initial version"
+ ::= { snmpModules 1 }
+
+example1 OBJECT IDENTIFIER ::= { experimental 7}
+
+
+ myName OBJECT-TYPE
+ SYNTAX DisplayString
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "My own name"
+ ::= { example1 1 }
+
+ friendsTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF FriendsEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A list of friends."
+ ::= { example1 4 }
+
+ friendsEntry OBJECT-TYPE
+ SYNTAX FriendsEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ ""
+ INDEX { fIndex }
+ ::= { friendsTable 1 }
+
+ FriendsEntry ::= SEQUENCE {
+ fIndex INTEGER,
+ fName DisplayString,
+ fAddress DisplayString,
+ fStatus RowStatus
+ }
+
+ fIndex OBJECT-TYPE
+ SYNTAX INTEGER
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "number of friend"
+ ::= { friendsEntry 1 }
+
+ fName OBJECT-TYPE
+ SYNTAX DisplayString (SIZE (0..255))
+ MAX-ACCESS read-write
+ STATUS deprecated
+ DESCRIPTION
+ "Name of a friend"
+ ::= { friendsEntry 2 }
+
+ fAddress OBJECT-TYPE
+ SYNTAX DisplayString (SIZE (0..255))
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "Address of a friend"
+ ::= { friendsEntry 3 }
+
+ fStatus OBJECT-TYPE
+ SYNTAX RowStatus
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The status of this conceptual row."
+ ::= { friendsEntry 4 }
+
+friendGroup OBJECT-GROUP
+ OBJECTS { myName, fIndex, fName,fAddress, fStatus }
+ STATUS current
+ DESCRIPTION " A object group"
+ ::= { example1 2 }
+
+END
diff --git a/lib/snmp/examples/ex1/Makefile b/lib/snmp/examples/ex1/Makefile
new file mode 100644
index 0000000000..1a55ba0470
--- /dev/null
+++ b/lib/snmp/examples/ex1/Makefile
@@ -0,0 +1,97 @@
+#-*-makefile-*- ; force emacs to enter makefile-mode
+
+# %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%
+
+include $(ERL_TOP)/make/target.mk
+include $(ERL_TOP)/make/$(TARGET)/otp.mk
+
+# ----------------------------------------------------
+# Application version
+# ----------------------------------------------------
+include ../../vsn.mk
+
+VSN = $(SNMP_VSN)
+
+# ----------------------------------------------------
+# FLAGS
+# ----------------------------------------------------
+
+ifneq ($(MIBS_VERBOSITY),)
+SNMP_FLAGS += +'{verbosity,$(MIBS_VERBOSITY)}'
+endif
+
+ERL_COMPILE_FLAGS += -I../include \
+ -Dversion=\"$(VSN)$(PRE_VSN)\" \
+ +'{parse_transform,sys_pre_attributes}' \
+ +'{attribute,insert,app_vsn,$(APP_VSN)}' \
+ -I$(ERL_TOP)/lib/stdlib \
+ $(SNMP_FLAGS)
+
+# ----------------------------------------------------
+# Release directory specification
+# ----------------------------------------------------
+RELSYSDIR = $(RELEASE_PATH)/lib/snmp-$(VSN)
+EXAMPLE_RELSYSDIR = $(RELSYSDIR)/examples
+EX1_RELSYSDIR = $(EXAMPLE_RELSYSDIR)/ex1
+
+# ----------------------------------------------------
+# Common macros
+# ----------------------------------------------------
+
+ERL_FILES = ex1.erl
+MIB_FILES = EX1-MIB.funcs EX1-MIB.mib
+BUILD_MIBS = EX1-MIB
+
+TARGET_FILES= \
+ $(BUILD_MIBS:%=%.bin) \
+ $(ERL_FILES:%.erl=%.$(EMULATOR))
+
+
+# ----------------------------------------------------
+# Targets
+# ----------------------------------------------------
+
+debug opt: build
+
+clean:
+ rm -f $(TARGET_FILES)
+ rm -f core *~
+
+docs:
+
+build: $(TARGET_FILES)
+
+
+info:
+ @echo "TARGET_FILES: $(TARGET_FILES)"
+ @echo "EXAMPLE_FILES: $(EXAMPLE_FILES)"
+
+
+# ----------------------------------------------------
+# Release Target
+# ----------------------------------------------------
+include $(ERL_TOP)/make/otp_release_targets.mk
+
+release_spec: opt
+ $(INSTALL_DIR) $(EXAMPLE_RELSYSDIR)
+ $(INSTALL_DIR) $(EX1_RELSYSDIR)
+ $(INSTALL_DATA) $(MIB_FILES) $(EX1_RELSYSDIR)
+ $(INSTALL_DATA) $(ERL_FILES) $(EX1_RELSYSDIR)
+ $(INSTALL_DATA) $(TARGET_FILES) $(EX1_RELSYSDIR)
+
+release_docs_spec:
diff --git a/lib/snmp/examples/ex1/ex1.erl b/lib/snmp/examples/ex1/ex1.erl
new file mode 100644
index 0000000000..3618cd3b8c
--- /dev/null
+++ b/lib/snmp/examples/ex1/ex1.erl
@@ -0,0 +1,256 @@
+%%<copyright>
+%% <year>1996-2007</year>
+%% <holder>Ericsson AB, All Rights Reserved</holder>
+%%</copyright>
+%%<legalnotice>
+%% 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.
+%%
+%% The Initial Developer of the Original Code is Ericsson AB.
+%%</legalnotice>
+%%
+-module(ex1).
+
+%% External exports
+-export([start/0, my_name/1, my_name/2, friends_table/3]).
+
+%% Internal exports
+-export([init/0]).
+
+-define(status_col, 4).
+
+-define(active, 1).
+-define(notInService, 2).
+-define(notReady, 3).
+-define(createAndGo, 4). % Action; written, not read
+-define(createAndWait, 5). % Action; written, not read
+-define(destroy, 6). % Action; written, not read
+
+start() ->
+ spawn(ex1, init, []).
+
+
+%%----------------------------------------------------------------
+%% Instrumentation function for variable myName.
+%% Returns: (get) {value, Name}
+%% (set) noError
+%%----------------------------------------------------------------
+my_name(get) ->
+ ex1_server ! {self(), get_my_name},
+ Name = wait_answer(),
+ {value, Name}.
+
+my_name(set, NewName) ->
+ ex1_server ! {self(), {set_my_name, NewName}},
+ noError.
+
+%%----------------------------------------------------------------
+%% Instrumentation function for table friendsTable.
+%%----------------------------------------------------------------
+friends_table(get, RowIndex, Cols) ->
+ case get_row(RowIndex) of
+ {ok, Row} ->
+ get_cols(Cols, Row);
+ _ ->
+ {noValue, noSuchInstance}
+ end;
+
+friends_table(get_next, RowIndex, Cols) ->
+ case get_next_row(RowIndex) of
+ {ok, Row} ->
+ get_next_cols(Cols, Row);
+ _ ->
+ case get_next_row([]) of
+ {ok, Row} ->
+ % Get next cols from first row.
+ NewCols = add_one_to_cols(Cols),
+ get_next_cols(NewCols, Row);
+ _ ->
+ end_of_table(Cols)
+ end
+ end;
+
+%%----------------------------------------------------------------
+%% If RowStatus is set, then:
+%% *) If set to destroy, check that row does exist
+%% *) If set to createAndGo, check that row doesn't exist AND
+%% that all columns are given values.
+%% *) Otherwise, error (for simplicity).
+%% Otherwise, row is modified; check that row exists.
+%%----------------------------------------------------------------
+friends_table(is_set_ok, RowIndex, Cols) ->
+ RowExists =
+ case get_row(RowIndex) of
+ {ok, _Row} -> true;
+ _ -> false
+ end,
+ case is_row_status_col_changed(Cols) of
+ {true, ?destroy} when RowExists == true ->
+ {noError, 0};
+ {true, ?createAndGo} when RowExists == false,
+ length(Cols) == 3 ->
+ {noError, 0};
+ {true, _} ->
+ {inconsistentValue, ?status_col};
+ false when RowExists == true ->
+ {noError, 0};
+ _ ->
+ [{Col, _NewVal} | _Cols] = Cols,
+ {inconsistentName, Col}
+ end;
+
+friends_table(set, RowIndex, Cols) ->
+ case is_row_status_col_changed(Cols) of
+ {true, ?destroy} ->
+ ex1_server ! {self(), {delete_row, RowIndex}};
+ {true, ?createAndGo} ->
+ NewRow = make_row(RowIndex, Cols),
+ ex1_server ! {self(), {add_row, NewRow}};
+ false ->
+ {ok, Row} = get_row(RowIndex),
+ NewRow = merge_rows(Row, Cols),
+ ex1_server ! {self(), {delete_row, RowIndex}},
+ ex1_server ! {self(), {add_row, NewRow}}
+ end,
+ {noError, 0}.
+
+%%----------------------------------------------------------------
+%% Make a list of {value, Val} of the Row and Cols list.
+%%----------------------------------------------------------------
+get_cols([Col | Cols], Row) ->
+ [{value, element(Col, Row)} | get_cols(Cols, Row)];
+get_cols([], _Row) ->
+ [].
+
+%%----------------------------------------------------------------
+%% As get_cols, but the Cols list may contain invalid column
+%% numbers. If it does, we must find the next valid column,
+%% or return endOfTable.
+%%----------------------------------------------------------------
+get_next_cols([Col | Cols], Row) when Col < 2 ->
+ [{[2, element(1, Row)], element(2, Row)} |
+ get_next_cols(Cols, Row)];
+get_next_cols([Col | Cols], Row) when Col > 4 ->
+ [endOfTable |
+ get_next_cols(Cols, Row)];
+get_next_cols([Col | Cols], Row) ->
+ [{[Col, element(1, Row)], element(Col, Row)} |
+ get_next_cols(Cols, Row)];
+get_next_cols([], _Row) ->
+ [].
+
+%%----------------------------------------------------------------
+%% Make a list of endOfTable with as many elems as Cols list.
+%%----------------------------------------------------------------
+end_of_table([_Col | Cols]) ->
+ [endOfTable | end_of_table(Cols)];
+end_of_table([]) ->
+ [].
+
+add_one_to_cols([Col | Cols]) ->
+ [Col + 1 | add_one_to_cols(Cols)];
+add_one_to_cols([]) ->
+ [].
+
+is_row_status_col_changed(Cols) ->
+ case lists:keysearch(?status_col, 1, Cols) of
+ {value, {?status_col, StatusVal}} ->
+ {true, StatusVal};
+ _ -> false
+ end.
+
+get_row(RowIndex) ->
+ ex1_server ! {self(), {get_row, RowIndex}},
+ wait_answer().
+
+get_next_row(RowIndex) ->
+ ex1_server ! {self(), {get_next_row, RowIndex}},
+ wait_answer().
+
+wait_answer() ->
+ receive
+ {ex1_server, Answer} ->
+ Answer
+ end.
+
+%%%----------------------------------------------------------------
+%%% Server code follows
+%%%----------------------------------------------------------------
+init() ->
+ register(ex1_server, self()),
+ loop("", []).
+
+loop(MyName, Table) ->
+ receive
+ {From, get_my_name} ->
+ From ! {ex1_server, MyName},
+ loop(MyName, Table);
+ {_From, {set_my_name, NewName}} ->
+ loop(NewName, Table);
+ {From, {get_row, RowIndex}} ->
+ Res = table_get_row(Table, RowIndex),
+ From ! {ex1_server, Res},
+ loop(MyName, Table);
+ {From, {get_next_row, RowIndex}} ->
+ Res = table_get_next_row(Table, RowIndex),
+ From ! {ex1_server, Res},
+ loop(MyName, Table);
+ {_From, {delete_row, RowIndex}} ->
+ NewTable = table_delete_row(Table, RowIndex),
+ loop(MyName, NewTable);
+ {_From, {add_row, NewRow}} ->
+ NewTable = table_add_row(Table, NewRow),
+ loop(MyName, NewTable)
+ end.
+
+
+%%-----------------------------------------------------------------
+%% Implementation of the table.
+%%-----------------------------------------------------------------
+table_get_row([{Index, Name, Address, Status} | _], [Index]) ->
+ {ok, {Index, Name, Address, Status}};
+table_get_row([_H | T], RowIndex) ->
+ table_get_row(T, RowIndex);
+table_get_row([], _RowIndex) ->
+ no_such_row.
+
+table_get_next_row([Row | _T], []) ->
+ {ok, Row};
+table_get_next_row([Row | _T], [Index | _]) when element(1, Row) > Index ->
+ {ok, Row};
+table_get_next_row([_Row | T], RowIndex) ->
+ table_get_next_row(T, RowIndex);
+table_get_next_row([], _RowIndex) ->
+ endOfTable.
+
+table_delete_row([{Index, _, _, _} | T], [Index]) ->
+ T;
+table_delete_row([H | T], RowIndex) ->
+ [H | table_delete_row(T, RowIndex)];
+table_delete_row([], _RowIndex) ->
+ [].
+
+table_add_row([Row | T], NewRow) when element(1, Row) > element(1, NewRow) ->
+ [NewRow, Row | T];
+table_add_row([H | T], NewRow) ->
+ [H | table_add_row(T, NewRow)];
+table_add_row([], NewRow) ->
+ [NewRow].
+
+make_row([Index], [{2, Name}, {3, Address} | _]) ->
+ {Index, Name, Address, ?active}.
+
+merge_rows(Row, [{Col, NewVal} | T]) ->
+ merge_rows(setelement(Col, Row, NewVal), T);
+merge_rows(Row, []) ->
+ Row.
+
+
diff --git a/lib/snmp/examples/ex2/Makefile b/lib/snmp/examples/ex2/Makefile
new file mode 100644
index 0000000000..7fbd7f530b
--- /dev/null
+++ b/lib/snmp/examples/ex2/Makefile
@@ -0,0 +1,93 @@
+#-*-makefile-*- ; force emacs to enter makefile-mode
+
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2006-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%
+
+include $(ERL_TOP)/make/target.mk
+include $(ERL_TOP)/make/$(TARGET)/otp.mk
+
+# ----------------------------------------------------
+# Application version
+# ----------------------------------------------------
+include ../../vsn.mk
+
+VSN = $(SNMP_VSN)
+
+# ----------------------------------------------------
+# FLAGS
+# ----------------------------------------------------
+
+ifneq ($(MIBS_VERBOSITY),)
+SNMP_FLAGS += +'{verbosity,$(MIBS_VERBOSITY)}'
+endif
+
+ERL_COMPILE_FLAGS += -pa $(ERL_TOP)/lib/snmp/ebin
+ERL_COMPILE_FLAGS += -I../include \
+ -Dversion=\"$(VSN)$(PRE_VSN)\" \
+ +'{parse_transform,sys_pre_attributes}' \
+ +'{attribute,insert,app_vsn,$(APP_VSN)}' \
+ -I$(ERL_TOP)/lib/stdlib \
+ $(SNMP_FLAGS)
+
+# ----------------------------------------------------
+# Release directory specification
+# ----------------------------------------------------
+RELSYSDIR = $(RELEASE_PATH)/lib/snmp-$(VSN)
+EXAMPLE_RELSYSDIR = $(RELSYSDIR)/examples
+EX2_RELSYSDIR = $(EXAMPLE_RELSYSDIR)/ex2
+
+# ----------------------------------------------------
+# Common macros
+# ----------------------------------------------------
+
+MODULES = \
+ snmp_ex2_manager \
+ snmp_ex2_simple_standard_test
+
+ERL_FILES = $(MODULES:%=%.erl)
+
+TARGET_FILES= \
+ $(ERL_FILES:%.erl=%.$(EMULATOR))
+
+
+# ----------------------------------------------------
+# Targets
+# ----------------------------------------------------
+
+debug opt: build
+
+clean:
+ rm -f $(TARGET_FILES)
+ rm -f core *~
+
+docs:
+
+build: $(TARGET_FILES)
+
+
+# ----------------------------------------------------
+# Release Target
+# ----------------------------------------------------
+include $(ERL_TOP)/make/otp_release_targets.mk
+
+release_spec: opt
+ $(INSTALL_DIR) $(EXAMPLE_RELSYSDIR)
+ $(INSTALL_DIR) $(EX2_RELSYSDIR)
+ $(INSTALL_DATA) $(ERL_FILES) $(EX2_RELSYSDIR)
+ $(INSTALL_DATA) $(TARGET_FILES) $(EX2_RELSYSDIR)
+
+release_docs_spec:
diff --git a/lib/snmp/examples/ex2/snmp_ex2_manager.erl b/lib/snmp/examples/ex2/snmp_ex2_manager.erl
new file mode 100644
index 0000000000..79cfd94469
--- /dev/null
+++ b/lib/snmp/examples/ex2/snmp_ex2_manager.erl
@@ -0,0 +1,407 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2006-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%
+%%
+%%----------------------------------------------------------------------
+%% This module examplifies how to write test suites for your SNMP agent.
+%%----------------------------------------------------------------------
+
+-module(snmp_ex2_manager).
+
+-behaviour(gen_server).
+-behaviour(snmpm_user).
+
+-export([start_link/0, start_link/1, stop/0,
+ agent/2,
+ sync_get/2,
+ sync_get_next/2,
+ sync_get_bulk/4,
+ sync_set/2,
+
+ oid_to_name/1
+ ]).
+
+%% Manager callback API:
+-export([handle_error/3,
+ handle_agent/4,
+ handle_pdu/4,
+ handle_trap/3,
+ handle_inform/3,
+ handle_report/3]).
+
+%% gen_server callbacks
+-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
+ code_change/3, terminate/2]).
+
+-include_lib("snmp/include/snmp_types.hrl").
+
+
+-define(SERVER, ?MODULE).
+-define(USER, ?MODULE).
+-define(USER_MOD, ?MODULE).
+
+-record(state, {parent}).
+
+
+%%%-------------------------------------------------------------------
+%%% API
+%%%-------------------------------------------------------------------
+
+start_link() ->
+ start_link([]).
+
+start_link(Opts) when is_list(Opts) ->
+ gen_server:start_link({local, ?SERVER}, ?MODULE, [self(), Opts], []).
+
+stop() ->
+ cast(stop).
+
+
+%% --- Instruct manager to handle an agent ---
+
+agent(TargetName, Conf) ->
+ call({agent, TargetName, Conf}).
+
+
+%% --- Various SNMP operations ----
+
+sync_get(TargetName, Oids) ->
+ call({sync_get, TargetName, Oids}).
+
+sync_get_next(TargetName, Oids) ->
+ call({sync_get_next, TargetName, Oids}).
+
+sync_get_bulk(TargetName, NR, MR, Oids) ->
+ call({sync_get_bulk, TargetName, NR, MR, Oids}).
+
+sync_set(TargetName, VarsAndVals) ->
+ call({sync_set, TargetName, VarsAndVals}).
+
+
+%% --- Misc utility functions ---
+
+oid_to_name(Oid) ->
+ call({oid_to_name, Oid}).
+
+
+%%%-------------------------------------------------------------------
+%%% Callback functions from gen_server
+%%%-------------------------------------------------------------------
+
+init([Parent, Opts]) ->
+ process_flag(trap_exit, true),
+ case (catch do_init(Opts)) of
+ {ok, State} ->
+ {ok, State#state{parent = Parent}};
+ {error, Reason} ->
+ {stop, Reason};
+ Crap ->
+ {stop, Crap}
+ end.
+
+do_init(Opts) ->
+ {Dir, MgrConf, MgrOpts} = parse_opts(Opts),
+ write_config(Dir, MgrConf),
+ start_manager(MgrOpts),
+ register_user(),
+ {ok, #state{}}.
+
+write_config(Dir, Conf) ->
+ case snmp_config:write_manager_config(Dir, "", Conf) of
+ ok ->
+ ok;
+ Error ->
+ error({failed_writing_config, Error})
+ end.
+
+start_manager(Opts) ->
+ case snmpm:start_link(Opts) of
+ ok ->
+ ok;
+ Error ->
+ error({failed_starting_manager, Error})
+ end.
+
+register_user() ->
+ case snmpm:register_user(?USER, ?USER_MOD, self()) of
+ ok ->
+ ok;
+ Error ->
+ error({failed_register_user, Error})
+ end.
+
+parse_opts(Opts) ->
+ Port = get_opt(port, Opts, 5000),
+ EngineId = get_opt(engine_id, Opts, "mgrEngine"),
+ MMS = get_opt(max_message_size, Opts, 484),
+
+ MgrConf = [{port, Port},
+ {engine_id, EngineId},
+ {max_message_size, MMS}],
+
+ %% Manager options
+ Mibs = get_opt(mibs, Opts, []),
+ Vsns = get_opt(versions, Opts, [v1, v2, v3]),
+ {ok, Cwd} = file:get_cwd(),
+ Dir = get_opt(dir, Opts, Cwd),
+ MgrOpts = [{mibs, Mibs},
+ {versions, Vsns},
+ %% {server, [{verbosity, trace}]},
+ {config, [% {verbosity, trace},
+ {dir, Dir}, {db_dir, Dir}]}],
+
+ {Dir, MgrConf, MgrOpts}.
+
+
+%%--------------------------------------------------------------------
+%% Func: handle_call/3
+%% Returns: {reply, Reply, State} |
+%% {reply, Reply, State, Timeout} |
+%% {noreply, State} |
+%% {noreply, State, Timeout} |
+%% {stop, Reason, Reply, State} | (terminate/2 is called)
+%% {stop, Reason, State} (terminate/2 is called)
+%%--------------------------------------------------------------------
+
+handle_call({agent, TargetName, Conf}, _From, S) ->
+ Reply = (catch snmpm:register_agent(?USER, TargetName, Conf)),
+ {reply, Reply, S};
+
+handle_call({oid_to_name, Oid}, _From, S) ->
+ Reply = (catch snmpm:oid_to_name(Oid)),
+ {reply, Reply, S};
+
+handle_call({sync_get, TargetName, Oids}, _From, S) ->
+ Reply = (catch snmpm:sync_get(?USER, TargetName, Oids)),
+ {reply, Reply, S};
+
+handle_call({sync_get_next, TargetName, Oids}, _From, S) ->
+ Reply = (catch snmpm:sync_get_next(?USER, TargetName, Oids)),
+ {reply, Reply, S};
+
+handle_call({sync_get_bulk, TargetName, NR, MR, Oids}, _From, S) ->
+ Reply = (catch snmpm:sync_get_bulk(?USER, TargetName, NR, MR, Oids)),
+ {reply, Reply, S};
+
+handle_call({sync_set, TargetName, VarsAndVals}, _From, S) ->
+ Reply = (catch snmpm:sync_set(?USER, TargetName, VarsAndVals)),
+ {reply, Reply, S};
+
+handle_call(Req, From, State) ->
+ error_msg("received unknown request ~n~p~nFrom ~p", [Req, From]),
+ {reply, {error, {unknown_request, Req}}, State}.
+
+
+%%--------------------------------------------------------------------
+%% Func: handle_cast/2
+%% Returns: {noreply, State} |
+%% {noreply, State, Timeout} |
+%% {stop, Reason, State} (terminate/2 is called)
+%%--------------------------------------------------------------------
+handle_cast(stop, S) ->
+ (catch snmpm:stop()),
+ {stop, normal, S};
+
+handle_cast(Msg, State) ->
+ error_msg("received unknown message ~n~p", [Msg]),
+ {noreply, State}.
+
+
+%%--------------------------------------------------------------------
+%% Func: handle_info/2
+%% Returns: {noreply, State} |
+%% {noreply, State, Timeout} |
+%% {stop, Reason, State} (terminate/2 is called)
+%%--------------------------------------------------------------------
+handle_info({snmp_callback, Tag, Info}, State) ->
+ handle_snmp_callback(Tag, Info),
+ {noreply, State};
+
+handle_info(Info, State) ->
+ error_msg("received unknown info: "
+ "~n Info: ~p", [Info]),
+ {noreply, State}.
+
+
+%%--------------------------------------------------------------------
+%% Func: terminate/2
+%% Purpose: Shutdown the server
+%% Returns: any (ignored by gen_server)
+%%--------------------------------------------------------------------
+terminate(_Reason, _State) ->
+ ok.
+
+
+code_change({down, _Vsn}, State, _Extra) ->
+ {ok, State};
+
+% upgrade
+code_change(_Vsn, State, _Extra) ->
+ {ok, State}.
+
+
+%% ========================================================================
+%% ========================================================================
+
+handle_snmp_callback(handle_error, {ReqId, Reason}) ->
+ io:format("*** FAILURE ***"
+ "~n Request Id: ~p"
+ "~n Reason: ~p"
+ "~n", [ReqId, Reason]),
+ ok;
+handle_snmp_callback(handle_agent, {Addr, Port, SnmpInfo}) ->
+ {ES, EI, VBs} = SnmpInfo,
+ io:format("*** UNKNOWN AGENT ***"
+ "~n Address: ~p"
+ "~n Port: ~p"
+ "~n SNMP Info: "
+ "~n Error Status: ~w"
+ "~n Error Index: ~w"
+ "~n Varbinds: ~p"
+ "~n", [Addr, Port, ES, EI, VBs]),
+ ok;
+handle_snmp_callback(handle_pdu, {TargetName, ReqId, SnmpResponse}) ->
+ {ES, EI, VBs} = SnmpResponse,
+ io:format("*** Received PDU ***"
+ "~n TargetName: ~p"
+ "~n Request Id: ~p"
+ "~n SNMP response:"
+ "~n Error Status: ~w"
+ "~n Error Index: ~w"
+ "~n Varbinds: ~p"
+ "~n", [TargetName, ReqId, ES, EI, VBs]),
+ ok;
+handle_snmp_callback(handle_trap, {TargetName, SnmpTrap}) ->
+ TrapStr =
+ case SnmpTrap of
+ {Enteprise, Generic, Spec, Timestamp, Varbinds} ->
+ io_lib:format("~n Generic: ~w"
+ "~n Exterprise: ~w"
+ "~n Specific: ~w"
+ "~n Timestamp: ~w"
+ "~n Varbinds: ~p",
+ [Generic, Enteprise, Spec, Timestamp, Varbinds]);
+ {ErrorStatus, ErrorIndex, Varbinds} ->
+ io_lib:format("~n Error Status: ~w"
+ "~n Error Index: ~w"
+ "~n Varbinds: ~p"
+ "~n", [ErrorStatus, ErrorIndex, Varbinds])
+ end,
+ io:format("*** Received TRAP ***"
+ "~n TargetName: ~p"
+ "~n SNMP trap: ~s"
+ "~n", [TargetName, lists:flatten(TrapStr)]),
+ ok;
+handle_snmp_callback(handle_inform, {TargetName, SnmpInform}) ->
+ {ES, EI, VBs} = SnmpInform,
+ io:format("*** Received INFORM ***"
+ "~n TargetName: ~p"
+ "~n SNMP inform: "
+ "~n Error Status: ~w"
+ "~n Error Index: ~w"
+ "~n Varbinds: ~p"
+ "~n", [TargetName, ES, EI, VBs]),
+ ok;
+handle_snmp_callback(handle_report, {TargetName, SnmpReport}) ->
+ {ES, EI, VBs} = SnmpReport,
+ io:format("*** Received REPORT ***"
+ "~n TargetName: ~p"
+ "~n SNMP report: "
+ "~n Error Status: ~w"
+ "~n Error Index: ~w"
+ "~n Varbinds: ~p"
+ "~n", [TargetName, ES, EI, VBs]),
+ ok;
+handle_snmp_callback(BadTag, Crap) ->
+ io:format("*** Received crap ***"
+ "~n ~p"
+ "~n ~p"
+ "~n", [BadTag, Crap]),
+ ok.
+
+
+
+error(Reason) ->
+ throw({error, Reason}).
+
+
+error_msg(F, A) ->
+ catch error_logger:error_msg("*** TEST-MANAGER: " ++ F ++ "~n", A).
+
+
+call(Req) ->
+ gen_server:call(?SERVER, Req, infinity).
+
+cast(Msg) ->
+ gen_server:cast(?SERVER, Msg).
+
+
+%% ========================================================================
+%% Misc internal utility functions
+%% ========================================================================
+
+%% get_opt(Key, Opts) ->
+%% case lists:keysearch(Key, 1, Opts) of
+%% {value, {Key, Val}} ->
+%% Val;
+%% false ->
+%% throw({error, {missing_mandatory, Key}})
+%% end.
+
+get_opt(Key, Opts, Def) ->
+ case lists:keysearch(Key, 1, Opts) of
+ {value, {Key, Val}} ->
+ Val;
+ false ->
+ Def
+ end.
+
+
+%% ========================================================================
+%% SNMPM user callback functions
+%% ========================================================================
+
+handle_error(ReqId, Reason, Server) when is_pid(Server) ->
+ report_callback(Server, handle_error, {ReqId, Reason}),
+ ignore.
+
+
+handle_agent(Addr, Port, SnmpInfo, Server) when is_pid(Server) ->
+ report_callback(Server, handle_agent, {Addr, Port, SnmpInfo}),
+ ignore.
+
+
+handle_pdu(TargetName, ReqId, SnmpResponse, Server) when is_pid(Server) ->
+ report_callback(Server, handle_pdu, {TargetName, ReqId, SnmpResponse}),
+ ignore.
+
+
+handle_trap(TargetName, SnmpTrap, Server) when is_pid(Server) ->
+ report_callback(Server, handle_trap, {TargetName, SnmpTrap}),
+ ok.
+
+handle_inform(TargetName, SnmpInform, Server) when is_pid(Server) ->
+ report_callback(Server, handle_inform, {TargetName, SnmpInform}),
+ ok.
+
+
+handle_report(TargetName, SnmpReport, Server) when is_pid(Server) ->
+ report_callback(Server, handle_inform, {TargetName, SnmpReport}),
+ ok.
+
+report_callback(Pid, Tag, Info) ->
+ Pid ! {snmp_callback, Tag, Info}.
diff --git a/lib/snmp/examples/ex2/snmp_ex2_simple_standard_test.erl b/lib/snmp/examples/ex2/snmp_ex2_simple_standard_test.erl
new file mode 100644
index 0000000000..16fe79d1a5
--- /dev/null
+++ b/lib/snmp/examples/ex2/snmp_ex2_simple_standard_test.erl
@@ -0,0 +1,287 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2006-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%
+%%
+%%----------------------------------------------------------------------
+%% This module examplifies how to write test suites for your SNMP agent.
+%%----------------------------------------------------------------------
+
+-module(snmp_ex2_simple_standard_test).
+
+-export([start/0, start/1, start/3]).
+
+-include_lib("snmp/include/snmp_types.hrl").
+
+%% -define(USER, agent_tester).
+%% -define(USER_MOD, ?MODULE).
+%% -define(USER_MOD, snmpm_user_default).
+
+-record(command, {tag, desc, cmd, verify}).
+
+start() ->
+ {ok, Hostname} = inet:gethostname(),
+ {ok, Addr} = inet:getaddr(Hostname, inet),
+ start(Addr).
+
+start(Addr) ->
+ start([std_mib("STANDARD-MIB")], Addr, [{community, "public"}]).
+
+start(Mibs, AgentAddr, AgentConfig) ->
+ Conf = [{mibs, Mibs}],
+ {ok, _Pid} = snmp_ex2_manager:start_link(Conf),
+ snmp_ex2_manager:agent(AgentAddr, AgentConfig),
+ simple_standard_test(AgentAddr),
+ snmp_ex2_manager:stop().
+
+simple_standard_test(AgentAddr) ->
+ Commands =
+ [
+ #command{tag = 1,
+ desc = "get-next [1,1]",
+ cmd = fun() ->
+ gn(AgentAddr, [1,1])
+ end,
+ verify = fun({ok, Res, _}) ->
+ verify_vbs(Res,
+ [{sysDescr, 'OCTET STRING'}]);
+ ({error, Reason}) ->
+ {error, {command_failed, Reason}};
+ (Crap) ->
+ {error, {unexpected_command_result, Crap}}
+ end},
+ #command{tag = 2,
+ desc = "get-next [1,3]",
+ cmd = fun() ->
+ gn(AgentAddr, [1,3])
+ end,
+ verify = fun({ok, Res, _}) ->
+ verify_vbs(Res,
+ [{sysDescr, 'OCTET STRING'}]);
+ ({error, Reason}) ->
+ {error, {command_failed, Reason}};
+ (Crap) ->
+ {error, {unexpected_command_result, Crap}}
+ end},
+ #command{tag = 3,
+ desc = "get-next [1,3,6]",
+ cmd = fun() ->
+ gn(AgentAddr, [1,3,6])
+ end,
+ verify = fun({ok, Res, _}) ->
+ verify_vbs(Res,
+ [{sysDescr, 'OCTET STRING'}]);
+ ({error, Reason}) ->
+ {error, {command_failed, Reason}};
+ (Crap) ->
+ {error, {unexpected_command_result, Crap}}
+ end},
+ #command{tag = 4,
+ desc = "get-next [1,3,6]",
+ cmd = fun() ->
+ gn(AgentAddr, [1,3,6,1])
+ end,
+ verify = fun({ok, Res, _}) ->
+ verify_vbs(Res,
+ [{sysDescr, 'OCTET STRING'}]);
+ ({error, Reason}) ->
+ {error, {command_failed, Reason}};
+ (Crap) ->
+ {error, {unexpected_command_result, Crap}}
+ end},
+ #command{tag = 5,
+ desc = "get-next [1,3,6,1,2]",
+ cmd = fun() ->
+ gn(AgentAddr, [1,3,6])
+ end,
+ verify = fun({ok, Res, _}) ->
+ verify_vbs(Res,
+ [{sysDescr, 'OCTET STRING'}]);
+ ({error, Reason}) ->
+ {error, {command_failed, Reason}};
+ (Crap) ->
+ {error, {unexpected_command_result, Crap}}
+ end},
+ #command{tag = 6,
+ desc = "get-next [1,3,6,1,2,1]",
+ cmd = fun() ->
+ gn(AgentAddr, [1,3,6])
+ end,
+ verify = fun({ok, Res, _}) ->
+ verify_vbs(Res,
+ [{sysDescr, 'OCTET STRING'}]);
+ ({error, Reason}) ->
+ {error, {command_failed, Reason}};
+ (Crap) ->
+ {error, {unexpected_command_result, Crap}}
+ end},
+ #command{tag = 7,
+ desc = "get-next [1,3,6,1,2,1,1]",
+ cmd = fun() ->
+ gn(AgentAddr, [1,3,6])
+ end,
+ verify = fun({ok, Res, _}) ->
+ verify_vbs(Res,
+ [{sysDescr, 'OCTET STRING'}]);
+ ({error, Reason}) ->
+ {error, {command_failed, Reason}};
+ (Crap) ->
+ {error, {unexpected_command_result, Crap}}
+ end},
+ #command{tag = 8,
+ desc = "get-next [1,3,6,1,2,1,1,1]",
+ cmd = fun() ->
+ gn(AgentAddr, [1,3,6])
+ end,
+ verify = fun({ok, Res, _}) ->
+ verify_vbs(Res,
+ [{sysDescr, 'OCTET STRING'}]);
+ ({error, Reason}) ->
+ {error, {command_failed, Reason}};
+ (Crap) ->
+ {error, {unexpected_command_result, Crap}}
+ end},
+ #command{tag = 9,
+ desc = "get [sysDescr,0]",
+ cmd = fun() ->
+ g(AgentAddr, [sysDescr,0])
+ end,
+ verify = fun({ok, Res, _}) ->
+ verify_vbs(Res,
+ [{sysDescr, 'OCTET STRING'}]);
+ ({error, Reason}) ->
+ {error, {command_failed, Reason}};
+ (Crap) ->
+ {error, {unexpected_command_result, Crap}}
+ end},
+ #command{tag = 10,
+ desc = "get [1,3,6,1,2,1,1,1]",
+ cmd = fun() ->
+ g(AgentAddr, [1,3,6,1,2,1,1,1])
+ end,
+ verify = fun({ok, {noError, 0, [Vb]}, _}) ->
+ case Vb of
+ #varbind{oid = [1,3,6,1,2,1,1,1],
+ value = noSuchInstance} ->
+ {ok,
+ lists:flatten(
+ io_lib:format("~n noSuchInstance", []))};
+ #varbind{oid = [1,3,6,1,2,1,1,1],
+ value = noSuchName} ->
+ {ok,
+ lists:flatten(
+ io_lib:format("~n noSuchName",
+ []))};
+ _ ->
+ {error, {unexpected_vb, Vb}}
+ end;
+ ({error, Reason}) ->
+ {error, {command_failed, Reason}};
+ (Crap) ->
+ {error, {unexpected_command_result, Crap}}
+ end}
+ ],
+ ok = commands(Commands),
+ io:format("Test completed.~n").
+
+
+commands([]) ->
+ ok;
+commands([#command{tag = Tag,
+ desc = Desc,
+ cmd = Cmd,
+ verify = Verify}|Commands]) ->
+ io:format("Command ~2w (~s): ", [Tag, Desc]),
+ case Verify((catch Cmd())) of
+ {ok, Val} ->
+ io:format("ok~s~n", [Val]),
+ ok;
+ {error, Reason} ->
+ io:format("error"
+ "~n ~p"
+ "~n", [Reason])
+ end,
+ commands(Commands).
+
+
+%% --- Command shorts ---
+
+gn(Addr, [H|_] = Oids) when is_list(H) ->
+ snmp_ex2_manager:sync_get_next(Addr, Oids);
+gn(Addr, Oid) ->
+ gn(Addr, [Oid]).
+
+g(Addr, [H|_] = Oids) when is_list(H) ->
+ snmp_ex2_manager:sync_get(Addr, Oids);
+g(Addr, Oid) ->
+ g(Addr, [Oid]).
+
+
+%% Verify that all varbinds have the expected name and type
+verify_vbs({noError, 0, Vbs}, NameAndTypes) ->
+ (catch verify_vbs(Vbs, NameAndTypes, ""));
+verify_vbs(Res, _) ->
+ {error, {unexpected_result, Res}}.
+
+verify_vbs([], _, Acc) ->
+ {ok, Acc};
+verify_vbs([Vb|T], NameAndTypes, Acc) ->
+ Val = verify_vb(Vb, NameAndTypes),
+ Acc2 = lists:flatten(io_lib:format("~s~n ~s", [Acc, Val])),
+ verify_vbs(T, NameAndTypes, Acc2).
+
+verify_vb(#varbind{oid = Oid, variabletype = Type, value = Val} = Vb,
+ NameAndTypes) ->
+ case lists:reverse(Oid) of
+ [0|RevOid] ->
+ case snmp_ex2_manager:oid_to_name(lists:reverse(RevOid)) of
+ {ok, Name} ->
+ case lists:keysearch(Name, 1, NameAndTypes) of
+ {value, {Name, Type}} ->
+ Val;
+ {value, {Name, WrongType}} ->
+ error({wrong_type, {WrongType, Vb}});
+ false ->
+ error({unexpected_name, {Name, Vb}})
+ end;
+ {error, Reason} ->
+ error({unexpected_oid, {Reason, Vb}})
+ end;
+ _ ->
+ case lists:keysearch(Oid, 1, NameAndTypes) of
+ {value, {Oid, Type}} ->
+ Val;
+ {value, {Oid, WrongType}} ->
+ error({wrong_type, {WrongType, Vb}});
+ false ->
+ error({unexpected_oid, Vb})
+ end
+ end.
+
+
+std_mib(MibName) ->
+ j(std_dir(), MibName).
+
+std_dir() -> j(code:priv_dir(snmp), "mibs").
+
+j(Dir, Filename) ->
+ filename:join(Dir, Filename).
+
+
+error(Reason) ->
+ throw({error, Reason}).
+
+
diff --git a/lib/snmp/examples/mcli/.gitignore b/lib/snmp/examples/mcli/.gitignore
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/lib/snmp/examples/mcli/.gitignore
diff --git a/lib/snmp/examples/subdirs.mk b/lib/snmp/examples/subdirs.mk
new file mode 100644
index 0000000000..9f4b69951e
--- /dev/null
+++ b/lib/snmp/examples/subdirs.mk
@@ -0,0 +1,21 @@
+#-*-makefile-*- ; force emacs to enter makefile-mode
+
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2004-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%
+
+SUB_DIRECTORIES = ex1 ex2
+
diff --git a/lib/snmp/include/SNMPv2-TC.hrl b/lib/snmp/include/SNMPv2-TC.hrl
new file mode 100644
index 0000000000..231be39220
--- /dev/null
+++ b/lib/snmp/include/SNMPv2-TC.hrl
@@ -0,0 +1,52 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2004-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%
+%%
+
+%% This file was automatically generated by snmp_mib_to_hrl v3.0
+%% Date: 22-Jan-2004::15:38:42
+
+-ifndef('SNMPv2-TC').
+-define('SNMPv2-TC', true).
+
+-define(snmpv2TC, [1,3,6,1,6,3,0]).
+
+%% Range values
+
+
+%% Definitions from 'StorageType'
+-define('StorageType_readOnly', 5).
+-define('StorageType_permanent', 4).
+-define('StorageType_nonVolatile', 3).
+-define('StorageType_volatile', 2).
+-define('StorageType_other', 1).
+
+%% Definitions from 'RowStatus'
+-define('RowStatus_destroy', 6).
+-define('RowStatus_createAndWait', 5).
+-define('RowStatus_createAndGo', 4).
+-define('RowStatus_notReady', 3).
+-define('RowStatus_notInService', 2).
+-define('RowStatus_active', 1).
+
+%% Definitions from 'TruthValue'
+-define('TruthValue_false', 2).
+-define('TruthValue_true', 1).
+
+%% Default values
+
+-endif.
diff --git a/lib/snmp/include/snmp_tables.hrl b/lib/snmp/include/snmp_tables.hrl
new file mode 100644
index 0000000000..4eea5ec282
--- /dev/null
+++ b/lib/snmp/include/snmp_tables.hrl
@@ -0,0 +1,109 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2004-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%
+%%
+
+%%-----------------------------------------------------------------
+%% This file contains the record definitions of the agent SNMP MIB
+%% tables to be used when creating the tables in Mnesia, for users
+%% that want to store this data in Mnesia rather than config files
+%% and ets/dets.
+%%-----------------------------------------------------------------
+
+-include("SNMPv2-TM.hrl").
+-include("SNMPv2-TC.hrl").
+
+-record(snmpCommunityTable,
+ {snmpCommunityIndex,
+ snmpCommunityName,
+ snmpCommunitySecurityName,
+ snmpCommunityContextEngineID,
+ snmpCommunityContextName = "",
+ snmpCommunityTransportTag,
+ snmpCommunityStorageType = ?StorageType_nonVolatile,
+ snmpCommunityStatus = ?RowStatus_active}).
+
+-record(snmpNotifyTable,
+ {snmpNotifyName,
+ snmpNotifyTag,
+ snmpNotifyType,
+ snmpNotifyStorageType = ?StorageType_nonVolatile,
+ snmpNotifyRowStatus = ?RowStatus_active}).
+
+-record(snmpTargetAddrTable,
+ {snmpTargetAddrName,
+ snmpTargetAddrTDomain = ?snmpUDPDomain,
+ snmpTargetAddrTAddress,
+ snmpTargetAddrTimeout = 1500,
+ snmpTargetAddrRetryCount = 3,
+ snmpTargetAddrTagList,
+ snmpTargetAddrParams,
+ snmpTargetAddrStorageType = ?StorageType_nonVolatile,
+ snmpTargetAddrRowStatus = ?RowStatus_active,
+ snmpTargetAddrEngineId = "", % not SNMP accessible
+ snmpTargetAddrTMask = [], % part of ext table
+ snmpTargetAddrMMS = 2048}). % part of ext table
+
+-record(snmpTargetParamsTable,
+ {snmpTargetParamsName,
+ snmpTargetParamsMPModel,
+ snmpTargetParamsSecurityModel,
+ snmpTargetParamsSecurityName,
+ snmpTargetParamsSecurityLevel,
+ snmpTargetParamsStorageType = ?StorageType_nonVolatile,
+ snmpTargetParamsRowStatus = ?RowStatus_active}).
+
+-record(usmUserTable,
+ {key, % {usmUserEngineID, usmUserName}
+ usmUserSecurityName,
+ usmUserCloneFrom,
+ usmUserAuthProtocol,
+ usmUserAuthKeyChange,
+ usmUserOwnAuthKeyChange,
+ usmUserPrivProtocol,
+ usmUserPrivKeyChange,
+ usmUserOwnPrivKeyChange,
+ usmUserPublic,
+ usmUserStorageType = ?StorageType_nonVolatile,
+ usmUserStatus = ?RowStatus_active,
+ authKey, % not SNMP accessible
+ privKey}). % not SNMP accessible
+
+-record(vacmSecurityToGroupTable,
+ {key, % {vacmSecurityModel, vacmSecurityName}
+ vacmGroupName,
+ vacmSecurityToGroupStorageType = ?StorageType_nonVolatile,
+ vacmSecurityToGroupStatus = ?RowStatus_active}).
+
+-record(vacmAccessTable,
+ {key, % {vacmGroupName, vacmAccessContextPrefix,
+ % vacmSecurityModel, vacmAccessSecurityLevel}
+ vacmAccessContextMatch,
+ vacmAccessReadViewName,
+ vacmAccessWriteViewName,
+ vacmAccessNotifyViewName,
+ vacmAccessStorageType = ?StorageType_nonVolatile,
+ vacmAccessStatus = ?RowStatus_active}).
+
+-record(vacmViewTreeFamilyTable,
+ {key, % {vacmViewTreeFamilyViewName, vacmViewTreeFamilySubtree}
+ vacmViewTreeFamilyMask,
+ vacmViewTreeFamilyType,
+ vacmViewTreeFamilyStorageType = ?StorageType_nonVolatile,
+ vacmViewTreeFamilyStatus = ?RowStatus_active}).
+
+
diff --git a/lib/snmp/include/snmp_types.hrl b/lib/snmp/include/snmp_types.hrl
new file mode 100644
index 0000000000..1fd6d153c9
--- /dev/null
+++ b/lib/snmp/include/snmp_types.hrl
@@ -0,0 +1,395 @@
+%%
+%% %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%
+%%
+
+%%----------------------------------------------------------------------
+%% Note: All internal representations may be changed without notice.
+%%----------------------------------------------------------------------
+
+%%----------------------------------------------------------------------
+%% Variablebinding
+%% oid: a list of integers (see snmp_misc:is_oid)
+%% variabletype corresponds to type in the asn1_type.
+%% variabletype=='NULL' =>
+%% value== 'NULL' | noSuchObject | noSuchInstance | endOfMibView
+%% else: variabletype == <one of the types defined in rfc1903>;
+%% 'INTEGER' | 'Integer32' | 'OCTET STRING' |
+%% 'OBJECT IDENTIFIER' | 'IpAddress' | 'Counter32' |
+%% 'TimeTicks' | 'Opaque' | 'Counter64' | 'Unsigned32'
+%% value: a value.
+%% org_index: an integer. Its position in the original varbindlist (the one
+%% from the get- or set-request).
+%%----------------------------------------------------------------------
+-record(varbind,
+ {oid,
+ variabletype,
+ value,
+ org_index
+ }
+ ).
+
+%%-----------------------------------------------------------------
+%% Internal Variablebinding
+%% status = noError | ErrorStatus
+%% mibentry = A mibentry if status == noError
+%% varbind = a varbind-record
+%%-----------------------------------------------------------------
+-record(ivarbind,
+ {status = noError,
+ mibentry,
+ varbind
+ }
+ ).
+
+%%----------------------------------------------------------------------
+%% ASN1_type. Everything that is needed to represent a typed variable.
+%% BERtype: Type used during Basic Encoding/Decoding Rules
+%% aliasname: The name of the derived type as defined in the MIB
+%% assocList can be list of:
+%% {enums, [{up, 1}, {down, 2}, {right, 3}, {left, 4}]}
+%%----------------------------------------------------------------------
+-record(asn1_type,
+ {bertype,
+ lo,
+ hi,
+ assocList = [],
+ imported = false,
+ aliasname,
+ implied = false,
+ display_hint
+ }
+ ).
+
+
+%%-----------------------------------------------------------------
+%% TableInfo - stored in snmp_symbolic_store for use by the
+%% generic table functions.
+%% nbr_of_cols is an integer
+%% defvals is a list of {Col, Defval}, ordered by column
+%% number
+%% status_col is an integer
+%% not_accessible a sorted list of columns (> first_accessible)
+%% that are 'not-accessible'
+%% indextypes is a list of #asn1_type for the index-columns,
+%% ordered by column number
+%% first_accessible is an integer, the first non-accessible
+%% column
+%% first_own_index is an integer. 0 if there is no such index for
+%% this table.
+%% This is not the same as the last integer in the oid!
+%% Example: If a table has one own index (oid.1), one
+%% column (oid.2) and one imported index then
+%% first_own_index will be 2.
+%%-----------------------------------------------------------------
+
+-record(table_info,
+ {nbr_of_cols,
+ defvals = [],
+ status_col,
+ not_accessible,
+ index_types,
+ first_accessible = 1,
+ first_own_index
+ }
+ ).
+
+
+%%-----------------------------------------------------------------
+%% TableInfo - stored in snmp_symbolic_store for use by the
+%% generic variable functions.
+%% defval is a default value for the variable
+%%-----------------------------------------------------------------
+-record(variable_info,
+ {
+ defval
+ }
+ ).
+
+
+%%----------------------------------------------------------------------
+%% MibEntry
+%% aliasname is the name for the oid.
+%% asn1_type is a record of asn1_type.
+%% entrytype: variable | table | table_column | internal
+%% access: notAccessible | readOnly | readWrite | readCreate (see rfc 1142)
+%% assocList: list of
+%% {table_info, #table_info} when entrytype == table
+%% {varable_info, #variable_info} when entrytype == variable
+%% {table_name, TableName} when entrytype == table_column
+%% {table_entry_with_sequence, NameOfSequence} when entrytype == table_entry
+%% description: DESCRIPTIONS field
+%%----------------------------------------------------------------------
+-record(me,
+ {
+ oid,
+ entrytype,
+ aliasname,
+ asn1_type,
+ access,
+ mfa,
+ imported = false,
+ assocList = [],
+ description = undefined,
+ units
+ }
+ ).
+
+
+%% oidobjects is a list of {oid, asn1_type} to be sent in the trap
+%% with the description field included.
+-record(trap,
+ {trapname,
+ enterpriseoid,
+ specificcode,
+ oidobjects,
+ description = undefined
+ }
+ ).
+
+%% oidobjects is a list of {oid, asn1_type} to be sent in the trap
+%% with the description field included.
+-record(notification,
+ {trapname,
+ oid,
+ oidobjects,
+ description = undefined
+ }
+ ).
+
+%%----------------------------------------------------------------------
+%% This is how a mib is represented on disk (as a binary)
+%% types is: [asn1_type()]
+%% variable_infos is a list of {Name, variable_info-record}
+%% table_infos is a list of {Name, table_info-record}
+%%
+%% The mib format version is a string with the following
+%% structure: Major.Minor
+%% The Major number is changed when the mib format is changed so
+%% that it is incompatible with previous versions. It still _might_
+%% be possible to convert (off-line or in run-time), but don't count
+%% on it.
+%% The Minor number is changed when a minor change has been made that
+%% does not effect the backward compatibillity.
+%% Both Major and Minor are integers.
+%%
+%% So, "2.0" is compatible with "2.1", but not with "3.0".
+%%
+%%----------------------------------------------------------------------
+-record(mib,
+ {misc = [],
+ mib_format_version = "3.1",
+ name = "",
+ module_identity, %% Not in SMIv1, and only with +module_identity
+ mes = [],
+ asn1_types = [],
+ traps = [],
+ variable_infos = [],
+ table_infos = [],
+ imports %% only with +imports
+ }
+ ).
+
+-record(module_identity,
+ {last_updated,
+ organization,
+ contact_info,
+ description,
+ revisions
+ }
+ ).
+
+%%----------------------------------------------------------------------
+%% version = 'version-1' | 'version-2' | 'version-3'
+%% vsn_hdr is dependent on version. If v1 | v2 it's the community string,
+%% if v3 its a v3_hdr record
+%% data is a PDU (v1 & v2c) or a (possibly encrypted) ScopedPDU (v3)
+%%
+%% The constant SNMP_USE_V3 is used for compatibility reasons. In earlier
+%% versions, the vsn_hdr field was called 'community'. This only worked
+%% for v1 and v2c. Thus, the field is renamed to vsn_hdr, and the
+%% content depend on the version as described above. An application
+%% that handles not only v1 and v2c, but also v3, *must* define the
+%% constant SNMP_USE_V3 before including this header file. This
+%% ensures that the application can refer to the field as 'vsn_hdr'.
+%% An old application, that doesn't handle v3, doesn't define
+%% the constant, can still refer to the field as 'coomunity'.
+%%----------------------------------------------------------------------
+-ifdef(SNMP_USE_V3).
+-record(message, {version, vsn_hdr, data}).
+-else.
+-record(message, {version, community, data}).
+-endif.
+
+-record(v3_hdr,
+ {msgID,
+ msgMaxSize,
+ msgFlags,
+ msgSecurityModel,
+ msgSecurityParameters,
+ hdr_size
+ }
+ ).
+
+-record(scopedPdu,
+ {contextEngineID,
+ contextName,
+ data
+ }
+ ).
+
+%%-----------------------------------------------------------------
+%% USM Security Model
+%%-----------------------------------------------------------------
+-record(usmSecurityParameters,
+ {msgAuthoritativeEngineID,
+ msgAuthoritativeEngineBoots,
+ msgAuthoritativeEngineTime,
+ msgUserName,
+ msgAuthenticationParameters,
+ msgPrivacyParameters
+ }
+ ).
+
+%%----------------------------------------------------------------------
+%% type: 'get-request' | 'get-next-request' | 'get-bulk-request' |
+%% 'get-response' | 'set-request' | 'inform-request' | 'snmpv2-trap' | report
+%% (see rfc 1905)
+%% request_id, error_status and error_index are integers.
+%% varbinds: a list of varbinds.
+%%----------------------------------------------------------------------
+%% if bulk non-repeaters max-repetitions resp
+-record(pdu,
+ {type,
+ request_id,
+ error_status,
+ error_index,
+ varbinds
+ }
+ ).
+
+-record(trappdu,
+ {enterprise,
+ agent_addr,
+ generic_trap,
+ specific_trap,
+ time_stamp,
+ varbinds
+ }
+ ).
+
+
+%%-----------------------------------------------------------------
+%% This record should be used when a Mnesia table for variables
+%% is created.
+%%-----------------------------------------------------------------
+-record(snmp_variables,
+ {name,
+ value
+ }
+ ).
+
+
+%%-----------------------------------------------------------------
+%% STD security models (from rfc2271)
+%%-----------------------------------------------------------------
+-define(SEC_ANY, 0).
+-define(SEC_V1, 1).
+-define(SEC_V2C, 2).
+-define(SEC_USM, 3).
+
+
+%%-----------------------------------------------------------------
+%% The OTP Security Model (ericsson * 256 + otp)
+%% (works for Community based SNMP i.e. v1 and v2c)
+%%-----------------------------------------------------------------
+-define(SEC_OTP, 49427).
+
+
+%%-----------------------------------------------------------------
+%% STD message processing models (from rfc2271)
+%%-----------------------------------------------------------------
+-define(MP_V1, 0).
+-define(MP_V2C, 1).
+-define('MP_V2U*', 2).
+-define(MP_V3, 3).
+
+
+%%-----------------------------------------------------------------
+%% Mib Views
+%%-----------------------------------------------------------------
+-define(view_included, 1).
+-define(view_excluded, 2).
+
+
+%%-----------------------------------------------------------------
+%% From SNMPv2-SMI
+%%-----------------------------------------------------------------
+-define(zeroDotZero, [0,0]).
+
+
+%%-----------------------------------------------------------------
+%% Incremental timer
+%%
+%% The timer sleeps in WaitFor milli seconds and when it
+%% times out, a new time out value is computed:
+%%
+%% WaitFor2 = WaitFor * Factor + Incr
+%%
+%% And the timer starts all over again with the new WaitFor value.
+%% The procedure is repeated at most MaxRetries.
+%%-----------------------------------------------------------------
+
+-record(snmp_incr_timer,
+ {wait_for = timer:seconds(5),
+ factor = 2,
+ incr = 0,
+ max_retries = infinity
+ }
+ ).
+
+%%-----------------------------------------------------------------
+%% Inform delivery information
+%%
+%% This record defines the info related to inform delivery info.
+%% That is, when sending an inform, info about the delivery (such
+%% if it was acknowledged) will be delivered using the info in
+%% this record.
+%%
+%% The delivery will be performed according to:
+%%
+%% Mod:inform_delivery_targets(Tag, Addresses, Extra)
+%% Mod:inform_delivery_info(Tag, Address, DeliveryResult, Extra)
+%%
+%% The Extra is any term, provided by the user.
+%%
+%% The fields of this record has the following meaning:
+%% tag - term() - Value selected by the user to identify this
+%% sending
+%% mod - module() - The callback module implementing the
+%% snmpa_notification_delivery_info_receiver
+%% behaviour
+%% extra - term() - Any extra info the user wants passed along
+%%
+%%-----------------------------------------------------------------
+
+-record(snmpa_notification_delivery_info,
+ {
+ tag,
+ mod,
+ extra
+ }).
diff --git a/lib/snmp/info b/lib/snmp/info
new file mode 100644
index 0000000000..6bda2fe73b
--- /dev/null
+++ b/lib/snmp/info
@@ -0,0 +1,3 @@
+group: oam Operation & Maintenance Applications
+short: Simple Network Management Protocol (SNMP) support including a
+short: MIB compiler and tools for creating SNMP agents
diff --git a/lib/snmp/mibs/INET-ADDRESS-MIB.mib b/lib/snmp/mibs/INET-ADDRESS-MIB.mib
new file mode 100644
index 0000000000..a778cba6b7
--- /dev/null
+++ b/lib/snmp/mibs/INET-ADDRESS-MIB.mib
@@ -0,0 +1,402 @@
+INET-ADDRESS-MIB DEFINITIONS ::= BEGIN
+
+IMPORTS
+ MODULE-IDENTITY, mib-2, Unsigned32 FROM SNMPv2-SMI
+ TEXTUAL-CONVENTION FROM SNMPv2-TC;
+
+inetAddressMIB MODULE-IDENTITY
+ LAST-UPDATED "200502040000Z"
+ ORGANIZATION
+ "IETF Operations and Management Area"
+ CONTACT-INFO
+ "Juergen Schoenwaelder (Editor)
+ International University Bremen
+ P.O. Box 750 561
+ 28725 Bremen, Germany
+
+ Phone: +49 421 200-3587
+
+ Send comments to <[email protected]>."
+ DESCRIPTION
+ "This MIB module defines textual conventions for
+ representing Internet addresses. An Internet
+ address can be an IPv4 address, an IPv6 address,
+ or a DNS domain name. This module also defines
+ textual conventions for Internet port numbers,
+ autonomous system numbers, and the length of an
+ Internet address prefix.
+
+ Copyright (C) The Internet Society (2005). This version
+ of this MIB module is part of RFC 4001, see the RFC
+ itself for full legal notices."
+ REVISION "200502040000Z"
+ DESCRIPTION
+ "Third version, published as RFC 4001. This revision
+ introduces the InetZoneIndex, InetScopeType, and
+ InetVersion textual conventions."
+ REVISION "200205090000Z"
+ DESCRIPTION
+ "Second version, published as RFC 3291. This
+ revision contains several clarifications and
+ introduces several new textual conventions:
+ InetAddressPrefixLength, InetPortNumber,
+ InetAutonomousSystemNumber, InetAddressIPv4z,
+ and InetAddressIPv6z."
+ REVISION "200006080000Z"
+ DESCRIPTION
+ "Initial version, published as RFC 2851."
+ ::= { mib-2 76 }
+
+InetAddressType ::= TEXTUAL-CONVENTION
+ STATUS current
+ DESCRIPTION
+ "A value that represents a type of Internet address.
+
+ unknown(0) An unknown address type. This value MUST
+ be used if the value of the corresponding
+ InetAddress object is a zero-length string.
+ It may also be used to indicate an IP address
+ that is not in one of the formats defined
+ below.
+
+ ipv4(1) An IPv4 address as defined by the
+ InetAddressIPv4 textual convention.
+
+ ipv6(2) An IPv6 address as defined by the
+ InetAddressIPv6 textual convention.
+
+ ipv4z(3) A non-global IPv4 address including a zone
+ index as defined by the InetAddressIPv4z
+ textual convention.
+
+ ipv6z(4) A non-global IPv6 address including a zone
+ index as defined by the InetAddressIPv6z
+ textual convention.
+
+ dns(16) A DNS domain name as defined by the
+ InetAddressDNS textual convention.
+
+ Each definition of a concrete InetAddressType value must be
+ accompanied by a definition of a textual convention for use
+ with that InetAddressType.
+
+ To support future extensions, the InetAddressType textual
+ convention SHOULD NOT be sub-typed in object type definitions.
+ It MAY be sub-typed in compliance statements in order to
+ require only a subset of these address types for a compliant
+ implementation.
+
+ Implementations must ensure that InetAddressType objects
+ and any dependent objects (e.g., InetAddress objects) are
+ consistent. An inconsistentValue error must be generated
+ if an attempt to change an InetAddressType object would,
+ for example, lead to an undefined InetAddress value. In
+
+ particular, InetAddressType/InetAddress pairs must be
+ changed together if the address type changes (e.g., from
+ ipv6(2) to ipv4(1))."
+ SYNTAX INTEGER {
+ unknown(0),
+ ipv4(1),
+ ipv6(2),
+ ipv4z(3),
+ ipv6z(4),
+ dns(16)
+ }
+
+InetAddress ::= TEXTUAL-CONVENTION
+ STATUS current
+ DESCRIPTION
+ "Denotes a generic Internet address.
+
+ An InetAddress value is always interpreted within the context
+ of an InetAddressType value. Every usage of the InetAddress
+ textual convention is required to specify the InetAddressType
+ object that provides the context. It is suggested that the
+ InetAddressType object be logically registered before the
+ object(s) that use the InetAddress textual convention, if
+ they appear in the same logical row.
+
+ The value of an InetAddress object must always be
+ consistent with the value of the associated InetAddressType
+ object. Attempts to set an InetAddress object to a value
+ inconsistent with the associated InetAddressType
+ must fail with an inconsistentValue error.
+
+ When this textual convention is used as the syntax of an
+ index object, there may be issues with the limit of 128
+ sub-identifiers specified in SMIv2, STD 58. In this case,
+ the object definition MUST include a 'SIZE' clause to
+ limit the number of potential instance sub-identifiers;
+ otherwise the applicable constraints MUST be stated in
+ the appropriate conceptual row DESCRIPTION clauses, or
+ in the surrounding documentation if there is no single
+ DESCRIPTION clause that is appropriate."
+ SYNTAX OCTET STRING (SIZE (0..255))
+
+InetAddressIPv4 ::= TEXTUAL-CONVENTION
+ DISPLAY-HINT "1d.1d.1d.1d"
+ STATUS current
+ DESCRIPTION
+ "Represents an IPv4 network address:
+
+ Octets Contents Encoding
+ 1-4 IPv4 address network-byte order
+
+ The corresponding InetAddressType value is ipv4(1).
+
+ This textual convention SHOULD NOT be used directly in object
+ definitions, as it restricts addresses to a specific format.
+ However, if it is used, it MAY be used either on its own or in
+ conjunction with InetAddressType, as a pair."
+ SYNTAX OCTET STRING (SIZE (4))
+
+InetAddressIPv6 ::= TEXTUAL-CONVENTION
+ DISPLAY-HINT "2x:2x:2x:2x:2x:2x:2x:2x"
+ STATUS current
+ DESCRIPTION
+ "Represents an IPv6 network address:
+
+ Octets Contents Encoding
+ 1-16 IPv6 address network-byte order
+
+ The corresponding InetAddressType value is ipv6(2).
+
+ This textual convention SHOULD NOT be used directly in object
+ definitions, as it restricts addresses to a specific format.
+ However, if it is used, it MAY be used either on its own or in
+ conjunction with InetAddressType, as a pair."
+ SYNTAX OCTET STRING (SIZE (16))
+
+InetAddressIPv4z ::= TEXTUAL-CONVENTION
+ DISPLAY-HINT "1d.1d.1d.1d%4d"
+ STATUS current
+ DESCRIPTION
+ "Represents a non-global IPv4 network address, together
+ with its zone index:
+
+ Octets Contents Encoding
+ 1-4 IPv4 address network-byte order
+ 5-8 zone index network-byte order
+
+ The corresponding InetAddressType value is ipv4z(3).
+
+ The zone index (bytes 5-8) is used to disambiguate identical
+ address values on nodes that have interfaces attached to
+ different zones of the same scope. The zone index may contain
+ the special value 0, which refers to the default zone for each
+ scope.
+
+ This textual convention SHOULD NOT be used directly in object
+
+ definitions, as it restricts addresses to a specific format.
+ However, if it is used, it MAY be used either on its own or in
+ conjunction with InetAddressType, as a pair."
+ SYNTAX OCTET STRING (SIZE (8))
+
+InetAddressIPv6z ::= TEXTUAL-CONVENTION
+ DISPLAY-HINT "2x:2x:2x:2x:2x:2x:2x:2x%4d"
+ STATUS current
+ DESCRIPTION
+ "Represents a non-global IPv6 network address, together
+ with its zone index:
+
+ Octets Contents Encoding
+ 1-16 IPv6 address network-byte order
+ 17-20 zone index network-byte order
+
+ The corresponding InetAddressType value is ipv6z(4).
+
+ The zone index (bytes 17-20) is used to disambiguate
+ identical address values on nodes that have interfaces
+ attached to different zones of the same scope. The zone index
+ may contain the special value 0, which refers to the default
+ zone for each scope.
+
+ This textual convention SHOULD NOT be used directly in object
+ definitions, as it restricts addresses to a specific format.
+ However, if it is used, it MAY be used either on its own or in
+ conjunction with InetAddressType, as a pair."
+ SYNTAX OCTET STRING (SIZE (20))
+
+InetAddressDNS ::= TEXTUAL-CONVENTION
+ DISPLAY-HINT "255a"
+ STATUS current
+ DESCRIPTION
+ "Represents a DNS domain name. The name SHOULD be fully
+ qualified whenever possible.
+
+ The corresponding InetAddressType is dns(16).
+
+ The DESCRIPTION clause of InetAddress objects that may have
+ InetAddressDNS values MUST fully describe how (and when)
+ these names are to be resolved to IP addresses.
+
+ The resolution of an InetAddressDNS value may require to
+ query multiple DNS records (e.g., A for IPv4 and AAAA for
+ IPv6). The order of the resolution process and which DNS
+ record takes precedence depends on the configuration of the
+ resolver.
+
+ This textual convention SHOULD NOT be used directly in object
+ definitions, as it restricts addresses to a specific format.
+ However, if it is used, it MAY be used either on its own or in
+ conjunction with InetAddressType, as a pair."
+ SYNTAX OCTET STRING (SIZE (1..255))
+
+InetAddressPrefixLength ::= TEXTUAL-CONVENTION
+ DISPLAY-HINT "d"
+ STATUS current
+ DESCRIPTION
+ "Denotes the length of a generic Internet network address
+ prefix. A value of n corresponds to an IP address mask
+ that has n contiguous 1-bits from the most significant
+ bit (MSB), with all other bits set to 0.
+
+ An InetAddressPrefixLength value is always interpreted within
+ the context of an InetAddressType value. Every usage of the
+ InetAddressPrefixLength textual convention is required to
+ specify the InetAddressType object that provides the
+ context. It is suggested that the InetAddressType object be
+ logically registered before the object(s) that use the
+ InetAddressPrefixLength textual convention, if they appear
+ in the same logical row.
+
+ InetAddressPrefixLength values larger than
+ the maximum length of an IP address for a specific
+ InetAddressType are treated as the maximum significant
+ value applicable for the InetAddressType. The maximum
+ significant value is 32 for the InetAddressType
+ 'ipv4(1)' and 'ipv4z(3)' and 128 for the InetAddressType
+ 'ipv6(2)' and 'ipv6z(4)'. The maximum significant value
+ for the InetAddressType 'dns(16)' is 0.
+
+ The value zero is object-specific and must be defined as
+ part of the description of any object that uses this
+ syntax. Examples of the usage of zero might include
+ situations where the Internet network address prefix
+ is unknown or does not apply.
+
+ The upper bound of the prefix length has been chosen to
+ be consistent with the maximum size of an InetAddress."
+ SYNTAX Unsigned32 (0..2040)
+
+InetPortNumber ::= TEXTUAL-CONVENTION
+ DISPLAY-HINT "d"
+ STATUS current
+ DESCRIPTION
+ "Represents a 16 bit port number of an Internet transport
+
+ layer protocol. Port numbers are assigned by IANA. A
+ current list of all assignments is available from
+ <http://www.iana.org/>.
+
+ The value zero is object-specific and must be defined as
+ part of the description of any object that uses this
+ syntax. Examples of the usage of zero might include
+ situations where a port number is unknown, or when the
+ value zero is used as a wildcard in a filter."
+ REFERENCE "STD 6 (RFC 768), STD 7 (RFC 793) and RFC 2960"
+ SYNTAX Unsigned32 (0..65535)
+
+InetAutonomousSystemNumber ::= TEXTUAL-CONVENTION
+ DISPLAY-HINT "d"
+ STATUS current
+ DESCRIPTION
+ "Represents an autonomous system number that identifies an
+ Autonomous System (AS). An AS is a set of routers under a
+ single technical administration, using an interior gateway
+ protocol and common metrics to route packets within the AS,
+ and using an exterior gateway protocol to route packets to
+ other ASes'. IANA maintains the AS number space and has
+ delegated large parts to the regional registries.
+
+ Autonomous system numbers are currently limited to 16 bits
+ (0..65535). There is, however, work in progress to enlarge the
+ autonomous system number space to 32 bits. Therefore, this
+ textual convention uses an Unsigned32 value without a
+ range restriction in order to support a larger autonomous
+ system number space."
+ REFERENCE "RFC 1771, RFC 1930"
+ SYNTAX Unsigned32
+
+InetScopeType ::= TEXTUAL-CONVENTION
+ STATUS current
+ DESCRIPTION
+ "Represents a scope type. This textual convention can be used
+ in cases where a MIB has to represent different scope types
+ and there is no context information, such as an InetAddress
+ object, that implicitly defines the scope type.
+
+ Note that not all possible values have been assigned yet, but
+ they may be assigned in future revisions of this specification.
+ Applications should therefore be able to deal with values
+ not yet assigned."
+ REFERENCE "RFC 3513"
+ SYNTAX INTEGER {
+ -- reserved(0),
+ interfaceLocal(1),
+ linkLocal(2),
+ subnetLocal(3),
+ adminLocal(4),
+ siteLocal(5), -- site-local unicast addresses
+ -- have been deprecated by RFC 3879
+ -- unassigned(6),
+ -- unassigned(7),
+ organizationLocal(8),
+ -- unassigned(9),
+ -- unassigned(10),
+ -- unassigned(11),
+ -- unassigned(12),
+ -- unassigned(13),
+ global(14)
+ -- reserved(15)
+ }
+
+InetZoneIndex ::= TEXTUAL-CONVENTION
+ DISPLAY-HINT "d"
+ STATUS current
+ DESCRIPTION
+ "A zone index identifies an instance of a zone of a
+ specific scope.
+
+ The zone index MUST disambiguate identical address
+ values. For link-local addresses, the zone index will
+ typically be the interface index (ifIndex as defined in the
+ IF-MIB) of the interface on which the address is configured.
+
+ The zone index may contain the special value 0, which refers
+ to the default zone. The default zone may be used in cases
+ where the valid zone index is not known (e.g., when a
+ management application has to write a link-local IPv6
+ address without knowing the interface index value). The
+ default zone SHOULD NOT be used as an easy way out in
+ cases where the zone index for a non-global IPv6 address
+ is known."
+ REFERENCE "RFC4007"
+ SYNTAX Unsigned32
+
+InetVersion ::= TEXTUAL-CONVENTION
+ STATUS current
+ DESCRIPTION
+ "A value representing a version of the IP protocol.
+
+ unknown(0) An unknown or unspecified version of the IP
+ protocol.
+
+ ipv4(1) The IPv4 protocol as defined in RFC 791 (STD 5).
+
+ ipv6(2) The IPv6 protocol as defined in RFC 2460.
+
+ Note that this textual convention SHOULD NOT be used to
+ distinguish different address types associated with IP
+ protocols. The InetAddressType has been designed for this
+ purpose."
+ REFERENCE "RFC 791, RFC 2460"
+ SYNTAX INTEGER {
+ unknown(0),
+ ipv4(1),
+ ipv6(2)
+ }
+END
diff --git a/lib/snmp/mibs/Makefile.in b/lib/snmp/mibs/Makefile.in
new file mode 100644
index 0000000000..b85a8b0767
--- /dev/null
+++ b/lib/snmp/mibs/Makefile.in
@@ -0,0 +1,194 @@
+#-*-makefile-*- ; force emacs to enter makefile-mode
+
+# %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%
+
+include $(ERL_TOP)/make/target.mk
+include $(ERL_TOP)/make/$(TARGET)/otp.mk
+
+# ----------------------------------------------------
+# Application version
+# ----------------------------------------------------
+include ../vsn.mk
+VSN = $(SNMP_VSN)
+
+# ----------------------------------------------------
+# Configured variables
+# ----------------------------------------------------
+PERL = @PERL@
+
+# ----------------------------------------------------
+# Release directory specification
+# ----------------------------------------------------
+RELSYSDIR = $(RELEASE_PATH)/lib/snmp-$(VSN)
+
+# ----------------------------------------------------
+# Common macros
+# ----------------------------------------------------
+
+# NOTE:
+# 1) Order is important; some MIBs include others
+# 2) The OTP-REG mib actually belongs to another
+# application (otp_mibs), and is exported by this
+# app. But since that app is built later, we have
+# to built it here in order to be able to build
+# OTP-SNMPEA-MIB (that needs otpModules and
+# otpApplications).
+MIBS_A = \
+ RFC1213-MIB \
+ STANDARD-MIB \
+ SNMPv2-TM \
+ SNMPv2-MIB \
+ SNMP-FRAMEWORK-MIB \
+ SNMP-MPD-MIB \
+ SNMP-TARGET-MIB \
+ SNMP-NOTIFICATION-MIB \
+ SNMP-COMMUNITY-MIB \
+ SNMP-USER-BASED-SM-MIB \
+ SNMP-VIEW-BASED-ACM-MIB \
+ SNMP-USM-AES-MIB \
+ INET-ADDRESS-MIB
+
+MIBS_B = OTP-SNMPEA-MIB
+
+BUILD_MIBS = \
+ $(MIBS_A) \
+ OTP-REG \
+ $(MIBS_B)
+
+MIBS = $(MIBS_A) $(MIBS_B)
+
+STD_v1_MIB_FILES = \
+ RFC1155-SMI.mib \
+ RFC-1212.mib \
+ RFC-1215.mib
+
+STD_v2_MIB_FILES = \
+ SNMPv2-SMI.mib \
+ SNMPv2-TC.mib \
+ SNMPv2-CONF.mib
+
+FUNCS_FILES = \
+ STANDARD-MIB.funcs \
+ SNMPv2-MIB.funcs \
+ SNMP-NOTIFICATION-MIB.funcs \
+ SNMP-TARGET-MIB.funcs
+
+V1_MIB_FILES = v1/OTP-SNMPEA-MIB.mib.v1
+
+MIB_FILES = $(MIBS:%=%.mib)
+BIN_TARGETS = $(MIBS:%=$(SNMP_BIN_TARGET_DIR)/%.bin)
+HRL_TARGETS = $(MIBS:%=$(SNMP_HRL_TARGET_DIR)/%.hrl)
+
+HRL_FILES = $(SNMP_HRL_TARGET_DIR)/SNMPv2-TC.hrl \
+ $(HRL_TARGETS)
+
+TARGET_FILES = \
+ $(ERL_TOP)/lib/snmp/bin/snmp-v2tov1 \
+ $(BUILD_MIBS:%=$(SNMP_BIN_TARGET_DIR)/%.bin) \
+ $(HRL_TARGETS) \
+ $(V1_MIB_FILES)
+
+
+# ----------------------------------------------------
+# FLAGS
+# ----------------------------------------------------
+
+SNMP_FLAGS += -pa ../ebin +version
+
+ifneq ($(MIBS_VERBOSITY),)
+SNMP_FLAGS += +'{verbosity,$(MIBS_VERBOSITY)}'
+endif
+
+ifneq ($(MIBS_REFERENCE),)
+SNMP_FLAGS += +reference
+endif
+
+ifneq ($(MIBS_OPTIONS),)
+SNMP_FLAGS += +options
+endif
+
+
+# ----------------------------------------------------
+# Targets
+# ----------------------------------------------------
+
+OTP_MIBDIR = $(shell if test -d ../../otp_mibs; then echo otp_mibs; \
+ else echo sasl; fi)
+
+debug opt: $(TARGET_FILES)
+
+$(ERL_TOP)/lib/snmp/bin/snmp-v2tov1: $(ERL_TOP)/lib/snmp/bin/snmp-v2tov1.src
+ $(PERL) -p -e 's?%PERL%?$(PERL)? ' < $< > $@
+ chmod 755 $@
+
+$(SNMP_BIN_TARGET_DIR)/OTP-REG.bin: $(ERL_TOP)/lib/$(OTP_MIBDIR)/mibs/OTP-REG.mib
+ $(ERLC) -pa $(SNMP_TOOLKIT)/ebin -I $(SNMP_TOOLKIT)/priv/mibs $(SNMP_FLAGS) -o $(SNMP_BIN_TARGET_DIR) $<
+
+clean:
+ rm -f $(TARGET_FILES)
+
+docs:
+
+conf:
+ cd ..; $(MAKE) conf
+
+info:
+ @echo "SNMP_FLAGS = $(SNMP_FLAGS)"
+ @echo ""
+ @echo "MIBS = $(MIBS)"
+ @echo ""
+ @echo "BUILD_MIBS = $(BUILD_MIBS)"
+ @echo ""
+ @echo "MIB_FILES = $(MIB_FILES)"
+ @echo ""
+ @echo "BIN_TARGETS = $(BIN_TARGETS)"
+ @echo ""
+ @echo "HRL_TARGETS = $(HRL_TARGETS)"
+ @echo ""
+ @echo "TARGET_FILES = $(TARGET_FILES)"
+ @echo ""
+ @echo "OTP_MIBDIR = $(OTP_MIBDIR)"
+ @echo ""
+ @echo "SNMP_VSN = $(SNMP_VSN)"
+ @echo "VSN = $(VSN)"
+ @echo "RELSYSDIR = $(RELSYSDIR)"
+
+v1/%.mib.v1: %.mib
+ $(ERL_TOP)/lib/snmp/bin/snmp-v2tov1 -o $@ $<
+
+
+# ----------------------------------------------------
+# Release Target
+# ----------------------------------------------------
+include $(ERL_TOP)/make/otp_release_targets.mk
+
+release_spec: opt
+ $(INSTALL_DIR) $(RELSYSDIR)/mibs
+ $(INSTALL_DIR) $(RELSYSDIR)/mibs/v1
+ $(INSTALL_DATA) $(MIB_FILES) $(RELSYSDIR)/mibs
+ $(INSTALL_DATA) $(STD_v2_MIB_FILES) $(RELSYSDIR)/mibs
+ $(INSTALL_DATA) $(FUNCS_FILES) $(RELSYSDIR)/mibs
+ $(INSTALL_DATA) $(STD_v1_MIB_FILES) $(RELSYSDIR)/mibs/v1
+ $(INSTALL_DATA) $(V1_MIB_FILES) $(RELSYSDIR)/mibs/v1
+ $(INSTALL_DIR) $(RELSYSDIR)/include
+ $(INSTALL_DATA) $(HRL_FILES) $(RELSYSDIR)/include
+ $(INSTALL_DIR) $(RELSYSDIR)/priv/mibs
+ $(INSTALL_DATA) $(BIN_TARGETS) $(RELSYSDIR)/priv/mibs
+
+release_docs_spec:
+
diff --git a/lib/snmp/mibs/OTP-SNMPEA-MIB.mib b/lib/snmp/mibs/OTP-SNMPEA-MIB.mib
new file mode 100644
index 0000000000..b0b598c6b8
--- /dev/null
+++ b/lib/snmp/mibs/OTP-SNMPEA-MIB.mib
@@ -0,0 +1,569 @@
+OTP-SNMPEA-MIB DEFINITIONS ::= BEGIN
+
+IMPORTS
+ MODULE-IDENTITY, OBJECT-TYPE,
+ Integer32, IpAddress
+ FROM SNMPv2-SMI
+ DisplayString, RowStatus, StorageType
+ FROM SNMPv2-TC
+ MODULE-COMPLIANCE, OBJECT-GROUP
+ FROM SNMPv2-CONF
+ otpModules, otpApplications
+ FROM OTP-REG
+ ;
+
+otpSnmpeaModule MODULE-IDENTITY
+ LAST-UPDATED "0305130000Z"
+ ORGANIZATION "Ericsson"
+ CONTACT-INFO
+ "Contact: Erlang Support see license agreement for Erlang/OTP."
+ DESCRIPTION
+ "This MIB module defines MIB objects for the SNMPEA
+ component in OTP."
+
+ REVISION "0305130000Z"
+ DESCRIPTION
+ "Changed CONTACT-INFO as it was outdated, made it more generic
+ to avoid such changes in the future."
+
+ REVISION "9808280000Z"
+ DESCRIPTION
+ "Since there are standard MIBs in the SNMPv3 framework that
+ implements the functionality defined in this MIB, all objects in
+ this MIB is now obsolete. There are still a few OID assignments
+ defined in this MIB.
+
+ Removed intCommunityTable; replaced by snmpCommunityTable in
+ SNMP-COMMUNITY-MIB.
+
+ Removed intAddressTable; replaced by SNMP-TARGET-MIB.
+
+ Removed intAgentMaxPacketSize, replaced by snmpEngineMaxPacketSize
+ in SNMP-FRAMEWORK-MIB.
+
+ Removed intAgentIpAddress and intAgentUDPPort.
+
+ Removed intViewTable, replaced by SNMP-VIEW-BASED-ACM-MIB."
+
+ REVISION "9804160000Z"
+ DESCRIPTION
+ "Updated to support MIBs from SNMPv3. Since SNMPv3 standardizes
+ some of the functionality provided by this MIB, we're using the
+ standard instead.
+
+ Removed intTrapDestTable; replaced by SNMP-TARGET-MIB and
+ SNMP-NOTIFICATION-MIB."
+
+ REVISION "9709220900Z"
+ DESCRIPTION
+ "The initial version of this MIB module. It is the old
+ INTERNAL-MIB renamed."
+ ::= { otpModules 5 }
+
+otpSnmpeaMIB OBJECT IDENTIFIER ::= { otpApplications 3 }
+otpSnmpeaMIBConformance
+ OBJECT IDENTIFIER ::= { otpSnmpeaMIB 1 }
+otpSnmpeaMIBObjects
+ OBJECT IDENTIFIER ::= { otpSnmpeaMIB 2 }
+
+snmpeaAdm OBJECT IDENTIFIER ::= { otpSnmpeaMIBObjects 1}
+community OBJECT IDENTIFIER ::= { snmpeaAdm 1 }
+trap OBJECT IDENTIFIER ::= { snmpeaAdm 2 }
+view OBJECT IDENTIFIER ::= { snmpeaAdm 3 }
+
+
+-- Obsolete objects
+
+-- The Administration Group
+--
+-- This group consists of objects to configure the access for
+-- managers to the MIB tree.
+--
+-- These objects were previously defined in INTERNAL-MIB
+
+intCommunityTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF IntCommunityEntry
+ MAX-ACCESS not-accessible
+ STATUS obsolete
+ DESCRIPTION
+ "This table defines access for the different
+ communities.
+
+ When a request comes from a certain ip address,
+ referring to a community string, the mib view
+ and access corresponding to these are looked up
+ in this table. Then the operation is validatated against
+ the access, and all requested objects validated against
+ the mib view."
+ ::= { community 1 }
+
+intCommunityEntry OBJECT-TYPE
+ SYNTAX IntCommunityEntry
+ MAX-ACCESS not-accessible
+ STATUS obsolete
+ DESCRIPTION
+ ""
+ INDEX { intCommunityDestination, intCommunityString }
+ ::= { intCommunityTable 1 }
+
+IntCommunityEntry ::=
+ SEQUENCE {
+ intCommunityDestination IpAddress,
+ intCommunityString DisplayString,
+ intCommunityViewIndex Integer32,
+ intCommunityAccess INTEGER,
+ intCommunityStatus RowStatus
+ }
+
+intCommunityDestination OBJECT-TYPE
+ SYNTAX IpAddress
+ MAX-ACCESS not-accessible
+ STATUS obsolete
+ DESCRIPTION
+ "The ip address of a management station. The special
+ ip address {0.0.0.0} is a wildcard, meaning all possible
+ ip addresses. In this way, access can be granted to all
+ ip addressed for some communities."
+ ::= { intCommunityEntry 1 }
+
+intCommunityString OBJECT-TYPE
+ SYNTAX DisplayString
+ MAX-ACCESS not-accessible
+ STATUS obsolete
+ DESCRIPTION
+ "The community string, defining the community."
+ ::= { intCommunityEntry 2 }
+
+intCommunityViewIndex OBJECT-TYPE
+ SYNTAX Integer32
+ MAX-ACCESS read-create
+ STATUS obsolete
+ DESCRIPTION
+ "Identifies a mib view. Index into the
+ intViewTable."
+ ::= { intCommunityEntry 3 }
+
+intCommunityAccess OBJECT-TYPE
+ SYNTAX INTEGER { read(1), readWrite(2) }
+ MAX-ACCESS read-create
+ STATUS obsolete
+ DESCRIPTION
+ "Defines which operations the manager can perform
+ on the objects in the mib view."
+ ::= { intCommunityEntry 4 }
+
+intCommunityStatus OBJECT-TYPE
+ SYNTAX RowStatus
+ MAX-ACCESS read-create
+ STATUS obsolete
+ DESCRIPTION
+ "The status of this conceptual row in the
+ intCommunityTable."
+ ::= { intCommunityEntry 5 }
+
+intAgentIpAddress OBJECT-TYPE
+ SYNTAX IpAddress
+ MAX-ACCESS read-only
+ STATUS obsolete
+ DESCRIPTION
+ "The IP address of this agent."
+ ::= { community 2 }
+
+intAgentUDPPort OBJECT-TYPE
+ SYNTAX Integer32
+ MAX-ACCESS read-only
+ STATUS obsolete
+ DESCRIPTION
+ "The UDP port the agent listens to."
+ ::= { community 3 }
+
+intAgentMaxPacketSize OBJECT-TYPE
+ SYNTAX Integer32 (484..65535)
+ MAX-ACCESS read-only
+ STATUS obsolete
+ DESCRIPTION
+ "The maximum packet size in bytes this agent will send to a
+ manager."
+ ::= { community 4 }
+
+
+intAddressTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF IntAddressEntry
+ MAX-ACCESS not-accessible
+ STATUS obsolete
+ DESCRIPTION
+ "This table holds UDP related information on each known
+ management station."
+ ::= { community 5 }
+
+
+intAddressEntry OBJECT-TYPE
+ SYNTAX IntAddressEntry
+ MAX-ACCESS not-accessible
+ STATUS obsolete
+ DESCRIPTION
+ ""
+ INDEX { intAddressDestination }
+ ::= { intAddressTable 1 }
+
+IntAddressEntry ::=
+ SEQUENCE {
+ intAddressDestination IpAddress,
+ intAddressUDPPort Integer32,
+ intAddressMaxPacketSize Integer32 (484..65535),
+ intAddressStatus RowStatus
+ }
+
+intAddressDestination OBJECT-TYPE
+ SYNTAX IpAddress
+ MAX-ACCESS not-accessible
+ STATUS obsolete
+ DESCRIPTION
+ "The ip address of the management station."
+ ::= { intAddressEntry 1 }
+
+intAddressUDPPort OBJECT-TYPE
+ SYNTAX Integer32
+ MAX-ACCESS read-create
+ STATUS obsolete
+ DESCRIPTION
+ "The UDP port to which traps will be sent to
+ this destination."
+ DEFVAL { 162 }
+ ::= { intAddressEntry 2 }
+
+intAddressMaxPacketSize OBJECT-TYPE
+ SYNTAX Integer32 (484..65535)
+ MAX-ACCESS read-create
+ STATUS obsolete
+ DESCRIPTION
+ "The maximum packet size in bytes for Messages
+ sent to this destination. The max size of a packet
+ sent to this destination will be the minumim of
+ this variable and agentMaxPacketSize.0."
+ ::= { intAddressEntry 3 }
+
+intAddressStatus OBJECT-TYPE
+ SYNTAX RowStatus
+ MAX-ACCESS read-create
+ STATUS obsolete
+ DESCRIPTION
+ "The status of this conceptual row in the
+ intAddressTable."
+ ::= { intAddressEntry 4 }
+
+intTrapDestTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF IntTrapDestEntry
+ MAX-ACCESS not-accessible
+ STATUS obsolete
+ DESCRIPTION
+ "The intTrapDestTable defines to which destination all traps
+ for a specific community should be sent."
+ ::= { trap 1 }
+
+intTrapDestEntry OBJECT-TYPE
+ SYNTAX IntTrapDestEntry
+ MAX-ACCESS not-accessible
+ STATUS obsolete
+ DESCRIPTION
+ ""
+ INDEX { intTrapDestCommunityString, intTrapDestDestination }
+ ::= { intTrapDestTable 1 }
+
+IntTrapDestEntry ::=
+ SEQUENCE {
+ intTrapDestCommunityString DisplayString,
+ intTrapDestDestination IpAddress,
+ intTrapDestStatus RowStatus,
+ intTrapDestSnmpVersion INTEGER
+ }
+
+intTrapDestCommunityString OBJECT-TYPE
+ SYNTAX DisplayString (SIZE (0..255))
+ MAX-ACCESS not-accessible
+ STATUS obsolete
+ DESCRIPTION
+ ""
+ ::= { intTrapDestEntry 1 }
+
+intTrapDestDestination OBJECT-TYPE
+ SYNTAX IpAddress
+ MAX-ACCESS not-accessible
+ STATUS obsolete
+ DESCRIPTION
+ ""
+ ::= { intTrapDestEntry 2 }
+
+intTrapDestStatus OBJECT-TYPE
+ SYNTAX RowStatus
+ MAX-ACCESS read-create
+ STATUS obsolete
+ DESCRIPTION
+ "The status of this conceptual row in the
+ intTrapDestTable."
+ ::= { intTrapDestEntry 3 }
+
+intTrapDestSnmpVersion OBJECT-TYPE
+ SYNTAX INTEGER { v1(1), v2(2) }
+ MAX-ACCESS read-create
+ STATUS obsolete
+ DESCRIPTION
+ "The SNMP version of the manager. If it is v1,
+ SNMPv1Traps are sent. If it is v2, SNMPv2Traps are sent"
+ ::= { intTrapDestEntry 4 }
+
+intViewTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF IntViewEntry
+ MAX-ACCESS not-accessible
+ STATUS obsolete
+ DESCRIPTION
+ "Locally held information about the MIB views
+ known to this agent.
+
+ Each MIB view is defined by two
+ collections of view subtrees: the included view
+ subtrees, and the excluded view subtrees. Every
+ such subtree, both included and excluded, is
+ defined in this table.
+
+ To determine if a particular object instance is in
+ a particular MIB view, compare the object
+ instance's OBJECT IDENTIFIER with each of the MIB
+ view's entries in this table. If none match, then
+ the object instance is not in the MIB view. If
+ one or more match, then the object instance is
+ included in, or excluded from, the MIB view
+ according to the value of viewType in the entry
+ whose value of viewSubtree has the most sub-
+ identifiers. If multiple entries match and have
+ the same number of sub-identifiers, then the
+ lexicographically greatest instance of viewType
+ determines the inclusion or exclusion.
+
+ An object instance's OBJECT IDENTIFIER X matches
+ an entry in this table when the number of sub-
+ identifiers in X is at least as many as in the
+ value of viewSubtree for the entry, and each sub-
+ identifier in the value of viewSubtree matches its
+ corresponding sub-identifier in X. Two sub-
+ identifiers match either if the corresponding bit
+ of viewMask is zero (the 'wild card' value), or if
+ they are equal.
+
+ Due to this 'wild card' capability, we introduce
+ the term, a 'family' of view subtrees, to refer to
+ the set of subtrees defined by a particular
+ combination of values of viewSubtree and viewMask.
+ In the case where no 'wild card' is defined in
+ viewMask, the family of view subtrees reduces to a
+ single view subtree."
+ ::= { view 1 }
+
+intViewEntry OBJECT-TYPE
+ SYNTAX IntViewEntry
+ MAX-ACCESS not-accessible
+ STATUS obsolete
+ DESCRIPTION
+ "Information on a particular family of view
+ subtrees included in or excluded from a particular
+ MIB view.
+
+ Implementations must not restrict the number of
+ families of view subtrees for a given MIB view,
+ except as dictated by resource constraints on the
+ overall number of entries in the viewTable."
+ INDEX { intViewIndex, intViewSubtree }
+ ::= { intViewTable 1 }
+
+IntViewEntry ::=
+ SEQUENCE {
+ intViewIndex Integer32,
+ intViewSubtree OBJECT IDENTIFIER,
+ intViewMask OCTET STRING,
+ intViewType INTEGER,
+ intViewStorageType StorageType,
+ intViewStatus RowStatus
+ }
+
+
+intViewIndex OBJECT-TYPE
+ SYNTAX Integer32 (1..65535)
+ MAX-ACCESS not-accessible
+ STATUS obsolete
+ DESCRIPTION
+ "A unique value for each MIB view. The value for
+ each MIB view must remain constant at least from
+ one re-initialization of the entity's network
+ management system to the next re-initialization."
+ ::= { intViewEntry 1 }
+
+intViewSubtree OBJECT-TYPE
+ SYNTAX OBJECT IDENTIFIER
+ MAX-ACCESS not-accessible
+ STATUS obsolete
+ DESCRIPTION
+ "A MIB subtree."
+ ::= { intViewEntry 2 }
+
+intViewMask OBJECT-TYPE
+ SYNTAX OCTET STRING (SIZE (0..16))
+ MAX-ACCESS read-create
+ STATUS obsolete
+ DESCRIPTION
+ "The bit mask which, in combination with the
+ corresponding instance of viewSubtree, defines a
+ family of view subtrees.
+
+ Each bit of this bit mask corresponds to a sub-
+ identifier of viewSubtree, with the most
+ significant bit of the i-th octet of this octet
+ string value (extended if necessary, see below)
+ corresponding to the (8*i - 7)-th sub-identifier,
+ and the least significant bit of the i-th octet of
+ this octet string corresponding to the (8*i)-th
+ sub-identifier, where i is in the range 1 through
+ 16.
+
+ Each bit of this bit mask specifies whether or not
+ the corresponding sub-identifiers must match when
+ determining if an OBJECT IDENTIFIER is in this
+ family of view subtrees; a '1' indicates that an
+ exact match must occur; a '0' indicates 'wild
+ card', i.e., any sub-identifier value matches.
+
+
+ Thus, the OBJECT IDENTIFIER X of an object
+ instance is contained in a family of view subtrees
+ if the following criteria are met:
+
+ for each sub-identifier of the value of
+ viewSubtree, either:
+
+ the i-th bit of viewMask is 0, or
+
+ the i-th sub-identifier of X is equal to
+ the i-th sub-identifier of the value of
+ viewSubtree.
+
+ If the value of this bit mask is M bits long and
+ there are more than M sub-identifiers in the
+ corresponding instance of viewSubtree, then the
+ bit mask is extended with 1's to be the required
+ length.
+
+ Note that when the value of this object is the
+ zero-length string, this extension rule results in
+ a mask of all-1's being used (i.e., no 'wild
+ card'), and the family of view subtrees is the one
+ view subtree uniquely identified by the
+ corresponding instance of viewSubtree."
+ DEFVAL { ''H }
+ ::= { intViewEntry 3 }
+
+
+intViewType OBJECT-TYPE
+ SYNTAX INTEGER {
+ included(1),
+ excluded(2)
+ }
+ MAX-ACCESS read-create
+ STATUS obsolete
+ DESCRIPTION
+ "The status of a particular family of view
+ subtrees within the particular
+ MIB view. The value 'included(1)' indicates that
+ the corresponding instances of viewSubtree and
+ viewMask define a family of view subtrees included
+ in the MIB view. The value 'excluded(2)'
+ indicates that the corresponding instances of
+ viewSubtree and viewMask define a family of view
+ subtrees excluded from the MIB view."
+ DEFVAL { included }
+ ::= { intViewEntry 4 }
+
+intViewStorageType OBJECT-TYPE
+ SYNTAX StorageType
+ MAX-ACCESS read-create
+ STATUS obsolete
+ DESCRIPTION
+ "The storage type for this conceptual row in the
+ intViewTable."
+ DEFVAL { nonVolatile }
+ ::= { intViewEntry 5 }
+
+intViewStatus OBJECT-TYPE
+ SYNTAX RowStatus
+ MAX-ACCESS read-create
+ STATUS obsolete
+ DESCRIPTION
+ "The status of this conceptual row in the
+ intViewTable."
+ ::= { intViewEntry 6 }
+
+-- conformance information
+
+otpSnmpeaMIBCompliances
+ OBJECT IDENTIFIER ::= { otpSnmpeaMIBConformance 1 }
+otpSnmpeaMIBGroups
+ OBJECT IDENTIFIER ::= { otpSnmpeaMIBConformance 2 }
+
+
+-- compliance statements
+
+otpSnmpeaBasicCompliance MODULE-COMPLIANCE
+ STATUS obsolete
+ DESCRIPTION
+ "The compliance statement for SNMPv2 entities which
+ implement the OTP-SNMPEA-MIB."
+ MODULE -- this module
+ MANDATORY-GROUPS { addressGroup }
+ ::= { otpSnmpeaMIBCompliances 1 }
+
+
+-- units of conformance
+
+communityGroup OBJECT-GROUP
+ OBJECTS { intCommunityViewIndex,
+ intCommunityAccess,
+ intCommunityStatus }
+ STATUS obsolete
+ DESCRIPTION
+ "A collection of objects providing basic instrumentation
+ of the load of the OTP system."
+ ::= { otpSnmpeaMIBGroups 1 }
+
+addressGroup OBJECT-GROUP
+ OBJECTS { intAgentIpAddress,
+ intAgentUDPPort,
+ intAgentMaxPacketSize,
+ intAddressUDPPort,
+ intAddressMaxPacketSize,
+ intAddressStatus }
+ STATUS obsolete
+ DESCRIPTION
+ "A collection of objects providing basic instrumentation
+ of the load of the OTP system."
+ ::= { otpSnmpeaMIBGroups 2 }
+
+trapGroup OBJECT-GROUP
+ OBJECTS { intTrapDestStatus,
+ intTrapDestSnmpVersion }
+ STATUS obsolete
+ DESCRIPTION
+ "A collection of objects providing basic instrumentation
+ of the load of the OTP system."
+ ::= { otpSnmpeaMIBGroups 3 }
+
+viewGroup OBJECT-GROUP
+ OBJECTS { intViewMask,
+ intViewType,
+ intViewStorageType,
+ intViewStatus }
+ STATUS obsolete
+ DESCRIPTION
+ "A collection of objects providing basic instrumentation
+ of the load of the OTP system."
+ ::= { otpSnmpeaMIBGroups 4 }
+
+
+END
diff --git a/lib/snmp/mibs/RFC-1212.mib b/lib/snmp/mibs/RFC-1212.mib
new file mode 100644
index 0000000000..eedb74a9a9
--- /dev/null
+++ b/lib/snmp/mibs/RFC-1212.mib
@@ -0,0 +1,74 @@
+RFC-1212 DEFINITIONS ::= BEGIN
+
+IMPORTS
+ ObjectName
+ FROM RFC1155-SMI
+ DisplayString
+ FROM RFC1158-MIB;
+
+OBJECT-TYPE MACRO ::=
+BEGIN
+ TYPE NOTATION ::=
+ -- must conform to
+ -- RFC1155's ObjectSyntax
+ "SYNTAX" type(ObjectSyntax)
+ "ACCESS" Access
+ "STATUS" Status
+ DescrPart
+ ReferPart
+ IndexPart
+ DefValPart
+ VALUE NOTATION ::= value (VALUE ObjectName)
+
+ Access ::= "read-only"
+ | "read-write"
+ | "write-only"
+ | "not-accessible"
+ Status ::= "mandatory"
+ | "optional"
+ | "obsolete"
+ | "deprecated"
+
+ DescrPart ::=
+ "DESCRIPTION" value (description DisplayString)
+ | empty
+
+ ReferPart ::=
+ "REFERENCE" value (reference DisplayString)
+ | empty
+
+ IndexPart ::=
+ "INDEX" "{" IndexTypes "}"
+ | empty
+ IndexTypes ::=
+ IndexType | IndexTypes "," IndexType
+ IndexType ::=
+ -- if indexobject, use the SYNTAX
+ -- value of the correspondent
+ -- OBJECT-TYPE invocation
+ value (indexobject ObjectName)
+ -- otherwise use named SMI type
+ -- must conform to IndexSyntax below
+ | type (indextype)
+
+ DefValPart ::=
+ "DEFVAL" "{" value (defvalue ObjectSyntax) "}"
+ | empty
+ END
+
+IndexSyntax ::=
+ CHOICE {
+ number
+ INTEGER (0..MAX),
+ string
+ OCTET STRING,
+ object
+ OBJECT IDENTIFIER,
+ address
+ NetworkAddress,
+ ipAddress
+ IpAddress
+ }
+
+END
+
diff --git a/lib/snmp/mibs/RFC-1215.mib b/lib/snmp/mibs/RFC-1215.mib
new file mode 100644
index 0000000000..046cbb9e01
--- /dev/null
+++ b/lib/snmp/mibs/RFC-1215.mib
@@ -0,0 +1,30 @@
+RFC-1215 DEFINITIONS ::= BEGIN
+
+IMPORTS
+ ObjectName
+ FROM RFC1155-SMI;
+
+TRAP-TYPE MACRO ::=
+BEGIN
+ TYPE NOTATION ::=
+ "ENTERPRISE" value (enterprise OBJECT IDENTIFIER)
+ VarPart
+ DescrPart
+ ReferPart
+ VALUE NOTATION ::=
+ value (VALUE INTEGER)
+ VarPart ::=
+ "VARIABLES" "{" VarTypes "}"
+ | empty
+ VarTypes ::=
+ VarType | VarTypes "," VarType
+ VarType ::=
+ value (vartype ObjectName)
+ DescrPart ::=
+ "DESCRIPTION" value (description DisplayString)
+ | empty
+ ReferPart ::=
+ "REFERENCE" value (reference DisplayString)
+ | empty
+END
+
diff --git a/lib/snmp/mibs/RFC1155-SMI.mib b/lib/snmp/mibs/RFC1155-SMI.mib
new file mode 100644
index 0000000000..8d45610a22
--- /dev/null
+++ b/lib/snmp/mibs/RFC1155-SMI.mib
@@ -0,0 +1,128 @@
+RFC1155-SMI DEFINITIONS ::= BEGIN
+
+EXPORTS -- EVERYTHING
+ internet, directory, mgmt,
+ experimental, private, enterprises,
+ OBJECT-TYPE, ObjectName, ObjectSyntax, SimpleSyntax,
+ ApplicationSyntax, NetworkAddress, IpAddress,
+ Counter, Gauge, TimeTicks, Opaque;
+
+-- the path to the root
+
+internet OBJECT IDENTIFIER ::= { iso org(3) dod(6) 1 }
+
+directory OBJECT IDENTIFIER ::= { internet 1 }
+
+mgmt OBJECT IDENTIFIER ::= { internet 2 }
+
+experimental OBJECT IDENTIFIER ::= { internet 3 }
+
+private OBJECT IDENTIFIER ::= { internet 4 }
+enterprises OBJECT IDENTIFIER ::= { private 1 }
+
+-- definition of object types
+
+OBJECT-TYPE MACRO ::=
+BEGIN
+ TYPE NOTATION ::= "SYNTAX" type (TYPE ObjectSyntax)
+ "ACCESS" Access
+ "STATUS" Status
+ VALUE NOTATION ::= value (VALUE ObjectName)
+
+ Access ::= "read-only"
+ | "read-write"
+ | "write-only"
+ | "not-accessible"
+ Status ::= "mandatory"
+ | "optional"
+ | "obsolete"
+END
+
+-- names of objects in the MIB
+
+ObjectName ::=
+ OBJECT IDENTIFIER
+
+ -- syntax of objects in the MIB
+
+ ObjectSyntax ::=
+ CHOICE {
+ simple
+ SimpleSyntax,
+
+ -- note that simple SEQUENCEs are not directly
+ -- mentioned here to keep things simple (i.e.,
+ -- prevent mis-use). However, application-wide
+ -- types which are IMPLICITly encoded simple
+ -- SEQUENCEs may appear in the following CHOICE
+
+ application-wide
+ ApplicationSyntax
+ }
+
+ SimpleSyntax ::=
+ CHOICE {
+ number
+ INTEGER,
+
+ string
+ OCTET STRING,
+
+ object
+ OBJECT IDENTIFIER,
+
+ empty
+ NULL
+ }
+
+ ApplicationSyntax ::=
+ CHOICE {
+ address
+ NetworkAddress,
+
+ counter
+ Counter,
+
+ gauge
+ Gauge,
+
+ ticks
+ TimeTicks,
+
+ arbitrary
+ Opaque
+
+ -- other application-wide types, as they are
+ -- defined, will be added here
+ }
+
+
+ -- application-wide types
+
+ NetworkAddress ::=
+ CHOICE {
+ internet
+ IpAddress
+ }
+
+ IpAddress ::=
+ [APPLICATION 0] -- in network-byte order
+ IMPLICIT OCTET STRING (SIZE (4))
+
+ Counter ::=
+ [APPLICATION 1]
+ IMPLICIT INTEGER (0..4294967295)
+
+ Gauge ::=
+ [APPLICATION 2]
+ IMPLICIT INTEGER (0..4294967295)
+
+ TimeTicks ::=
+ [APPLICATION 3]
+ IMPLICIT INTEGER (0..4294967295)
+
+ Opaque ::=
+ [APPLICATION 4] -- arbitrary ASN.1 value,
+ IMPLICIT OCTET STRING -- "double-wrapped"
+
+END
diff --git a/lib/snmp/mibs/RFC1213-MIB.mib b/lib/snmp/mibs/RFC1213-MIB.mib
new file mode 100644
index 0000000000..0421e64d62
--- /dev/null
+++ b/lib/snmp/mibs/RFC1213-MIB.mib
@@ -0,0 +1,2888 @@
+ RFC1213-MIB DEFINITIONS ::= BEGIN
+
+ IMPORTS
+ mgmt, NetworkAddress, IpAddress, Counter, Gauge,
+ TimeTicks
+ FROM RFC1155-SMI
+ OBJECT-TYPE
+ FROM RFC-1212;
+
+ -- This MIB module uses the extended OBJECT-TYPE macro as
+ -- defined in [14];
+
+
+ -- MIB-II (same prefix as MIB-I)
+
+ mib-2 OBJECT IDENTIFIER ::= { mgmt 1 }
+
+ -- textual conventions
+
+ DisplayString ::=
+ OCTET STRING
+ -- This data type is used to model textual information taken
+ -- from the NVT ASCII character set. By convention, objects
+ -- with this syntax are declared as having
+
+
+
+ --
+ -- SIZE (0..255)
+
+ PhysAddress ::=
+ OCTET STRING
+ -- This data type is used to model media addresses. For many
+ -- types of media, this will be in a binary representation.
+ -- For example, an ethernet address would be represented as
+ -- a string of 6 octets.
+
+
+ -- groups in MIB-II
+
+ system OBJECT IDENTIFIER ::= { mib-2 1 }
+
+ interfaces OBJECT IDENTIFIER ::= { mib-2 2 }
+
+ at OBJECT IDENTIFIER ::= { mib-2 3 }
+
+ ip OBJECT IDENTIFIER ::= { mib-2 4 }
+
+ icmp OBJECT IDENTIFIER ::= { mib-2 5 }
+
+ tcp OBJECT IDENTIFIER ::= { mib-2 6 }
+
+ udp OBJECT IDENTIFIER ::= { mib-2 7 }
+
+ egp OBJECT IDENTIFIER ::= { mib-2 8 }
+
+ -- historical (some say hysterical)
+ -- cmot OBJECT IDENTIFIER ::= { mib-2 9 }
+
+ transmission OBJECT IDENTIFIER ::= { mib-2 10 }
+
+ snmp OBJECT IDENTIFIER ::= { mib-2 11 }
+
+
+ -- the System group
+
+ -- Implementation of the System group is mandatory for all
+ -- systems. If an agent is not configured to have a value
+ -- for any of these variables, a string of length 0 is
+ -- returned.
+
+ sysDescr OBJECT-TYPE
+ SYNTAX DisplayString (SIZE (0..255))
+ ACCESS read-only
+ STATUS mandatory
+
+
+
+
+
+ DESCRIPTION
+ "A textual description of the entity. This value
+ should include the full name and version
+ identification of the system's hardware type,
+ software operating-system, and networking
+ software. It is mandatory that this only contain
+ printable ASCII characters."
+ ::= { system 1 }
+
+ sysObjectID OBJECT-TYPE
+ SYNTAX OBJECT IDENTIFIER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The vendor's authoritative identification of the
+ network management subsystem contained in the
+ entity. This value is allocated within the SMI
+ enterprises subtree (1.3.6.1.4.1) and provides an
+ easy and unambiguous means for determining `what
+ kind of box' is being managed. For example, if
+ vendor `Flintstones, Inc.' was assigned the
+ subtree 1.3.6.1.4.1.4242, it could assign the
+ identifier 1.3.6.1.4.1.4242.1.1 to its `Fred
+ Router'."
+ ::= { system 2 }
+
+ sysUpTime OBJECT-TYPE
+ SYNTAX TimeTicks
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The time (in hundredths of a second) since the
+ network management portion of the system was last
+ re-initialized."
+ ::= { system 3 }
+
+ sysContact OBJECT-TYPE
+ SYNTAX DisplayString (SIZE (0..255))
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The textual identification of the contact person
+ for this managed node, together with information
+ on how to contact this person."
+ ::= { system 4 }
+
+ sysName OBJECT-TYPE
+ SYNTAX DisplayString (SIZE (0..255))
+
+
+
+
+
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "An administratively-assigned name for this
+ managed node. By convention, this is the node's
+ fully-qualified domain name."
+ ::= { system 5 }
+
+ sysLocation OBJECT-TYPE
+ SYNTAX DisplayString (SIZE (0..255))
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The physical location of this node (e.g.,
+ `telephone closet, 3rd floor')."
+ ::= { system 6 }
+
+ sysServices OBJECT-TYPE
+ SYNTAX INTEGER (0..127)
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "A value which indicates the set of services that
+ this entity primarily offers.
+
+ The value is a sum. This sum initially takes the
+ value zero, Then, for each layer, L, in the range
+ 1 through 7, that this node performs transactions
+ for, 2 raised to (L - 1) is added to the sum. For
+ example, a node which performs primarily routing
+ functions would have a value of 4 (2^(3-1)). In
+ contrast, a node which is a host offering
+ application services would have a value of 72
+ (2^(4-1) + 2^(7-1)). Note that in the context of
+ the Internet suite of protocols, values should be
+ calculated accordingly:
+
+ layer functionality
+ 1 physical (e.g., repeaters)
+ 2 datalink/subnetwork (e.g., bridges)
+ 3 internet (e.g., IP gateways)
+ 4 end-to-end (e.g., IP hosts)
+ 7 applications (e.g., mail relays)
+
+ For systems including OSI protocols, layers 5 and
+ 6 may also be counted."
+ ::= { system 7 }
+
+
+
+
+
+
+ -- the Interfaces group
+
+ -- Implementation of the Interfaces group is mandatory for
+ -- all systems.
+
+ ifNumber OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of network interfaces (regardless of
+ their current state) present on this system."
+ ::= { interfaces 1 }
+
+
+ -- the Interfaces table
+
+ -- The Interfaces table contains information on the entity's
+ -- interfaces. Each interface is thought of as being
+ -- attached to a `subnetwork'. Note that this term should
+ -- not be confused with `subnet' which refers to an
+ -- addressing partitioning scheme used in the Internet suite
+ -- of protocols.
+
+ ifTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF IfEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A list of interface entries. The number of
+ entries is given by the value of ifNumber."
+ ::= { interfaces 2 }
+
+ ifEntry OBJECT-TYPE
+ SYNTAX IfEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "An interface entry containing objects at the
+ subnetwork layer and below for a particular
+ interface."
+ INDEX { ifIndex }
+ ::= { ifTable 1 }
+
+ IfEntry ::=
+ SEQUENCE {
+ ifIndex
+ INTEGER,
+ ifDescr
+ DisplayString,
+ ifType
+ INTEGER,
+ ifMtu
+ INTEGER,
+ ifSpeed
+ Gauge,
+ ifPhysAddress
+ PhysAddress,
+ ifAdminStatus
+ INTEGER,
+ ifOperStatus
+ INTEGER,
+ ifLastChange
+ TimeTicks,
+ ifInOctets
+ Counter,
+ ifInUcastPkts
+ Counter,
+ ifInNUcastPkts
+ Counter,
+ ifInDiscards
+ Counter,
+ ifInErrors
+ Counter,
+ ifInUnknownProtos
+ Counter,
+ ifOutOctets
+ Counter,
+ ifOutUcastPkts
+ Counter,
+ ifOutNUcastPkts
+ Counter,
+ ifOutDiscards
+ Counter,
+ ifOutErrors
+ Counter,
+ ifOutQLen
+ Gauge,
+ ifSpecific
+ OBJECT IDENTIFIER
+ }
+
+ ifIndex OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+
+
+
+
+
+ DESCRIPTION
+ "A unique value for each interface. Its value
+ ranges between 1 and the value of ifNumber. The
+ value for each interface must remain constant at
+ least from one re-initialization of the entity's
+ network management system to the next re-
+ initialization."
+ ::= { ifEntry 1 }
+
+ ifDescr OBJECT-TYPE
+ SYNTAX DisplayString (SIZE (0..255))
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "A textual string containing information about the
+ interface. This string should include the name of
+ the manufacturer, the product name and the version
+ of the hardware interface."
+ ::= { ifEntry 2 }
+
+ ifType OBJECT-TYPE
+ SYNTAX INTEGER {
+ other(1), -- none of the following
+ regular1822(2),
+ hdh1822(3),
+ ddn-x25(4),
+ rfc877-x25(5),
+ ethernet-csmacd(6),
+ iso88023-csmacd(7),
+ iso88024-tokenBus(8),
+ iso88025-tokenRing(9),
+ iso88026-man(10),
+ starLan(11),
+ proteon-10Mbit(12),
+ proteon-80Mbit(13),
+ hyperchannel(14),
+ fddi(15),
+ lapb(16),
+ sdlc(17),
+ ds1(18), -- T-1
+ e1(19), -- european equiv. of T-1
+ basicISDN(20),
+ primaryISDN(21), -- proprietary serial
+ propPointToPointSerial(22),
+ ppp(23),
+ softwareLoopback(24),
+ eon(25), -- CLNP over IP [11]
+ ethernet-3Mbit(26),
+
+
+
+
+
+ nsip(27), -- XNS over IP
+ slip(28), -- generic SLIP
+ ultra(29), -- ULTRA technologies
+ ds3(30), -- T-3
+ sip(31), -- SMDS
+ frame-relay(32)
+ }
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The type of interface, distinguished according to
+ the physical/link protocol(s) immediately `below'
+ the network layer in the protocol stack."
+ ::= { ifEntry 3 }
+
+ ifMtu OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The size of the largest datagram which can be
+ sent/received on the interface, specified in
+ octets. For interfaces that are used for
+ transmitting network datagrams, this is the size
+ of the largest network datagram that can be sent
+ on the interface."
+ ::= { ifEntry 4 }
+
+ ifSpeed OBJECT-TYPE
+ SYNTAX Gauge
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "An estimate of the interface's current bandwidth
+ in bits per second. For interfaces which do not
+ vary in bandwidth or for those where no accurate
+ estimation can be made, this object should contain
+ the nominal bandwidth."
+ ::= { ifEntry 5 }
+
+ ifPhysAddress OBJECT-TYPE
+ SYNTAX PhysAddress
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The interface's address at the protocol layer
+ immediately `below' the network layer in the
+ protocol stack. For interfaces which do not have
+
+
+
+
+
+ such an address (e.g., a serial line), this object
+ should contain an octet string of zero length."
+ ::= { ifEntry 6 }
+
+ ifAdminStatus OBJECT-TYPE
+ SYNTAX INTEGER {
+ up(1), -- ready to pass packets
+ down(2),
+ testing(3) -- in some test mode
+ }
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The desired state of the interface. The
+ testing(3) state indicates that no operational
+ packets can be passed."
+ ::= { ifEntry 7 }
+
+ ifOperStatus OBJECT-TYPE
+ SYNTAX INTEGER {
+ up(1), -- ready to pass packets
+ down(2),
+ testing(3) -- in some test mode
+ }
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The current operational state of the interface.
+ The testing(3) state indicates that no operational
+ packets can be passed."
+ ::= { ifEntry 8 }
+
+ ifLastChange OBJECT-TYPE
+ SYNTAX TimeTicks
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The value of sysUpTime at the time the interface
+ entered its current operational state. If the
+ current state was entered prior to the last re-
+ initialization of the local network management
+ subsystem, then this object contains a zero
+ value."
+ ::= { ifEntry 9 }
+
+ ifInOctets OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+
+
+
+
+
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of octets received on the
+ interface, including framing characters."
+ ::= { ifEntry 10 }
+
+ ifInUcastPkts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of subnetwork-unicast packets
+ delivered to a higher-layer protocol."
+ ::= { ifEntry 11 }
+
+ ifInNUcastPkts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of non-unicast (i.e., subnetwork-
+ broadcast or subnetwork-multicast) packets
+ delivered to a higher-layer protocol."
+ ::= { ifEntry 12 }
+
+ ifInDiscards OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of inbound packets which were chosen
+ to be discarded even though no errors had been
+ detected to prevent their being deliverable to a
+ higher-layer protocol. One possible reason for
+ discarding such a packet could be to free up
+ buffer space."
+ ::= { ifEntry 13 }
+
+ ifInErrors OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of inbound packets that contained
+ errors preventing them from being deliverable to a
+ higher-layer protocol."
+ ::= { ifEntry 14 }
+
+
+
+
+
+
+ ifInUnknownProtos OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of packets received via the interface
+ which were discarded because of an unknown or
+ unsupported protocol."
+ ::= { ifEntry 15 }
+
+ ifOutOctets OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of octets transmitted out of the
+ interface, including framing characters."
+ ::= { ifEntry 16 }
+
+ ifOutUcastPkts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of packets that higher-level
+ protocols requested be transmitted to a
+ subnetwork-unicast address, including those that
+ were discarded or not sent."
+ ::= { ifEntry 17 }
+
+ ifOutNUcastPkts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of packets that higher-level
+ protocols requested be transmitted to a non-
+ unicast (i.e., a subnetwork-broadcast or
+ subnetwork-multicast) address, including those
+ that were discarded or not sent."
+ ::= { ifEntry 18 }
+
+ ifOutDiscards OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of outbound packets which were chosen
+
+
+
+
+
+ to be discarded even though no errors had been
+ detected to prevent their being transmitted. One
+ possible reason for discarding such a packet could
+ be to free up buffer space."
+ ::= { ifEntry 19 }
+
+ ifOutErrors OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of outbound packets that could not be
+ transmitted because of errors."
+ ::= { ifEntry 20 }
+
+ ifOutQLen OBJECT-TYPE
+ SYNTAX Gauge
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The length of the output packet queue (in
+ packets)."
+ ::= { ifEntry 21 }
+
+ ifSpecific OBJECT-TYPE
+ SYNTAX OBJECT IDENTIFIER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "A reference to MIB definitions specific to the
+ particular media being used to realize the
+ interface. For example, if the interface is
+ realized by an ethernet, then the value of this
+ object refers to a document defining objects
+ specific to ethernet. If this information is not
+ present, its value should be set to the OBJECT
+ IDENTIFIER { 0 0 }, which is a syntatically valid
+ object identifier, and any conformant
+ implementation of ASN.1 and BER must be able to
+ generate and recognize this value."
+ ::= { ifEntry 22 }
+
+
+ -- the Address Translation group
+
+ -- Implementation of the Address Translation group is
+ -- mandatory for all systems. Note however that this group
+ -- is deprecated by MIB-II. That is, it is being included
+
+
+
+
+
+ -- solely for compatibility with MIB-I nodes, and will most
+ -- likely be excluded from MIB-III nodes. From MIB-II and
+ -- onwards, each network protocol group contains its own
+ -- address translation tables.
+
+ -- The Address Translation group contains one table which is
+ -- the union across all interfaces of the translation tables
+ -- for converting a NetworkAddress (e.g., an IP address) into
+ -- a subnetwork-specific address. For lack of a better term,
+ -- this document refers to such a subnetwork-specific address
+ -- as a `physical' address.
+
+ -- Examples of such translation tables are: for broadcast
+ -- media where ARP is in use, the translation table is
+ -- equivalent to the ARP cache; or, on an X.25 network where
+ -- non-algorithmic translation to X.121 addresses is
+ -- required, the translation table contains the
+ -- NetworkAddress to X.121 address equivalences.
+
+ atTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF AtEntry
+ ACCESS not-accessible
+ STATUS deprecated
+ DESCRIPTION
+ "The Address Translation tables contain the
+ NetworkAddress to `physical' address equivalences.
+ Some interfaces do not use translation tables for
+ determining address equivalences (e.g., DDN-X.25
+ has an algorithmic method); if all interfaces are
+ of this type, then the Address Translation table
+ is empty, i.e., has zero entries."
+ ::= { at 1 }
+
+ atEntry OBJECT-TYPE
+ SYNTAX AtEntry
+ ACCESS not-accessible
+ STATUS deprecated
+ DESCRIPTION
+ "Each entry contains one NetworkAddress to
+ `physical' address equivalence."
+ INDEX { atIfIndex,
+ atNetAddress }
+ ::= { atTable 1 }
+
+ AtEntry ::=
+ SEQUENCE {
+ atIfIndex
+ INTEGER,
+
+
+
+
+
+ atPhysAddress
+ PhysAddress,
+ atNetAddress
+ NetworkAddress
+ }
+
+ atIfIndex OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-write
+ STATUS deprecated
+ DESCRIPTION
+ "The interface on which this entry's equivalence
+ is effective. The interface identified by a
+ particular value of this index is the same
+ interface as identified by the same value of
+ ifIndex."
+ ::= { atEntry 1 }
+
+ atPhysAddress OBJECT-TYPE
+ SYNTAX PhysAddress
+ ACCESS read-write
+ STATUS deprecated
+ DESCRIPTION
+ "The media-dependent `physical' address.
+
+ Setting this object to a null string (one of zero
+ length) has the effect of invaliding the
+ corresponding entry in the atTable object. That
+ is, it effectively dissasociates the interface
+ identified with said entry from the mapping
+ identified with said entry. It is an
+ implementation-specific matter as to whether the
+ agent removes an invalidated entry from the table.
+ Accordingly, management stations must be prepared
+ to receive tabular information from agents that
+ corresponds to entries not currently in use.
+ Proper interpretation of such entries requires
+ examination of the relevant atPhysAddress object."
+ ::= { atEntry 2 }
+
+ atNetAddress OBJECT-TYPE
+ SYNTAX NetworkAddress
+ ACCESS read-write
+ STATUS deprecated
+ DESCRIPTION
+ "The NetworkAddress (e.g., the IP address)
+ corresponding to the media-dependent `physical'
+ address."
+
+
+
+
+
+ ::= { atEntry 3 }
+
+
+ -- the IP group
+
+ -- Implementation of the IP group is mandatory for all
+ -- systems.
+
+ ipForwarding OBJECT-TYPE
+ SYNTAX INTEGER {
+ forwarding(1), -- acting as a gateway
+ not-forwarding(2) -- NOT acting as a gateway
+ }
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The indication of whether this entity is acting
+ as an IP gateway in respect to the forwarding of
+ datagrams received by, but not addressed to, this
+ entity. IP gateways forward datagrams. IP hosts
+ do not (except those source-routed via the host).
+
+ Note that for some managed nodes, this object may
+ take on only a subset of the values possible.
+ Accordingly, it is appropriate for an agent to
+ return a `badValue' response if a management
+ station attempts to change this object to an
+ inappropriate value."
+ ::= { ip 1 }
+
+ ipDefaultTTL OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The default value inserted into the Time-To-Live
+ field of the IP header of datagrams originated at
+ this entity, whenever a TTL value is not supplied
+ by the transport layer protocol."
+ ::= { ip 2 }
+
+ ipInReceives OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of input datagrams received from
+ interfaces, including those received in error."
+
+
+
+
+
+ ::= { ip 3 }
+
+ ipInHdrErrors OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of input datagrams discarded due to
+ errors in their IP headers, including bad
+ checksums, version number mismatch, other format
+ errors, time-to-live exceeded, errors discovered
+ in processing their IP options, etc."
+ ::= { ip 4 }
+
+ ipInAddrErrors OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of input datagrams discarded because
+ the IP address in their IP header's destination
+ field was not a valid address to be received at
+ this entity. This count includes invalid
+ addresses (e.g., 0.0.0.0) and addresses of
+ unsupported Classes (e.g., Class E). For entities
+ which are not IP Gateways and therefore do not
+ forward datagrams, this counter includes datagrams
+ discarded because the destination address was not
+ a local address."
+ ::= { ip 5 }
+
+ ipForwDatagrams OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of input datagrams for which this
+ entity was not their final IP destination, as a
+ result of which an attempt was made to find a
+ route to forward them to that final destination.
+ In entities which do not act as IP Gateways, this
+ counter will include only those packets which were
+ Source-Routed via this entity, and the Source-
+ Route option processing was successful."
+ ::= { ip 6 }
+
+ ipInUnknownProtos OBJECT-TYPE
+ SYNTAX Counter
+
+
+
+
+
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of locally-addressed datagrams
+ received successfully but discarded because of an
+ unknown or unsupported protocol."
+ ::= { ip 7 }
+
+ ipInDiscards OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of input IP datagrams for which no
+ problems were encountered to prevent their
+ continued processing, but which were discarded
+ (e.g., for lack of buffer space). Note that this
+ counter does not include any datagrams discarded
+ while awaiting re-assembly."
+ ::= { ip 8 }
+
+ ipInDelivers OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of input datagrams successfully
+ delivered to IP user-protocols (including ICMP)."
+ ::= { ip 9 }
+
+ ipOutRequests OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of IP datagrams which local IP
+ user-protocols (including ICMP) supplied to IP in
+ requests for transmission. Note that this counter
+ does not include any datagrams counted in
+ ipForwDatagrams."
+ ::= { ip 10 }
+
+ ipOutDiscards OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of output IP datagrams for which no
+
+
+
+
+
+ problem was encountered to prevent their
+ transmission to their destination, but which were
+ discarded (e.g., for lack of buffer space). Note
+ that this counter would include datagrams counted
+ in ipForwDatagrams if any such packets met this
+ (discretionary) discard criterion."
+ ::= { ip 11 }
+
+ ipOutNoRoutes OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of IP datagrams discarded because no
+ route could be found to transmit them to their
+ destination. Note that this counter includes any
+ packets counted in ipForwDatagrams which meet this
+ `no-route' criterion. Note that this includes any
+ datagarms which a host cannot route because all of
+ its default gateways are down."
+ ::= { ip 12 }
+
+ ipReasmTimeout OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The maximum number of seconds which received
+ fragments are held while they are awaiting
+ reassembly at this entity."
+ ::= { ip 13 }
+
+ ipReasmReqds OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of IP fragments received which needed
+ to be reassembled at this entity."
+ ::= { ip 14 }
+
+ ipReasmOKs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of IP datagrams successfully re-
+ assembled."
+
+
+
+
+
+ ::= { ip 15 }
+
+ ipReasmFails OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of failures detected by the IP re-
+ assembly algorithm (for whatever reason: timed
+ out, errors, etc). Note that this is not
+ necessarily a count of discarded IP fragments
+ since some algorithms (notably the algorithm in
+ RFC 815) can lose track of the number of fragments
+ by combining them as they are received."
+ ::= { ip 16 }
+
+ ipFragOKs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of IP datagrams that have been
+ successfully fragmented at this entity."
+ ::= { ip 17 }
+
+ ipFragFails OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of IP datagrams that have been
+ discarded because they needed to be fragmented at
+ this entity but could not be, e.g., because their
+ Don't Fragment flag was set."
+ ::= { ip 18 }
+
+ ipFragCreates OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of IP datagram fragments that have
+ been generated as a result of fragmentation at
+ this entity."
+ ::= { ip 19 }
+
+
+
+
+
+
+
+
+ -- the IP address table
+
+ -- The IP address table contains this entity's IP addressing
+ -- information.
+
+ ipAddrTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF IpAddrEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "The table of addressing information relevant to
+ this entity's IP addresses."
+ ::= { ip 20 }
+
+ ipAddrEntry OBJECT-TYPE
+ SYNTAX IpAddrEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "The addressing information for one of this
+ entity's IP addresses."
+ INDEX { ipAdEntAddr }
+ ::= { ipAddrTable 1 }
+
+ IpAddrEntry ::=
+ SEQUENCE {
+ ipAdEntAddr
+ IpAddress,
+ ipAdEntIfIndex
+ INTEGER,
+ ipAdEntNetMask
+ IpAddress,
+ ipAdEntBcastAddr
+ INTEGER,
+ ipAdEntReasmMaxSize
+ INTEGER (0..65535)
+ }
+
+ ipAdEntAddr OBJECT-TYPE
+ SYNTAX IpAddress
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The IP address to which this entry's addressing
+ information pertains."
+ ::= { ipAddrEntry 1 }
+
+
+
+
+
+
+
+ ipAdEntIfIndex OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The index value which uniquely identifies the
+ interface to which this entry is applicable. The
+ interface identified by a particular value of this
+ index is the same interface as identified by the
+ same value of ifIndex."
+ ::= { ipAddrEntry 2 }
+
+ ipAdEntNetMask OBJECT-TYPE
+ SYNTAX IpAddress
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The subnet mask associated with the IP address of
+ this entry. The value of the mask is an IP
+ address with all the network bits set to 1 and all
+ the hosts bits set to 0."
+ ::= { ipAddrEntry 3 }
+
+ ipAdEntBcastAddr OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The value of the least-significant bit in the IP
+ broadcast address used for sending datagrams on
+ the (logical) interface associated with the IP
+ address of this entry. For example, when the
+ Internet standard all-ones broadcast address is
+ used, the value will be 1. This value applies to
+ both the subnet and network broadcasts addresses
+ used by the entity on this (logical) interface."
+ ::= { ipAddrEntry 4 }
+
+ ipAdEntReasmMaxSize OBJECT-TYPE
+ SYNTAX INTEGER (0..65535)
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The size of the largest IP datagram which this
+ entity can re-assemble from incoming IP fragmented
+ datagrams received on this interface."
+ ::= { ipAddrEntry 5 }
+
+
+
+
+
+
+ -- the IP routing table
+
+ -- The IP routing table contains an entry for each route
+ -- presently known to this entity.
+
+ ipRouteTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF IpRouteEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "This entity's IP Routing table."
+ ::= { ip 21 }
+
+ ipRouteEntry OBJECT-TYPE
+ SYNTAX IpRouteEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A route to a particular destination."
+ INDEX { ipRouteDest }
+ ::= { ipRouteTable 1 }
+
+ IpRouteEntry ::=
+ SEQUENCE {
+ ipRouteDest
+ IpAddress,
+ ipRouteIfIndex
+ INTEGER,
+ ipRouteMetric1
+ INTEGER,
+ ipRouteMetric2
+ INTEGER,
+ ipRouteMetric3
+ INTEGER,
+ ipRouteMetric4
+ INTEGER,
+ ipRouteNextHop
+ IpAddress,
+ ipRouteType
+ INTEGER,
+ ipRouteProto
+ INTEGER,
+ ipRouteAge
+ INTEGER,
+ ipRouteMask
+ IpAddress,
+ ipRouteMetric5
+ INTEGER,
+
+
+
+
+
+ ipRouteInfo
+ OBJECT IDENTIFIER
+ }
+
+ ipRouteDest OBJECT-TYPE
+ SYNTAX IpAddress
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The destination IP address of this route. An
+ entry with a value of 0.0.0.0 is considered a
+ default route. Multiple routes to a single
+ destination can appear in the table, but access to
+ such multiple entries is dependent on the table-
+ access mechanisms defined by the network
+ management protocol in use."
+ ::= { ipRouteEntry 1 }
+
+ ipRouteIfIndex OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The index value which uniquely identifies the
+ local interface through which the next hop of this
+ route should be reached. The interface identified
+ by a particular value of this index is the same
+ interface as identified by the same value of
+ ifIndex."
+ ::= { ipRouteEntry 2 }
+
+ ipRouteMetric1 OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The primary routing metric for this route. The
+ semantics of this metric are determined by the
+ routing-protocol specified in the route's
+ ipRouteProto value. If this metric is not used,
+ its value should be set to -1."
+ ::= { ipRouteEntry 3 }
+
+ ipRouteMetric2 OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+
+
+
+
+
+ "An alternate routing metric for this route. The
+ semantics of this metric are determined by the
+ routing-protocol specified in the route's
+ ipRouteProto value. If this metric is not used,
+ its value should be set to -1."
+ ::= { ipRouteEntry 4 }
+
+ ipRouteMetric3 OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "An alternate routing metric for this route. The
+ semantics of this metric are determined by the
+ routing-protocol specified in the route's
+ ipRouteProto value. If this metric is not used,
+ its value should be set to -1."
+ ::= { ipRouteEntry 5 }
+
+ ipRouteMetric4 OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "An alternate routing metric for this route. The
+ semantics of this metric are determined by the
+ routing-protocol specified in the route's
+ ipRouteProto value. If this metric is not used,
+ its value should be set to -1."
+ ::= { ipRouteEntry 6 }
+
+ ipRouteNextHop OBJECT-TYPE
+ SYNTAX IpAddress
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The IP address of the next hop of this route.
+ (In the case of a route bound to an interface
+ which is realized via a broadcast media, the value
+ of this field is the agent's IP address on that
+ interface.)"
+ ::= { ipRouteEntry 7 }
+
+ ipRouteType OBJECT-TYPE
+ SYNTAX INTEGER {
+ other(1), -- none of the following
+
+ invalid(2), -- an invalidated route
+
+
+
+
+
+ -- route to directly
+ direct(3), -- connected (sub-)network
+
+ -- route to a non-local
+ indirect(4) -- host/network/sub-network
+ }
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The type of route. Note that the values
+ direct(3) and indirect(4) refer to the notion of
+ direct and indirect routing in the IP
+ architecture.
+
+ Setting this object to the value invalid(2) has
+ the effect of invalidating the corresponding entry
+ in the ipRouteTable object. That is, it
+ effectively dissasociates the destination
+ identified with said entry from the route
+ identified with said entry. It is an
+ implementation-specific matter as to whether the
+ agent removes an invalidated entry from the table.
+ Accordingly, management stations must be prepared
+ to receive tabular information from agents that
+ corresponds to entries not currently in use.
+ Proper interpretation of such entries requires
+ examination of the relevant ipRouteType object."
+ ::= { ipRouteEntry 8 }
+
+ ipRouteProto OBJECT-TYPE
+ SYNTAX INTEGER {
+ other(1), -- none of the following
+
+ -- non-protocol information,
+ -- e.g., manually configured
+ local(2), -- entries
+
+ -- set via a network
+ netmgmt(3), -- management protocol
+
+ -- obtained via ICMP,
+ icmp(4), -- e.g., Redirect
+
+ -- the remaining values are
+ -- all gateway routing
+ -- protocols
+ egp(5),
+ ggp(6),
+
+
+
+
+
+ hello(7),
+ rip(8),
+ is-is(9),
+ es-is(10),
+ ciscoIgrp(11),
+ bbnSpfIgp(12),
+ ospf(13),
+ bgp(14)
+ }
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The routing mechanism via which this route was
+ learned. Inclusion of values for gateway routing
+ protocols is not intended to imply that hosts
+ should support those protocols."
+ ::= { ipRouteEntry 9 }
+
+ ipRouteAge OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The number of seconds since this route was last
+ updated or otherwise determined to be correct.
+ Note that no semantics of `too old' can be implied
+ except through knowledge of the routing protocol
+ by which the route was learned."
+ ::= { ipRouteEntry 10 }
+
+ ipRouteMask OBJECT-TYPE
+ SYNTAX IpAddress
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "Indicate the mask to be logical-ANDed with the
+ destination address before being compared to the
+ value in the ipRouteDest field. For those systems
+ that do not support arbitrary subnet masks, an
+ agent constructs the value of the ipRouteMask by
+ determining whether the value of the correspondent
+ ipRouteDest field belong to a class-A, B, or C
+ network, and then using one of:
+
+ mask network
+ 255.0.0.0 class-A
+ 255.255.0.0 class-B
+ 255.255.255.0 class-C
+
+
+
+
+
+ If the value of the ipRouteDest is 0.0.0.0 (a
+ default route), then the mask value is also
+ 0.0.0.0. It should be noted that all IP routing
+ subsystems implicitly use this mechanism."
+ ::= { ipRouteEntry 11 }
+
+ ipRouteMetric5 OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "An alternate routing metric for this route. The
+ semantics of this metric are determined by the
+ routing-protocol specified in the route's
+ ipRouteProto value. If this metric is not used,
+ its value should be set to -1."
+ ::= { ipRouteEntry 12 }
+
+ ipRouteInfo OBJECT-TYPE
+ SYNTAX OBJECT IDENTIFIER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "A reference to MIB definitions specific to the
+ particular routing protocol which is responsible
+ for this route, as determined by the value
+ specified in the route's ipRouteProto value. If
+ this information is not present, its value should
+ be set to the OBJECT IDENTIFIER { 0 0 }, which is
+ a syntatically valid object identifier, and any
+ conformant implementation of ASN.1 and BER must be
+ able to generate and recognize this value."
+ ::= { ipRouteEntry 13 }
+
+
+ -- the IP Address Translation table
+
+ -- The IP address translation table contain the IpAddress to
+ -- `physical' address equivalences. Some interfaces do not
+ -- use translation tables for determining address
+ -- equivalences (e.g., DDN-X.25 has an algorithmic method);
+ -- if all interfaces are of this type, then the Address
+ -- Translation table is empty, i.e., has zero entries.
+
+ ipNetToMediaTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF IpNetToMediaEntry
+ ACCESS not-accessible
+ STATUS mandatory
+
+
+
+
+
+ DESCRIPTION
+ "The IP Address Translation table used for mapping
+ from IP addresses to physical addresses."
+ ::= { ip 22 }
+
+ ipNetToMediaEntry OBJECT-TYPE
+ SYNTAX IpNetToMediaEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "Each entry contains one IpAddress to `physical'
+ address equivalence."
+ INDEX { ipNetToMediaIfIndex,
+ ipNetToMediaNetAddress }
+ ::= { ipNetToMediaTable 1 }
+
+ IpNetToMediaEntry ::=
+ SEQUENCE {
+ ipNetToMediaIfIndex
+ INTEGER,
+ ipNetToMediaPhysAddress
+ PhysAddress,
+ ipNetToMediaNetAddress
+ IpAddress,
+ ipNetToMediaType
+ INTEGER
+ }
+
+ ipNetToMediaIfIndex OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The interface on which this entry's equivalence
+ is effective. The interface identified by a
+ particular value of this index is the same
+ interface as identified by the same value of
+ ifIndex."
+ ::= { ipNetToMediaEntry 1 }
+
+ ipNetToMediaPhysAddress OBJECT-TYPE
+ SYNTAX PhysAddress
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The media-dependent `physical' address."
+ ::= { ipNetToMediaEntry 2 }
+
+
+
+
+
+
+ ipNetToMediaNetAddress OBJECT-TYPE
+ SYNTAX IpAddress
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The IpAddress corresponding to the media-
+ dependent `physical' address."
+ ::= { ipNetToMediaEntry 3 }
+
+ ipNetToMediaType OBJECT-TYPE
+ SYNTAX INTEGER {
+ other(1), -- none of the following
+ invalid(2), -- an invalidated mapping
+ dynamic(3),
+ static(4)
+ }
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The type of mapping.
+
+ Setting this object to the value invalid(2) has
+ the effect of invalidating the corresponding entry
+ in the ipNetToMediaTable. That is, it effectively
+ dissasociates the interface identified with said
+ entry from the mapping identified with said entry.
+ It is an implementation-specific matter as to
+ whether the agent removes an invalidated entry
+ from the table. Accordingly, management stations
+ must be prepared to receive tabular information
+ from agents that corresponds to entries not
+ currently in use. Proper interpretation of such
+ entries requires examination of the relevant
+ ipNetToMediaType object."
+ ::= { ipNetToMediaEntry 4 }
+
+
+ -- additional IP objects
+
+ ipRoutingDiscards OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of routing entries which were chosen
+ to be discarded even though they are valid. One
+ possible reason for discarding such an entry could
+ be to free-up buffer space for other routing
+
+
+
+
+
+ entries."
+ ::= { ip 23 }
+
+
+ -- the ICMP group
+
+ -- Implementation of the ICMP group is mandatory for all
+ -- systems.
+
+ icmpInMsgs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of ICMP messages which the
+ entity received. Note that this counter includes
+ all those counted by icmpInErrors."
+ ::= { icmp 1 }
+
+ icmpInErrors OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP messages which the entity
+ received but determined as having ICMP-specific
+ errors (bad ICMP checksums, bad length, etc.)."
+ ::= { icmp 2 }
+
+ icmpInDestUnreachs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Destination Unreachable
+ messages received."
+ ::= { icmp 3 }
+
+ icmpInTimeExcds OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Time Exceeded messages
+ received."
+ ::= { icmp 4 }
+
+
+
+
+
+
+
+ icmpInParmProbs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Parameter Problem messages
+ received."
+ ::= { icmp 5 }
+
+ icmpInSrcQuenchs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Source Quench messages
+ received."
+ ::= { icmp 6 }
+
+ icmpInRedirects OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Redirect messages received."
+ ::= { icmp 7 }
+
+ icmpInEchos OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Echo (request) messages
+ received."
+ ::= { icmp 8 }
+
+ icmpInEchoReps OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Echo Reply messages received."
+ ::= { icmp 9 }
+
+ icmpInTimestamps OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+
+
+
+
+
+ "The number of ICMP Timestamp (request) messages
+ received."
+ ::= { icmp 10 }
+
+ icmpInTimestampReps OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Timestamp Reply messages
+ received."
+ ::= { icmp 11 }
+
+ icmpInAddrMasks OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Address Mask Request messages
+ received."
+ ::= { icmp 12 }
+
+ icmpInAddrMaskReps OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Address Mask Reply messages
+ received."
+ ::= { icmp 13 }
+
+ icmpOutMsgs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of ICMP messages which this
+ entity attempted to send. Note that this counter
+ includes all those counted by icmpOutErrors."
+ ::= { icmp 14 }
+
+ icmpOutErrors OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP messages which this entity did
+ not send due to problems discovered within ICMP
+
+
+
+
+
+ such as a lack of buffers. This value should not
+ include errors discovered outside the ICMP layer
+ such as the inability of IP to route the resultant
+ datagram. In some implementations there may be no
+ types of error which contribute to this counter's
+ value."
+ ::= { icmp 15 }
+
+ icmpOutDestUnreachs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Destination Unreachable
+ messages sent."
+ ::= { icmp 16 }
+
+ icmpOutTimeExcds OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Time Exceeded messages sent."
+ ::= { icmp 17 }
+
+ icmpOutParmProbs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Parameter Problem messages
+ sent."
+ ::= { icmp 18 }
+
+ icmpOutSrcQuenchs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Source Quench messages sent."
+ ::= { icmp 19 }
+
+ icmpOutRedirects OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Redirect messages sent. For a
+
+
+
+
+
+ host, this object will always be zero, since hosts
+ do not send redirects."
+ ::= { icmp 20 }
+
+ icmpOutEchos OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Echo (request) messages sent."
+ ::= { icmp 21 }
+
+ icmpOutEchoReps OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Echo Reply messages sent."
+ ::= { icmp 22 }
+
+ icmpOutTimestamps OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Timestamp (request) messages
+ sent."
+ ::= { icmp 23 }
+
+ icmpOutTimestampReps OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Timestamp Reply messages
+ sent."
+ ::= { icmp 24 }
+
+ icmpOutAddrMasks OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Address Mask Request messages
+ sent."
+ ::= { icmp 25 }
+
+
+
+
+
+
+
+ icmpOutAddrMaskReps OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Address Mask Reply messages
+ sent."
+ ::= { icmp 26 }
+
+
+ -- the TCP group
+
+ -- Implementation of the TCP group is mandatory for all
+ -- systems that implement the TCP.
+
+ -- Note that instances of object types that represent
+ -- information about a particular TCP connection are
+ -- transient; they persist only as long as the connection
+ -- in question.
+
+ tcpRtoAlgorithm OBJECT-TYPE
+ SYNTAX INTEGER {
+ other(1), -- none of the following
+
+ constant(2), -- a constant rto
+ rsre(3), -- MIL-STD-1778, Appendix B
+ vanj(4) -- Van Jacobson's algorithm [10]
+ }
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The algorithm used to determine the timeout value
+ used for retransmitting unacknowledged octets."
+ ::= { tcp 1 }
+
+ tcpRtoMin OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The minimum value permitted by a TCP
+ implementation for the retransmission timeout,
+ measured in milliseconds. More refined semantics
+ for objects of this type depend upon the algorithm
+ used to determine the retransmission timeout. In
+ particular, when the timeout algorithm is rsre(3),
+ an object of this type has the semantics of the
+ LBOUND quantity described in RFC 793."
+
+
+
+
+
+ ::= { tcp 2 }
+
+
+ tcpRtoMax OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The maximum value permitted by a TCP
+ implementation for the retransmission timeout,
+ measured in milliseconds. More refined semantics
+ for objects of this type depend upon the algorithm
+ used to determine the retransmission timeout. In
+ particular, when the timeout algorithm is rsre(3),
+ an object of this type has the semantics of the
+ UBOUND quantity described in RFC 793."
+ ::= { tcp 3 }
+
+ tcpMaxConn OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The limit on the total number of TCP connections
+ the entity can support. In entities where the
+ maximum number of connections is dynamic, this
+ object should contain the value -1."
+ ::= { tcp 4 }
+
+ tcpActiveOpens OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of times TCP connections have made a
+ direct transition to the SYN-SENT state from the
+ CLOSED state."
+ ::= { tcp 5 }
+
+ tcpPassiveOpens OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of times TCP connections have made a
+ direct transition to the SYN-RCVD state from the
+ LISTEN state."
+ ::= { tcp 6 }
+
+
+
+
+
+ tcpAttemptFails OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of times TCP connections have made a
+ direct transition to the CLOSED state from either
+ the SYN-SENT state or the SYN-RCVD state, plus the
+ number of times TCP connections have made a direct
+ transition to the LISTEN state from the SYN-RCVD
+ state."
+ ::= { tcp 7 }
+
+ tcpEstabResets OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of times TCP connections have made a
+ direct transition to the CLOSED state from either
+ the ESTABLISHED state or the CLOSE-WAIT state."
+ ::= { tcp 8 }
+
+ tcpCurrEstab OBJECT-TYPE
+ SYNTAX Gauge
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of TCP connections for which the
+ current state is either ESTABLISHED or CLOSE-
+ WAIT."
+ ::= { tcp 9 }
+
+ tcpInSegs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of segments received, including
+ those received in error. This count includes
+ segments received on currently established
+ connections."
+ ::= { tcp 10 }
+
+ tcpOutSegs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+
+
+
+
+
+ DESCRIPTION
+ "The total number of segments sent, including
+ those on current connections but excluding those
+ containing only retransmitted octets."
+ ::= { tcp 11 }
+
+ tcpRetransSegs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of segments retransmitted - that
+ is, the number of TCP segments transmitted
+ containing one or more previously transmitted
+ octets."
+ ::= { tcp 12 }
+
+
+ -- the TCP Connection table
+
+ -- The TCP connection table contains information about this
+ -- entity's existing TCP connections.
+
+ tcpConnTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF TcpConnEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A table containing TCP connection-specific
+ information."
+ ::= { tcp 13 }
+
+ tcpConnEntry OBJECT-TYPE
+ SYNTAX TcpConnEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "Information about a particular current TCP
+ connection. An object of this type is transient,
+ in that it ceases to exist when (or soon after)
+ the connection makes the transition to the CLOSED
+ state."
+ INDEX { tcpConnLocalAddress,
+ tcpConnLocalPort,
+ tcpConnRemAddress,
+ tcpConnRemPort }
+ ::= { tcpConnTable 1 }
+
+
+
+
+
+
+ TcpConnEntry ::=
+ SEQUENCE {
+ tcpConnState
+ INTEGER,
+ tcpConnLocalAddress
+ IpAddress,
+ tcpConnLocalPort
+ INTEGER (0..65535),
+ tcpConnRemAddress
+ IpAddress,
+ tcpConnRemPort
+ INTEGER (0..65535)
+ }
+
+ tcpConnState OBJECT-TYPE
+ SYNTAX INTEGER {
+ closed(1),
+ listen(2),
+ synSent(3),
+ synReceived(4),
+ established(5),
+ finWait1(6),
+ finWait2(7),
+ closeWait(8),
+ lastAck(9),
+ closing(10),
+ timeWait(11),
+ deleteTCB(12)
+ }
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The state of this TCP connection.
+
+ The only value which may be set by a management
+ station is deleteTCB(12). Accordingly, it is
+ appropriate for an agent to return a `badValue'
+ response if a management station attempts to set
+ this object to any other value.
+
+ If a management station sets this object to the
+ value deleteTCB(12), then this has the effect of
+ deleting the TCB (as defined in RFC 793) of the
+ corresponding connection on the managed node,
+ resulting in immediate termination of the
+ connection.
+
+ As an implementation-specific option, a RST
+
+
+
+
+
+ segment may be sent from the managed node to the
+ other TCP endpoint (note however that RST segments
+ are not sent reliably)."
+ ::= { tcpConnEntry 1 }
+
+ tcpConnLocalAddress OBJECT-TYPE
+ SYNTAX IpAddress
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The local IP address for this TCP connection. In
+ the case of a connection in the listen state which
+ is willing to accept connections for any IP
+ interface associated with the node, the value
+ 0.0.0.0 is used."
+ ::= { tcpConnEntry 2 }
+
+ tcpConnLocalPort OBJECT-TYPE
+ SYNTAX INTEGER (0..65535)
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The local port number for this TCP connection."
+ ::= { tcpConnEntry 3 }
+
+ tcpConnRemAddress OBJECT-TYPE
+ SYNTAX IpAddress
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The remote IP address for this TCP connection."
+ ::= { tcpConnEntry 4 }
+
+ tcpConnRemPort OBJECT-TYPE
+ SYNTAX INTEGER (0..65535)
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The remote port number for this TCP connection."
+ ::= { tcpConnEntry 5 }
+
+
+ -- additional TCP objects
+
+ tcpInErrs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+
+
+
+
+
+ DESCRIPTION
+ "The total number of segments received in error
+ (e.g., bad TCP checksums)."
+ ::= { tcp 14 }
+
+ tcpOutRsts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of TCP segments sent containing the
+ RST flag."
+ ::= { tcp 15 }
+
+
+ -- the UDP group
+
+ -- Implementation of the UDP group is mandatory for all
+ -- systems which implement the UDP.
+
+ udpInDatagrams OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of UDP datagrams delivered to
+ UDP users."
+ ::= { udp 1 }
+
+ udpNoPorts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of received UDP datagrams for
+ which there was no application at the destination
+ port."
+ ::= { udp 2 }
+
+ udpInErrors OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of received UDP datagrams that could
+ not be delivered for reasons other than the lack
+ of an application at the destination port."
+ ::= { udp 3 }
+
+
+
+
+
+ udpOutDatagrams OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of UDP datagrams sent from this
+ entity."
+ ::= { udp 4 }
+
+
+ -- the UDP Listener table
+
+ -- The UDP listener table contains information about this
+ -- entity's UDP end-points on which a local application is
+ -- currently accepting datagrams.
+
+ udpTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF UdpEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A table containing UDP listener information."
+ ::= { udp 5 }
+
+ udpEntry OBJECT-TYPE
+ SYNTAX UdpEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "Information about a particular current UDP
+ listener."
+ INDEX { udpLocalAddress, udpLocalPort }
+ ::= { udpTable 1 }
+
+ UdpEntry ::=
+ SEQUENCE {
+ udpLocalAddress
+ IpAddress,
+ udpLocalPort
+ INTEGER (0..65535)
+ }
+
+ udpLocalAddress OBJECT-TYPE
+ SYNTAX IpAddress
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The local IP address for this UDP listener. In
+
+
+
+
+
+ the case of a UDP listener which is willing to
+ accept datagrams for any IP interface associated
+ with the node, the value 0.0.0.0 is used."
+ ::= { udpEntry 1 }
+
+ udpLocalPort OBJECT-TYPE
+ SYNTAX INTEGER (0..65535)
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The local port number for this UDP listener."
+ ::= { udpEntry 2 }
+
+
+ -- the EGP group
+
+ -- Implementation of the EGP group is mandatory for all
+ -- systems which implement the EGP.
+
+ egpInMsgs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of EGP messages received without
+ error."
+ ::= { egp 1 }
+
+ egpInErrors OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of EGP messages received that proved
+ to be in error."
+ ::= { egp 2 }
+
+ egpOutMsgs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of locally generated EGP
+ messages."
+ ::= { egp 3 }
+
+ egpOutErrors OBJECT-TYPE
+ SYNTAX Counter
+
+
+
+
+
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of locally generated EGP messages not
+ sent due to resource limitations within an EGP
+ entity."
+ ::= { egp 4 }
+
+
+ -- the EGP Neighbor table
+
+ -- The EGP neighbor table contains information about this
+ -- entity's EGP neighbors.
+
+ egpNeighTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF EgpNeighEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "The EGP neighbor table."
+ ::= { egp 5 }
+
+ egpNeighEntry OBJECT-TYPE
+ SYNTAX EgpNeighEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "Information about this entity's relationship with
+ a particular EGP neighbor."
+ INDEX { egpNeighAddr }
+ ::= { egpNeighTable 1 }
+
+ EgpNeighEntry ::=
+ SEQUENCE {
+ egpNeighState
+ INTEGER,
+ egpNeighAddr
+ IpAddress,
+ egpNeighAs
+ INTEGER,
+ egpNeighInMsgs
+ Counter,
+ egpNeighInErrs
+ Counter,
+ egpNeighOutMsgs
+ Counter,
+ egpNeighOutErrs
+ Counter,
+
+
+
+
+
+ egpNeighInErrMsgs
+ Counter,
+ egpNeighOutErrMsgs
+ Counter,
+ egpNeighStateUps
+ Counter,
+ egpNeighStateDowns
+ Counter,
+ egpNeighIntervalHello
+ INTEGER,
+ egpNeighIntervalPoll
+ INTEGER,
+ egpNeighMode
+ INTEGER,
+ egpNeighEventTrigger
+ INTEGER
+ }
+
+ egpNeighState OBJECT-TYPE
+ SYNTAX INTEGER {
+ idle(1),
+ acquisition(2),
+ down(3),
+ up(4),
+ cease(5)
+ }
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The EGP state of the local system with respect to
+ this entry's EGP neighbor. Each EGP state is
+ represented by a value that is one greater than
+ the numerical value associated with said state in
+ RFC 904."
+ ::= { egpNeighEntry 1 }
+
+ egpNeighAddr OBJECT-TYPE
+ SYNTAX IpAddress
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The IP address of this entry's EGP neighbor."
+ ::= { egpNeighEntry 2 }
+
+ egpNeighAs OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+
+
+
+
+
+ DESCRIPTION
+ "The autonomous system of this EGP peer. Zero
+ should be specified if the autonomous system
+ number of the neighbor is not yet known."
+ ::= { egpNeighEntry 3 }
+
+ egpNeighInMsgs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of EGP messages received without error
+ from this EGP peer."
+ ::= { egpNeighEntry 4 }
+
+ egpNeighInErrs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of EGP messages received from this EGP
+ peer that proved to be in error (e.g., bad EGP
+ checksum)."
+ ::= { egpNeighEntry 5 }
+
+ egpNeighOutMsgs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of locally generated EGP messages to
+ this EGP peer."
+ ::= { egpNeighEntry 6 }
+
+ egpNeighOutErrs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of locally generated EGP messages not
+ sent to this EGP peer due to resource limitations
+ within an EGP entity."
+ ::= { egpNeighEntry 7 }
+
+ egpNeighInErrMsgs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+
+
+
+
+
+ DESCRIPTION
+ "The number of EGP-defined error messages received
+ from this EGP peer."
+ ::= { egpNeighEntry 8 }
+
+ egpNeighOutErrMsgs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of EGP-defined error messages sent to
+ this EGP peer."
+ ::= { egpNeighEntry 9 }
+
+ egpNeighStateUps OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of EGP state transitions to the UP
+ state with this EGP peer."
+ ::= { egpNeighEntry 10 }
+
+ egpNeighStateDowns OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of EGP state transitions from the UP
+ state to any other state with this EGP peer."
+ ::= { egpNeighEntry 11 }
+
+ egpNeighIntervalHello OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The interval between EGP Hello command
+ retransmissions (in hundredths of a second). This
+ represents the t1 timer as defined in RFC 904."
+ ::= { egpNeighEntry 12 }
+
+ egpNeighIntervalPoll OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The interval between EGP poll command
+
+
+
+
+
+ retransmissions (in hundredths of a second). This
+ represents the t3 timer as defined in RFC 904."
+ ::= { egpNeighEntry 13 }
+
+ egpNeighMode OBJECT-TYPE
+ SYNTAX INTEGER { active(1), passive(2) }
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The polling mode of this EGP entity, either
+ passive or active."
+ ::= { egpNeighEntry 14 }
+
+ egpNeighEventTrigger OBJECT-TYPE
+ SYNTAX INTEGER { start(1), stop(2) }
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "A control variable used to trigger operator-
+ initiated Start and Stop events. When read, this
+ variable always returns the most recent value that
+ egpNeighEventTrigger was set to. If it has not
+ been set since the last initialization of the
+ network management subsystem on the node, it
+ returns a value of `stop'.
+
+ When set, this variable causes a Start or Stop
+ event on the specified neighbor, as specified on
+ pages 8-10 of RFC 904. Briefly, a Start event
+ causes an Idle peer to begin neighbor acquisition
+ and a non-Idle peer to reinitiate neighbor
+ acquisition. A stop event causes a non-Idle peer
+ to return to the Idle state until a Start event
+ occurs, either via egpNeighEventTrigger or
+ otherwise."
+ ::= { egpNeighEntry 15 }
+
+
+ -- additional EGP objects
+
+ egpAs OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The autonomous system number of this EGP entity."
+ ::= { egp 6 }
+
+
+
+
+
+
+ -- the Transmission group
+
+ -- Based on the transmission media underlying each interface
+ -- on a system, the corresponding portion of the Transmission
+ -- group is mandatory for that system.
+
+ -- When Internet-standard definitions for managing
+ -- transmission media are defined, the transmission group is
+ -- used to provide a prefix for the names of those objects.
+
+ -- Typically, such definitions reside in the experimental
+ -- portion of the MIB until they are "proven", then as a
+ -- part of the Internet standardization process, the
+ -- definitions are accordingly elevated and a new object
+ -- identifier, under the transmission group is defined. By
+ -- convention, the name assigned is:
+ --
+ -- type OBJECT IDENTIFIER ::= { transmission number }
+ --
+ -- where "type" is the symbolic value used for the media in
+ -- the ifType column of the ifTable object, and "number" is
+ -- the actual integer value corresponding to the symbol.
+
+
+ -- the SNMP group
+
+ -- Implementation of the SNMP group is mandatory for all
+ -- systems which support an SNMP protocol entity. Some of
+ -- the objects defined below will be zero-valued in those
+ -- SNMP implementations that are optimized to support only
+ -- those functions specific to either a management agent or
+ -- a management station. In particular, it should be
+ -- observed that the objects below refer to an SNMP entity,
+ -- and there may be several SNMP entities residing on a
+ -- managed node (e.g., if the node is hosting acting as
+ -- a management station).
+
+ snmpInPkts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of Messages delivered to the
+ SNMP entity from the transport service."
+ ::= { snmp 1 }
+
+ snmpOutPkts OBJECT-TYPE
+ SYNTAX Counter
+
+
+
+
+
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Messages which were
+ passed from the SNMP protocol entity to the
+ transport service."
+ ::= { snmp 2 }
+
+ snmpInBadVersions OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Messages which were
+ delivered to the SNMP protocol entity and were for
+ an unsupported SNMP version."
+ ::= { snmp 3 }
+
+ snmpInBadCommunityNames OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Messages delivered to
+ the SNMP protocol entity which used a SNMP
+ community name not known to said entity."
+ ::= { snmp 4 }
+
+ snmpInBadCommunityUses OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Messages delivered to
+ the SNMP protocol entity which represented an SNMP
+ operation which was not allowed by the SNMP
+ community named in the Message."
+ ::= { snmp 5 }
+
+ snmpInASNParseErrs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of ASN.1 or BER errors
+ encountered by the SNMP protocol entity when
+ decoding received SNMP Messages."
+ ::= { snmp 6 }
+
+
+
+
+
+ -- { snmp 7 } is not used
+
+ snmpInTooBigs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP PDUs which were
+ delivered to the SNMP protocol entity and for
+ which the value of the error-status field is
+ `tooBig'."
+ ::= { snmp 8 }
+
+ snmpInNoSuchNames OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP PDUs which were
+ delivered to the SNMP protocol entity and for
+ which the value of the error-status field is
+ `noSuchName'."
+ ::= { snmp 9 }
+
+ snmpInBadValues OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP PDUs which were
+ delivered to the SNMP protocol entity and for
+ which the value of the error-status field is
+ `badValue'."
+ ::= { snmp 10 }
+
+ snmpInReadOnlys OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number valid SNMP PDUs which were
+ delivered to the SNMP protocol entity and for
+ which the value of the error-status field is
+ `readOnly'. It should be noted that it is a
+ protocol error to generate an SNMP PDU which
+ contains the value `readOnly' in the error-status
+ field, as such this object is provided as a means
+ of detecting incorrect implementations of the
+
+
+
+
+
+ SNMP."
+ ::= { snmp 11 }
+
+ snmpInGenErrs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP PDUs which were
+ delivered to the SNMP protocol entity and for
+ which the value of the error-status field is
+ `genErr'."
+ ::= { snmp 12 }
+
+ snmpInTotalReqVars OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of MIB objects which have been
+ retrieved successfully by the SNMP protocol entity
+ as the result of receiving valid SNMP Get-Request
+ and Get-Next PDUs."
+ ::= { snmp 13 }
+
+ snmpInTotalSetVars OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of MIB objects which have been
+ altered successfully by the SNMP protocol entity
+ as the result of receiving valid SNMP Set-Request
+ PDUs."
+ ::= { snmp 14 }
+
+ snmpInGetRequests OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Get-Request PDUs which
+ have been accepted and processed by the SNMP
+ protocol entity."
+ ::= { snmp 15 }
+
+ snmpInGetNexts OBJECT-TYPE
+ SYNTAX Counter
+
+
+
+
+
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Get-Next PDUs which have
+ been accepted and processed by the SNMP protocol
+ entity."
+ ::= { snmp 16 }
+
+ snmpInSetRequests OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Set-Request PDUs which
+ have been accepted and processed by the SNMP
+ protocol entity."
+ ::= { snmp 17 }
+
+ snmpInGetResponses OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Get-Response PDUs which
+ have been accepted and processed by the SNMP
+ protocol entity."
+ ::= { snmp 18 }
+
+ snmpInTraps OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Trap PDUs which have
+ been accepted and processed by the SNMP protocol
+ entity."
+ ::= { snmp 19 }
+
+ snmpOutTooBigs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP PDUs which were
+ generated by the SNMP protocol entity and for
+ which the value of the error-status field is
+ `tooBig.'"
+ ::= { snmp 20 }
+
+
+
+
+
+ snmpOutNoSuchNames OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP PDUs which were
+ generated by the SNMP protocol entity and for
+ which the value of the error-status is
+ `noSuchName'."
+ ::= { snmp 21 }
+
+ snmpOutBadValues OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP PDUs which were
+ generated by the SNMP protocol entity and for
+ which the value of the error-status field is
+ `badValue'."
+ ::= { snmp 22 }
+
+ -- { snmp 23 } is not used
+
+ snmpOutGenErrs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP PDUs which were
+ generated by the SNMP protocol entity and for
+ which the value of the error-status field is
+ `genErr'."
+ ::= { snmp 24 }
+
+ snmpOutGetRequests OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Get-Request PDUs which
+ have been generated by the SNMP protocol entity."
+ ::= { snmp 25 }
+
+ snmpOutGetNexts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+
+
+
+
+
+ DESCRIPTION
+ "The total number of SNMP Get-Next PDUs which have
+ been generated by the SNMP protocol entity."
+ ::= { snmp 26 }
+
+ snmpOutSetRequests OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Set-Request PDUs which
+ have been generated by the SNMP protocol entity."
+ ::= { snmp 27 }
+
+ snmpOutGetResponses OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Get-Response PDUs which
+ have been generated by the SNMP protocol entity."
+ ::= { snmp 28 }
+
+ snmpOutTraps OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Trap PDUs which have
+ been generated by the SNMP protocol entity."
+ ::= { snmp 29 }
+
+ snmpEnableAuthenTraps OBJECT-TYPE
+ SYNTAX INTEGER { enabled(1), disabled(2) }
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "Indicates whether the SNMP agent process is
+ permitted to generate authentication-failure
+ traps. The value of this object overrides any
+ configuration information; as such, it provides a
+ means whereby all authentication-failure traps may
+ be disabled.
+
+ Note that it is strongly recommended that this
+ object be stored in non-volatile memory so that it
+ remains constant between re-initializations of the
+ network management system."
+
+
+
+
+
+ ::= { snmp 30 }
+
+ END
+
diff --git a/lib/snmp/mibs/SNMP-COMMUNITY-MIB.funcs b/lib/snmp/mibs/SNMP-COMMUNITY-MIB.funcs
new file mode 100644
index 0000000000..58e09b9421
--- /dev/null
+++ b/lib/snmp/mibs/SNMP-COMMUNITY-MIB.funcs
@@ -0,0 +1,2 @@
+{snmpCommunityTable, {snmp_community_mib, snmpCommunityTable, []}}.
+{snmpTargetAddrExtTable, {snmp_community_mib, snmpTargetAddrExtTable, []}}.
diff --git a/lib/snmp/mibs/SNMP-COMMUNITY-MIB.mib b/lib/snmp/mibs/SNMP-COMMUNITY-MIB.mib
new file mode 100644
index 0000000000..e9a545ffc5
--- /dev/null
+++ b/lib/snmp/mibs/SNMP-COMMUNITY-MIB.mib
@@ -0,0 +1,377 @@
+SNMP-COMMUNITY-MIB DEFINITIONS ::= BEGIN
+
+IMPORTS
+ IpAddress
+ FROM RFC1155-SMI
+ MODULE-IDENTITY,
+ OBJECT-TYPE,
+ Integer32,
+ snmpModules
+ FROM SNMPv2-SMI
+ RowStatus,
+ TestAndIncr,
+ StorageType
+ FROM SNMPv2-TC
+ SnmpAdminString,
+ SnmpEngineID
+ FROM SNMP-FRAMEWORK-MIB
+ SnmpTagValue,
+ snmpTargetAddrEntry
+ FROM SNMP-TARGET-MIB
+ MODULE-COMPLIANCE,
+ OBJECT-GROUP
+ FROM SNMPv2-CONF;
+
+snmpCommunityMIB MODULE-IDENTITY
+ LAST-UPDATED "9805110000Z" -- 11 May 1998, midnight
+ ORGANIZATION "SNMPv3 Working Group"
+ CONTACT-INFO "WG-email: [email protected]
+ Subscribe: [email protected]
+ In msg body: subscribe snmpv3
+
+ Chair: Russ Mundy
+ Trusted Information Systems
+ postal: 3060 Washington Rd
+ Glenwood MD 21738
+ USA
+ phone: +1-301-854-6889
+
+ Co-editor: Rob Frye
+ MCI Communications Corp.
+ Postal: 2100 Reston Parkway, Suite 600
+ Reston, VA 20191
+ USA
+ Phone: +1 703 715 7225
+
+ Co-editor: David B. Levi
+ SNMP Research, Inc.
+ Postal: 3001 Kimberlin Heights Road
+ Knoxville, TN 37920-9716
+ Phone: +1 423 573 1434
+
+ Co-editor: Shawn A. Routhier
+ Integrated Systems Inc.
+ Postal: 333 North Ave 4th Floor
+ Wakefield, MA 01880
+ Phone: +1 781 245 0804
+
+ Co-editor: Bert Wijnen
+ IBM T. J. Watson Research
+ postal: Schagen 33
+ 3461 GL Linschoten
+ Netherlands
+ phone: +31-348-432-794
+ "
+
+ DESCRIPTION
+ "This MIB module defines objects to help support coexistence
+ between SNMPv1, SNMPv2, and SNMPv3."
+ ::= { snmpModules 18 }
+
+-- Administrative assignments ****************************************
+
+snmpCommunityMIBObjects OBJECT IDENTIFIER ::= { snmpCommunityMIB 1 }
+snmpCommunityMIBConformance OBJECT IDENTIFIER ::= { snmpCommunityMIB 2 }
+
+--
+-- The snmpCommunityTable contains a database of community strings.
+-- This table provides mappings between community strings, and the
+-- parameters required for View-based Access Control.
+--
+
+snmpCommunityTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF SnmpCommunityEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "The table of community strings configured in the SNMP
+ engine's Local Configuration Datastore (LCD)."
+ ::= { snmpCommunityMIBObjects 1 }
+
+snmpCommunityEntry OBJECT-TYPE
+ SYNTAX SnmpCommunityEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "Information about a particular community string."
+ INDEX { IMPLIED snmpCommunityIndex }
+ ::= { snmpCommunityTable 1 }
+
+SnmpCommunityEntry ::= SEQUENCE {
+ snmpCommunityIndex SnmpAdminString,
+ snmpCommunityName OCTET STRING,
+ snmpCommunitySecurityName SnmpAdminString,
+ snmpCommunityContextEngineID SnmpEngineID,
+ snmpCommunityContextName SnmpAdminString,
+ snmpCommunityTransportTag SnmpTagValue,
+ snmpCommunityStorageType StorageType,
+ snmpCommunityStatus RowStatus
+}
+
+snmpCommunityIndex OBJECT-TYPE
+ SYNTAX SnmpAdminString (SIZE(1..32))
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "The unique index value of a row in this table."
+ ::= { snmpCommunityEntry 1 }
+
+snmpCommunityName OBJECT-TYPE
+ SYNTAX OCTET STRING (SIZE(1..64))
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "The community string for which a row in this table
+ represents a configuration."
+ ::= { snmpCommunityEntry 2 }
+
+snmpCommunitySecurityName OBJECT-TYPE
+ SYNTAX SnmpAdminString
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "A human readable string representing the corresponding
+ value of snmpCommunityName in a Security Model
+ independent format."
+ ::= { snmpCommunityEntry 3 }
+
+snmpCommunityContextEngineID OBJECT-TYPE
+ SYNTAX SnmpEngineID
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "The contextEngineID indicating the location of the
+ context in which management information is accessed
+ when using the community string specified by the
+ corresponding instance of snmpCommunityName.
+
+ The default value is the snmpEngineID of the entity in
+ which this object is instantiated."
+ ::= { snmpCommunityEntry 4 }
+
+snmpCommunityContextName OBJECT-TYPE
+ SYNTAX SnmpAdminString
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "The context in which management information is accessed
+ when using the community string specified by the corresponding
+ instance of snmpCommunityName."
+ DEFVAL { ''H } -- the empty string
+ ::= { snmpCommunityEntry 5 }
+
+snmpCommunityTransportTag OBJECT-TYPE
+ SYNTAX SnmpTagValue
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "This object specifies a set of transport endpoints
+ from which an agent will accept management requests.
+ If a management request containing this community
+ is received on a transport endpoint other than the
+ transport endpoints identified by this object, the
+ request is deemed unauthentic.
+
+ The transports identified by this object are specified
+ in the snmpTargetAddrTable. Entries in that table
+ whose snmpTargetAddrTagList contains this tag value
+ are identified.
+
+ If the value of this object has zero-length, transport
+ endpoints are not checked when authenticating messages
+ containing this community string."
+ DEFVAL { ''H } -- the empty string
+ ::= { snmpCommunityEntry 6 }
+
+snmpCommunityStorageType OBJECT-TYPE
+ SYNTAX StorageType
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "The storage type for this conceptual row in the
+ snmpCommunityTable. Conceptual rows having the value
+ 'permanent' need not allow write-access to any
+ columnar object in the row."
+ ::= { snmpCommunityEntry 7 }
+
+snmpCommunityStatus OBJECT-TYPE
+ SYNTAX RowStatus
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "The status of this conceptual row in the snmpCommunityTable.
+
+ An entry in this table is not qualified for activation
+ until instances of all corresponding columns have been
+ initialized, either through default values, or through
+ Set operations. The snmpCommunityName and
+ snmpCommunitySecurityName objects must be explicitly set."
+ ::= { snmpCommunityEntry 8 }
+
+--
+-- The snmpTargetAddrExtTable augments the snmpTargetAddrTable with
+-- a transport address mask value and a maximum message size value.
+-- The transport address mask allows entries in the
+-- snmpTargetAddrTable to define a set of addresses instead of just
+-- a single address. The maximum message size value allows the
+-- maximum message size of another SNMP entity to be configured
+-- for use in SNMPv1 (and SNMPv2c) transactions, where the message
+-- format does not specify a maximum message size.
+--
+
+snmpTargetAddrExtTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF SnmpTargetAddrExtEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "The table of mask and mms values associated with the
+ snmpTargetAddrTable."
+ ::= { snmpCommunityMIBObjects 2 }
+
+snmpTargetAddrExtEntry OBJECT-TYPE
+ SYNTAX SnmpTargetAddrExtEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "Information about a particular mask and mms value."
+ AUGMENTS { snmpTargetAddrEntry }
+ ::= { snmpTargetAddrExtTable 1 }
+
+SnmpTargetAddrExtEntry ::= SEQUENCE {
+ snmpTargetAddrTMask OCTET STRING,
+ snmpTargetAddrMMS Integer32
+}
+
+snmpTargetAddrTMask OBJECT-TYPE
+ SYNTAX OCTET STRING (SIZE (0..255))
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "The mask value associated with an entry in the
+ snmpTargetAddrTable. The value of this object must
+ have the same length as the corresponding instance of
+ snmpTargetAddrTAddress, or must have length 0."
+ DEFVAL { ''H }
+ ::= { snmpTargetAddrExtEntry 1 }
+
+snmpTargetAddrMMS OBJECT-TYPE
+ SYNTAX Integer32 (484..65535)
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "The maximum message size value associated with an entry
+ in the snmpTargetAddrTable."
+ DEFVAL { 2048 }
+ ::= { snmpTargetAddrExtEntry 2 }
+
+--
+-- The snmpTrapAddress and snmpTrapCommunity objects are included
+-- in notifications that are forwarded by a proxy, which were
+-- originally received as SNMPv1 Trap messages.
+--
+
+snmpTrapAddress OBJECT-TYPE
+ SYNTAX IpAddress
+ MAX-ACCESS accessible-for-notify
+ STATUS current
+ DESCRIPTION
+ "The value of the agent-addr field of a Trap PDU which
+ is forwarded by a proxy forwarder application using
+ an SNMP version other than SNMPv1. The value of this
+ object SHOULD contain the value of the agent-addr field
+ from the original Trap PDU as generated by an SNMPv1
+ agent."
+ ::= { snmpCommunityMIBObjects 3 }
+
+snmpTrapCommunity OBJECT-TYPE
+ SYNTAX OCTET STRING
+ MAX-ACCESS accessible-for-notify
+ STATUS current
+ DESCRIPTION
+ "The value of the community string field of an SNMPv1
+ message containing a Trap PDU which is forwarded by a
+ a proxy forwarder application using an SNMP version
+ other than SNMPv1. The value of this object SHOULD
+ contain the value of the community string field from
+ the original SNMPv1 message containing a Trap PDU as
+ generated by an SNMPv1 agent."
+ ::= { snmpCommunityMIBObjects 4 }
+
+-- Conformance Information *******************************************
+
+snmpCommunityMIBCompliances OBJECT IDENTIFIER
+ ::= { snmpCommunityMIBConformance 1 }
+snmpCommunityMIBGroups OBJECT IDENTIFIER
+ ::= { snmpCommunityMIBConformance 2 }
+
+-- Compliance statements
+
+snmpCommunityMIBCompliance MODULE-COMPLIANCE
+ STATUS current
+ DESCRIPTION
+ "The compliance statement for SNMP engines which
+ implement the SNMP-COMMUNITY-MIB."
+
+ MODULE -- this module
+ MANDATORY-GROUPS { snmpCommunityGroup }
+
+ OBJECT snmpCommunityName
+ MIN-ACCESS read-only
+ DESCRIPTION "Write access is not required."
+
+ OBJECT snmpCommunitySecurityName
+ MIN-ACCESS read-only
+ DESCRIPTION "Write access is not required."
+
+ OBJECT snmpCommunitySecurityLevel
+ MIN-ACCESS read-only
+ DESCRIPTION "Write access is not required."
+
+ OBJECT snmpCommunityContextEngineID
+ MIN-ACCESS read-only
+ DESCRIPTION "Write access is not required."
+
+ OBJECT snmpCommunityContextName
+ MIN-ACCESS read-only
+ DESCRIPTION "Write access is not required."
+
+ OBJECT snmpCommunityTransportTag
+ MIN-ACCESS read-only
+ DESCRIPTION "Write access is not required."
+
+ OBJECT snmpCommunityStorageType
+ MIN-ACCESS read-only
+ DESCRIPTION "Write access is not required."
+
+ OBJECT snmpCommunityStatus
+ MIN-ACCESS read-only
+ DESCRIPTION "Write access is not required."
+
+ ::= { snmpCommunityMIBCompliances 1 }
+
+snmpCommunityGroup OBJECT-GROUP
+ OBJECTS {
+ snmpCommunityName,
+ snmpCommunitySecurityName,
+ snmpCommunityContextEngineID,
+ snmpCommunityContextName,
+ snmpCommunityTransportTag,
+ snmpCommunityStorageType,
+ snmpCommunityStatus,
+ snmpTargetAddrTMask,
+ snmpTargetAddrMMS,
+ snmpTrapCommunity,
+ snmpTrapAddress
+ }
+ STATUS current
+ DESCRIPTION
+ "A collection of objects providing for configuration
+ of community strings for SNMPv1 (and SNMPv2c) usage."
+ ::= { snmpCommunityMIBGroups 1 }
+
+END
diff --git a/lib/snmp/mibs/SNMP-FRAMEWORK-MIB.funcs b/lib/snmp/mibs/SNMP-FRAMEWORK-MIB.funcs
new file mode 100644
index 0000000000..22cc24d44e
--- /dev/null
+++ b/lib/snmp/mibs/SNMP-FRAMEWORK-MIB.funcs
@@ -0,0 +1,4 @@
+{snmpEngineID, {snmp_framework_mib, snmpEngineID, []}}.
+{snmpEngineBoots, {snmp_framework_mib, snmpEngineBoots, []}}.
+{snmpEngineTime, {snmp_framework_mib, snmpEngineTime, []}}.
+{snmpEngineMaxMessageSize, {snmp_framework_mib, snmpEngineMaxMessageSize, []}}.
diff --git a/lib/snmp/mibs/SNMP-FRAMEWORK-MIB.mib b/lib/snmp/mibs/SNMP-FRAMEWORK-MIB.mib
new file mode 100644
index 0000000000..a3fa40cf0e
--- /dev/null
+++ b/lib/snmp/mibs/SNMP-FRAMEWORK-MIB.mib
@@ -0,0 +1,493 @@
+ SNMP-FRAMEWORK-MIB DEFINITIONS ::= BEGIN
+
+ IMPORTS
+ MODULE-IDENTITY, OBJECT-TYPE,
+ OBJECT-IDENTITY,
+ snmpModules FROM SNMPv2-SMI
+ TEXTUAL-CONVENTION FROM SNMPv2-TC
+ MODULE-COMPLIANCE, OBJECT-GROUP FROM SNMPv2-CONF;
+
+ snmpFrameworkMIB MODULE-IDENTITY
+ LAST-UPDATED "9901190000Z" -- 19 January 1999
+ ORGANIZATION "SNMPv3 Working Group"
+ CONTACT-INFO "WG-EMail: [email protected]
+ Subscribe: [email protected]
+ In message body: subscribe snmpv3
+
+ Chair: Russ Mundy
+ TIS Labs at Network Associates
+ postal: 3060 Washington Rd
+ Glenwood MD 21738
+ USA
+ phone: +1 301-854-6889
+
+ Co-editor Dave Harrington
+ Cabletron Systems, Inc.
+ postal: Post Office Box 5005
+ Mail Stop: Durham
+ 35 Industrial Way
+ Rochester, NH 03867-5005
+ USA
+ phone: +1 603-337-7357
+
+ Co-editor Randy Presuhn
+ BMC Software, Inc.
+ postal: 965 Stewart Drive
+ Sunnyvale, CA 94086
+ USA
+ phone: +1 408-616-3100
+
+ Co-editor: Bert Wijnen
+ IBM T.J. Watson Research
+ postal: Schagen 33
+ 3461 GL Linschoten
+ Netherlands
+ phone: +31 348-432-794
+ "
+ DESCRIPTION "The SNMP Management Architecture MIB"
+ REVISION "9901190000Z" -- 19 January 1999
+ DESCRIPTION "Updated editors' addresses, fixed typos.
+ "
+ REVISION "9711200000Z" -- 20 November 1997
+ DESCRIPTION "The initial version, published in RFC 2271.
+ "
+ ::= { snmpModules 10 }
+
+ -- Textual Conventions used in the SNMP Management Architecture ***
+
+ SnmpEngineID ::= TEXTUAL-CONVENTION
+ STATUS current
+ DESCRIPTION "An SNMP engine's administratively-unique identifier.
+ Objects of this type are for identification, not for
+ addressing, even though it is possible that an
+ address may have been used in the generation of
+ a specific value.
+
+ The value for this object may not be all zeros or
+ all 'ff'H or the empty (zero length) string.
+
+ The initial value for this object may be configured
+ via an operator console entry or via an algorithmic
+ function. In the latter case, the following
+ example algorithm is recommended.
+
+ In cases where there are multiple engines on the
+ same system, the use of this algorithm is NOT
+ appropriate, as it would result in all of those
+ engines ending up with the same ID value.
+
+ 1) The very first bit is used to indicate how the
+ rest of the data is composed.
+
+ 0 - as defined by enterprise using former methods
+ that existed before SNMPv3. See item 2 below.
+
+ 1 - as defined by this architecture, see item 3
+ below.
+
+ Note that this allows existing uses of the
+ engineID (also known as AgentID [RFC1910]) to
+ co-exist with any new uses.
+
+ 2) The snmpEngineID has a length of 12 octets.
+
+ The first four octets are set to the binary
+ equivalent of the agent's SNMP management
+ private enterprise number as assigned by the
+ Internet Assigned Numbers Authority (IANA).
+ For example, if Acme Networks has been assigned
+ { enterprises 696 }, the first four octets would
+ be assigned '000002b8'H.
+
+ The remaining eight octets are determined via
+ one or more enterprise-specific methods. Such
+ methods must be designed so as to maximize the
+ possibility that the value of this object will
+ be unique in the agent's administrative domain.
+ For example, it may be the IP address of the SNMP
+ entity, or the MAC address of one of the
+ interfaces, with each address suitably padded
+ with random octets. If multiple methods are
+ defined, then it is recommended that the first
+ octet indicate the method being used and the
+ remaining octets be a function of the method.
+
+ 3) The length of the octet strings varies.
+
+ The first four octets are set to the binary
+ equivalent of the agent's SNMP management
+ private enterprise number as assigned by the
+ Internet Assigned Numbers Authority (IANA).
+ For example, if Acme Networks has been assigned
+ { enterprises 696 }, the first four octets would
+ be assigned '000002b8'H.
+
+ The very first bit is set to 1. For example, the
+ above value for Acme Networks now changes to be
+ '800002b8'H.
+
+ The fifth octet indicates how the rest (6th and
+ following octets) are formatted. The values for
+ the fifth octet are:
+
+ 0 - reserved, unused.
+
+ 1 - IPv4 address (4 octets)
+ lowest non-special IP address
+
+ 2 - IPv6 address (16 octets)
+ lowest non-special IP address
+
+ 3 - MAC address (6 octets)
+ lowest IEEE MAC address, canonical
+ order
+
+ 4 - Text, administratively assigned
+ Maximum remaining length 27
+
+ 5 - Octets, administratively assigned
+ Maximum remaining length 27
+
+ 6-127 - reserved, unused
+
+ 127-255 - as defined by the enterprise
+ Maximum remaining length 27
+ "
+ SYNTAX OCTET STRING (SIZE(5..32))
+
+ SnmpSecurityModel ::= TEXTUAL-CONVENTION
+ STATUS current
+ DESCRIPTION "An identifier that uniquely identifies a
+ securityModel of the Security Subsystem within the
+ SNMP Management Architecture.
+
+ The values for securityModel are allocated as
+ follows:
+
+ - The zero value is reserved.
+ - Values between 1 and 255, inclusive, are reserved
+ for standards-track Security Models and are
+ managed by the Internet Assigned Numbers Authority
+ (IANA).
+ - Values greater than 255 are allocated to
+ enterprise-specific Security Models. An
+ enterprise-specific securityModel value is defined
+ to be:
+
+ enterpriseID * 256 + security model within
+ enterprise
+
+ For example, the fourth Security Model defined by
+ the enterprise whose enterpriseID is 1 would be
+ 260.
+
+ This scheme for allocation of securityModel
+ values allows for a maximum of 255 standards-
+ based Security Models, and for a maximum of
+ 255 Security Models per enterprise.
+
+ It is believed that the assignment of new
+ securityModel values will be rare in practice
+ because the larger the number of simultaneously
+ utilized Security Models, the larger the
+ chance that interoperability will suffer.
+ Consequently, it is believed that such a range
+ will be sufficient. In the unlikely event that
+ the standards committee finds this number to be
+ insufficient over time, an enterprise number
+ can be allocated to obtain an additional 255
+ possible values.
+
+ Note that the most significant bit must be zero;
+ hence, there are 23 bits allocated for various
+ organizations to design and define non-standard
+ securityModels. This limits the ability to
+ define new proprietary implementations of Security
+ Models to the first 8,388,608 enterprises.
+
+ It is worthwhile to note that, in its encoded
+ form, the securityModel value will normally
+ require only a single byte since, in practice,
+ the leftmost bits will be zero for most messages
+ and sign extension is suppressed by the encoding
+ rules.
+
+ As of this writing, there are several values
+ of securityModel defined for use with SNMP or
+ reserved for use with supporting MIB objects.
+ They are as follows:
+
+ 0 reserved for 'any'
+ 1 reserved for SNMPv1
+ 2 reserved for SNMPv2c
+ 3 User-Based Security Model (USM)
+ "
+ SYNTAX INTEGER(0 .. 2147483647)
+
+ SnmpMessageProcessingModel ::= TEXTUAL-CONVENTION
+ STATUS current
+ DESCRIPTION "An identifier that uniquely identifies a Message
+ Processing Model of the Message Processing
+ Subsystem within a SNMP Management Architecture.
+
+ The values for messageProcessingModel are
+ allocated as follows:
+
+ - Values between 0 and 255, inclusive, are
+ reserved for standards-track Message Processing
+ Models and are managed by the Internet Assigned
+ Numbers Authority (IANA).
+
+ - Values greater than 255 are allocated to
+ enterprise-specific Message Processing Models.
+ An enterprise messageProcessingModel value is
+ defined to be:
+
+ enterpriseID * 256 +
+ messageProcessingModel within enterprise
+
+ For example, the fourth Message Processing Model
+ defined by the enterprise whose enterpriseID
+ is 1 would be 260.
+
+ This scheme for allocating messageProcessingModel
+ values allows for a maximum of 255 standards-
+ based Message Processing Models, and for a
+ maximum of 255 Message Processing Models per
+ enterprise.
+
+ It is believed that the assignment of new
+ messageProcessingModel values will be rare
+ in practice because the larger the number of
+ simultaneously utilized Message Processing Models,
+ the larger the chance that interoperability
+ will suffer. It is believed that such a range
+ will be sufficient. In the unlikely event that
+ the standards committee finds this number to be
+ insufficient over time, an enterprise number
+ can be allocated to obtain an additional 256
+ possible values.
+
+ Note that the most significant bit must be zero;
+ hence, there are 23 bits allocated for various
+ organizations to design and define non-standard
+ messageProcessingModels. This limits the ability
+ to define new proprietary implementations of
+ Message Processing Models to the first 8,388,608
+ enterprises.
+
+ It is worthwhile to note that, in its encoded
+ form, the messageProcessingModel value will
+ normally require only a single byte since, in
+ practice, the leftmost bits will be zero for
+ most messages and sign extension is suppressed
+ by the encoding rules.
+
+ As of this writing, there are several values of
+ messageProcessingModel defined for use with SNMP.
+ They are as follows:
+
+ 0 reserved for SNMPv1
+ 1 reserved for SNMPv2c
+ 2 reserved for SNMPv2u and SNMPv2*
+ 3 reserved for SNMPv3
+ "
+ SYNTAX INTEGER(0 .. 2147483647)
+
+ SnmpSecurityLevel ::= TEXTUAL-CONVENTION
+ STATUS current
+ DESCRIPTION "A Level of Security at which SNMP messages can be
+ sent or with which operations are being processed;
+ in particular, one of:
+
+ noAuthNoPriv - without authentication and
+ without privacy,
+ authNoPriv - with authentication but
+ without privacy,
+ authPriv - with authentication and
+ with privacy.
+
+ These three values are ordered such that
+ noAuthNoPriv is less than authNoPriv and
+ authNoPriv is less than authPriv.
+ "
+ SYNTAX INTEGER { noAuthNoPriv(1),
+ authNoPriv(2),
+ authPriv(3)
+ }
+
+ SnmpAdminString ::= TEXTUAL-CONVENTION
+ DISPLAY-HINT "255a"
+ STATUS current
+ DESCRIPTION "An octet string containing administrative
+ information, preferably in human-readable form.
+
+ To facilitate internationalization, this
+ information is represented using the ISO/IEC
+ IS 10646-1 character set, encoded as an octet
+ string using the UTF-8 transformation format
+ described in [RFC2279].
+
+ Since additional code points are added by
+ amendments to the 10646 standard from time
+ to time, implementations must be prepared to
+ encounter any code point from 0x00000000 to
+ 0x7fffffff. Byte sequences that do not
+ correspond to the valid UTF-8 encoding of a
+ code point or are outside this range are
+ prohibited.
+
+ The use of control codes should be avoided.
+
+ When it is necessary to represent a newline,
+ the control code sequence CR LF should be used.
+
+ The use of leading or trailing white space should
+ be avoided.
+
+ For code points not directly supported by user
+ interface hardware or software, an alternative
+ means of entry and display, such as hexadecimal,
+ may be provided.
+
+ For information encoded in 7-bit US-ASCII,
+ the UTF-8 encoding is identical to the
+ US-ASCII encoding.
+
+ UTF-8 may require multiple bytes to represent a
+ single character / code point; thus the length
+ of this object in octets may be different from
+ the number of characters encoded. Similarly,
+ size constraints refer to the number of encoded
+ octets, not the number of characters represented
+ by an encoding.
+
+ Note that when this TC is used for an object that
+ is used or envisioned to be used as an index, then
+ a SIZE restriction MUST be specified so that the
+ number of sub-identifiers for any object instance
+ does not exceed the limit of 128, as defined by
+ [RFC1905].
+
+ Note that the size of an SnmpAdminString object is
+ measured in octets, not characters.
+ "
+ SYNTAX OCTET STRING (SIZE (0..255))
+
+
+ -- Administrative assignments ***************************************
+
+ snmpFrameworkAdmin
+ OBJECT IDENTIFIER ::= { snmpFrameworkMIB 1 }
+ snmpFrameworkMIBObjects
+ OBJECT IDENTIFIER ::= { snmpFrameworkMIB 2 }
+ snmpFrameworkMIBConformance
+ OBJECT IDENTIFIER ::= { snmpFrameworkMIB 3 }
+
+ -- the snmpEngine Group ********************************************
+
+ snmpEngine OBJECT IDENTIFIER ::= { snmpFrameworkMIBObjects 1 }
+
+ snmpEngineID OBJECT-TYPE
+ SYNTAX SnmpEngineID
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION "An SNMP engine's administratively-unique identifier.
+ "
+ ::= { snmpEngine 1 }
+
+ snmpEngineBoots OBJECT-TYPE
+ SYNTAX INTEGER (1..2147483647)
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION "The number of times that the SNMP engine has
+ (re-)initialized itself since snmpEngineID
+ was last configured.
+ "
+ ::= { snmpEngine 2 }
+
+ snmpEngineTime OBJECT-TYPE
+ SYNTAX INTEGER (0..2147483647)
+ UNITS "seconds"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION "The number of seconds since the value of
+ the snmpEngineBoots object last changed.
+ When incrementing this object's value would
+ cause it to exceed its maximum,
+ snmpEngineBoots is incremented as if a
+ re-initialization had occurred, and this
+ object's value consequently reverts to zero.
+ "
+ ::= { snmpEngine 3 }
+
+ snmpEngineMaxMessageSize OBJECT-TYPE
+ SYNTAX INTEGER (484..2147483647)
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION "The maximum length in octets of an SNMP message
+ which this SNMP engine can send or receive and
+ process, determined as the minimum of the maximum
+ message size values supported among all of the
+ transports available to and supported by the engine.
+ "
+ ::= { snmpEngine 4 }
+
+
+ -- Registration Points for Authentication and Privacy Protocols **
+
+ snmpAuthProtocols OBJECT-IDENTITY
+ STATUS current
+ DESCRIPTION "Registration point for standards-track
+ authentication protocols used in SNMP Management
+ Frameworks.
+ "
+ ::= { snmpFrameworkAdmin 1 }
+
+ snmpPrivProtocols OBJECT-IDENTITY
+ STATUS current
+ DESCRIPTION "Registration point for standards-track privacy
+ protocols used in SNMP Management Frameworks.
+ "
+ ::= { snmpFrameworkAdmin 2 }
+
+ -- Conformance information ******************************************
+
+ snmpFrameworkMIBCompliances
+ OBJECT IDENTIFIER ::= {snmpFrameworkMIBConformance 1}
+ snmpFrameworkMIBGroups
+ OBJECT IDENTIFIER ::= {snmpFrameworkMIBConformance 2}
+
+ -- compliance statements
+
+ snmpFrameworkMIBCompliance MODULE-COMPLIANCE
+ STATUS current
+ DESCRIPTION "The compliance statement for SNMP engines which
+ implement the SNMP Management Framework MIB.
+ "
+ MODULE -- this module
+ MANDATORY-GROUPS { snmpEngineGroup }
+
+ ::= { snmpFrameworkMIBCompliances 1 }
+
+ -- units of conformance
+
+ snmpEngineGroup OBJECT-GROUP
+ OBJECTS {
+ snmpEngineID,
+ snmpEngineBoots,
+ snmpEngineTime,
+ snmpEngineMaxMessageSize
+ }
+ STATUS current
+ DESCRIPTION "A collection of objects for identifying and
+ determining the configuration and current timeliness
+ values of an SNMP engine.
+ "
+ ::= { snmpFrameworkMIBGroups 1 }
+
+ END
diff --git a/lib/snmp/mibs/SNMP-MPD-MIB.funcs b/lib/snmp/mibs/SNMP-MPD-MIB.funcs
new file mode 100644
index 0000000000..a5939123ea
--- /dev/null
+++ b/lib/snmp/mibs/SNMP-MPD-MIB.funcs
@@ -0,0 +1,6 @@
+{snmpUnknownSecurityModels,
+ {snmp_standard_mib, variable_func, [snmpUnknownSecurityModels]}}.
+{snmpInvalidMsgs,
+ {snmp_standard_mib, variable_func, [snmpInvalidMsgs]}}.
+{snmpUnknownPDUHandlers,
+ {snmp_standard_mib, variable_func, [snmpUnknownPDUHandlers]}}.
diff --git a/lib/snmp/mibs/SNMP-MPD-MIB.mib b/lib/snmp/mibs/SNMP-MPD-MIB.mib
new file mode 100644
index 0000000000..4dea362f8a
--- /dev/null
+++ b/lib/snmp/mibs/SNMP-MPD-MIB.mib
@@ -0,0 +1,140 @@
+ SNMP-MPD-MIB DEFINITIONS ::= BEGIN
+
+ IMPORTS
+ MODULE-COMPLIANCE, OBJECT-GROUP FROM SNMPv2-CONF
+ MODULE-IDENTITY, OBJECT-TYPE,
+ snmpModules, Counter32 FROM SNMPv2-SMI;
+
+ snmpMPDMIB MODULE-IDENTITY
+ LAST-UPDATED "9901190000Z" -- 19 January 1999
+ ORGANIZATION "SNMPv3 Working Group"
+ CONTACT-INFO "WG-EMail: [email protected]
+ Subscribe: [email protected]
+ In message body: subscribe snmpv3
+
+ Chair: Russ Mundy
+ TIS Labs at Network Associates
+ postal: 3060 Washington Road
+ Glenwood, MD 21738
+ USA
+ phone: +1 301-854-6889
+
+ Co-editor: Jeffrey Case
+ SNMP Research, Inc.
+ postal: 3001 Kimberlin Heights Road
+ Knoxville, TN 37920-9716
+ USA
+ phone: +1 423-573-1434
+
+ Co-editor Dave Harrington
+ Cabletron Systems, Inc.
+ postal: Post Office Box 5005
+ MailStop: Durham
+ 35 Industrial Way
+ Rochester, NH 03867-5005
+ USA
+ phone: +1 603-337-7357
+
+ Co-editor: Randy Presuhn
+ BMC Software, Inc.
+ postal: 965 Stewart Drive
+ Sunnyvale, CA 94086
+ USA
+ phone: +1 408-616-3100
+
+ Co-editor: Bert Wijnen
+ IBM T. J. Watson Research
+ postal: Schagen 33
+ 3461 GL Linschoten
+ Netherlands
+ phone: +31 348-432-794
+
+ "
+ DESCRIPTION "The MIB for Message Processing and Dispatching"
+ REVISION "9901190000Z" -- 19 January 1999
+ DESCRIPTION "Corrected co-editors' address information."
+ REVISION "9709300000Z" -- 30 September 1997
+ DESCRIPTION "Original version, published as RFC 2272."
+ ::= { snmpModules 11 }
+
+ -- Administrative assignments ***************************************
+
+ snmpMPDAdmin OBJECT IDENTIFIER ::= { snmpMPDMIB 1 }
+ snmpMPDMIBObjects OBJECT IDENTIFIER ::= { snmpMPDMIB 2 }
+ snmpMPDMIBConformance OBJECT IDENTIFIER ::= { snmpMPDMIB 3 }
+
+ -- Statistics for SNMP Messages *************************************
+
+ snmpMPDStats OBJECT IDENTIFIER ::= { snmpMPDMIBObjects 1 }
+
+ snmpUnknownSecurityModels OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION "The total number of packets received by the SNMP
+ engine which were dropped because they referenced a
+ securityModel that was not known to or supported by
+ the SNMP engine.
+ "
+ ::= { snmpMPDStats 1 }
+
+ snmpInvalidMsgs OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION "The total number of packets received by the SNMP
+ engine which were dropped because there were invalid
+ or inconsistent components in the SNMP message.
+ "
+ ::= { snmpMPDStats 2 }
+
+ snmpUnknownPDUHandlers OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION "The total number of packets received by the SNMP
+ engine which were dropped because the PDU contained
+ in the packet could not be passed to an application
+ responsible for handling the pduType, e.g. no SNMP
+ application had registered for the proper
+ combination of the contextEngineID and the pduType.
+ "
+ ::= { snmpMPDStats 3 }
+
+ -- Conformance information ******************************************
+
+ snmpMPDMIBCompliances OBJECT IDENTIFIER ::= {snmpMPDMIBConformance 1}
+ snmpMPDMIBGroups OBJECT IDENTIFIER ::= {snmpMPDMIBConformance 2}
+
+ -- Compliance statements
+
+ snmpMPDCompliance MODULE-COMPLIANCE
+ STATUS current
+ DESCRIPTION "The compliance statement for SNMP entities which
+ implement the SNMP-MPD-MIB.
+ "
+
+ MODULE -- this module
+ MANDATORY-GROUPS { snmpMPDGroup }
+
+ ::= { snmpMPDMIBCompliances 1 }
+
+ snmpMPDGroup OBJECT-GROUP
+ OBJECTS {
+ snmpUnknownSecurityModels,
+ snmpInvalidMsgs,
+ snmpUnknownPDUHandlers
+ }
+ STATUS current
+ DESCRIPTION "A collection of objects providing for remote
+ monitoring of the SNMP Message Processing and
+ Dispatching process.
+ "
+ ::= { snmpMPDMIBGroups 1 }
+
+ END
diff --git a/lib/snmp/mibs/SNMP-NOTIFICATION-MIB.funcs b/lib/snmp/mibs/SNMP-NOTIFICATION-MIB.funcs
new file mode 100644
index 0000000000..9e0f533f57
--- /dev/null
+++ b/lib/snmp/mibs/SNMP-NOTIFICATION-MIB.funcs
@@ -0,0 +1,3 @@
+{snmpNotifyTable, {snmp_notification_mib, snmpNotifyTable, []}}.
+{snmpNotifyFilterProfileTable, {snmp_notification_mib, snmpNotifyFilterProfileTable, []}}.
+{snmpNotifyFilterTable, {snmp_notification_mib, snmpNotifyFilterTable, []}}.
diff --git a/lib/snmp/mibs/SNMP-NOTIFICATION-MIB.mib b/lib/snmp/mibs/SNMP-NOTIFICATION-MIB.mib
new file mode 100644
index 0000000000..fcb7a444b2
--- /dev/null
+++ b/lib/snmp/mibs/SNMP-NOTIFICATION-MIB.mib
@@ -0,0 +1,568 @@
+ SNMP-NOTIFICATION-MIB DEFINITIONS ::= BEGIN
+
+ IMPORTS
+ MODULE-IDENTITY,
+ OBJECT-TYPE,
+ snmpModules
+ FROM SNMPv2-SMI
+
+ RowStatus,
+ StorageType
+ FROM SNMPv2-TC
+
+ SnmpAdminString
+ FROM SNMP-FRAMEWORK-MIB
+
+ SnmpTagValue,
+ snmpTargetParamsName
+ FROM SNMP-TARGET-MIB
+
+ MODULE-COMPLIANCE,
+ OBJECT-GROUP
+ FROM SNMPv2-CONF;
+
+ snmpNotificationMIB MODULE-IDENTITY
+ LAST-UPDATED "9808040000Z"
+ ORGANIZATION "IETF SNMPv3 Working Group"
+ CONTACT-INFO
+ "WG-email: [email protected]
+ Subscribe: [email protected]
+ In message body: subscribe snmpv3
+
+ Chair: Russ Mundy
+ Trusted Information Systems
+ Postal: 3060 Washington Rd
+ Glenwood MD 21738
+ USA
+ Phone: +1-301-854-6889
+
+ Co-editor: David B. Levi
+ SNMP Research, Inc.
+ Postal: 3001 Kimberlin Heights Road
+ Knoxville, TN 37920-9716
+ Phone: +1 423 573 1434
+
+ Co-editor: Paul Meyer
+ Secure Computing Corporation
+ Postal: 2675 Long Lake Road
+ Roseville, MN 55113
+ Phone: +1 651 628 1592
+
+ Co-editor: Bob Stewart
+ Cisco Systems, Inc.
+ Postal: 170 West Tasman Drive
+ San Jose, CA 95134-1706
+ Phone: +1 603 654 2686"
+ DESCRIPTION
+ "This MIB module defines MIB objects which provide
+ mechanisms to remotely configure the parameters
+ used by an SNMP entity for the generation of
+ notifications."
+ REVISION "9808040000Z"
+ DESCRIPTION "Clarifications, published as
+ draft-ietf-snmpv3-appl-v2-01.txt."
+ REVISION "9707140000Z"
+ DESCRIPTION "The initial revision, published as RFC2273."
+ ::= { snmpModules 13 }
+
+ snmpNotifyObjects OBJECT IDENTIFIER ::=
+ { snmpNotificationMIB 1 }
+
+ snmpNotifyConformance OBJECT IDENTIFIER ::=
+ { snmpNotificationMIB 3 }
+
+ --
+ --
+ -- The snmpNotifyObjects group
+ --
+ --
+
+ snmpNotifyTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF SnmpNotifyEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "This table is used to select management targets which should
+ receive notifications, as well as the type of notification
+ which should be sent to each selected management target."
+ ::= { snmpNotifyObjects 1 }
+
+ snmpNotifyEntry OBJECT-TYPE
+ SYNTAX SnmpNotifyEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "An entry in this table selects a set of management targets
+ which should receive notifications, as well as the type of
+ notification which should be sent to each selected
+ management target.
+
+ Entries in the snmpNotifyTable are created and
+ deleted using the snmpNotifyRowStatus object."
+ INDEX { IMPLIED snmpNotifyName }
+ ::= { snmpNotifyTable 1 }
+
+ SnmpNotifyEntry ::= SEQUENCE {
+ snmpNotifyName SnmpAdminString,
+ snmpNotifyTag SnmpTagValue,
+ snmpNotifyType INTEGER,
+ snmpNotifyStorageType StorageType,
+ snmpNotifyRowStatus RowStatus
+ }
+
+ snmpNotifyName OBJECT-TYPE
+ SYNTAX SnmpAdminString (SIZE(1..32))
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "The locally arbitrary, but unique identifier associated
+ with this snmpNotifyEntry."
+ ::= { snmpNotifyEntry 1 }
+
+ snmpNotifyTag OBJECT-TYPE
+ SYNTAX SnmpTagValue
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "This object contains a single tag value which is used
+ to select entries in the snmpTargetAddrTable. Any entry
+ in the snmpTargetAddrTable which contains a tag value
+ which is equal to the value of an instance of this
+ object is selected. If this object contains a value
+ of zero length, no entries are selected."
+ DEFVAL { "" }
+ ::= { snmpNotifyEntry 2 }
+
+ snmpNotifyType OBJECT-TYPE
+ SYNTAX INTEGER {
+ trap(1),
+ inform(2)
+ }
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "This object determines the type of notification to
+ be generated for entries in the snmpTargetAddrTable
+ selected by the corresponding instance of
+ snmpNotifyTag. This value is only used when
+ generating notifications, and is ignored when
+ using the snmpTargetAddrTable for other purposes.
+
+ If the value of this object is trap(1), then any
+ messages generated for selected rows will contain
+ Unconfirmed-Class PDUs.
+
+ If the value of this object is inform(2), then any
+ messages generated for selected rows will contain
+ Confirmed-Class PDUs.
+
+ Note that if an SNMP entity only supports
+ generation of Unconfirmed-Class PDUs (and not
+ Confirmed-Class PDUs), then this object may be
+ read-only."
+ DEFVAL { trap }
+ ::= { snmpNotifyEntry 3 }
+
+ snmpNotifyStorageType OBJECT-TYPE
+ SYNTAX StorageType
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "The storage type for this conceptual row."
+ DEFVAL { nonVolatile }
+ ::= { snmpNotifyEntry 4 }
+
+ snmpNotifyRowStatus OBJECT-TYPE
+ SYNTAX RowStatus
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "The status of this conceptual row.
+
+ To create a row in this table, a manager must
+ set this object to either createAndGo(4) or
+ createAndWait(5)."
+ ::= { snmpNotifyEntry 5 }
+
+ snmpNotifyFilterProfileTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF SnmpNotifyFilterProfileEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "This table is used to associate a notification filter
+ profile with a particular set of target parameters."
+ ::= { snmpNotifyObjects 2 }
+
+ snmpNotifyFilterProfileEntry OBJECT-TYPE
+ SYNTAX SnmpNotifyFilterProfileEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "An entry in this table indicates the name of the filter
+ profile to be used when generating notifications using
+ the corresponding entry in the snmpTargetParamsTable.
+
+ Entries in the snmpNotifyFilterProfileTable are created
+ and deleted using the snmpNotifyFilterProfileRowStatus
+ object."
+ INDEX { IMPLIED snmpTargetParamsName }
+ ::= { snmpNotifyFilterProfileTable 1 }
+
+ SnmpNotifyFilterProfileEntry ::= SEQUENCE {
+ snmpNotifyFilterProfileName SnmpAdminString,
+ snmpNotifyFilterProfileStorType StorageType,
+ snmpNotifyFilterProfileRowStatus RowStatus
+ }
+
+ snmpNotifyFilterProfileName OBJECT-TYPE
+ SYNTAX SnmpAdminString (SIZE(1..32))
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "The name of the filter profile to be used when generating
+ notifications using the corresponding entry in the
+ snmpTargetAddrTable."
+ ::= { snmpNotifyFilterProfileEntry 1 }
+
+ snmpNotifyFilterProfileStorType OBJECT-TYPE
+ SYNTAX StorageType
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "The storage type of this conceptual row."
+ DEFVAL { nonVolatile }
+ ::= { snmpNotifyFilterProfileEntry 2 }
+
+ snmpNotifyFilterProfileRowStatus OBJECT-TYPE
+ SYNTAX RowStatus
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "The status of this conceptual row.
+
+ To create a row in this table, a manager must
+ set this object to either createAndGo(4) or
+ createAndWait(5).
+
+ Until instances of all corresponding columns are
+ appropriately configured, the value of the
+ corresponding instance of the
+ snmpNotifyFilterProfileRowStatus column is 'notReady'.
+
+ In particular, a newly created row cannot be made
+ active until the corresponding instance of
+ snmpNotifyFilterProfileName has been set."
+ ::= { snmpNotifyFilterProfileEntry 3 }
+
+ snmpNotifyFilterTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF SnmpNotifyFilterEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "The table of filter profiles. Filter profiles are used
+ to determine whether particular management targets should
+ receive particular notifications.
+
+ When a notification is generated, it must be compared
+ with the filters associated with each management target
+ which is configured to receive notifications, in order to
+ determine whether it may be sent to each such management
+ target.
+
+ A more complete discussion of notification filtering
+ can be found in section 6. of [SNMP-APPL]."
+ ::= { snmpNotifyObjects 3 }
+
+ snmpNotifyFilterEntry OBJECT-TYPE
+ SYNTAX SnmpNotifyFilterEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "An element of a filter profile.
+
+ Entries in the snmpNotifyFilterTable are created and
+ deleted using the snmpNotifyFilterRowStatus object."
+ INDEX { snmpNotifyFilterProfileName,
+ IMPLIED snmpNotifyFilterSubtree }
+ ::= { snmpNotifyFilterTable 1 }
+
+ SnmpNotifyFilterEntry ::= SEQUENCE {
+ snmpNotifyFilterSubtree OBJECT IDENTIFIER,
+ snmpNotifyFilterMask OCTET STRING,
+ snmpNotifyFilterType INTEGER,
+ snmpNotifyFilterStorageType StorageType,
+ snmpNotifyFilterRowStatus RowStatus
+ }
+
+ snmpNotifyFilterSubtree OBJECT-TYPE
+ SYNTAX OBJECT IDENTIFIER
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "The MIB subtree which, when combined with the corresponding
+ instance of snmpNotifyFilterMask, defines a family of
+ subtrees which are included in or excluded from the
+ filter profile."
+ ::= { snmpNotifyFilterEntry 1 }
+
+ snmpNotifyFilterMask OBJECT-TYPE
+ SYNTAX OCTET STRING (SIZE(0..16))
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "The bit mask which, in combination with the corresponding
+ instance of snmpNotifyFilterSubtree, defines a family of
+ subtrees which are included in or excluded from the
+ filter profile.
+
+ Each bit of this bit mask corresponds to a
+ sub-identifier of snmpNotifyFilterSubtree, with the
+ most significant bit of the i-th octet of this octet
+ string value (extended if necessary, see below)
+ corresponding to the (8*i - 7)-th sub-identifier, and
+ the least significant bit of the i-th octet of this
+ octet string corresponding to the (8*i)-th
+ sub-identifier, where i is in the range 1 through 16.
+
+ Each bit of this bit mask specifies whether or not
+ the corresponding sub-identifiers must match when
+ determining if an OBJECT IDENTIFIER matches this
+ family of filter subtrees; a '1' indicates that an
+ exact match must occur; a '0' indicates 'wild card',
+ i.e., any sub-identifier value matches.
+
+ Thus, the OBJECT IDENTIFIER X of an object instance
+ is contained in a family of filter subtrees if, for
+ each sub-identifier of the value of
+ snmpNotifyFilterSubtree, either:
+
+ the i-th bit of snmpNotifyFilterMask is 0, or
+
+ the i-th sub-identifier of X is equal to the i-th
+ sub-identifier of the value of
+ snmpNotifyFilterSubtree.
+
+ If the value of this bit mask is M bits long and
+ there are more than M sub-identifiers in the
+ corresponding instance of snmpNotifyFilterSubtree,
+ then the bit mask is extended with 1's to be the
+ required length.
+
+ Note that when the value of this object is the
+ zero-length string, this extension rule results in
+ a mask of all-1's being used (i.e., no 'wild card'),
+ and the family of filter subtrees is the one
+ subtree uniquely identified by the corresponding
+ instance of snmpNotifyFilterSubtree."
+ DEFVAL { ''H }
+ ::= { snmpNotifyFilterEntry 2 }
+
+ snmpNotifyFilterType OBJECT-TYPE
+ SYNTAX INTEGER {
+ included(1),
+ excluded(2)
+ }
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "This object indicates whether the family of filter subtrees
+ defined by this entry are included in or excluded from a
+ filter. A more detailed discussion of the use of this
+ object can be found in section 6. of [SNMP-APPL]."
+ DEFVAL { included }
+ ::= { snmpNotifyFilterEntry 3 }
+
+ snmpNotifyFilterStorageType OBJECT-TYPE
+ SYNTAX StorageType
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "The storage type of this conceptual row."
+ DEFVAL { nonVolatile }
+ ::= { snmpNotifyFilterEntry 4 }
+
+ snmpNotifyFilterRowStatus OBJECT-TYPE
+ SYNTAX RowStatus
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "The status of this conceptual row.
+
+ To create a row in this table, a manager must
+ set this object to either createAndGo(4) or
+ createAndWait(5)."
+ ::= { snmpNotifyFilterEntry 5 }
+
+ --
+ --
+ -- Conformance information
+ --
+ --
+ snmpNotifyCompliances OBJECT IDENTIFIER ::=
+ { snmpNotifyConformance 1 }
+ snmpNotifyGroups OBJECT IDENTIFIER ::=
+ { snmpNotifyConformance 2 }
+
+ --
+ --
+ -- Compliance statements
+ --
+ --
+
+ snmpNotifyBasicCompliance MODULE-COMPLIANCE
+ STATUS current
+ DESCRIPTION
+ "The compliance statement for minimal SNMP entities which
+ implement only SNMP Unconfirmed-Class notifications and
+ read-create operations on only the snmpTargetAddrTable."
+ MODULE SNMP-TARGET-MIB
+ MANDATORY-GROUPS { snmpTargetBasicGroup }
+
+ OBJECT snmpTargetParamsMPModel
+ MIN-ACCESS read-only
+ DESCRIPTION
+ "Create/delete/modify access is not required."
+
+ OBJECT snmpTargetParamsSecurityModel
+ MIN-ACCESS read-only
+ DESCRIPTION
+ "Create/delete/modify access is not required."
+
+ OBJECT snmpTargetParamsSecurityName
+ MIN-ACCESS read-only
+ DESCRIPTION
+ "Create/delete/modify access is not required."
+
+ OBJECT snmpTargetParamsSecurityLevel
+ MIN-ACCESS read-only
+ DESCRIPTION
+ "Create/delete/modify access is not required."
+
+ OBJECT snmpTargetParamsStorageType
+ SYNTAX INTEGER {
+ readOnly(5)
+ }
+ MIN-ACCESS read-only
+ DESCRIPTION
+ "Create/delete/modify access is not required.
+ Support of the values other(1), volatile(2),
+ nonVolatile(3), and permanent(4) is not required."
+
+ OBJECT snmpTargetParamsRowStatus
+ SYNTAX INTEGER {
+ active(1)
+ }
+ MIN-ACCESS read-only
+ DESCRIPTION
+ "Create/delete/modify access to the
+ snmpTargetParamsTable is not required.
+ Support of the values notInService(2), notReady(3),
+ createAndGo(4), createAndWait(5), and destroy(6) is
+ not required."
+
+ MODULE -- This Module
+ MANDATORY-GROUPS { snmpNotifyGroup }
+
+ OBJECT snmpNotifyTag
+ MIN-ACCESS read-only
+ DESCRIPTION
+ "Create/delete/modify access is not required."
+
+ OBJECT snmpNotifyType
+ SYNTAX INTEGER {
+ trap(1)
+ }
+ MIN-ACCESS read-only
+ DESCRIPTION
+ "Create/delete/modify access is not required.
+ Support of the value notify(2) is not required."
+
+ OBJECT snmpNotifyStorageType
+ SYNTAX INTEGER {
+ readOnly(5)
+ }
+ MIN-ACCESS read-only
+ DESCRIPTION
+ "Create/delete/modify access is not required.
+ Support of the values other(1), volatile(2),
+ nonVolatile(3), and permanent(4) is not required."
+
+ OBJECT snmpNotifyRowStatus
+ SYNTAX INTEGER {
+ active(1)
+ }
+ MIN-ACCESS read-only
+ DESCRIPTION
+ "Create/delete/modify access to the
+ snmpNotifyTable is not required.
+ Support of the values notInService(2), notReady(3),
+ createAndGo(4), createAndWait(5), and destroy(6) is
+ not required."
+
+ ::= { snmpNotifyCompliances 1 }
+
+ snmpNotifyBasicFiltersCompliance MODULE-COMPLIANCE
+ STATUS current
+ DESCRIPTION
+ "The compliance statement for SNMP entities which implement
+ SNMP Unconfirmed-Class notifications with filtering, and
+ read-create operations on all related tables."
+ MODULE SNMP-TARGET-MIB
+ MANDATORY-GROUPS { snmpTargetBasicGroup }
+ MODULE -- This Module
+ MANDATORY-GROUPS { snmpNotifyGroup,
+ snmpNotifyFilterGroup }
+ ::= { snmpNotifyCompliances 2 }
+
+ snmpNotifyFullCompliance MODULE-COMPLIANCE
+ STATUS current
+ DESCRIPTION
+ "The compliance statement for SNMP entities which either
+ implement only SNMP Confirmed-Class notifications, or both
+ SNMP Unconfirmed-Class and Confirmed-Class notifications,
+ plus filtering and read-create operations on all related
+ tables."
+ MODULE SNMP-TARGET-MIB
+ MANDATORY-GROUPS { snmpTargetBasicGroup,
+ snmpTargetResponseGroup }
+ MODULE -- This Module
+ MANDATORY-GROUPS { snmpNotifyGroup,
+ snmpNotifyFilterGroup }
+ ::= { snmpNotifyCompliances 3 }
+
+ snmpNotifyGroup OBJECT-GROUP
+ OBJECTS {
+ snmpNotifyTag,
+ snmpNotifyType,
+ snmpNotifyStorageType,
+ snmpNotifyRowStatus
+ }
+ STATUS current
+ DESCRIPTION
+ "A collection of objects for selecting which management
+ targets are used for generating notifications, and the
+ type of notification to be generated for each selected
+ management target."
+ ::= { snmpNotifyGroups 1 }
+
+ snmpNotifyFilterGroup OBJECT-GROUP
+ OBJECTS {
+ snmpNotifyFilterProfileName,
+ snmpNotifyFilterProfileStorType,
+ snmpNotifyFilterProfileRowStatus,
+ snmpNotifyFilterMask,
+ snmpNotifyFilterType,
+ snmpNotifyFilterStorageType,
+ snmpNotifyFilterRowStatus
+ }
+ STATUS current
+ DESCRIPTION
+ "A collection of objects providing remote configuration
+ of notification filters."
+ ::= { snmpNotifyGroups 2 }
+
+ END
diff --git a/lib/snmp/mibs/SNMP-TARGET-MIB.funcs b/lib/snmp/mibs/SNMP-TARGET-MIB.funcs
new file mode 100644
index 0000000000..a4aca711fb
--- /dev/null
+++ b/lib/snmp/mibs/SNMP-TARGET-MIB.funcs
@@ -0,0 +1,7 @@
+{snmpTargetAddrTable, {snmp_target_mib, snmpTargetAddrTable, []}}.
+{snmpTargetParamsTable, {snmp_target_mib, snmpTargetParamsTable, []}}.
+{snmpTargetSpinLock, {snmp_target_mib, snmpTargetSpinLock, []}}.
+{snmpUnavailableContexts, {snmp_standard_mib, variable_func,
+ [snmpUnavailableContexts]}}.
+{snmpUnknownContexts, {snmp_standard_mib, variable_func,
+ [snmpUnavailableContexts]}}.
diff --git a/lib/snmp/mibs/SNMP-TARGET-MIB.mib b/lib/snmp/mibs/SNMP-TARGET-MIB.mib
new file mode 100644
index 0000000000..b1b2c49753
--- /dev/null
+++ b/lib/snmp/mibs/SNMP-TARGET-MIB.mib
@@ -0,0 +1,629 @@
+ SNMP-TARGET-MIB DEFINITIONS ::= BEGIN
+
+ IMPORTS
+ MODULE-IDENTITY,
+ OBJECT-TYPE,
+ snmpModules,
+ Counter32,
+ Integer32
+ FROM SNMPv2-SMI
+
+ TEXTUAL-CONVENTION,
+ TDomain,
+ TAddress,
+ TimeInterval,
+ RowStatus,
+ StorageType,
+ TestAndIncr
+ FROM SNMPv2-TC
+
+ SnmpSecurityModel,
+ SnmpMessageProcessingModel,
+ SnmpSecurityLevel,
+ SnmpAdminString
+ FROM SNMP-FRAMEWORK-MIB
+
+ MODULE-COMPLIANCE,
+ OBJECT-GROUP
+ FROM SNMPv2-CONF;
+
+ snmpTargetMIB MODULE-IDENTITY
+ LAST-UPDATED "9808040000Z"
+ ORGANIZATION "IETF SNMPv3 Working Group"
+ CONTACT-INFO
+ "WG-email: [email protected]
+ Subscribe: [email protected]
+ In message body: subscribe snmpv3
+
+ Chair: Russ Mundy
+ Trusted Information Systems
+ Postal: 3060 Washington Rd
+ Glenwood MD 21738
+ USA
+ Phone: +1-301-854-6889
+
+ Co-editor: David B. Levi
+ SNMP Research, Inc.
+ Postal: 3001 Kimberlin Heights Road
+ Knoxville, TN 37920-9716
+ Phone: +1 423 573 1434
+
+ Co-editor: Paul Meyer
+ Secure Computing Corporation
+ Postal: 2675 Long Lake Road
+ Roseville, MN 55113
+ Phone: +1 651 628 1592
+
+ Co-editor: Bob Stewart
+ Cisco Systems, Inc.
+ Postal: 170 West Tasman Drive
+ San Jose, CA 95134-1706
+ Phone: +1 603 654 2686"
+ DESCRIPTION
+ "This MIB module defines MIB objects which provide
+ mechanisms to remotely configure the parameters used
+ by an SNMP entity for the generation of SNMP messages."
+ REVISION "9808040000Z"
+ DESCRIPTION "Clarifications, published as
+ draft-ietf-snmpv3-appl-v2-01.txt."
+ REVISION "9707140000Z"
+ DESCRIPTION "The initial revision, published as RFC2273."
+ ::= { snmpModules 12 }
+
+ snmpTargetObjects OBJECT IDENTIFIER ::= { snmpTargetMIB 1 }
+ snmpTargetConformance OBJECT IDENTIFIER ::= { snmpTargetMIB 3 }
+
+ SnmpTagValue ::= TEXTUAL-CONVENTION
+ DISPLAY-HINT "255a"
+ STATUS current
+ DESCRIPTION
+ "An octet string containing a tag value.
+ Tag values are preferably in human-readable form.
+
+ To facilitate internationalization, this information
+ is represented using the ISO/IEC IS 10646-1 character
+ set, encoded as an octet string using the UTF-8
+ character encoding scheme described in RFC 2279.
+
+ Since additional code points are added by amendments
+ to the 10646 standard from time to time,
+ implementations must be prepared to encounter any code
+ point from 0x00000000 to 0x7fffffff.
+
+ The use of control codes should be avoided, and certain
+ control codes are not allowed as described below.
+
+ For code points not directly supported by user
+ interface hardware or software, an alternative means
+ of entry and display, such as hexadecimal, may be
+ provided.
+
+ For information encoded in 7-bit US-ASCII, the UTF-8
+ representation is identical to the US-ASCII encoding.
+
+ Note that when this TC is used for an object that
+ is used or envisioned to be used as an index, then a
+ SIZE restriction must be specified so that the number
+ of sub-identifiers for any object instance does not
+ exceed the limit of 128, as defined by [RFC1905].
+
+ An object of this type contains a single tag value
+ which is used to select a set of entries in a table.
+
+ A tag value is an arbitrary string of octets, but
+ may not contain a delimiter character. Delimiter
+ characters are defined to be one of the following:
+
+ - An ASCII space character (0x20).
+
+ - An ASCII TAB character (0x09).
+
+ - An ASCII carriage return (CR) character (0x0D).
+
+ - An ASCII line feed (LF) character (0x0B).
+
+ Delimiter characters are used to separate tag values
+ in a tag list. An object of this type may only
+ contain a single tag value, and so delimiter
+ characters are not allowed in a value of this type.
+
+ Some examples of valid tag values are:
+
+ - 'acme'
+
+ - 'router'
+
+ - 'host'
+
+ The use of a tag value to select table entries is
+ application and MIB specific."
+ SYNTAX OCTET STRING (SIZE (0..255))
+
+ SnmpTagList ::= TEXTUAL-CONVENTION
+ DISPLAY-HINT "255a"
+ STATUS current
+ DESCRIPTION
+ "An octet string containing a list of tag values.
+ Tag values are preferably in human-readable form.
+
+ To facilitate internationalization, this information
+ is represented using the ISO/IEC IS 10646-1 character
+ set, encoded as an octet string using the UTF-8
+ character encoding scheme described in RFC 2279.
+
+ Since additional code points are added by amendments
+ to the 10646 standard from time to time,
+ implementations must be prepared to encounter any code
+ point from 0x00000000 to 0x7fffffff.
+
+ The use of control codes should be avoided, except as
+ described below.
+
+ For code points not directly supported by user
+ interface hardware or software, an alternative means
+ of entry and display, such as hexadecimal, may be
+ provided.
+
+ For information encoded in 7-bit US-ASCII, the UTF-8
+ representation is identical to the US-ASCII encoding.
+
+ An object of this type contains a list of tag values
+ which are used to select a set of entries in a table.
+
+ A tag value is an arbitrary string of octets, but
+ may not contain a delimiter character. Delimiter
+ characters are defined to be one of the following:
+
+ - An ASCII space character (0x20).
+
+ - An ASCII TAB character (0x09).
+
+ - An ASCII carriage return (CR) character (0x0D).
+
+ - An ASCII line feed (LF) character (0x0B).
+
+ Delimiter characters are used to separate tag values
+ in a tag list. Only a single delimiter character may
+ occur between two tag values. A tag value may not
+ have a zero length. These constraints imply certain
+ restrictions on the contents of this object:
+
+ - There cannot be a leading or trailing delimiter
+ character.
+
+ - There cannot be multiple adjacent delimiter
+ characters.
+
+ Some examples of valid tag lists are:
+
+ - An empty string
+
+ - 'acme router'
+
+ - 'host managerStation'
+
+ Note that although a tag value may not have a length of
+ zero, an empty string is still valid. This indicates
+ an empty list (i.e. there are no tag values in the list).
+
+ The use of the tag list to select table entries is
+ application and MIB specific. Typically, an application
+ will provide one or more tag values, and any entry
+ which contains some combination of these tag values
+ will be selected."
+ SYNTAX OCTET STRING (SIZE (0..255))
+
+ --
+ --
+ -- The snmpTargetObjects group
+ --
+ --
+
+ snmpTargetSpinLock OBJECT-TYPE
+ SYNTAX TestAndIncr
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "This object is used to facilitate modification of table
+ entries in the SNMP-TARGET-MIB module by multiple
+ managers. In particular, it is useful when modifying
+ the value of the snmpTargetAddrTagList object.
+
+ The procedure for modifying the snmpTargetAddrTagList
+ object is as follows:
+
+ 1. Retrieve the value of snmpTargetSpinLock and
+ of snmpTargetAddrTagList.
+
+ 2. Generate a new value for snmpTargetAddrTagList.
+
+ 3. Set the value of snmpTargetSpinLock to the
+ retrieved value, and the value of
+ snmpTargetAddrTagList to the new value. If
+ the set fails for the snmpTargetSpinLock
+ object, go back to step 1."
+ ::= { snmpTargetObjects 1 }
+
+ snmpTargetAddrTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF SnmpTargetAddrEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A table of transport addresses to be used in the generation
+ of SNMP messages."
+ ::= { snmpTargetObjects 2 }
+
+ snmpTargetAddrEntry OBJECT-TYPE
+ SYNTAX SnmpTargetAddrEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A transport address to be used in the generation
+ of SNMP operations.
+
+ Entries in the snmpTargetAddrTable are created and
+ deleted using the snmpTargetAddrRowStatus object."
+ INDEX { IMPLIED snmpTargetAddrName }
+ ::= { snmpTargetAddrTable 1 }
+
+ SnmpTargetAddrEntry ::= SEQUENCE {
+ snmpTargetAddrName SnmpAdminString,
+ snmpTargetAddrTDomain TDomain,
+ snmpTargetAddrTAddress TAddress,
+ snmpTargetAddrTimeout TimeInterval,
+ snmpTargetAddrRetryCount Integer32,
+ snmpTargetAddrTagList SnmpTagList,
+ snmpTargetAddrParams SnmpAdminString,
+ snmpTargetAddrStorageType StorageType,
+ snmpTargetAddrRowStatus RowStatus
+ }
+
+ snmpTargetAddrName OBJECT-TYPE
+ SYNTAX SnmpAdminString (SIZE(1..32))
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "The locally arbitrary, but unique identifier associated
+ with this snmpTargetAddrEntry."
+ ::= { snmpTargetAddrEntry 1 }
+
+ snmpTargetAddrTDomain OBJECT-TYPE
+ SYNTAX TDomain
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "This object indicates the transport type of the address
+ contained in the snmpTargetAddrTAddress object."
+ ::= { snmpTargetAddrEntry 2 }
+
+ snmpTargetAddrTAddress OBJECT-TYPE
+ SYNTAX TAddress
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "This object contains a transport address. The format of
+ this address depends on the value of the
+ snmpTargetAddrTDomain object."
+ ::= { snmpTargetAddrEntry 3 }
+
+ snmpTargetAddrTimeout OBJECT-TYPE
+ SYNTAX TimeInterval
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "This object should reflect the expected maximum round
+ trip time for communicating with the transport address
+ defined by this row. When a message is sent to this
+ address, and a response (if one is expected) is not
+ received within this time period, an implementation
+ may assume that the response will not be delivered.
+
+ Note that the time interval that an application waits
+ for a response may actually be derived from the value
+ of this object. The method for deriving the actual time
+ interval is implementation dependent. One such method
+ is to derive the expected round trip time based on a
+ particular retransmission algorithm and on the number
+ of timeouts which have occurred. The type of message may
+ also be considered when deriving expected round trip
+ times for retransmissions. For example, if a message is
+ being sent with a securityLevel that indicates both
+ authentication and privacy, the derived value may be
+ increased to compensate for extra processing time spent
+ during authentication and encryption processing."
+ DEFVAL { 1500 }
+ ::= { snmpTargetAddrEntry 4 }
+
+ snmpTargetAddrRetryCount OBJECT-TYPE
+ SYNTAX Integer32 (0..255)
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "This object specifies a default number of retries to be
+ attempted when a response is not received for a generated
+ message. An application may provide its own retry count,
+ in which case the value of this object is ignored."
+ DEFVAL { 3 }
+ ::= { snmpTargetAddrEntry 5 }
+
+ snmpTargetAddrTagList OBJECT-TYPE
+ SYNTAX SnmpTagList
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "This object contains a list of tag values which are
+ used to select target addresses for a particular
+ operation."
+ DEFVAL { "" }
+ ::= { snmpTargetAddrEntry 6 }
+
+ snmpTargetAddrParams OBJECT-TYPE
+ SYNTAX SnmpAdminString (SIZE(1..32))
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "The value of this object identifies an entry in the
+ snmpTargetParamsTable. The identified entry
+ contains SNMP parameters to be used when generating
+ messages to be sent to this transport address."
+ ::= { snmpTargetAddrEntry 7 }
+
+ snmpTargetAddrStorageType OBJECT-TYPE
+ SYNTAX StorageType
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "The storage type for this conceptual row."
+ DEFVAL { nonVolatile }
+ ::= { snmpTargetAddrEntry 8 }
+
+ snmpTargetAddrRowStatus OBJECT-TYPE
+ SYNTAX RowStatus
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "The status of this conceptual row.
+
+ To create a row in this table, a manager must
+ set this object to either createAndGo(4) or
+ createAndWait(5).
+
+ Until instances of all corresponding columns are
+ appropriately configured, the value of the
+ corresponding instance of the snmpTargetAddrRowStatus
+ column is 'notReady'.
+
+ In particular, a newly created row cannot be made
+ active until the corresponding instances of
+ snmpTargetAddrTDomain, snmpTargetAddrTAddress, and
+ snmpTargetAddrParams have all been set.
+
+ The following objects may not be modified while the
+ value of this object is active(1):
+ - snmpTargetAddrTDomain
+ - snmpTargetAddrTAddress
+ An attempt to set these objects while the value of
+ snmpTargetAddrRowStatus is active(1) will result in
+ an inconsistentValue error."
+ ::= { snmpTargetAddrEntry 9 }
+
+ snmpTargetParamsTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF SnmpTargetParamsEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A table of SNMP target information to be used
+ in the generation of SNMP messages."
+ ::= { snmpTargetObjects 3 }
+
+ snmpTargetParamsEntry OBJECT-TYPE
+ SYNTAX SnmpTargetParamsEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A set of SNMP target information.
+
+ Entries in the snmpTargetParamsTable are created and
+ deleted using the snmpTargetParamsRowStatus object."
+ INDEX { IMPLIED snmpTargetParamsName }
+ ::= { snmpTargetParamsTable 1 }
+
+ SnmpTargetParamsEntry ::= SEQUENCE {
+ snmpTargetParamsName SnmpAdminString,
+ snmpTargetParamsMPModel SnmpMessageProcessingModel,
+ snmpTargetParamsSecurityModel SnmpSecurityModel,
+ snmpTargetParamsSecurityName SnmpAdminString,
+ snmpTargetParamsSecurityLevel SnmpSecurityLevel,
+ snmpTargetParamsStorageType StorageType,
+ snmpTargetParamsRowStatus RowStatus
+ }
+
+ snmpTargetParamsName OBJECT-TYPE
+ SYNTAX SnmpAdminString (SIZE(1..32))
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "The locally arbitrary, but unique identifier associated
+ with this snmpTargetParamsEntry."
+ ::= { snmpTargetParamsEntry 1 }
+
+ snmpTargetParamsMPModel OBJECT-TYPE
+ SYNTAX SnmpMessageProcessingModel
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "The Message Processing Model to be used when generating
+ SNMP messages using this entry."
+ ::= { snmpTargetParamsEntry 2 }
+
+ snmpTargetParamsSecurityModel OBJECT-TYPE
+ SYNTAX SnmpSecurityModel (1..2147483647)
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "The Security Model to be used when generating SNMP
+ messages using this entry. An implementation may
+ choose to return an inconsistentValue error if an
+ attempt is made to set this variable to a value
+ for a security model which the implementation does
+ not support."
+ ::= { snmpTargetParamsEntry 3 }
+
+ snmpTargetParamsSecurityName OBJECT-TYPE
+ SYNTAX SnmpAdminString
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "The securityName which identifies the Principal on
+ whose behalf SNMP messages will be generated using
+ this entry."
+ ::= { snmpTargetParamsEntry 4 }
+
+ snmpTargetParamsSecurityLevel OBJECT-TYPE
+ SYNTAX SnmpSecurityLevel
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "The Level of Security to be used when generating
+ SNMP messages using this entry."
+ ::= { snmpTargetParamsEntry 5 }
+
+ snmpTargetParamsStorageType OBJECT-TYPE
+ SYNTAX StorageType
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "The storage type for this conceptual row."
+ DEFVAL { nonVolatile }
+ ::= { snmpTargetParamsEntry 6 }
+
+ snmpTargetParamsRowStatus OBJECT-TYPE
+ SYNTAX RowStatus
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "The status of this conceptual row.
+
+ To create a row in this table, a manager must
+ set this object to either createAndGo(4) or
+ createAndWait(5).
+
+ Until instances of all corresponding columns are
+ appropriately configured, the value of the
+ corresponding instance of the snmpTargetParamsRowStatus
+ column is 'notReady'.
+
+ In particular, a newly created row cannot be made
+ active until the corresponding
+ snmpTargetParamsMPModel,
+ snmpTargetParamsSecurityModel,
+ snmpTargetParamsSecurityName,
+ and snmpTargetParamsSecurityLevel have all been set.
+
+ The following objects may not be modified while the
+ value of this object is active(1):
+ - snmpTargetParamsMPModel
+ - snmpTargetParamsSecurityModel
+ - snmpTargetParamsSecurityName
+ - snmpTargetParamsSecurityLevel
+ An attempt to set these objects while the value of
+ snmpTargetParamsRowStatus is active(1) will result in
+ an inconsistentValue error."
+ ::= { snmpTargetParamsEntry 7 }
+
+ snmpUnavailableContexts OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The total number of packets received by the SNMP
+ engine which were dropped because the context
+ contained in the message was unavailable."
+ ::= { snmpTargetObjects 4 }
+
+ snmpUnknownContexts OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The total number of packets received by the SNMP
+ engine which were dropped because the context
+ contained in the message was unknown."
+ ::= { snmpTargetObjects 5 }
+
+ --
+ --
+ -- Conformance information
+ --
+ --
+
+ snmpTargetCompliances OBJECT IDENTIFIER ::=
+ { snmpTargetConformance 1 }
+ snmpTargetGroups OBJECT IDENTIFIER ::=
+ { snmpTargetConformance 2 }
+
+ --
+ --
+ -- Compliance statements
+ --
+ --
+ snmpTargetCommandResponderCompliance MODULE-COMPLIANCE
+ STATUS current
+ DESCRIPTION
+ "The compliance statement for SNMP entities which include
+ a command responder application."
+ MODULE -- This Module
+ MANDATORY-GROUPS { snmpTargetCommandResponderGroup }
+ ::= { snmpTargetCompliances 1 }
+
+ snmpTargetBasicGroup OBJECT-GROUP
+ OBJECTS {
+ snmpTargetSpinLock,
+ snmpTargetAddrTDomain,
+ snmpTargetAddrTAddress,
+ snmpTargetAddrTagList,
+ snmpTargetAddrParams,
+ snmpTargetAddrStorageType,
+ snmpTargetAddrRowStatus,
+ snmpTargetParamsMPModel,
+ snmpTargetParamsSecurityModel,
+ snmpTargetParamsSecurityName,
+ snmpTargetParamsSecurityLevel,
+ snmpTargetParamsStorageType,
+ snmpTargetParamsRowStatus
+ }
+ STATUS current
+ DESCRIPTION
+ "A collection of objects providing basic remote
+ configuration of management targets."
+ ::= { snmpTargetGroups 1 }
+
+ snmpTargetResponseGroup OBJECT-GROUP
+ OBJECTS {
+ snmpTargetAddrTimeout,
+ snmpTargetAddrRetryCount
+ }
+ STATUS current
+ DESCRIPTION
+ "A collection of objects providing remote configuration
+ of management targets for applications which generate
+ SNMP messages for which a response message would be
+ expected."
+ ::= { snmpTargetGroups 2 }
+
+ snmpTargetCommandResponderGroup OBJECT-GROUP
+ OBJECTS {
+ snmpUnavailableContexts,
+ snmpUnknownContexts
+ }
+ STATUS current
+ DESCRIPTION
+ "A collection of objects required for command responder
+ applications, used for counting error conditions."
+ ::= { snmpTargetGroups 3 }
+
+ END
diff --git a/lib/snmp/mibs/SNMP-USER-BASED-SM-MIB.funcs b/lib/snmp/mibs/SNMP-USER-BASED-SM-MIB.funcs
new file mode 100644
index 0000000000..76344ec70c
--- /dev/null
+++ b/lib/snmp/mibs/SNMP-USER-BASED-SM-MIB.funcs
@@ -0,0 +1,14 @@
+{usmStatsUnsupportedSecLevels,
+ {snmp_standard_mib, variable_func, [usmStatsUnsupportedSecLevels]}}.
+{usmStatsNotInTimeWindows,
+ {snmp_standard_mib, variable_func, [usmStatsNotInTimeWindows]}}.
+{usmStatsUnknownUserNames,
+ {snmp_standard_mib, variable_func, [usmStatsUnknownUserNames]}}.
+{usmStatsUnknownEngineIDs,
+ {snmp_standard_mib, variable_func, [usmStatsUnknownEngineIDs]}}.
+{usmStatsWrongDigests,
+ {snmp_standard_mib, variable_func, [usmStatsWrongDigests]}}.
+{usmStatsDecryptionErrors,
+ {snmp_standard_mib, variable_func, [usmStatsDecryptionErrors]}}.
+{usmUserTable, {snmp_user_based_sm_mib, usmUserTable, []}}.
+{usmUserSpinLock, {snmp_user_based_sm_mib, usmUserSpinLock, []}}.
diff --git a/lib/snmp/mibs/SNMP-USER-BASED-SM-MIB.mib b/lib/snmp/mibs/SNMP-USER-BASED-SM-MIB.mib
new file mode 100644
index 0000000000..50d7011ef7
--- /dev/null
+++ b/lib/snmp/mibs/SNMP-USER-BASED-SM-MIB.mib
@@ -0,0 +1,887 @@
+SNMP-USER-BASED-SM-MIB DEFINITIONS ::= BEGIN
+
+IMPORTS
+ MODULE-IDENTITY, OBJECT-TYPE,
+ OBJECT-IDENTITY,
+ snmpModules, Counter32 FROM SNMPv2-SMI
+ TEXTUAL-CONVENTION, TestAndIncr,
+ RowStatus, RowPointer,
+ StorageType, AutonomousType FROM SNMPv2-TC
+ MODULE-COMPLIANCE, OBJECT-GROUP FROM SNMPv2-CONF
+ SnmpAdminString, SnmpEngineID,
+ snmpAuthProtocols, snmpPrivProtocols FROM SNMP-FRAMEWORK-MIB;
+
+snmpUsmMIB MODULE-IDENTITY
+ LAST-UPDATED "9901200000Z" -- 20 Jan 1999, midnight
+ ORGANIZATION "SNMPv3 Working Group"
+ CONTACT-INFO "WG-email: [email protected]
+ Subscribe: [email protected]
+ In msg body: subscribe snmpv3
+
+ Chair: Russ Mundy
+ Trusted Information Systems
+ postal: 3060 Washington Rd
+ Glenwood MD 21738
+ USA
+ phone: +1-301-854-6889
+
+ Co-editor Uri Blumenthal
+ IBM T. J. Watson Research
+ postal: 30 Saw Mill River Pkwy,
+ Hawthorne, NY 10532
+ USA
+ phone: +1-914-784-7964
+
+ Co-editor: Bert Wijnen
+ IBM T. J. Watson Research
+ postal: Schagen 33
+ 3461 GL Linschoten
+ Netherlands
+ phone: +31-348-432-794
+ "
+ DESCRIPTION "The management information definitions for the
+ SNMP User-based Security Model.
+ "
+-- Revision history
+ REVISION "9901200000Z" -- 20 Jan 1999, midnight
+ -- RFC-Editor assigns RFCxxxx
+ DESCRIPTION "Clarifications, published as RFCxxxx"
+
+ REVISION "9711200000Z" -- 20 Nov 1997, midnight
+ DESCRIPTION "Initial version, published as RFC2274"
+
+ ::= { snmpModules 15 }
+
+-- Administrative assignments ****************************************
+
+usmMIBObjects OBJECT IDENTIFIER ::= { snmpUsmMIB 1 }
+usmMIBConformance OBJECT IDENTIFIER ::= { snmpUsmMIB 2 }
+
+-- Identification of Authentication and Privacy Protocols ************
+
+usmNoAuthProtocol OBJECT-IDENTITY
+ STATUS current
+ DESCRIPTION "No Authentication Protocol."
+ ::= { snmpAuthProtocols 1 }
+
+usmHMACMD5AuthProtocol OBJECT-IDENTITY
+ STATUS current
+ DESCRIPTION "The HMAC-MD5-96 Digest Authentication Protocol."
+ REFERENCE "- H. Krawczyk, M. Bellare, R. Canetti HMAC:
+ Keyed-Hashing for Message Authentication,
+ RFC2104, Feb 1997.
+ - Rivest, R., Message Digest Algorithm MD5, RFC1321.
+ "
+ ::= { snmpAuthProtocols 2 }
+
+usmHMACSHAAuthProtocol OBJECT-IDENTITY
+ STATUS current
+ DESCRIPTION "The HMAC-SHA-96 Digest Authentication Protocol."
+ REFERENCE "- H. Krawczyk, M. Bellare, R. Canetti, HMAC:
+ Keyed-Hashing for Message Authentication,
+ RFC2104, Feb 1997.
+ - Secure Hash Algorithm. NIST FIPS 180-1.
+ "
+ ::= { snmpAuthProtocols 3 }
+
+usmNoPrivProtocol OBJECT-IDENTITY
+ STATUS current
+ DESCRIPTION "No Privacy Protocol."
+ ::= { snmpPrivProtocols 1 }
+
+usmDESPrivProtocol OBJECT-IDENTITY
+ STATUS current
+ DESCRIPTION "The CBC-DES Symmetric Encryption Protocol."
+ REFERENCE "- Data Encryption Standard, National Institute of
+ Standards and Technology. Federal Information
+ Processing Standard (FIPS) Publication 46-1.
+ Supersedes FIPS Publication 46,
+ (January, 1977; reaffirmed January, 1988).
+
+ - Data Encryption Algorithm, American National
+ Standards Institute. ANSI X3.92-1981,
+ (December, 1980).
+
+ - DES Modes of Operation, National Institute of
+ Standards and Technology. Federal Information
+ Processing Standard (FIPS) Publication 81,
+ (December, 1980).
+
+ - Data Encryption Algorithm - Modes of Operation,
+ American National Standards Institute.
+ ANSI X3.106-1983, (May 1983).
+ "
+ ::= { snmpPrivProtocols 2 }
+
+
+-- Textual Conventions ***********************************************
+
+
+KeyChange ::= TEXTUAL-CONVENTION
+ STATUS current
+ DESCRIPTION
+ "Every definition of an object with this syntax must identify
+ a protocol P, a secret key K, and a hash algorithm H
+ that produces output of L octets.
+
+ The object's value is a manager-generated, partially-random
+ value which, when modified, causes the value of the secret
+ key K, to be modified via a one-way function.
+
+ The value of an instance of this object is the concatenation
+ of two components: first a 'random' component and then a
+ 'delta' component.
+
+ The lengths of the random and delta components
+ are given by the corresponding value of the protocol P;
+ if P requires K to be a fixed length, the length of both the
+ random and delta components is that fixed length; if P
+ allows the length of K to be variable up to a particular
+ maximum length, the length of the random component is that
+ maximum length and the length of the delta component is any
+ length less than or equal to that maximum length.
+ For example, usmHMACMD5AuthProtocol requires K to be a fixed
+ length of 16 octets and L - of 16 octets.
+ usmHMACSHAAuthProtocol requires K to be a fixed length of
+ 20 octets and L - of 20 octets. Other protocols may define
+ other sizes, as deemed appropriate.
+
+ When a requester wants to change the old key K to a new
+ key keyNew on a remote entity, the 'random' component is
+ obtained from either a true random generator, or from a
+ pseudorandom generator, and the 'delta' component is
+ computed as follows:
+
+ - a temporary variable is initialized to the existing value
+ of K;
+ - if the length of the keyNew is greater than L octets,
+ then:
+ - the random component is appended to the value of the
+ temporary variable, and the result is input to the
+ the hash algorithm H to produce a digest value, and
+ the temporary variable is set to this digest value;
+ - the value of the temporary variable is XOR-ed with
+ the first (next) L-octets (16 octets in case of MD5)
+ of the keyNew to produce the first (next) L-octets
+ (16 octets in case of MD5) of the 'delta' component.
+ - the above two steps are repeated until the unused
+ portion of the keyNew component is L octets or less,
+ - the random component is appended to the value of the
+ temporary variable, and the result is input to the
+ hash algorithm H to produce a digest value;
+ - this digest value, truncated if necessary to be the same
+ length as the unused portion of the keyNew, is XOR-ed
+ with the unused portion of the keyNew to produce the
+ (final portion of the) 'delta' component.
+
+ For example, using MD5 as the hash algorithm H:
+
+ iterations = (lenOfDelta - 1)/16; /* integer division */
+ temp = keyOld;
+ for (i = 0; i < iterations; i++) {
+ temp = MD5 (temp || random);
+ delta[i*16 .. (i*16)+15] =
+ temp XOR keyNew[i*16 .. (i*16)+15];
+ }
+ temp = MD5 (temp || random);
+ delta[i*16 .. lenOfDelta-1] =
+ temp XOR keyNew[i*16 .. lenOfDelta-1];
+
+ The 'random' and 'delta' components are then concatenated as
+ described above, and the resulting octet string is sent to
+ the recipient as the new value of an instance of this object.
+
+ At the receiver side, when an instance of this object is set
+ to a new value, then a new value of K is computed as follows:
+
+ - a temporary variable is initialized to the existing value
+ of K;
+ - if the length of the delta component is greater than L
+ octets, then:
+ - the random component is appended to the value of the
+ temporary variable, and the result is input to the
+ hash algorithm H to produce a digest value, and the
+ temporary variable is set to this digest value;
+ - the value of the temporary variable is XOR-ed with
+ the first (next) L-octets (16 octets in case of MD5)
+ of the delta component to produce the first (next)
+ L-octets (16 octets in case of MD5) of the new value
+ of K.
+ - the above two steps are repeated until the unused
+ portion of the delta component is L octets or less,
+ - the random component is appended to the value of the
+ temporary variable, and the result is input to the
+ hash algorithm H to produce a digest value;
+ - this digest value, truncated if necessary to be the same
+ length as the unused portion of the delta component, is
+ XOR-ed with the unused portion of the delta component to
+ produce the (final portion of the) new value of K.
+
+ For example, using MD5 as the hash algorithm H:
+
+ iterations = (lenOfDelta - 1)/16; /* integer division */
+ temp = keyOld;
+ for (i = 0; i < iterations; i++) {
+ temp = MD5 (temp || random);
+ keyNew[i*16 .. (i*16)+15] =
+ temp XOR delta[i*16 .. (i*16)+15];
+ }
+ temp = MD5 (temp || random);
+ keyNew[i*16 .. lenOfDelta-1] =
+ temp XOR delta[i*16 .. lenOfDelta-1];
+
+ The value of an object with this syntax, whenever it is
+ retrieved by the management protocol, is always the zero
+ length string.
+
+ Note that the keyOld and keyNew are the localized keys.
+
+ Note that it is probably wise that when an SNMP entity sends
+ a SetRequest to change a key, that it keeps a copy of the old
+ key until it has confirmed that the key change actually
+ succeeded.
+ "
+ SYNTAX OCTET STRING
+
+
+-- Statistics for the User-based Security Model **********************
+
+
+usmStats OBJECT IDENTIFIER ::= { usmMIBObjects 1 }
+
+
+usmStatsUnsupportedSecLevels OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION "The total number of packets received by the SNMP
+ engine which were dropped because they requested a
+ securityLevel that was unknown to the SNMP engine
+ or otherwise unavailable.
+ "
+ ::= { usmStats 1 }
+
+usmStatsNotInTimeWindows OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION "The total number of packets received by the SNMP
+ engine which were dropped because they appeared
+ outside of the authoritative SNMP engine's window.
+ "
+ ::= { usmStats 2 }
+
+usmStatsUnknownUserNames OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION "The total number of packets received by the SNMP
+ engine which were dropped because they referenced a
+ user that was not known to the SNMP engine.
+ "
+ ::= { usmStats 3 }
+
+usmStatsUnknownEngineIDs OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION "The total number of packets received by the SNMP
+ engine which were dropped because they referenced an
+ snmpEngineID that was not known to the SNMP engine.
+ "
+ ::= { usmStats 4 }
+
+usmStatsWrongDigests OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION "The total number of packets received by the SNMP
+ engine which were dropped because they didn't
+ contain the expected digest value.
+ "
+ ::= { usmStats 5 }
+
+usmStatsDecryptionErrors OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION "The total number of packets received by the SNMP
+ engine which were dropped because they could not be
+ decrypted.
+ "
+ ::= { usmStats 6 }
+
+-- The usmUser Group ************************************************
+
+usmUser OBJECT IDENTIFIER ::= { usmMIBObjects 2 }
+
+usmUserSpinLock OBJECT-TYPE
+ SYNTAX TestAndIncr
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION "An advisory lock used to allow several cooperating
+ Command Generator Applications to coordinate their
+ use of facilities to alter secrets in the
+ usmUserTable.
+ "
+ ::= { usmUser 1 }
+
+-- The table of valid users for the User-based Security Model ********
+
+usmUserTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF UsmUserEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION "The table of users configured in the SNMP engine's
+ Local Configuration Datastore (LCD).
+
+ To create a new user (i.e., to instantiate a new
+ conceptual row in this table), it is recommended to
+ follow this procedure:
+
+ 1) GET(usmUserSpinLock.0) and save in sValue.
+ 2) SET(usmUserSpinLock.0=sValue,
+ usmUserCloneFrom=templateUser,
+ usmUserStatus=createAndWait)
+ You should use a template user to clone from
+ which has the proper auth/priv protocol defined.
+
+ If the new user is to use privacy:
+
+ 3) generate the keyChange value based on the secret
+ privKey of the clone-from user and the secret key
+ to be used for the new user. Let us call this
+ pkcValue.
+ 4) GET(usmUserSpinLock.0) and save in sValue.
+ 5) SET(usmUserSpinLock.0=sValue,
+ usmUserPrivKeyChange=pkcValue
+ usmUserPublic=randomValue1)
+ 6) GET(usmUserPulic) and check it has randomValue1.
+ If not, repeat steps 4-6.
+
+ If the new user will never use privacy:
+
+ 7) SET(usmUserPrivProtocol=usmNoPrivProtocol)
+
+ If the new user is to use authentication:
+
+ 8) generate the keyChange value based on the secret
+ authKey of the clone-from user and the secret key
+ to be used for the new user. Let us call this
+ akcValue.
+ 9) GET(usmUserSpinLock.0) and save in sValue.
+ 10) SET(usmUserSpinLock.0=sValue,
+ usmUserAuthKeyChange=akcValue
+ usmUserPublic=randomValue2)
+ 11) GET(usmUserPulic) and check it has randomValue2.
+ If not, repeat steps 9-11.
+
+ If the new user will never use authentication:
+
+ 12) SET(usmUserAuthProtocol=usmNoAuthProtocol)
+
+ Finally, activate the new user:
+
+ 13) SET(usmUserStatus=active)
+
+ The new user should now be available and ready to be
+ used for SNMPv3 communication. Note however that access
+ to MIB data must be provided via configuration of the
+ SNMP-VIEW-BASED-ACM-MIB.
+
+ The use of usmUserSpinlock is to avoid conflicts with
+ another SNMP command responder application which may
+ also be acting on the usmUserTable.
+ "
+ ::= { usmUser 2 }
+
+usmUserEntry OBJECT-TYPE
+ SYNTAX UsmUserEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION "A user configured in the SNMP engine's Local
+ Configuration Datastore (LCD) for the User-based
+ Security Model.
+ "
+ INDEX { usmUserEngineID,
+ usmUserName
+ }
+ ::= { usmUserTable 1 }
+
+UsmUserEntry ::= SEQUENCE
+ {
+ usmUserEngineID SnmpEngineID,
+ usmUserName SnmpAdminString,
+ usmUserSecurityName SnmpAdminString,
+ usmUserCloneFrom RowPointer,
+ usmUserAuthProtocol AutonomousType,
+ usmUserAuthKeyChange KeyChange,
+ usmUserOwnAuthKeyChange KeyChange,
+ usmUserPrivProtocol AutonomousType,
+ usmUserPrivKeyChange KeyChange,
+ usmUserOwnPrivKeyChange KeyChange,
+ usmUserPublic OCTET STRING,
+ usmUserStorageType StorageType,
+ usmUserStatus RowStatus
+ }
+
+usmUserEngineID OBJECT-TYPE
+ SYNTAX SnmpEngineID
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION "An SNMP engine's administratively-unique identifier.
+
+ In a simple agent, this value is always that agent's
+ own snmpEngineID value.
+
+ The value can also take the value of the snmpEngineID
+ of a remote SNMP engine with which this user can
+ communicate.
+ "
+ ::= { usmUserEntry 1 }
+
+usmUserName OBJECT-TYPE
+ SYNTAX SnmpAdminString (SIZE(1..32))
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION "A human readable string representing the name of
+ the user.
+
+ This is the (User-based Security) Model dependent
+ security ID.
+ "
+ ::= { usmUserEntry 2 }
+
+usmUserSecurityName OBJECT-TYPE
+ SYNTAX SnmpAdminString
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION "A human readable string representing the user in
+ Security Model independent format.
+
+ The default transformation of the User-based Security
+ Model dependent security ID to the securityName and
+ vice versa is the identity function so that the
+ securityName is the same as the userName.
+ "
+ ::= { usmUserEntry 3 }
+
+usmUserCloneFrom OBJECT-TYPE
+ SYNTAX RowPointer
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION "A pointer to another conceptual row in this
+ usmUserTable. The user in this other conceptual
+ row is called the clone-from user.
+
+ When a new user is created (i.e., a new conceptual
+ row is instantiated in this table), the privacy and
+ authentication parameters of the new user must be
+ cloned from its clone-from user. These parameters are:
+ - authentication protocol (usmUserAuthProtocol)
+ - privacy protocol (usmUserPrivProtocol)
+ They will be copied regardless of what the current
+ value is.
+
+ Cloning also causes the initial values of the secret
+ authentication key (authKey) and the secret encryption
+ key (privKey) of the new user to be set to the same
+ value as the corresponding secret of the clone-from
+ user.
+
+ The first time an instance of this object is set by
+ a management operation (either at or after its
+ instantiation), the cloning process is invoked.
+ Subsequent writes are successful but invoke no
+ action to be taken by the receiver.
+ The cloning process fails with an 'inconsistentName'
+ error if the conceptual row representing the
+ clone-from user does not exist or is not in an active
+ state when the cloning process is invoked.
+
+ When this object is read, the ZeroDotZero OID
+ is returned.
+ "
+ ::= { usmUserEntry 4 }
+
+usmUserAuthProtocol OBJECT-TYPE
+ SYNTAX AutonomousType
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION "An indication of whether messages sent on behalf of
+ this user to/from the SNMP engine identified by
+ usmUserEngineID, can be authenticated, and if so,
+ the type of authentication protocol which is used.
+
+ An instance of this object is created concurrently
+ with the creation of any other object instance for
+ the same user (i.e., as part of the processing of
+ the set operation which creates the first object
+ instance in the same conceptual row).
+
+ If an initial set operation (i.e. at row creation time)
+ tries to set a value for an unknown or unsupported
+ protocol, then a 'wrongValue' error must be returned.
+
+ The value will be overwritten/set when a set operation
+ is performed on the corresponding instance of
+ usmUserCloneFrom.
+
+ Once instantiated, the value of such an instance of
+ this object can only be changed via a set operation to
+ the value of the usmNoAuthProtocol.
+
+ If a set operation tries to change the value of an
+ existing instance of this object to any value other
+ than usmNoAuthProtocol, then an 'inconsistentValue'
+ error must be returned.
+
+ If a set operation tries to set the value to the
+ usmNoAuthProtocol while the usmUserPrivProtocol value
+ in the same row is not equal to usmNoPrivProtocol,
+ then an 'inconsistentValue' error must be returned.
+ That means that an SNMP command generator application
+ must first ensure that the usmUserPrivProtocol is set
+ to the usmNoPrivProtocol value before it can set
+ the usmUserAuthProtocol value to usmNoAuthProtocol.
+ "
+ DEFVAL { usmNoAuthProtocol }
+ ::= { usmUserEntry 5 }
+
+usmUserAuthKeyChange OBJECT-TYPE
+ SYNTAX KeyChange -- typically (SIZE (0 | 32)) for HMACMD5
+ -- typically (SIZE (0 | 40)) for HMACSHA
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION "An object, which when modified, causes the secret
+ authentication key used for messages sent on behalf
+ of this user to/from the SNMP engine identified by
+ usmUserEngineID, to be modified via a one-way
+ function.
+
+ The associated protocol is the usmUserAuthProtocol.
+ The associated secret key is the user's secret
+ authentication key (authKey). The associated hash
+ algorithm is the algorithm used by the user's
+ usmUserAuthProtocol.
+
+ When creating a new user, it is an 'inconsistentName'
+ error for a set operation to refer to this object
+ unless it is previously or concurrently initialized
+ through a set operation on the corresponding instance
+ of usmUserCloneFrom.
+
+ When the value of the corresponding usmUserAuthProtocol
+ is usmNoAuthProtocol, then a set is successful, but
+ effectively is a no-op.
+
+ When this object is read, the zero-length (empty)
+ string is returned.
+
+ The recommended way to do a key change is as follows:
+
+ 1) GET(usmUserSpinLock.0) and save in sValue.
+ 2) generate the keyChange value based on the old
+ (existing) secret key and the new secret key,
+ let us call this kcValue.
+
+ If you do the key change on behalf of another user:
+
+ 3) SET(usmUserSpinLock.0=sValue,
+ usmUserAuthKeyChange=kcValue
+ usmUserPublic=randomValue)
+
+ If you do the key change for yourself:
+
+ 4) SET(usmUserSpinLock.0=sValue,
+ usmUserOwnAuthKeyChange=kcValue
+ usmUserPublic=randomValue)
+
+ If you get a response with error-status of noError,
+ then the SET succeeded and the new key is active.
+ If you do not get a response, then you can issue a
+ GET(usmUserPublic) and check if the value is equal
+ to the randomValue you did send in the SET. If so, then
+ the key change succeeded and the new key is active
+ (probably the response got lost). If not, then the SET
+ request probably never reached the target and so you
+ can start over with the procedure above.
+ "
+ DEFVAL { ''H } -- the empty string
+ ::= { usmUserEntry 6 }
+
+usmUserOwnAuthKeyChange OBJECT-TYPE
+ SYNTAX KeyChange -- typically (SIZE (0 | 32)) for HMACMD5
+ -- typically (SIZE (0 | 40)) for HMACSHA
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION "Behaves exactly as usmUserAuthKeyChange, with one
+ notable difference: in order for the set operation
+ to succeed, the usmUserName of the operation
+ requester must match the usmUserName that
+ indexes the row which is targeted by this
+ operation.
+ In addition, the USM security model must be
+ used for this operation.
+
+ The idea here is that access to this column can be
+ public, since it will only allow a user to change
+ his own secret authentication key (authKey).
+ Note that this can only be done once the row is active.
+
+ When a set is received and the usmUserName of the
+ requester is not the same as the umsUserName that
+ indexes the row which is targeted by this operation,
+ then a 'noAccess' error must be returned.
+
+ When a set is received and the security model in use
+ is not USM, then a 'noAccess' error must be returned.
+ "
+ DEFVAL { ''H } -- the empty string
+ ::= { usmUserEntry 7 }
+
+usmUserPrivProtocol OBJECT-TYPE
+ SYNTAX AutonomousType
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION "An indication of whether messages sent on behalf of
+ this user to/from the SNMP engine identified by
+ usmUserEngineID, can be protected from disclosure,
+ and if so, the type of privacy protocol which is used.
+
+ An instance of this object is created concurrently
+ with the creation of any other object instance for
+ the same user (i.e., as part of the processing of
+ the set operation which creates the first object
+ instance in the same conceptual row).
+
+ If an initial set operation (i.e. at row creation time)
+ tries to set a value for an unknown or unsupported
+ protocol, then a 'wrongValue' error must be returned.
+
+ The value will be overwritten/set when a set operation
+ is performed on the corresponding instance of
+ usmUserCloneFrom.
+
+ Once instantiated, the value of such an instance of
+ this object can only be changed via a set operation to
+ the value of the usmNoPrivProtocol.
+
+ If a set operation tries to change the value of an
+ existing instance of this object to any value other
+ than usmNoPrivProtocol, then an 'inconsistentValue'
+ error must be returned.
+
+ Note that if any privacy protocol is used, then you
+ must also use an authentication protocol. In other
+ words, if usmUserPrivProtocol is set to anything else
+ than usmNoPrivProtocol, then the corresponding instance
+ of usmUserAuthProtocol cannot have a value of
+ usmNoAuthProtocol. If it does, then an
+ 'inconsistentValue' error must be returned.
+ "
+ DEFVAL { usmNoPrivProtocol }
+ ::= { usmUserEntry 8 }
+
+usmUserPrivKeyChange OBJECT-TYPE
+ SYNTAX KeyChange -- typically (SIZE (0 | 32)) for DES
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION "An object, which when modified, causes the secret
+ encryption key used for messages sent on behalf
+ of this user to/from the SNMP engine identified by
+ usmUserEngineID, to be modified via a one-way
+ function.
+
+ The associated protocol is the usmUserPrivProtocol.
+ The associated secret key is the user's secret
+ privacy key (privKey). The associated hash
+ algorithm is the algorithm used by the user's
+ usmUserAuthProtocol.
+
+ When creating a new user, it is an 'inconsistentName'
+ error for a set operation to refer to this object
+ unless it is previously or concurrently initialized
+ through a set operation on the corresponding instance
+ of usmUserCloneFrom.
+
+ When the value of the corresponding usmUserPrivProtocol
+ is usmNoPrivProtocol, then a set is successful, but
+ effectively is a no-op.
+
+ When this object is read, the zero-length (empty)
+ string is returned.
+ See the description clause of usmUserAuthKeyChange for
+ a recommended procedure to do a key change.
+ "
+ DEFVAL { ''H } -- the empty string
+ ::= { usmUserEntry 9 }
+
+usmUserOwnPrivKeyChange OBJECT-TYPE
+ SYNTAX KeyChange -- typically (SIZE (0 | 32)) for DES
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION "Behaves exactly as usmUserPrivKeyChange, with one
+ notable difference: in order for the Set operation
+ to succeed, the usmUserName of the operation
+ requester must match the usmUserName that indexes
+ the row which is targeted by this operation.
+ In addition, the USM security model must be
+ used for this operation.
+
+ The idea here is that access to this column can be
+ public, since it will only allow a user to change
+ his own secret privacy key (privKey).
+ Note that this can only be done once the row is active.
+
+ When a set is received and the usmUserName of the
+ requester is not the same as the umsUserName that
+ indexes the row which is targeted by this operation,
+ then a 'noAccess' error must be returned.
+
+ When a set is received and the security model in use
+ is not USM, then a 'noAccess' error must be returned.
+ "
+ DEFVAL { ''H } -- the empty string
+ ::= { usmUserEntry 10 }
+
+usmUserPublic OBJECT-TYPE
+ SYNTAX OCTET STRING (SIZE(0..32))
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION "A publicly-readable value which can be written as part
+ of the procedure for changing a user's secret
+ authentication and/or privacy key, and later read to
+ determine whether the change of the secret was
+ effected.
+ "
+ DEFVAL { ''H } -- the empty string
+ ::= { usmUserEntry 11 }
+
+usmUserStorageType OBJECT-TYPE
+ SYNTAX StorageType
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION "The storage type for this conceptual row.
+
+ Conceptual rows having the value 'permanent' must
+ allow write-access at a minimum to:
+
+ - usmUserAuthKeyChange, usmUserOwnAuthKeyChange
+ and usmUserPublic for a user who employs
+ authentication, and
+ - usmUserPrivKeyChange, usmUserOwnPrivKeyChange
+ and usmUserPublic for a user who employs
+ privacy.
+
+ Note that any user who employs authentication or
+ privacy must allow its secret(s) to be updated and
+ thus cannot be 'readOnly'.
+
+ If an initial set operation tries to set the value to
+ 'readOnly' for a user who employs authentication or
+ privacy, then an 'inconsistentValue' error must be
+ returned. Note that if the value has been previously
+ set (implicit or explicit) to any value, then the rules
+ as defined in the StorageType Textual Convention apply.
+
+ It is an implementation issue to decide if a SET for
+ a readOnly or permanent row is accepted at all. In some
+ contexts this may make sense, in others it may not. If
+ a SET for a readOnly or permanent row is not accepted
+ at all, then a 'wrongValue' error must be returned.
+ "
+ DEFVAL { nonVolatile }
+ ::= { usmUserEntry 12 }
+
+usmUserStatus OBJECT-TYPE
+ SYNTAX RowStatus
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION "The status of this conceptual row.
+
+ Until instances of all corresponding columns are
+ appropriately configured, the value of the
+ corresponding instance of the usmUserStatus column
+ is 'notReady'.
+
+ In particular, a newly created row for a user who
+ employs authentication, cannot be made active until the
+ corresponding usmUserCloneFrom and usmUserAuthKeyChange
+ have been set.
+
+ Further, a newly created row for a user who also
+ employs privacy, cannot be made active until the
+ usmUserPrivKeyChange has been set.
+
+ The RowStatus TC [RFC1903] requires that this
+ DESCRIPTION clause states under which circumstances
+ other objects in this row can be modified:
+
+ The value of this object has no effect on whether
+ other objects in this conceptual row can be modified,
+ except for usmUserOwnAuthKeyChange and
+ usmUserOwnPrivKeyChange. For these 2 objects, the
+ value of usmUserStatus MUST be active.
+ "
+ ::= { usmUserEntry 13 }
+
+-- Conformance Information *******************************************
+
+usmMIBCompliances OBJECT IDENTIFIER ::= { usmMIBConformance 1 }
+usmMIBGroups OBJECT IDENTIFIER ::= { usmMIBConformance 2 }
+
+-- Compliance statements
+
+usmMIBCompliance MODULE-COMPLIANCE
+ STATUS current
+ DESCRIPTION "The compliance statement for SNMP engines which
+ implement the SNMP-USER-BASED-SM-MIB.
+ "
+
+ MODULE -- this module
+ MANDATORY-GROUPS { usmMIBBasicGroup }
+
+ OBJECT usmUserAuthProtocol
+ MIN-ACCESS read-only
+ DESCRIPTION "Write access is not required."
+
+ OBJECT usmUserPrivProtocol
+ MIN-ACCESS read-only
+ DESCRIPTION "Write access is not required."
+
+ ::= { usmMIBCompliances 1 }
+
+-- Units of compliance
+usmMIBBasicGroup OBJECT-GROUP
+ OBJECTS {
+ usmStatsUnsupportedSecLevels,
+ usmStatsNotInTimeWindows,
+ usmStatsUnknownUserNames,
+ usmStatsUnknownEngineIDs,
+ usmStatsWrongDigests,
+ usmStatsDecryptionErrors,
+ usmUserSpinLock,
+ usmUserSecurityName,
+ usmUserCloneFrom,
+ usmUserAuthProtocol,
+ usmUserAuthKeyChange,
+ usmUserOwnAuthKeyChange,
+ usmUserPrivProtocol,
+ usmUserPrivKeyChange,
+ usmUserOwnPrivKeyChange,
+ usmUserPublic,
+ usmUserStorageType,
+ usmUserStatus
+ }
+ STATUS current
+ DESCRIPTION "A collection of objects providing for configuration
+ of an SNMP engine which implements the SNMP
+ User-based Security Model.
+ "
+ ::= { usmMIBGroups 1 }
+
+END
diff --git a/lib/snmp/mibs/SNMP-USM-AES-MIB.mib b/lib/snmp/mibs/SNMP-USM-AES-MIB.mib
new file mode 100644
index 0000000000..e9e9fb827b
--- /dev/null
+++ b/lib/snmp/mibs/SNMP-USM-AES-MIB.mib
@@ -0,0 +1,62 @@
+SNMP-USM-AES-MIB DEFINITIONS ::= BEGIN
+ IMPORTS
+ MODULE-IDENTITY, OBJECT-IDENTITY,
+ snmpModules FROM SNMPv2-SMI -- [RFC2578]
+ snmpPrivProtocols FROM SNMP-FRAMEWORK-MIB; -- [RFC3411]
+
+snmpUsmAesMIB MODULE-IDENTITY
+ LAST-UPDATED "200406140000Z"
+ ORGANIZATION "IETF"
+ CONTACT-INFO "Uri Blumenthal
+ Lucent Technologies / Bell Labs
+ 67 Whippany Rd.
+ 14D-318
+ Whippany, NJ 07981, USA
+ 973-386-2163
+
+ Fabio Maino
+ Andiamo Systems, Inc.
+ 375 East Tasman Drive
+ San Jose, CA 95134, USA
+ 408-853-7530
+
+ Keith McCloghrie
+ Cisco Systems, Inc.
+ 170 West Tasman Drive
+ San Jose, CA 95134-1706, USA
+
+ 408-526-5260
+ DESCRIPTION "Definitions of Object Identities needed for
+ the use of AES by SNMP's User-based Security
+ Model.
+
+ Copyright (C) The Internet Society (2004).
+
+ This version of this MIB module is part of RFC 3826;
+ see the RFC itself for full legal notices.
+ Supplementary information may be available on
+ http://www.ietf.org/copyrights/ianamib.html."
+ REVISION "200406140000Z"
+ DESCRIPTION "Initial version, published as RFC3826"
+
+ ::= { snmpModules 20 }
+
+usmAesCfb128Protocol OBJECT-IDENTITY
+ STATUS current
+ DESCRIPTION "The CFB128-AES-128 Privacy Protocol."
+ REFERENCE "- Specification for the ADVANCED ENCRYPTION
+ STANDARD. Federal Information Processing
+ Standard (FIPS) Publication 197.
+ (November 2001).
+
+ - Dworkin, M., NIST Recommendation for Block
+ Cipher Modes of Operation, Methods and
+ Techniques. NIST Special Publication 800-38A
+ (December 2001).
+ "
+ ::= { snmpPrivProtocols 4 }
+
+END
diff --git a/lib/snmp/mibs/SNMP-VIEW-BASED-ACM-MIB.funcs b/lib/snmp/mibs/SNMP-VIEW-BASED-ACM-MIB.funcs
new file mode 100644
index 0000000000..ec6301f4ac
--- /dev/null
+++ b/lib/snmp/mibs/SNMP-VIEW-BASED-ACM-MIB.funcs
@@ -0,0 +1,7 @@
+{vacmAccessTable, {snmp_view_based_acm_mib, vacmAccessTable, []}}.
+{vacmContextTable, {snmp_view_based_acm_mib, vacmContextTable, []}}.
+{vacmSecurityToGroupTable,
+ {snmp_view_based_acm_mib, vacmSecurityToGroupTable, []}}.
+{vacmViewSpinLock, {snmp_view_based_acm_mib, vacmViewSpinLock, []}}.
+{vacmViewTreeFamilyTable,
+ {snmp_view_based_acm_mib, vacmViewTreeFamilyTable, []}}.
diff --git a/lib/snmp/mibs/SNMP-VIEW-BASED-ACM-MIB.mib b/lib/snmp/mibs/SNMP-VIEW-BASED-ACM-MIB.mib
new file mode 100644
index 0000000000..fe0f0ce283
--- /dev/null
+++ b/lib/snmp/mibs/SNMP-VIEW-BASED-ACM-MIB.mib
@@ -0,0 +1,805 @@
+SNMP-VIEW-BASED-ACM-MIB DEFINITIONS ::= BEGIN
+
+IMPORTS
+ MODULE-COMPLIANCE, OBJECT-GROUP FROM SNMPv2-CONF
+ MODULE-IDENTITY, OBJECT-TYPE,
+ snmpModules FROM SNMPv2-SMI
+ TestAndIncr,
+ RowStatus, StorageType FROM SNMPv2-TC
+ SnmpAdminString,
+ SnmpSecurityLevel,
+ SnmpSecurityModel FROM SNMP-FRAMEWORK-MIB;
+
+snmpVacmMIB MODULE-IDENTITY
+ LAST-UPDATED "9901200000Z" -- 20 Jan 1999, midnight
+ ORGANIZATION "SNMPv3 Working Group"
+ CONTACT-INFO "WG-email: [email protected]
+ Subscribe: [email protected]
+ In message body: subscribe snmpv3
+
+ Chair: Russ Mundy
+ Trusted Information Systems
+ postal: 3060 Washington Rd
+ Glenwood MD 21738
+ USA
+ phone: +1-301-854-6889
+
+ Co-editor: Bert Wijnen
+ IBM T.J. Watson Research
+ postal: Schagen 33
+ 3461 GL Linschoten
+ Netherlands
+ phone: +31-348-432-794
+
+ Co-editor: Randy Presuhn
+ BMC Software, Inc
+ postal: 965 Stewart Drive
+ Sunnyvale, CA 94086
+ USA
+ phone: +1-408-616-3100
+
+ Co-editor: Keith McCloghrie
+ Cisco Systems, Inc.
+ postal: 170 West Tasman Drive
+ San Jose, CA 95134-1706
+ USA
+ phone: +1-408-526-5260
+ "
+ DESCRIPTION "The management information definitions for the
+ View-based Access Control Model for SNMP.
+ "
+-- Revision history
+ REVISION "9901200000Z" -- 20 Jan 1999, midnight
+ -- RFC-Editor assigns RFCxxxx
+ DESCRIPTION "Clarifications, published as RFCxxxx"
+
+ REVISION "9711200000Z" -- 20 Nov 1997, midnight
+ DESCRIPTION "Initial version, published as RFC2275"
+
+ ::= { snmpModules 16 }
+
+-- Administrative assignments ****************************************
+
+vacmMIBObjects OBJECT IDENTIFIER ::= { snmpVacmMIB 1 }
+vacmMIBConformance OBJECT IDENTIFIER ::= { snmpVacmMIB 2 }
+
+-- Information about Local Contexts **********************************
+
+vacmContextTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF VacmContextEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION "The table of locally available contexts.
+
+ This table provides information to SNMP Command
+ Generator applications so that they can properly
+ configure the vacmAccessTable to control access to
+ all contexts at the SNMP entity.
+
+ This table may change dynamically if the SNMP entity
+ allows that contexts are added/deleted dynamically
+ (for instance when its configuration changes). Such
+ changes would happen only if the management
+ instrumentation at that SNMP entity recognizes more
+ (or fewer) contexts.
+
+ The presence of entries in this table and of entries
+ in the vacmAccessTable are independent. That is, a
+ context identified by an entry in this table is not
+ necessarily referenced by any entries in the
+ vacmAccessTable; and the context(s) referenced by an
+ entry in the vacmAccessTable does not necessarily
+ currently exist and thus need not be identified by an
+ entry in this table.
+
+ This table must be made accessible via the default
+ context so that Command Responder applications have
+ a standard way of retrieving the information.
+
+ This table is read-only. It cannot be configured via
+ SNMP.
+ "
+ ::= { vacmMIBObjects 1 }
+
+vacmContextEntry OBJECT-TYPE
+ SYNTAX VacmContextEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION "Information about a particular context."
+ INDEX {
+ vacmContextName
+ }
+ ::= { vacmContextTable 1 }
+
+VacmContextEntry ::= SEQUENCE
+ {
+ vacmContextName SnmpAdminString
+ }
+
+vacmContextName OBJECT-TYPE
+ SYNTAX SnmpAdminString (SIZE(0..32))
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION "A human readable name identifying a particular
+ context at a particular SNMP entity.
+
+ The empty contextName (zero length) represents the
+ default context.
+ "
+ ::= { vacmContextEntry 1 }
+
+-- Information about Groups ******************************************
+
+vacmSecurityToGroupTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF VacmSecurityToGroupEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION "This table maps a combination of securityModel and
+ securityName into a groupName which is used to define
+ an access control policy for a group of principals.
+ "
+ ::= { vacmMIBObjects 2 }
+
+vacmSecurityToGroupEntry OBJECT-TYPE
+ SYNTAX VacmSecurityToGroupEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION "An entry in this table maps the combination of a
+ securityModel and securityName into a groupName.
+ "
+ INDEX {
+ vacmSecurityModel,
+ vacmSecurityName
+ }
+ ::= { vacmSecurityToGroupTable 1 }
+
+VacmSecurityToGroupEntry ::= SEQUENCE
+ {
+ vacmSecurityModel SnmpSecurityModel,
+ vacmSecurityName SnmpAdminString,
+ vacmGroupName SnmpAdminString,
+ vacmSecurityToGroupStorageType StorageType,
+ vacmSecurityToGroupStatus RowStatus
+ }
+
+vacmSecurityModel OBJECT-TYPE
+ SYNTAX SnmpSecurityModel(1..2147483647)
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION "The Security Model, by which the vacmSecurityName
+ referenced by this entry is provided.
+
+ Note, this object may not take the 'any' (0) value.
+ "
+ ::= { vacmSecurityToGroupEntry 1 }
+
+vacmSecurityName OBJECT-TYPE
+ SYNTAX SnmpAdminString (SIZE(1..32))
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION "The securityName for the principal, represented in a
+ Security Model independent format, which is mapped by
+ this entry to a groupName.
+ "
+ ::= { vacmSecurityToGroupEntry 2 }
+
+vacmGroupName OBJECT-TYPE
+ SYNTAX SnmpAdminString (SIZE(1..32))
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION "The name of the group to which this entry (e.g., the
+ combination of securityModel and securityName)
+ belongs.
+
+ This groupName is used as index into the
+ vacmAccessTable to select an access control policy.
+ However, a value in this table does not imply that an
+ instance with the value exists in table vacmAccesTable.
+ "
+ ::= { vacmSecurityToGroupEntry 3 }
+
+vacmSecurityToGroupStorageType OBJECT-TYPE
+ SYNTAX StorageType
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION "The storage type for this conceptual row.
+ Conceptual rows having the value 'permanent' need not
+ allow write-access to any columnar objects in the row.
+ "
+ DEFVAL { nonVolatile }
+ ::= { vacmSecurityToGroupEntry 4 }
+
+vacmSecurityToGroupStatus OBJECT-TYPE
+ SYNTAX RowStatus
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION "The status of this conceptual row.
+
+ Until instances of all corresponding columns are
+ appropriately configured, the value of the
+ corresponding instance of the vacmSecurityToGroupStatus
+ column is 'notReady'.
+
+ In particular, a newly created row cannot be made
+ active until a value has been set for vacmGroupName.
+
+ The RowStatus TC [RFC1903] requires that this
+ DESCRIPTION clause states under which circumstances
+ other objects in this row can be modified:
+
+ The value of this object has no effect on whether
+ other objects in this conceptual row can be modified.
+ "
+ ::= { vacmSecurityToGroupEntry 5 }
+
+-- Information about Access Rights ***********************************
+
+vacmAccessTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF VacmAccessEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION "The table of access rights for groups.
+
+ Each entry is indexed by a groupName, a contextPrefix,
+ a securityModel and a securityLevel. To determine
+ whether access is allowed, one entry from this table
+ needs to be selected and the proper viewName from that
+ entry must be used for access control checking.
+
+ To select the proper entry, follow these steps:
+
+ 1) the set of possible matches is formed by the
+ intersection of the following sets of entries:
+ the set of entries with identical vacmGroupName
+ the union of these two sets:
+ - the set with identical vacmAccessContextPrefix
+ - the set of entries with vacmAccessContextMatch
+ value of 'prefix' and matching
+ vacmAccessContextPrefix
+ intersected with the union of these two sets:
+ - the set of entries with identical
+ vacmSecurityModel
+ - the set of entries with vacmSecurityModel
+ value of 'any'
+ intersected with the set of entries with
+ vacmAccessSecurityLevel value less than or equal
+ to the requested securityLevel
+
+ 2) if this set has only one member, we're done
+ otherwise, it comes down to deciding how to weight
+ the preferences between ContextPrefixes,
+ SecurityModels, and SecurityLevels as follows:
+ a) if the subset of entries with securityModel
+ matching the securityModel in the message is
+ not empty, then discard the rest.
+ b) if the subset of entries with
+ vacmAccessContextPrefix matching the contextName
+ in the message is not empty,
+ then discard the rest
+ c) discard all entries with ContextPrefixes shorter
+ than the longest one remaining in the set
+ d) select the entry with the highest securityLevel
+
+ Please note that for securityLevel noAuthNoPriv, all
+ groups are really equivalent since the assumption that
+ the securityName has been authenticated does not hold.
+ "
+ ::= { vacmMIBObjects 4 }
+
+vacmAccessEntry OBJECT-TYPE
+ SYNTAX VacmAccessEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION "An access right configured in the Local Configuration
+ Datastore (LCD) authorizing access to an SNMP context.
+
+ Entries in this table can use an instance value for
+ object vacmGroupName even if no entry in table
+ vacmAccessSecurityToGroupTable has a corresponding
+ value for object vacmGroupName.
+ "
+ INDEX { vacmGroupName,
+ vacmAccessContextPrefix,
+ vacmAccessSecurityModel,
+ vacmAccessSecurityLevel
+ }
+ ::= { vacmAccessTable 1 }
+
+VacmAccessEntry ::= SEQUENCE
+ {
+ vacmAccessContextPrefix SnmpAdminString,
+ vacmAccessSecurityModel SnmpSecurityModel,
+ vacmAccessSecurityLevel SnmpSecurityLevel,
+ vacmAccessContextMatch INTEGER,
+ vacmAccessReadViewName SnmpAdminString,
+ vacmAccessWriteViewName SnmpAdminString,
+ vacmAccessNotifyViewName SnmpAdminString,
+ vacmAccessStorageType StorageType,
+ vacmAccessStatus RowStatus
+ }
+
+vacmAccessContextPrefix OBJECT-TYPE
+ SYNTAX SnmpAdminString (SIZE(0..32))
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION "In order to gain the access rights allowed by this
+ conceptual row, a contextName must match exactly
+ (if the value of vacmAccessContextMatch is 'exact')
+ or partially (if the value of vacmAccessContextMatch
+ is 'prefix') to the value of the instance of this
+ object.
+ "
+ ::= { vacmAccessEntry 1 }
+
+vacmAccessSecurityModel OBJECT-TYPE
+ SYNTAX SnmpSecurityModel
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION "In order to gain the access rights allowed by this
+ conceptual row, this securityModel must be in use.
+ "
+ ::= { vacmAccessEntry 2 }
+
+vacmAccessSecurityLevel OBJECT-TYPE
+ SYNTAX SnmpSecurityLevel
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION "The minimum level of security required in order to
+ gain the access rights allowed by this conceptual
+ row. A securityLevel of noAuthNoPriv is less than
+ authNoPriv which in turn is less than authPriv.
+
+ If multiple entries are equally indexed except for
+ this vacmAccessSecurityLevel index, then the entry
+ which has the highest value for
+ vacmAccessSecurityLevel is selected.
+ "
+ ::= { vacmAccessEntry 3 }
+
+vacmAccessContextMatch OBJECT-TYPE
+ SYNTAX INTEGER
+ { exact (1), -- exact match of prefix and contextName
+ prefix (2) -- Only match to the prefix
+ }
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION "If the value of this object is exact(1), then all
+ rows where the contextName exactly matches
+ vacmAccessContextPrefix are selected.
+
+ If the value of this object is prefix(2), then all
+ rows where the contextName whose starting octets
+ exactly match vacmAccessContextPrefix are selected.
+ This allows for a simple form of wildcarding.
+ "
+ DEFVAL { exact }
+ ::= { vacmAccessEntry 4 }
+
+vacmAccessReadViewName OBJECT-TYPE
+ SYNTAX SnmpAdminString (SIZE(0..32))
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION "The value of an instance of this object identifies
+ the MIB view of the SNMP context to which this
+ conceptual row authorizes read access.
+
+ The identified MIB view is that one for which the
+ vacmViewTreeFamilyViewName has the same value as the
+ instance of this object; if the value is the empty
+ string or if there is no active MIB view having this
+ value of vacmViewTreeFamilyViewName, then no access
+ is granted.
+ "
+ DEFVAL { ''H } -- the empty string
+ ::= { vacmAccessEntry 5 }
+
+vacmAccessWriteViewName OBJECT-TYPE
+ SYNTAX SnmpAdminString (SIZE(0..32))
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION "The value of an instance of this object identifies
+ the MIB view of the SNMP context to which this
+ conceptual row authorizes write access.
+
+ The identified MIB view is that one for which the
+ vacmViewTreeFamilyViewName has the same value as the
+ instance of this object; if the value is the empty
+ string or if there is no active MIB view having this
+ value of vacmViewTreeFamilyViewName, then no access
+ is granted.
+ "
+ DEFVAL { ''H } -- the empty string
+ ::= { vacmAccessEntry 6 }
+
+vacmAccessNotifyViewName OBJECT-TYPE
+ SYNTAX SnmpAdminString (SIZE(0..32))
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION "The value of an instance of this object identifies
+ the MIB view of the SNMP context to which this
+ conceptual row authorizes access for notifications.
+
+ The identified MIB view is that one for which the
+ vacmViewTreeFamilyViewName has the same value as the
+ instance of this object; if the value is the empty
+ string or if there is no active MIB view having this
+ value of vacmViewTreeFamilyViewName, then no access
+ is granted.
+ "
+ DEFVAL { ''H } -- the empty string
+ ::= { vacmAccessEntry 7 }
+
+vacmAccessStorageType OBJECT-TYPE
+ SYNTAX StorageType
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION "The storage type for this conceptual row.
+
+ Conceptual rows having the value 'permanent' need not
+ allow write-access to any columnar objects in the row.
+ "
+ DEFVAL { nonVolatile }
+ ::= { vacmAccessEntry 8 }
+
+vacmAccessStatus OBJECT-TYPE
+ SYNTAX RowStatus
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION "The status of this conceptual row.
+
+ The RowStatus TC [RFC1903] requires that this
+ DESCRIPTION clause states under which circumstances
+ other objects in this row can be modified:
+
+ The value of this object has no effect on whether
+ other objects in this conceptual row can be modified.
+ "
+ ::= { vacmAccessEntry 9 }
+
+-- Information about MIB views ***************************************
+
+-- Support for instance-level granularity is optional.
+--
+-- In some implementations, instance-level access control
+-- granularity may come at a high performance cost. Managers
+-- should avoid requesting such configurations unnecessarily.
+
+vacmMIBViews OBJECT IDENTIFIER ::= { vacmMIBObjects 5 }
+
+vacmViewSpinLock OBJECT-TYPE
+ SYNTAX TestAndIncr
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION "An advisory lock used to allow cooperating SNMP
+ Command Generator applications to coordinate their
+ use of the Set operation in creating or modifying
+ views.
+
+ When creating a new view or altering an existing
+ view, it is important to understand the potential
+ interactions with other uses of the view. The
+ vacmViewSpinLock should be retrieved. The name of
+ the view to be created should be determined to be
+ unique by the SNMP Command Generator application by
+ consulting the vacmViewTreeFamilyTable. Finally,
+ the named view may be created (Set), including the
+ advisory lock.
+ If another SNMP Command Generator application has
+ altered the views in the meantime, then the spin
+ lock's value will have changed, and so this creation
+ will fail because it will specify the wrong value for
+ the spin lock.
+
+ Since this is an advisory lock, the use of this lock
+ is not enforced.
+ "
+ ::= { vacmMIBViews 1 }
+
+vacmViewTreeFamilyTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF VacmViewTreeFamilyEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION "Locally held information about families of subtrees
+ within MIB views.
+
+ Each MIB view is defined by two sets of view subtrees:
+ - the included view subtrees, and
+ - the excluded view subtrees.
+ Every such view subtree, both the included and the
+ excluded ones, is defined in this table.
+
+ To determine if a particular object instance is in
+ a particular MIB view, compare the object instance's
+ OBJECT IDENTIFIER with each of the MIB view's active
+ entries in this table. If none match, then the
+ object instance is not in the MIB view. If one or
+ more match, then the object instance is included in,
+ or excluded from, the MIB view according to the
+ value of vacmViewTreeFamilyType in the entry whose
+ value of vacmViewTreeFamilySubtree has the most
+ sub-identifiers. If multiple entries match and have
+ the same number of sub-identifiers (when wildcarding
+ is specified with the value of vacmViewTreeFamilyMask),
+ then the lexicographically greatest instance of
+ vacmViewTreeFamilyType determines the inclusion or
+ exclusion.
+
+ An object instance's OBJECT IDENTIFIER X matches an
+ active entry in this table when the number of
+ sub-identifiers in X is at least as many as in the
+ value of vacmViewTreeFamilySubtree for the entry,
+ and each sub-identifier in the value of
+ vacmViewTreeFamilySubtree matches its corresponding
+ sub-identifier in X. Two sub-identifiers match
+ either if the corresponding bit of the value of
+ vacmViewTreeFamilyMask for the entry is zero (the
+ 'wild card' value), or if they are equal.
+
+ A 'family' of subtrees is the set of subtrees defined
+ by a particular combination of values of
+ vacmViewTreeFamilySubtree and vacmViewTreeFamilyMask.
+ In the case where no 'wild card' is defined in the
+ vacmViewTreeFamilyMask, the family of subtrees reduces
+ to a single subtree.
+
+ When creating or changing MIB views, an SNMP Command
+ Generator application should utilize the
+ vacmViewSpinLock to try to avoid collisions. See
+ DESCRIPTION clause of vacmViewSpinLock.
+
+ When creating MIB views, it is strongly advised that
+ first the 'excluded' vacmViewTreeFamilyEntries are
+ created and then the 'included' entries.
+
+ When deleting MIB views, it is strongly advised that
+ first the 'included' vacmViewTreeFamilyEntries are
+ deleted and then the 'excluded' entries.
+
+ If a create for an entry for instance-level access
+ control is received and the implementation does not
+ support instance-level granularity, then an
+ inconsistentName error must be returned.
+ "
+ ::= { vacmMIBViews 2 }
+
+vacmViewTreeFamilyEntry OBJECT-TYPE
+ SYNTAX VacmViewTreeFamilyEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION "Information on a particular family of view subtrees
+ included in or excluded from a particular SNMP
+ context's MIB view.
+
+ Implementations must not restrict the number of
+ families of view subtrees for a given MIB view,
+ except as dictated by resource constraints on the
+ overall number of entries in the
+ vacmViewTreeFamilyTable.
+
+ If no conceptual rows exist in this table for a given
+ MIB view (viewName), that view may be thought of as
+ consisting of the empty set of view subtrees.
+ "
+ INDEX { vacmViewTreeFamilyViewName,
+ vacmViewTreeFamilySubtree
+ }
+ ::= { vacmViewTreeFamilyTable 1 }
+
+VacmViewTreeFamilyEntry ::= SEQUENCE
+ {
+ vacmViewTreeFamilyViewName SnmpAdminString,
+ vacmViewTreeFamilySubtree OBJECT IDENTIFIER,
+ vacmViewTreeFamilyMask OCTET STRING,
+ vacmViewTreeFamilyType INTEGER,
+ vacmViewTreeFamilyStorageType StorageType,
+ vacmViewTreeFamilyStatus RowStatus
+ }
+
+vacmViewTreeFamilyViewName OBJECT-TYPE
+ SYNTAX SnmpAdminString (SIZE(1..32))
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION "The human readable name for a family of view subtrees.
+ "
+ ::= { vacmViewTreeFamilyEntry 1 }
+
+vacmViewTreeFamilySubtree OBJECT-TYPE
+ SYNTAX OBJECT IDENTIFIER
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION "The MIB subtree which when combined with the
+ corresponding instance of vacmViewTreeFamilyMask
+ defines a family of view subtrees.
+ "
+ ::= { vacmViewTreeFamilyEntry 2 }
+
+vacmViewTreeFamilyMask OBJECT-TYPE
+ SYNTAX OCTET STRING (SIZE (0..16))
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION "The bit mask which, in combination with the
+ corresponding instance of vacmViewTreeFamilySubtree,
+ defines a family of view subtrees.
+
+ Each bit of this bit mask corresponds to a
+ sub-identifier of vacmViewTreeFamilySubtree, with the
+ most significant bit of the i-th octet of this octet
+ string value (extended if necessary, see below)
+ corresponding to the (8*i - 7)-th sub-identifier, and
+ the least significant bit of the i-th octet of this
+ octet string corresponding to the (8*i)-th
+ sub-identifier, where i is in the range 1 through 16.
+
+ Each bit of this bit mask specifies whether or not
+ the corresponding sub-identifiers must match when
+ determining if an OBJECT IDENTIFIER is in this
+ family of view subtrees; a '1' indicates that an
+ exact match must occur; a '0' indicates 'wild card',
+ i.e., any sub-identifier value matches.
+
+ Thus, the OBJECT IDENTIFIER X of an object instance
+ is contained in a family of view subtrees if, for
+ each sub-identifier of the value of
+ vacmViewTreeFamilySubtree, either:
+
+ the i-th bit of vacmViewTreeFamilyMask is 0, or
+
+ the i-th sub-identifier of X is equal to the i-th
+ sub-identifier of the value of
+ vacmViewTreeFamilySubtree.
+
+ If the value of this bit mask is M bits long and
+ there are more than M sub-identifiers in the
+ corresponding instance of vacmViewTreeFamilySubtree,
+ then the bit mask is extended with 1's to be the
+ required length.
+
+ Note that when the value of this object is the
+ zero-length string, this extension rule results in
+ a mask of all-1's being used (i.e., no 'wild card'),
+ and the family of view subtrees is the one view
+ subtree uniquely identified by the corresponding
+ instance of vacmViewTreeFamilySubtree.
+
+ Note that masks of length greater than zero length
+ do not need to be supported. In this case this
+ object is made read-only.
+ "
+ DEFVAL { ''H }
+ ::= { vacmViewTreeFamilyEntry 3 }
+
+vacmViewTreeFamilyType OBJECT-TYPE
+ SYNTAX INTEGER { included(1), excluded(2) }
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION "Indicates whether the corresponding instances of
+ vacmViewTreeFamilySubtree and vacmViewTreeFamilyMask
+ define a family of view subtrees which is included in
+ or excluded from the MIB view.
+ "
+ DEFVAL { included }
+ ::= { vacmViewTreeFamilyEntry 4 }
+
+vacmViewTreeFamilyStorageType OBJECT-TYPE
+ SYNTAX StorageType
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION "The storage type for this conceptual row.
+
+ Conceptual rows having the value 'permanent' need not
+ allow write-access to any columnar objects in the row.
+ "
+ DEFVAL { nonVolatile }
+ ::= { vacmViewTreeFamilyEntry 5 }
+
+vacmViewTreeFamilyStatus OBJECT-TYPE
+ SYNTAX RowStatus
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION "The status of this conceptual row.
+
+ The RowStatus TC [RFC1903] requires that this
+ DESCRIPTION clause states under which circumstances
+ other objects in this row can be modified:
+
+ The value of this object has no effect on whether
+ other objects in this conceptual row can be modified.
+ "
+ ::= { vacmViewTreeFamilyEntry 6 }
+
+-- Conformance information *******************************************
+
+vacmMIBCompliances OBJECT IDENTIFIER ::= { vacmMIBConformance 1 }
+vacmMIBGroups OBJECT IDENTIFIER ::= { vacmMIBConformance 2 }
+
+-- Compliance statements *********************************************
+
+vacmMIBCompliance MODULE-COMPLIANCE
+ STATUS current
+ DESCRIPTION "The compliance statement for SNMP engines which
+ implement the SNMP View-based Access Control Model
+ configuration MIB.
+ "
+ MODULE -- this module
+ MANDATORY-GROUPS { vacmBasicGroup }
+
+ OBJECT vacmAccessContextMatch
+ MIN-ACCESS read-only
+ DESCRIPTION "Write access is not required."
+
+ OBJECT vacmAccessReadViewName
+ MIN-ACCESS read-only
+ DESCRIPTION "Write access is not required."
+
+ OBJECT vacmAccessWriteViewName
+ MIN-ACCESS read-only
+ DESCRIPTION "Write access is not required."
+
+ OBJECT vacmAccessNotifyViewName
+ MIN-ACCESS read-only
+ DESCRIPTION "Write access is not required."
+
+ OBJECT vacmAccessStorageType
+ MIN-ACCESS read-only
+ DESCRIPTION "Write access is not required."
+
+ OBJECT vacmAccessStatus
+ MIN-ACCESS read-only
+ DESCRIPTION "Create/delete/modify access to the
+ vacmAccessTable is not required.
+ "
+
+ OBJECT vacmViewTreeFamilyMask
+ WRITE-SYNTAX OCTET STRING (SIZE (0))
+ MIN-ACCESS read-only
+ DESCRIPTION "Support for configuration via SNMP of subtree
+ families using wild-cards is not required.
+ "
+
+ OBJECT vacmViewTreeFamilyType
+ MIN-ACCESS read-only
+ DESCRIPTION "Write access is not required."
+
+ OBJECT vacmViewTreeFamilyStorageType
+ MIN-ACCESS read-only
+ DESCRIPTION "Write access is not required."
+
+ OBJECT vacmViewTreeFamilyStatus
+ MIN-ACCESS read-only
+ DESCRIPTION "Create/delete/modify access to the
+ vacmViewTreeFamilyTable is not required.
+ "
+ ::= { vacmMIBCompliances 1 }
+
+-- Units of conformance **********************************************
+
+vacmBasicGroup OBJECT-GROUP
+ OBJECTS {
+ vacmContextName,
+ vacmGroupName,
+ vacmSecurityToGroupStorageType,
+ vacmSecurityToGroupStatus,
+ vacmAccessContextMatch,
+ vacmAccessReadViewName,
+ vacmAccessWriteViewName,
+ vacmAccessNotifyViewName,
+ vacmAccessStorageType,
+ vacmAccessStatus,
+ vacmViewSpinLock,
+ vacmViewTreeFamilyMask,
+ vacmViewTreeFamilyType,
+ vacmViewTreeFamilyStorageType,
+ vacmViewTreeFamilyStatus
+ }
+ STATUS current
+ DESCRIPTION "A collection of objects providing for remote
+ configuration of an SNMP engine which implements
+ the SNMP View-based Access Control Model.
+ "
+ ::= { vacmMIBGroups 1 }
+
+END
diff --git a/lib/snmp/mibs/SNMPv2-CONF.mib b/lib/snmp/mibs/SNMPv2-CONF.mib
new file mode 100644
index 0000000000..1bff73ca68
--- /dev/null
+++ b/lib/snmp/mibs/SNMPv2-CONF.mib
@@ -0,0 +1,290 @@
+SNMPv2-CONF DEFINITIONS ::= BEGIN
+
+-- definitions for conformance groups
+
+OBJECT-GROUP MACRO ::=
+BEGIN
+ TYPE NOTATION ::=
+ ObjectsPart
+ "STATUS" Status
+ "DESCRIPTION" Text
+ ReferPart
+
+ VALUE NOTATION ::=
+ value(VALUE OBJECT IDENTIFIER)
+
+ ObjectsPart ::=
+ "OBJECTS" "{" Objects "}"
+ Objects ::=
+ Object
+ | Objects "," Object
+ Object ::=
+ value(Name ObjectName)
+
+ Status ::=
+ "current"
+ | "deprecated"
+ | "obsolete"
+
+ ReferPart ::=
+ "REFERENCE" Text
+ | empty
+
+ -- uses the NVT ASCII character set
+ Text ::= """" string """"
+END
+
+
+-- more definitions for conformance groups
+
+NOTIFICATION-GROUP MACRO ::=
+BEGIN
+ TYPE NOTATION ::=
+ NotificationsPart
+ "STATUS" Status
+ "DESCRIPTION" Text
+ ReferPart
+
+ VALUE NOTATION ::=
+ value(VALUE OBJECT IDENTIFIER)
+
+ NotificationsPart ::=
+ "NOTIFICATIONS" "{" Notifications "}"
+ Notifications ::=
+ Notification
+ | Notifications "," Notification
+ Notification ::=
+ value(Name NotificationName)
+
+ Status ::=
+ "current"
+ | "deprecated"
+ | "obsolete"
+
+ ReferPart ::=
+ "REFERENCE" Text
+ | empty
+
+ -- uses the NVT ASCII character set
+ Text ::= """" string """"
+
+END
+
+
+-- definitions for compliance statements
+
+MODULE-COMPLIANCE MACRO ::=
+BEGIN
+ TYPE NOTATION ::=
+ "STATUS" Status
+ "DESCRIPTION" Text
+ ReferPart
+ ModulePart
+
+ VALUE NOTATION ::=
+ value(VALUE OBJECT IDENTIFIER)
+
+ Status ::=
+ "current"
+ | "deprecated"
+ | "obsolete"
+
+ ReferPart ::=
+ "REFERENCE" Text
+ | empty
+
+ ModulePart ::=
+ Modules
+ | empty
+ Modules ::=
+ Module
+ | Modules Module
+ Module ::=
+ -- name of module --
+ "MODULE" ModuleName
+ MandatoryPart
+ CompliancePart
+
+ ModuleName ::=
+ modulereference ModuleIdentifier
+ -- must not be empty unless contained
+ -- in MIB Module
+ | empty
+ ModuleIdentifier ::=
+ value(ModuleID OBJECT IDENTIFIER)
+ | empty
+
+ MandatoryPart ::=
+ "MANDATORY-GROUPS" "{" Groups "}"
+ | empty
+
+ Groups ::=
+ Group
+ | Groups "," Group
+ Group ::=
+ value(Group OBJECT IDENTIFIER)
+
+ CompliancePart ::=
+ Compliances
+ | empty
+
+ Compliances ::=
+ Compliance
+ | Compliances Compliance
+ Compliance ::=
+ ComplianceGroup
+ | Object
+
+ ComplianceGroup ::=
+ "GROUP" value(Name OBJECT IDENTIFIER)
+ "DESCRIPTION" Text
+
+ Object ::=
+ "OBJECT" value(Name ObjectName)
+ SyntaxPart
+ WriteSyntaxPart
+ AccessPart
+ "DESCRIPTION" Text
+
+ -- must be a refinement for object's SYNTAX clause
+ SyntaxPart ::=
+ "SYNTAX" type(SYNTAX)
+ | empty
+
+ -- must be a refinement for object's SYNTAX clause
+ WriteSyntaxPart ::=
+ "WRITE-SYNTAX" type(WriteSYNTAX)
+ | empty
+
+ AccessPart ::=
+ "MIN-ACCESS" Access
+ | empty
+ Access ::=
+ "not-accessible"
+ | "accessible-for-notify"
+ | "read-only"
+ | "read-write"
+ | "read-create"
+
+ -- uses the NVT ASCII character set
+ Text ::= """" string """"
+END
+
+
+-- definitions for capabilities statements
+
+AGENT-CAPABILITIES MACRO ::=
+BEGIN
+ TYPE NOTATION ::=
+ "PRODUCT-RELEASE" Text
+ "STATUS" Status
+ "DESCRIPTION" Text
+ ReferPart
+ ModulePart
+
+ VALUE NOTATION ::=
+ value(VALUE OBJECT IDENTIFIER)
+
+ Status ::=
+ "current"
+ | "obsolete"
+
+ ReferPart ::=
+ "REFERENCE" Text
+ | empty
+
+ ModulePart ::=
+ Modules
+ | empty
+ Modules ::=
+ Module
+ | Modules Module
+ Module ::=
+ -- name of module --
+ "SUPPORTS" ModuleName
+ "INCLUDES" "{" Groups "}"
+ VariationPart
+
+ ModuleName ::=
+ identifier ModuleIdentifier
+ ModuleIdentifier ::=
+ value(ModuleID OBJECT IDENTIFIER)
+ | empty
+
+ Groups ::=
+ Group
+ | Groups "," Group
+ Group ::=
+ value(Name OBJECT IDENTIFIER)
+
+ VariationPart ::=
+ Variations
+ | empty
+ Variations ::=
+ Variation
+ | Variations Variation
+
+ Variation ::=
+ ObjectVariation
+ | NotificationVariation
+
+ NotificationVariation ::=
+ "VARIATION" value(Name NotificationName)
+ AccessPart
+ "DESCRIPTION" Text
+
+ ObjectVariation ::=
+ "VARIATION" value(Name ObjectName)
+ SyntaxPart
+ WriteSyntaxPart
+ AccessPart
+ CreationPart
+ DefValPart
+ "DESCRIPTION" Text
+
+ -- must be a refinement for object's SYNTAX clause
+ SyntaxPart ::=
+ "SYNTAX" type(SYNTAX)
+ | empty
+
+ -- must be a refinement for object's SYNTAX clause
+ WriteSyntaxPart ::=
+ "WRITE-SYNTAX" type(WriteSYNTAX)
+ | empty
+
+ AccessPart ::=
+ "ACCESS" Access
+ | empty
+
+ Access ::=
+ "not-implemented"
+ -- only "not-implemented" for notifications
+ | "accessible-for-notify"
+ | "read-only"
+ | "read-write"
+ | "read-create"
+ -- following is for backward-compatibility only
+ | "write-only"
+
+ CreationPart ::=
+ "CREATION-REQUIRES" "{" Cells "}"
+ | empty
+
+ Cells ::=
+ Cell
+ | Cells "," Cell
+
+ Cell ::=
+ value(Cell ObjectName)
+
+ DefValPart ::=
+ "DEFVAL" "{" value(Defval ObjectSyntax) "}"
+ | empty
+
+ -- uses the NVT ASCII character set
+ Text ::= """" string """"
+END
+
+
+END
+
diff --git a/lib/snmp/mibs/SNMPv2-MIB.funcs b/lib/snmp/mibs/SNMPv2-MIB.funcs
new file mode 100644
index 0000000000..8fe25bb477
--- /dev/null
+++ b/lib/snmp/mibs/SNMPv2-MIB.funcs
@@ -0,0 +1,28 @@
+%% The system group
+{sysUpTime, {snmp_standard_mib, sys_up_time, []}}.
+{sysDescr, {snmp_generic, variable_func, [{sysDescr, permanent}]}}.
+{sysObjectID, {snmp_generic, variable_func, [{sysObjectID, permanent}]}}.
+{sysContact, {snmp_generic, variable_func, [{sysContact, permanent}]}}.
+{sysName, {snmp_generic, variable_func, [{sysName, permanent}]}}.
+{sysLocation, {snmp_generic, variable_func, [{sysLocation, permanent}]}}.
+{sysServices, {snmp_generic, variable_func, [{sysServices, permanent}]}}.
+
+{sysORLastChange, {snmp_generic, variable_func, [{sysORLastChange, volatile}]}}.
+{sysORTable, {snmp_standard_mib, sys_or_table, []}}.
+
+%% Snmp special objects
+{snmpEnableAuthenTraps, {snmp_standard_mib, snmp_enable_authen_traps, []}}.
+{snmpSetSerialNo, {snmp_standard_mib, snmp_set_serial_no, []}}.
+
+%% Counters
+{snmpInPkts, {snmp_standard_mib, variable_func, [snmpInPkts]}}.
+{snmpInBadVersions, {snmp_standard_mib, variable_func, [snmpInBadVersions]}}.
+{snmpInBadCommunityNames, {snmp_standard_mib, variable_func, [snmpInBadCommunityNames]}}.
+{snmpInBadCommunityUses, {snmp_standard_mib, variable_func, [snmpInBadCommunityUses]}}.
+{snmpInASNParseErrs, {snmp_standard_mib, variable_func, [snmpInASNParseErrs]}}.
+{snmpProxyDrops, {snmp_standard_mib, variable_func, [snmpProxyDrops]}}.
+{snmpSilentDrops, {snmp_standard_mib, variable_func, [snmpSilentDrops]}}.
+
+%% Dummy objects, included in notifications
+{snmpTrapEnterprise, {snmp_standard_mib, dummy, []}}.
+{snmpTrapOID, {snmp_standard_mib, dummy, []}}.
diff --git a/lib/snmp/mibs/SNMPv2-MIB.mib b/lib/snmp/mibs/SNMPv2-MIB.mib
new file mode 100644
index 0000000000..8c828305e0
--- /dev/null
+++ b/lib/snmp/mibs/SNMPv2-MIB.mib
@@ -0,0 +1,854 @@
+SNMPv2-MIB DEFINITIONS ::= BEGIN
+
+IMPORTS
+ MODULE-IDENTITY, OBJECT-TYPE, NOTIFICATION-TYPE,
+ TimeTicks, Counter32, snmpModules, mib-2
+ FROM SNMPv2-SMI
+ DisplayString, TestAndIncr, TimeStamp
+
+ FROM SNMPv2-TC
+ MODULE-COMPLIANCE, OBJECT-GROUP, NOTIFICATION-GROUP
+ FROM SNMPv2-CONF;
+
+snmpMIB MODULE-IDENTITY
+ LAST-UPDATED "200210160000Z"
+ ORGANIZATION "IETF SNMPv3 Working Group"
+ CONTACT-INFO
+ "WG-EMail: [email protected]
+ Subscribe: [email protected]
+
+ Co-Chair: Russ Mundy
+ Network Associates Laboratories
+ postal: 15204 Omega Drive, Suite 300
+ Rockville, MD 20850-4601
+ USA
+ phone: +1 301 947-7107
+
+ Co-Chair: David Harrington
+ Enterasys Networks
+ postal: 35 Industrial Way
+ P. O. Box 5005
+ Rochester, NH 03866-5005
+ USA
+ phone: +1 603 337-2614
+
+ Editor: Randy Presuhn
+ BMC Software, Inc.
+ postal: 2141 North First Street
+ San Jose, CA 95131
+ USA
+ phone: +1 408 546-1006"
+ DESCRIPTION
+ "The MIB module for SNMP entities.
+
+ Copyright (C) The Internet Society (2002). This
+ version of this MIB module is part of RFC 3418;
+ see the RFC itself for full legal notices.
+ "
+ REVISION "200210160000Z"
+ DESCRIPTION
+ "This revision of this MIB module was published as
+ RFC 3418."
+ REVISION "199511090000Z"
+ DESCRIPTION
+ "This revision of this MIB module was published as
+ RFC 1907."
+ REVISION "199304010000Z"
+ DESCRIPTION
+ "The initial revision of this MIB module was published
+ as RFC 1450."
+ ::= { snmpModules 1 }
+
+snmpMIBObjects OBJECT IDENTIFIER ::= { snmpMIB 1 }
+
+-- ::= { snmpMIBObjects 1 } this OID is obsolete
+-- ::= { snmpMIBObjects 2 } this OID is obsolete
+-- ::= { snmpMIBObjects 3 } this OID is obsolete
+
+-- the System group
+--
+-- a collection of objects common to all managed systems.
+
+system OBJECT IDENTIFIER ::= { mib-2 1 }
+
+sysDescr OBJECT-TYPE
+ SYNTAX DisplayString (SIZE (0..255))
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "A textual description of the entity. This value should
+ include the full name and version identification of
+ the system's hardware type, software operating-system,
+ and networking software."
+ ::= { system 1 }
+
+sysObjectID OBJECT-TYPE
+ SYNTAX OBJECT IDENTIFIER
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The vendor's authoritative identification of the
+ network management subsystem contained in the entity.
+ This value is allocated within the SMI enterprises
+ subtree (1.3.6.1.4.1) and provides an easy and
+ unambiguous means for determining `what kind of box' is
+ being managed. For example, if vendor `Flintstones,
+ Inc.' was assigned the subtree 1.3.6.1.4.1.424242,
+ it could assign the identifier 1.3.6.1.4.1.424242.1.1
+ to its `Fred Router'."
+ ::= { system 2 }
+
+sysUpTime OBJECT-TYPE
+ SYNTAX TimeTicks
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The time (in hundredths of a second) since the
+ network management portion of the system was last
+ re-initialized."
+ ::= { system 3 }
+
+sysContact OBJECT-TYPE
+ SYNTAX DisplayString (SIZE (0..255))
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The textual identification of the contact person for
+ this managed node, together with information on how
+ to contact this person. If no contact information is
+ known, the value is the zero-length string."
+ ::= { system 4 }
+
+sysName OBJECT-TYPE
+ SYNTAX DisplayString (SIZE (0..255))
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "An administratively-assigned name for this managed
+ node. By convention, this is the node's fully-qualified
+ domain name. If the name is unknown, the value is
+ the zero-length string."
+ ::= { system 5 }
+
+sysLocation OBJECT-TYPE
+ SYNTAX DisplayString (SIZE (0..255))
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The physical location of this node (e.g., 'telephone
+ closet, 3rd floor'). If the location is unknown, the
+ value is the zero-length string."
+ ::= { system 6 }
+
+sysServices OBJECT-TYPE
+ SYNTAX INTEGER (0..127)
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "A value which indicates the set of services that this
+ entity may potentially offer. The value is a sum.
+
+ This sum initially takes the value zero. Then, for
+ each layer, L, in the range 1 through 7, that this node
+ performs transactions for, 2 raised to (L - 1) is added
+ to the sum. For example, a node which performs only
+ routing functions would have a value of 4 (2^(3-1)).
+ In contrast, a node which is a host offering application
+ services would have a value of 72 (2^(4-1) + 2^(7-1)).
+ Note that in the context of the Internet suite of
+ protocols, values should be calculated accordingly:
+
+ layer functionality
+ 1 physical (e.g., repeaters)
+ 2 datalink/subnetwork (e.g., bridges)
+ 3 internet (e.g., supports the IP)
+ 4 end-to-end (e.g., supports the TCP)
+ 7 applications (e.g., supports the SMTP)
+
+ For systems including OSI protocols, layers 5 and 6
+ may also be counted."
+ ::= { system 7 }
+
+-- object resource information
+--
+-- a collection of objects which describe the SNMP entity's
+-- (statically and dynamically configurable) support of
+-- various MIB modules.
+
+sysORLastChange OBJECT-TYPE
+ SYNTAX TimeStamp
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The value of sysUpTime at the time of the most recent
+ change in state or value of any instance of sysORID."
+ ::= { system 8 }
+
+sysORTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF SysOREntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "The (conceptual) table listing the capabilities of
+ the local SNMP application acting as a command
+ responder with respect to various MIB modules.
+ SNMP entities having dynamically-configurable support
+ of MIB modules will have a dynamically-varying number
+ of conceptual rows."
+ ::= { system 9 }
+
+sysOREntry OBJECT-TYPE
+ SYNTAX SysOREntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "An entry (conceptual row) in the sysORTable."
+ INDEX { sysORIndex }
+ ::= { sysORTable 1 }
+
+SysOREntry ::= SEQUENCE {
+ sysORIndex INTEGER,
+ sysORID OBJECT IDENTIFIER,
+ sysORDescr DisplayString,
+ sysORUpTime TimeStamp
+}
+
+sysORIndex OBJECT-TYPE
+ SYNTAX INTEGER (1..2147483647)
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "The auxiliary variable used for identifying instances
+ of the columnar objects in the sysORTable."
+ ::= { sysOREntry 1 }
+
+sysORID OBJECT-TYPE
+ SYNTAX OBJECT IDENTIFIER
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "An authoritative identification of a capabilities
+ statement with respect to various MIB modules supported
+ by the local SNMP application acting as a command
+ responder."
+ ::= { sysOREntry 2 }
+
+sysORDescr OBJECT-TYPE
+ SYNTAX DisplayString
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "A textual description of the capabilities identified
+ by the corresponding instance of sysORID."
+ ::= { sysOREntry 3 }
+
+sysORUpTime OBJECT-TYPE
+ SYNTAX TimeStamp
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The value of sysUpTime at the time this conceptual
+ row was last instantiated."
+ ::= { sysOREntry 4 }
+
+-- the SNMP group
+--
+-- a collection of objects providing basic instrumentation and
+-- control of an SNMP entity.
+
+snmp OBJECT IDENTIFIER ::= { mib-2 11 }
+
+snmpInPkts OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The total number of messages delivered to the SNMP
+ entity from the transport service."
+ ::= { snmp 1 }
+
+snmpInBadVersions OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The total number of SNMP messages which were delivered
+ to the SNMP entity and were for an unsupported SNMP
+ version."
+ ::= { snmp 3 }
+
+snmpInBadCommunityNames OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The total number of community-based SNMP messages (for
+ example, SNMPv1) delivered to the SNMP entity which
+ used an SNMP community name not known to said entity.
+ Also, implementations which authenticate community-based
+ SNMP messages using check(s) in addition to matching
+ the community name (for example, by also checking
+ whether the message originated from a transport address
+ allowed to use a specified community name) MAY include
+ in this value the number of messages which failed the
+ additional check(s). It is strongly RECOMMENDED that
+
+ the documentation for any security model which is used
+ to authenticate community-based SNMP messages specify
+ the precise conditions that contribute to this value."
+ ::= { snmp 4 }
+
+snmpInBadCommunityUses OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The total number of community-based SNMP messages (for
+ example, SNMPv1) delivered to the SNMP entity which
+ represented an SNMP operation that was not allowed for
+ the SNMP community named in the message. The precise
+ conditions under which this counter is incremented
+ (if at all) depend on how the SNMP entity implements
+ its access control mechanism and how its applications
+ interact with that access control mechanism. It is
+ strongly RECOMMENDED that the documentation for any
+ access control mechanism which is used to control access
+ to and visibility of MIB instrumentation specify the
+ precise conditions that contribute to this value."
+ ::= { snmp 5 }
+
+snmpInASNParseErrs OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The total number of ASN.1 or BER errors encountered by
+ the SNMP entity when decoding received SNMP messages."
+ ::= { snmp 6 }
+
+snmpEnableAuthenTraps OBJECT-TYPE
+ SYNTAX INTEGER { enabled(1), disabled(2) }
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "Indicates whether the SNMP entity is permitted to
+ generate authenticationFailure traps. The value of this
+ object overrides any configuration information; as such,
+ it provides a means whereby all authenticationFailure
+ traps may be disabled.
+
+ Note that it is strongly recommended that this object
+ be stored in non-volatile memory so that it remains
+ constant across re-initializations of the network
+ management system."
+ ::= { snmp 30 }
+
+snmpSilentDrops OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The total number of Confirmed Class PDUs (such as
+ GetRequest-PDUs, GetNextRequest-PDUs,
+ GetBulkRequest-PDUs, SetRequest-PDUs, and
+ InformRequest-PDUs) delivered to the SNMP entity which
+ were silently dropped because the size of a reply
+ containing an alternate Response Class PDU (such as a
+ Response-PDU) with an empty variable-bindings field
+ was greater than either a local constraint or the
+ maximum message size associated with the originator of
+ the request."
+ ::= { snmp 31 }
+
+snmpProxyDrops OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The total number of Confirmed Class PDUs
+ (such as GetRequest-PDUs, GetNextRequest-PDUs,
+ GetBulkRequest-PDUs, SetRequest-PDUs, and
+ InformRequest-PDUs) delivered to the SNMP entity which
+ were silently dropped because the transmission of
+ the (possibly translated) message to a proxy target
+ failed in a manner (other than a time-out) such that
+ no Response Class PDU (such as a Response-PDU) could
+ be returned."
+ ::= { snmp 32 }
+
+-- information for notifications
+--
+-- a collection of objects which allow the SNMP entity, when
+-- supporting a notification originator application,
+-- to be configured to generate SNMPv2-Trap-PDUs.
+
+snmpTrap OBJECT IDENTIFIER ::= { snmpMIBObjects 4 }
+
+snmpTrapOID OBJECT-TYPE
+ SYNTAX OBJECT IDENTIFIER
+ MAX-ACCESS accessible-for-notify
+ STATUS current
+ DESCRIPTION
+ "The authoritative identification of the notification
+ currently being sent. This variable occurs as
+ the second varbind in every SNMPv2-Trap-PDU and
+ InformRequest-PDU."
+ ::= { snmpTrap 1 }
+
+-- ::= { snmpTrap 2 } this OID is obsolete
+
+snmpTrapEnterprise OBJECT-TYPE
+ SYNTAX OBJECT IDENTIFIER
+ MAX-ACCESS accessible-for-notify
+ STATUS current
+ DESCRIPTION
+ "The authoritative identification of the enterprise
+ associated with the trap currently being sent. When an
+ SNMP proxy agent is mapping an RFC1157 Trap-PDU
+ into a SNMPv2-Trap-PDU, this variable occurs as the
+ last varbind."
+ ::= { snmpTrap 3 }
+
+-- ::= { snmpTrap 4 } this OID is obsolete
+
+-- well-known traps
+
+snmpTraps OBJECT IDENTIFIER ::= { snmpMIBObjects 5 }
+
+coldStart NOTIFICATION-TYPE
+ STATUS current
+ DESCRIPTION
+ "A coldStart trap signifies that the SNMP entity,
+ supporting a notification originator application, is
+ reinitializing itself and that its configuration may
+ have been altered."
+ ::= { snmpTraps 1 }
+
+warmStart NOTIFICATION-TYPE
+ STATUS current
+ DESCRIPTION
+ "A warmStart trap signifies that the SNMP entity,
+ supporting a notification originator application,
+ is reinitializing itself such that its configuration
+ is unaltered."
+ ::= { snmpTraps 2 }
+
+-- Note the linkDown NOTIFICATION-TYPE ::= { snmpTraps 3 }
+-- and the linkUp NOTIFICATION-TYPE ::= { snmpTraps 4 }
+-- are defined in RFC 2863 [RFC2863]
+
+authenticationFailure NOTIFICATION-TYPE
+ STATUS current
+ DESCRIPTION
+ "An authenticationFailure trap signifies that the SNMP
+ entity has received a protocol message that is not
+ properly authenticated. While all implementations
+ of SNMP entities MAY be capable of generating this
+ trap, the snmpEnableAuthenTraps object indicates
+ whether this trap will be generated."
+ ::= { snmpTraps 5 }
+
+-- Note the egpNeighborLoss notification is defined
+-- as { snmpTraps 6 } in RFC 1213
+
+-- the set group
+--
+-- a collection of objects which allow several cooperating
+-- command generator applications to coordinate their use of the
+-- set operation.
+
+snmpSet OBJECT IDENTIFIER ::= { snmpMIBObjects 6 }
+
+snmpSetSerialNo OBJECT-TYPE
+ SYNTAX TestAndIncr
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "An advisory lock used to allow several cooperating
+ command generator applications to coordinate their
+ use of the SNMP set operation.
+
+ This object is used for coarse-grain coordination.
+ To achieve fine-grain coordination, one or more similar
+ objects might be defined within each MIB group, as
+ appropriate."
+ ::= { snmpSet 1 }
+
+-- conformance information
+
+snmpMIBConformance
+ OBJECT IDENTIFIER ::= { snmpMIB 2 }
+
+snmpMIBCompliances
+ OBJECT IDENTIFIER ::= { snmpMIBConformance 1 }
+snmpMIBGroups OBJECT IDENTIFIER ::= { snmpMIBConformance 2 }
+
+-- compliance statements
+
+-- ::= { snmpMIBCompliances 1 } this OID is obsolete
+snmpBasicCompliance MODULE-COMPLIANCE
+ STATUS deprecated
+ DESCRIPTION
+ "The compliance statement for SNMPv2 entities which
+ implement the SNMPv2 MIB.
+
+ This compliance statement is replaced by
+ snmpBasicComplianceRev2."
+ MODULE -- this module
+ MANDATORY-GROUPS { snmpGroup, snmpSetGroup, systemGroup,
+ snmpBasicNotificationsGroup }
+
+ GROUP snmpCommunityGroup
+ DESCRIPTION
+ "This group is mandatory for SNMPv2 entities which
+ support community-based authentication."
+ ::= { snmpMIBCompliances 2 }
+
+snmpBasicComplianceRev2 MODULE-COMPLIANCE
+ STATUS current
+ DESCRIPTION
+ "The compliance statement for SNMP entities which
+ implement this MIB module."
+ MODULE -- this module
+ MANDATORY-GROUPS { snmpGroup, snmpSetGroup, systemGroup,
+ snmpBasicNotificationsGroup }
+
+ GROUP snmpCommunityGroup
+ DESCRIPTION
+ "This group is mandatory for SNMP entities which
+ support community-based authentication."
+
+ GROUP snmpWarmStartNotificationGroup
+ DESCRIPTION
+ "This group is mandatory for an SNMP entity which
+ supports command responder applications, and is
+ able to reinitialize itself such that its
+ configuration is unaltered."
+ ::= { snmpMIBCompliances 3 }
+
+-- units of conformance
+
+-- ::= { snmpMIBGroups 1 } this OID is obsolete
+-- ::= { snmpMIBGroups 2 } this OID is obsolete
+-- ::= { snmpMIBGroups 3 } this OID is obsolete
+
+-- ::= { snmpMIBGroups 4 } this OID is obsolete
+
+snmpGroup OBJECT-GROUP
+ OBJECTS { snmpInPkts,
+ snmpInBadVersions,
+ snmpInASNParseErrs,
+ snmpSilentDrops,
+ snmpProxyDrops,
+ snmpEnableAuthenTraps }
+ STATUS current
+ DESCRIPTION
+ "A collection of objects providing basic instrumentation
+ and control of an SNMP entity."
+ ::= { snmpMIBGroups 8 }
+
+snmpCommunityGroup OBJECT-GROUP
+ OBJECTS { snmpInBadCommunityNames,
+ snmpInBadCommunityUses }
+ STATUS current
+ DESCRIPTION
+ "A collection of objects providing basic instrumentation
+ of a SNMP entity which supports community-based
+ authentication."
+ ::= { snmpMIBGroups 9 }
+
+snmpSetGroup OBJECT-GROUP
+ OBJECTS { snmpSetSerialNo }
+ STATUS current
+ DESCRIPTION
+ "A collection of objects which allow several cooperating
+ command generator applications to coordinate their
+ use of the set operation."
+ ::= { snmpMIBGroups 5 }
+
+systemGroup OBJECT-GROUP
+ OBJECTS { sysDescr, sysObjectID, sysUpTime,
+ sysContact, sysName, sysLocation,
+ sysServices,
+ sysORLastChange, sysORID,
+ sysORUpTime, sysORDescr }
+ STATUS current
+ DESCRIPTION
+ "The system group defines objects which are common to all
+ managed systems."
+ ::= { snmpMIBGroups 6 }
+
+snmpBasicNotificationsGroup NOTIFICATION-GROUP
+ NOTIFICATIONS { coldStart, authenticationFailure }
+ STATUS current
+ DESCRIPTION
+ "The basic notifications implemented by an SNMP entity
+ supporting command responder applications."
+ ::= { snmpMIBGroups 7 }
+
+snmpWarmStartNotificationGroup NOTIFICATION-GROUP
+ NOTIFICATIONS { warmStart }
+ STATUS current
+ DESCRIPTION
+ "An additional notification for an SNMP entity supporting
+ command responder applications, if it is able to reinitialize
+ itself such that its configuration is unaltered."
+ ::= { snmpMIBGroups 11 }
+
+snmpNotificationGroup OBJECT-GROUP
+ OBJECTS { snmpTrapOID, snmpTrapEnterprise }
+ STATUS current
+ DESCRIPTION
+ "These objects are required for entities
+ which support notification originator applications."
+ ::= { snmpMIBGroups 12 }
+
+-- definitions in RFC 1213 made obsolete by the inclusion of a
+-- subset of the snmp group in this MIB
+
+snmpOutPkts OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS obsolete
+ DESCRIPTION
+ "The total number of SNMP Messages which were
+ passed from the SNMP protocol entity to the
+ transport service."
+ ::= { snmp 2 }
+
+-- { snmp 7 } is not used
+
+snmpInTooBigs OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS obsolete
+ DESCRIPTION
+ "The total number of SNMP PDUs which were
+ delivered to the SNMP protocol entity and for
+ which the value of the error-status field was
+ `tooBig'."
+ ::= { snmp 8 }
+
+snmpInNoSuchNames OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS obsolete
+ DESCRIPTION
+ "The total number of SNMP PDUs which were
+ delivered to the SNMP protocol entity and for
+ which the value of the error-status field was
+ `noSuchName'."
+ ::= { snmp 9 }
+
+snmpInBadValues OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS obsolete
+ DESCRIPTION
+ "The total number of SNMP PDUs which were
+ delivered to the SNMP protocol entity and for
+ which the value of the error-status field was
+ `badValue'."
+ ::= { snmp 10 }
+
+snmpInReadOnlys OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS obsolete
+ DESCRIPTION
+ "The total number valid SNMP PDUs which were delivered
+ to the SNMP protocol entity and for which the value
+ of the error-status field was `readOnly'. It should
+ be noted that it is a protocol error to generate an
+ SNMP PDU which contains the value `readOnly' in the
+ error-status field, as such this object is provided
+ as a means of detecting incorrect implementations of
+ the SNMP."
+ ::= { snmp 11 }
+
+snmpInGenErrs OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS obsolete
+ DESCRIPTION
+ "The total number of SNMP PDUs which were delivered
+ to the SNMP protocol entity and for which the value
+ of the error-status field was `genErr'."
+ ::= { snmp 12 }
+
+snmpInTotalReqVars OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS obsolete
+ DESCRIPTION
+ "The total number of MIB objects which have been
+ retrieved successfully by the SNMP protocol entity
+ as the result of receiving valid SNMP Get-Request
+ and Get-Next PDUs."
+ ::= { snmp 13 }
+
+snmpInTotalSetVars OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS obsolete
+ DESCRIPTION
+ "The total number of MIB objects which have been
+ altered successfully by the SNMP protocol entity as
+ the result of receiving valid SNMP Set-Request PDUs."
+ ::= { snmp 14 }
+
+snmpInGetRequests OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS obsolete
+ DESCRIPTION
+ "The total number of SNMP Get-Request PDUs which
+ have been accepted and processed by the SNMP
+ protocol entity."
+ ::= { snmp 15 }
+
+snmpInGetNexts OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS obsolete
+ DESCRIPTION
+ "The total number of SNMP Get-Next PDUs which have been
+ accepted and processed by the SNMP protocol entity."
+ ::= { snmp 16 }
+
+snmpInSetRequests OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS obsolete
+ DESCRIPTION
+ "The total number of SNMP Set-Request PDUs which
+ have been accepted and processed by the SNMP protocol
+ entity."
+ ::= { snmp 17 }
+
+snmpInGetResponses OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS obsolete
+ DESCRIPTION
+ "The total number of SNMP Get-Response PDUs which
+ have been accepted and processed by the SNMP protocol
+ entity."
+ ::= { snmp 18 }
+
+snmpInTraps OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS obsolete
+ DESCRIPTION
+ "The total number of SNMP Trap PDUs which have been
+ accepted and processed by the SNMP protocol entity."
+ ::= { snmp 19 }
+
+snmpOutTooBigs OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS obsolete
+ DESCRIPTION
+ "The total number of SNMP PDUs which were generated
+ by the SNMP protocol entity and for which the value
+ of the error-status field was `tooBig.'"
+ ::= { snmp 20 }
+
+snmpOutNoSuchNames OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS obsolete
+ DESCRIPTION
+ "The total number of SNMP PDUs which were generated
+ by the SNMP protocol entity and for which the value
+ of the error-status was `noSuchName'."
+ ::= { snmp 21 }
+
+snmpOutBadValues OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS obsolete
+ DESCRIPTION
+ "The total number of SNMP PDUs which were generated
+ by the SNMP protocol entity and for which the value
+ of the error-status field was `badValue'."
+ ::= { snmp 22 }
+
+-- { snmp 23 } is not used
+
+snmpOutGenErrs OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS obsolete
+ DESCRIPTION
+ "The total number of SNMP PDUs which were generated
+ by the SNMP protocol entity and for which the value
+ of the error-status field was `genErr'."
+ ::= { snmp 24 }
+
+snmpOutGetRequests OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS obsolete
+ DESCRIPTION
+ "The total number of SNMP Get-Request PDUs which
+ have been generated by the SNMP protocol entity."
+ ::= { snmp 25 }
+
+snmpOutGetNexts OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS obsolete
+ DESCRIPTION
+ "The total number of SNMP Get-Next PDUs which have
+ been generated by the SNMP protocol entity."
+ ::= { snmp 26 }
+
+snmpOutSetRequests OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS obsolete
+ DESCRIPTION
+ "The total number of SNMP Set-Request PDUs which
+ have been generated by the SNMP protocol entity."
+ ::= { snmp 27 }
+
+snmpOutGetResponses OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS obsolete
+ DESCRIPTION
+ "The total number of SNMP Get-Response PDUs which
+ have been generated by the SNMP protocol entity."
+ ::= { snmp 28 }
+
+snmpOutTraps OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS obsolete
+ DESCRIPTION
+ "The total number of SNMP Trap PDUs which have
+ been generated by the SNMP protocol entity."
+ ::= { snmp 29 }
+
+snmpObsoleteGroup OBJECT-GROUP
+ OBJECTS { snmpOutPkts, snmpInTooBigs, snmpInNoSuchNames,
+ snmpInBadValues, snmpInReadOnlys, snmpInGenErrs,
+ snmpInTotalReqVars, snmpInTotalSetVars,
+ snmpInGetRequests, snmpInGetNexts, snmpInSetRequests,
+ snmpInGetResponses, snmpInTraps, snmpOutTooBigs,
+ snmpOutNoSuchNames, snmpOutBadValues,
+ snmpOutGenErrs, snmpOutGetRequests, snmpOutGetNexts,
+ snmpOutSetRequests, snmpOutGetResponses, snmpOutTraps
+ }
+ STATUS obsolete
+ DESCRIPTION
+ "A collection of objects from RFC 1213 made obsolete
+ by this MIB module."
+ ::= { snmpMIBGroups 10 }
+
+END
diff --git a/lib/snmp/mibs/SNMPv2-SMI.mib b/lib/snmp/mibs/SNMPv2-SMI.mib
new file mode 100644
index 0000000000..99a4f558e2
--- /dev/null
+++ b/lib/snmp/mibs/SNMPv2-SMI.mib
@@ -0,0 +1,314 @@
+SNMPv2-SMI DEFINITIONS ::= BEGIN
+
+-- the path to the root
+
+org OBJECT IDENTIFIER ::= { iso 3 }
+dod OBJECT IDENTIFIER ::= { org 6 }
+internet OBJECT IDENTIFIER ::= { dod 1 }
+
+directory OBJECT IDENTIFIER ::= { internet 1 }
+
+mgmt OBJECT IDENTIFIER ::= { internet 2 }
+mib-2 OBJECT IDENTIFIER ::= { mgmt 1 }
+transmission OBJECT IDENTIFIER ::= { mib-2 10 }
+
+experimental OBJECT IDENTIFIER ::= { internet 3 }
+
+private OBJECT IDENTIFIER ::= { internet 4 }
+enterprises OBJECT IDENTIFIER ::= { private 1 }
+
+security OBJECT IDENTIFIER ::= { internet 5 }
+
+snmpV2 OBJECT IDENTIFIER ::= { internet 6 }
+
+-- transport domains
+snmpDomains OBJECT IDENTIFIER ::= { snmpV2 1 }
+
+-- transport proxies
+snmpProxys OBJECT IDENTIFIER ::= { snmpV2 2 }
+
+-- module identities
+snmpModules OBJECT IDENTIFIER ::= { snmpV2 3 }
+
+
+-- definitions for information modules
+
+MODULE-IDENTITY MACRO ::=
+BEGIN
+ TYPE NOTATION ::=
+ "LAST-UPDATED" value(Update UTCTime)
+ "ORGANIZATION" Text
+ "CONTACT-INFO" Text
+ "DESCRIPTION" Text
+ RevisionPart
+
+ VALUE NOTATION ::=
+ value(VALUE OBJECT IDENTIFIER)
+
+ RevisionPart ::=
+ Revisions
+ | empty
+ Revisions ::=
+ Revision
+ | Revisions Revision
+ Revision ::=
+ "REVISION" value(Update UTCTime)
+ "DESCRIPTION" Text
+
+ -- uses the NVT ASCII character set
+ Text ::= """" string """"
+END
+
+
+OBJECT-IDENTITY MACRO ::=
+BEGIN
+ TYPE NOTATION ::=
+ "STATUS" Status
+ "DESCRIPTION" Text
+ ReferPart
+
+ VALUE NOTATION ::=
+ value(VALUE OBJECT IDENTIFIER)
+
+ Status ::=
+ "current"
+ | "deprecated"
+ | "obsolete"
+
+ ReferPart ::=
+ "REFERENCE" Text
+ | empty
+
+ Text ::= """" string """"
+END
+
+
+-- names of objects
+
+ObjectName ::=
+ OBJECT IDENTIFIER
+
+NotificationName ::=
+ OBJECT IDENTIFIER
+
+-- syntax of objects
+
+ObjectSyntax ::=
+ CHOICE {
+ simple
+ SimpleSyntax,
+
+ -- note that SEQUENCEs for conceptual tables and
+ -- rows are not mentioned here...
+
+ application-wide
+ ApplicationSyntax
+ }
+
+
+-- built-in ASN.1 types
+
+SimpleSyntax ::=
+ CHOICE {
+ -- INTEGERs with a more restrictive range
+ -- may also be used
+ integer-value -- includes Integer32
+ INTEGER (-2147483648..2147483647),
+
+ -- OCTET STRINGs with a more restrictive size
+ -- may also be used
+ string-value
+ OCTET STRING (SIZE (0..65535)),
+
+ objectID-value
+ OBJECT IDENTIFIER
+ }
+
+
+-- indistinguishable from INTEGER, but never needs more than
+-- 32-bits for a two's complement representation
+Integer32 ::=
+ [UNIVERSAL 2]
+ IMPLICIT INTEGER (-2147483648..2147483647)
+
+
+-- application-wide types
+
+ApplicationSyntax ::=
+ CHOICE {
+ ipAddress-value
+ IpAddress,
+
+ counter-value
+ Counter32,
+
+ timeticks-value
+ TimeTicks,
+
+ arbitrary-value
+ Opaque,
+
+ big-counter-value
+ Counter64,
+
+ unsigned-integer-value -- includes Gauge32
+ Unsigned32
+ }
+
+-- in network-byte order
+-- (this is a tagged type for historical reasons)
+IpAddress ::=
+ [APPLICATION 0]
+ IMPLICIT OCTET STRING (SIZE (4))
+
+-- this wraps
+Counter32 ::=
+ [APPLICATION 1]
+ IMPLICIT INTEGER (0..4294967295)
+
+-- this doesn't wrap
+Gauge32 ::=
+ [APPLICATION 2]
+ IMPLICIT INTEGER (0..4294967295)
+
+-- an unsigned 32-bit quantity
+-- indistinguishable from Gauge32
+Unsigned32 ::=
+ [APPLICATION 2]
+ IMPLICIT INTEGER (0..4294967295)
+
+-- hundredths of seconds since an epoch
+TimeTicks ::=
+ [APPLICATION 3]
+ IMPLICIT INTEGER (0..4294967295)
+
+-- for backward-compatibility only
+Opaque ::=
+ [APPLICATION 4]
+ IMPLICIT OCTET STRING
+
+-- for counters that wrap in less than one hour with only 32 bits
+Counter64 ::=
+ [APPLICATION 6]
+ IMPLICIT INTEGER (0..18446744073709551615)
+
+
+-- definition for objects
+
+OBJECT-TYPE MACRO ::=
+BEGIN
+ TYPE NOTATION ::=
+ "SYNTAX" Syntax
+ UnitsPart
+ "MAX-ACCESS" Access
+ "STATUS" Status
+ "DESCRIPTION" Text
+ ReferPart
+ IndexPart
+ DefValPart
+
+ VALUE NOTATION ::=
+ value(VALUE ObjectName)
+
+ Syntax ::=
+ type(ObjectSyntax)
+ | "BITS" "{" Kibbles "}"
+ Kibbles ::=
+ Kibble
+ | Kibbles "," Kibble
+ Kibble ::=
+ identifier "(" nonNegativeNumber ")"
+
+ UnitsPart ::=
+ "UNITS" Text
+ | empty
+
+ Access ::=
+ "not-accessible"
+ | "accessible-for-notify"
+ | "read-only"
+ | "read-write"
+ | "read-create"
+
+ Status ::=
+ "current"
+ | "deprecated"
+ | "obsolete"
+
+ ReferPart ::=
+ "REFERENCE" Text
+ | empty
+
+ IndexPart ::=
+ "INDEX" "{" IndexTypes "}"
+ | "AUGMENTS" "{" Entry "}"
+ | empty
+ IndexTypes ::=
+ IndexType
+ | IndexTypes "," IndexType
+ IndexType ::=
+ "IMPLIED" Index
+ | Index
+ Index ::=
+ -- use the SYNTAX value of the
+ -- correspondent OBJECT-TYPE invocation
+ value(Indexobject ObjectName)
+ Entry ::=
+ -- use the INDEX value of the
+ -- correspondent OBJECT-TYPE invocation
+ value(Entryobject ObjectName)
+
+ DefValPart ::=
+ "DEFVAL" "{" value(Defval Syntax) "}"
+ | empty
+
+ -- uses the NVT ASCII character set
+ Text ::= """" string """"
+END
+
+
+-- definitions for notifications
+
+NOTIFICATION-TYPE MACRO ::=
+BEGIN
+ TYPE NOTATION ::=
+ ObjectsPart
+ "STATUS" Status
+ "DESCRIPTION" Text
+ ReferPart
+
+ VALUE NOTATION ::=
+ value(VALUE NotificationName)
+
+ ObjectsPart ::=
+ "OBJECTS" "{" Objects "}"
+ | empty
+ Objects ::=
+ Object
+ | Objects "," Object
+ Object ::=
+ value(Name ObjectName)
+
+ Status ::=
+ "current"
+ | "deprecated"
+ | "obsolete"
+
+ ReferPart ::=
+ "REFERENCE" Text
+ | empty
+
+ -- uses the NVT ASCII character set
+ Text ::= """" string """"
+END
+
+-- definitions of administrative identifiers
+
+zeroDotZero OBJECT-IDENTITY
+ STATUS current
+ DESCRIPTION
+ "A value used for null identifiers."
+ ::= { 0 0 }
+
+END
+
diff --git a/lib/snmp/mibs/SNMPv2-TC.mib b/lib/snmp/mibs/SNMPv2-TC.mib
new file mode 100644
index 0000000000..048f4a9406
--- /dev/null
+++ b/lib/snmp/mibs/SNMPv2-TC.mib
@@ -0,0 +1,535 @@
+SNMPv2-TC DEFINITIONS ::= BEGIN
+
+IMPORTS
+ ObjectSyntax, TimeTicks FROM SNMPv2-SMI;
+
+-- definition of textual conventions
+
+TEXTUAL-CONVENTION MACRO ::=
+BEGIN
+
+ TYPE NOTATION ::=
+ DisplayPart
+ "STATUS" Status
+ "DESCRIPTION" Text
+ ReferPart
+ "SYNTAX" Syntax
+
+ VALUE NOTATION ::=
+ value(VALUE Syntax)
+
+ DisplayPart ::=
+ "DISPLAY-HINT" Text
+ | empty
+
+ Status ::=
+ "current"
+ | "deprecated"
+ | "obsolete"
+
+ ReferPart ::=
+ "REFERENCE" Text
+ | empty
+
+ -- uses the NVT ASCII character set
+ Text ::= """" string """"
+
+ Syntax ::=
+ type(ObjectSyntax)
+ | "BITS" "{" Kibbles "}"
+ Kibbles ::=
+ Kibble
+ | Kibbles "," Kibble
+ Kibble ::=
+ identifier "(" nonNegativeNumber ")"
+
+END
+
+DisplayString ::= TEXTUAL-CONVENTION
+ DISPLAY-HINT "255a"
+
+ STATUS current
+ DESCRIPTION
+ "Represents textual information taken from the NVT ASCII
+ character set, as defined in pages 4, 10-11 of RFC 854.
+
+ To summarize RFC 854, the NVT ASCII repertoire specifies:
+
+ - the use of character codes 0-127 (decimal)
+
+ - the graphics characters (32-126) are interpreted as
+ US ASCII
+
+ - NUL, LF, CR, BEL, BS, HT, VT and FF have the special
+ meanings specified in RFC 854
+
+ - the other 25 codes have no standard interpretation
+
+ - the sequence 'CR LF' means newline
+
+ - the sequence 'CR NUL' means carriage-return
+
+ - an 'LF' not preceded by a 'CR' means moving to the
+ same column on the next line.
+
+ - the sequence 'CR x' for any x other than LF or NUL is
+ illegal. (Note that this also means that a string may
+ end with either 'CR LF' or 'CR NUL', but not with CR.)
+
+ Any object defined using this syntax may not exceed 255 characters in length."
+
+ SYNTAX OCTET STRING (SIZE (0..255))
+
+PhysAddress ::= TEXTUAL-CONVENTION
+ DISPLAY-HINT "1x:"
+
+ STATUS current
+ DESCRIPTION
+ "Represents media- or physical-level addresses."
+ SYNTAX OCTET STRING
+
+
+MacAddress ::= TEXTUAL-CONVENTION
+ DISPLAY-HINT "1x:"
+
+ STATUS current
+ DESCRIPTION
+ "Represents an 802 MAC address represented in the
+ `canonical' order defined by IEEE 802.1a, i.e., as if it
+ were transmitted least significant bit first, even though
+ 802.5 (in contrast to other 802.x protocols) requires MAC
+ addresses to be transmitted most significant bit first."
+ SYNTAX OCTET STRING (SIZE (6))
+
+
+TruthValue ::= TEXTUAL-CONVENTION
+
+ STATUS current
+ DESCRIPTION
+ "Represents a boolean value."
+ SYNTAX INTEGER { true(1), false(2) }
+
+
+TestAndIncr ::= TEXTUAL-CONVENTION
+
+ STATUS current
+ DESCRIPTION
+ "Represents integer-valued information used for atomic
+ operations. When the management protocol is used to specify
+ that an object instance having this syntax is to be
+ modified, the new value supplied via the management protocol
+ must precisely match the value presently held by the
+ instance. If not, the management protocol set operation
+ fails with an error of `inconsistentValue'. Otherwise, if
+ the current value is the maximum value of 2^31-1 (2147483647
+ decimal), then the value held by the instance is wrapped to
+ zero; otherwise, the value held by the instance is
+ incremented by one. (Note that regardless of whether the
+ management protocol set operation succeeds, the variable-
+ binding in the request and response PDUs are identical.)
+
+ The value of the ACCESS clause for objects having this syntax is either `read-write' or `read-create'. When an instance of a columnar object having this syntax is created, any value may be supplied via the management protocol.
+
+ When the network management portion of the system is re- initialized, the value of every object instance having this syntax must either be incremented from its value prior to the re-initialization, or (if the value prior to the re- initialization is unknown) be set to a pseudo-randomly generated value."
+
+ SYNTAX INTEGER (0..2147483647)
+
+
+AutonomousType ::= TEXTUAL-CONVENTION
+
+ STATUS current
+ DESCRIPTION
+ "Represents an independently extensible type identification
+ value. It may, for example, indicate a particular sub-tree
+ with further MIB definitions, or define a particular type of
+ protocol or hardware."
+ SYNTAX OBJECT IDENTIFIER
+
+
+InstancePointer ::= TEXTUAL-CONVENTION
+
+ STATUS obsolete
+ DESCRIPTION
+ "A pointer to either a specific instance of a MIB object or
+ a conceptual row of a MIB table in the managed device. In
+ the latter case, by convention, it is the name of the
+ particular instance of the first accessible columnar object
+ in the conceptual row.
+
+ The two uses of this textual convention are replaced by VariablePointer and RowPointer, respectively."
+
+ SYNTAX OBJECT IDENTIFIER
+
+
+VariablePointer ::= TEXTUAL-CONVENTION
+
+ STATUS current
+ DESCRIPTION
+ "A pointer to a specific object instance. For example,
+ sysContact.0 or ifInOctets.3."
+ SYNTAX OBJECT IDENTIFIER
+
+
+RowPointer ::= TEXTUAL-CONVENTION
+
+ STATUS current
+ DESCRIPTION
+ "Represents a pointer to a conceptual row. The value is the
+ name of the instance of the first accessible columnar object
+ in the conceptual row.
+
+ For example, ifIndex.3 would point to the 3rd row in the ifTable (note that if ifIndex were not-accessible, then ifDescr.3 would be used instead)."
+
+ SYNTAX OBJECT IDENTIFIER
+
+
+RowStatus ::= TEXTUAL-CONVENTION
+
+ STATUS current
+ DESCRIPTION
+ "The RowStatus textual convention is used to manage the
+
+ creation and deletion of conceptual rows, and is used as the value of the SYNTAX clause for the status column of a conceptual row (as described in Section 7.7.1 of [2].)
+
+ The status column has six defined values:
+
+ - `active', which indicates that the conceptual row is
+ available for use by the managed device;
+
+ - `notInService', which indicates that the conceptual
+ row exists in the agent, but is unavailable for use by
+ the managed device (see NOTE below);
+
+ - `notReady', which indicates that the conceptual row
+ exists in the agent, but is missing information
+ necessary in order to be available for use by the
+ managed device;
+
+ - `createAndGo', which is supplied by a management
+ station wishing to create a new instance of a
+ conceptual row and to have its status automatically set
+ to active, making it available for use by the managed
+ device;
+
+ - `createAndWait', which is supplied by a management
+ station wishing to create a new instance of a
+ conceptual row (but not make it available for use by
+ the managed device); and,
+
+ - `destroy', which is supplied by a management station
+ wishing to delete all of the instances associated with
+ an existing conceptual row.
+
+ Whereas five of the six values (all except `notReady') may be specified in a management protocol set operation, only three values will be returned in response to a management protocol retrieval operation: `notReady', `notInService' or `active'. That is, when queried, an existing conceptual row has only three states: it is either available for use by the managed device (the status column has value `active'); it is not available for use by the managed device, though the agent has sufficient information to make it so (the status column has value `notInService'); or, it is not available for use by the managed device, and an attempt to make it so would fail because the agent has insufficient information (the state column has value `notReady').
+
+ NOTE WELL
+
+ This textual convention may be used for a MIB table, irrespective of whether the values of that table's conceptual rows are able to be modified while it is active, or whether its conceptual rows must be taken out of service in order to be modified. That is, it is the responsibility of the DESCRIPTION clause of the status column to specify whether the status column must not be `active' in order for the value of some other column of the same conceptual row to be modified. If such a specification is made, affected columns may be changed by an SNMP set PDU if the RowStatus would not be equal to `active' either immediately before or after processing the PDU. In other words, if the PDU also contained a varbind that would change the RowStatus value, the column in question may be changed if the RowStatus was not equal to `active' as the PDU was received, or if the varbind sets the status to a value other than 'active'.
+
+ Also note that whenever any elements of a row exist, the RowStatus column must also exist.
+
+ To summarize the effect of having a conceptual row with a status column having a SYNTAX clause value of RowStatus, consider the following state diagram:
+
+ STATE
+
+ +--------------+-----------+-------------+-------------
+ | A | B | C | D
+ | |status col.|status column|
+ |status column | is | is |status column
+ ACTION |does not exist| notReady | notInService| is active
+
+--------------+--------------+-----------+-------------+-------------
+set status |noError ->D|inconsist- |inconsistent-|inconsistent-
+column to | or | entValue| Value| Value
+createAndGo |inconsistent- | | |
+ | Value| | |
+
+--------------+--------------+-----------+-------------+-------------
+set status |noError see 1|inconsist- |inconsistent-|inconsistent-
+column to | or | entValue| Value| Value
+createAndWait |wrongValue | | |
+
+--------------+--------------+-----------+-------------+-------------
+set status |inconsistent- |inconsist- |noError |noError
+column to | Value| entValue| |
+active | | | |
+ | | or | |
+ | | | |
+ | |see 2 ->D| ->D| ->D
+
+--------------+--------------+-----------+-------------+-------------
+set status |inconsistent- |inconsist- |noError |noError ->C
+column to | Value| entValue| |
+notInService | | | |
+ | | or | | or
+ | | | |
+ | |see 3 ->C| ->C|wrongValue
+
+--------------+--------------+-----------+-------------+-------------
+set status |noError |noError |noError |noError
+column to | | | |
+destroy | ->A| ->A| ->A| ->A
+
+--------------+--------------+-----------+-------------+-------------
+set any other |see 4 |noError |noError |see 5
+column to some| | | |
+value | | see 1| ->C| ->D
+
+--------------+--------------+-----------+-------------+-------------
+
+ (1) goto B or C, depending on information available to the agent.
+
+ (2) if other variable bindings included in the same PDU, provide values for all columns which are missing but required, then return noError and goto D.
+
+ (3) if other variable bindings included in the same PDU, provide values for all columns which are missing but required, then return noError and goto C.
+
+ (4) at the discretion of the agent, the return value may be either:
+
+ inconsistentName: because the agent does not choose to create such an instance when the corresponding RowStatus instance does not exist, or
+
+ inconsistentValue: if the supplied value is inconsistent with the state of some other MIB object's value, or
+
+ noError: because the agent chooses to create the instance.
+
+ If noError is returned, then the instance of the status column must also be created, and the new state is B or C, depending on the information available to the agent. If inconsistentName or inconsistentValue is returned, the row remains in state A.
+
+ (5) depending on the MIB definition for the column/table, either noError or inconsistentValue may be returned.
+
+ NOTE: Other processing of the set request may result in a response other than noError being returned, e.g., wrongValue, noCreation, etc.
+
+ Conceptual Row Creation
+
+ There are four potential interactions when creating a conceptual row: selecting an instance-identifier which is not in use; creating the conceptual row; initializing any objects for which the agent does not supply a default; and, making the conceptual row available for use by the managed device.
+
+ Interaction 1: Selecting an Instance-Identifier
+
+ The algorithm used to select an instance-identifier varies for each conceptual row. In some cases, the instance- identifier is semantically significant, e.g., the destination address of a route, and a management station selects the instance-identifier according to the semantics.
+
+ In other cases, the instance-identifier is used solely to distinguish conceptual rows, and a management station without specific knowledge of the conceptual row might examine the instances present in order to determine an unused instance-identifier. (This approach may be used, but it is often highly sub-optimal; however, it is also a questionable practice for a naive management station to attempt conceptual row creation.)
+
+ Alternately, the MIB module which defines the conceptual row might provide one or more objects which provide assistance in determining an unused instance-identifier. For example, if the conceptual row is indexed by an integer-value, then an object having an integer-valued SYNTAX clause might be defined for such a purpose, allowing a management station to issue a management protocol retrieval operation. In order to avoid unnecessary collisions between competing management stations, `adjacent' retrievals of this object should be different.
+
+ Finally, the management station could select a pseudo-random number to use as the index. In the event that this index was already in use and an inconsistentValue was returned in response to the management protocol set operation, the management station should simply select a new pseudo-random number and retry the operation.
+
+ A MIB designer should choose between the two latter algorithms based on the size of the table (and therefore the efficiency of each algorithm). For tables in which a large number of entries are expected, it is recommended that a MIB object be defined that returns an acceptable index for creation. For tables with small numbers of entries, it is recommended that the latter pseudo-random index mechanism be used.
+
+ Interaction 2: Creating the Conceptual Row
+
+ Once an unused instance-identifier has been selected, the management station determines if it wishes to create and activate the conceptual row in one transaction or in a negotiated set of interactions.
+
+ Interaction 2a: Creating and Activating the Conceptual Row
+
+ The management station must first determine the column requirements, i.e., it must determine those columns for which it must or must not provide values. Depending on the complexity of the table and the management station's knowledge of the agent's capabilities, this determination can be made locally by the management station. Alternately, the management station issues a management protocol get operation to examine all columns in the conceptual row that it wishes to create. In response, for each column, there are three possible outcomes:
+
+ - a value is returned, indicating that some other
+ management station has already created this conceptual
+ row. We return to interaction 1.
+
+ - the exception `noSuchInstance' is returned,
+ indicating that the agent implements the object-type
+ associated with this column, and that this column in at
+ least one conceptual row would be accessible in the MIB
+ view used by the retrieval were it to exist. For those
+ columns to which the agent provides read-create access,
+ the `noSuchInstance' exception tells the management
+ station that it should supply a value for this column
+ when the conceptual row is to be created.
+
+ - the exception `noSuchObject' is returned, indicating
+ that the agent does not implement the object-type
+ associated with this column or that there is no
+ conceptual row for which this column would be
+ accessible in the MIB view used by the retrieval. As
+ such, the management station can not issue any
+ management protocol set operations to create an
+ instance of this column.
+
+ Once the column requirements have been determined, a management protocol set operation is accordingly issued. This operation also sets the new instance of the status column to `createAndGo'.
+
+ When the agent processes the set operation, it verifies that it has sufficient information to make the conceptual row available for use by the managed device. The information available to the agent is provided by two sources: the management protocol set operation which creates the conceptual row, and, implementation-specific defaults supplied by the agent (note that an agent must provide implementation-specific defaults for at least those objects which it implements as read-only). If there is sufficient information available, then the conceptual row is created, a `noError' response is returned, the status column is set to `active', and no further interactions are necessary (i.e., interactions 3 and 4 are skipped). If there is insufficient information, then the conceptual row is not created, and the set operation fails with an error of `inconsistentValue'. On this error, the management station can issue a management protocol retrieval operation to determine if this was because it failed to specify a value for a required column, or, because the selected instance of the status column already existed. In the latter case, we return to interaction 1. In the former case, the management station can re-issue the set operation with the additional information, or begin interaction 2 again using
+ `createAndWait' in order to negotiate creation of the conceptual row.
+
+ NOTE WELL
+
+ Regardless of the method used to determine the column requirements, it is possible that the management station might deem a column necessary when, in fact, the agent will not allow that particular columnar instance to be created or written. In this case, the management protocol set operation will fail with an error such as `noCreation' or `notWritable'. In this case, the management station decides whether it needs to be able to set a value for that particular columnar instance. If not, the management station re-issues the management protocol set operation, but without setting a value for that particular columnar instance; otherwise, the management station aborts the row creation algorithm.
+
+ Interaction 2b: Negotiating the Creation of the Conceptual Row
+
+ The management station issues a management protocol set operation which sets the desired instance of the status
+
+ column to `createAndWait'. If the agent is unwilling to process a request of this sort, the set operation fails with an error of `wrongValue'. (As a consequence, such an agent must be prepared to accept a single management protocol set operation, i.e., interaction 2a above, containing all of the columns indicated by its column requirements.) Otherwise, the conceptual row is created, a `noError' response is returned, and the status column is immediately set to either `notInService' or `notReady', depending on whether it has sufficient information to make the conceptual row available for use by the managed device. If there is sufficient information available, then the status column is set to `notInService'; otherwise, if there is insufficient information, then the status column is set to `notReady'. Regardless, we proceed to interaction 3.
+
+ Interaction 3: Initializing non-defaulted Objects
+
+ The management station must now determine the column requirements. It issues a management protocol get operation to examine all columns in the created conceptual row. In the response, for each column, there are three possible outcomes:
+
+ - a value is returned, indicating that the agent
+ implements the object-type associated with this column
+ and had sufficient information to provide a value. For
+ those columns to which the agent provides read-create
+ access (and for which the agent allows their values to
+ be changed after their creation), a value return tells
+ the management station that it may issue additional
+ management protocol set operations, if it desires, in
+ order to change the value associated with this column.
+
+ - the exception `noSuchInstance' is returned,
+ indicating that the agent implements the object-type
+ associated with this column, and that this column in at
+ least one conceptual row would be accessible in the MIB
+ view used by the retrieval were it to exist. However,
+ the agent does not have sufficient information to
+ provide a value, and until a value is provided, the
+ conceptual row may not be made available for use by the
+ managed device. For those columns to which the agent
+ provides read-create access, the `noSuchInstance'
+ exception tells the management station that it must
+ issue additional management protocol set operations, in
+ order to provide a value associated with this column.
+
+ - the exception `noSuchObject' is returned, indicating
+ that the agent does not implement the object-type
+ associated with this column or that there is no
+ conceptual row for which this column would be
+ accessible in the MIB view used by the retrieval. As
+ such, the management station can not issue any
+ management protocol set operations to create an
+ instance of this column.
+
+ If the value associated with the status column is `notReady', then the management station must first deal with all `noSuchInstance' columns, if any. Having done so, the value of the status column becomes `notInService', and we proceed to interaction 4.
+
+ Interaction 4: Making the Conceptual Row Available
+
+ Once the management station is satisfied with the values associated with the columns of the conceptual row, it issues a management protocol set operation to set the status column to `active'. If the agent has sufficient information to make the conceptual row available for use by the managed device, the management protocol set operation succeeds (a `noError' response is returned). Otherwise, the management protocol set operation fails with an error of
+ `inconsistentValue'.
+
+ NOTE WELL
+
+ A conceptual row having a status column with value `notInService' or `notReady' is unavailable to the managed device. As such, it is possible for the managed device to create its own instances during the time between the management protocol set operation which sets the status column to `createAndWait' and the management protocol set operation which sets the status column to `active'. In this case, when the management protocol set operation is issued to set the status column to `active', the values held in the agent supersede those used by the managed device.
+
+ If the management station is prevented from setting the status column to `active' (e.g., due to management station or network failure) the conceptual row will be left in the `notInService' or `notReady' state, consuming resources indefinitely. The agent must detect conceptual rows that have been in either state for an abnormally long period of
+
+ time and remove them. It is the responsibility of the DESCRIPTION clause of the status column to indicate what an abnormally long period of time would be. This period of time should be long enough to allow for human response time (including `think time') between the creation of the conceptual row and the setting of the status to `active'. In the absense of such information in the DESCRIPTION clause, it is suggested that this period be approximately 5 minutes in length. This removal action applies not only to newly-created rows, but also to previously active rows which are set to, and left in, the notInService state for a prolonged period exceeding that which is considered normal for such a conceptual row.
+
+ Conceptual Row Suspension
+
+ When a conceptual row is `active', the management station may issue a management protocol set operation which sets the instance of the status column to `notInService'. If the agent is unwilling to do so, the set operation fails with an error of `wrongValue'. Otherwise, the conceptual row is taken out of service, and a `noError' response is returned. It is the responsibility of the DESCRIPTION clause of the status column to indicate under what circumstances the status column should be taken out of service (e.g., in order for the value of some other column of the same conceptual row to be modified).
+
+ Conceptual Row Deletion
+
+ For deletion of conceptual rows, a management protocol set operation is issued which sets the instance of the status column to `destroy'. This request may be made regardless of the current value of the status column (e.g., it is possible to delete conceptual rows which are either `notReady', `notInService' or `active'.) If the operation succeeds, then all instances associated with the conceptual row are immediately removed."
+
+ SYNTAX INTEGER {
+ -- the following two values are states:
+ -- these values may be read or written
+ active(1),
+ notInService(2),
+
+ -- the following value is a state:
+ -- this value may be read, but not written
+ notReady(3),
+
+ -- the following three values are
+ -- actions: these values may be written,
+ -- but are never read
+ createAndGo(4),
+ createAndWait(5),
+ destroy(6)
+ }
+
+
+TimeStamp ::= TEXTUAL-CONVENTION
+
+ STATUS current
+ DESCRIPTION
+ "The value of the sysUpTime object at which a specific
+ occurrence happened. The specific occurrence must be
+ defined in the description of any object defined using this
+ type."
+ SYNTAX TimeTicks
+
+
+TimeInterval ::= TEXTUAL-CONVENTION
+
+ STATUS current
+ DESCRIPTION
+ "A period of time, measured in units of 0.01 seconds."
+ SYNTAX INTEGER (0..2147483647)
+
+
+DateAndTime ::= TEXTUAL-CONVENTION
+ DISPLAY-HINT "2d-1d-1d,1d:1d:1d.1d,1a1d:1d"
+
+ STATUS current
+ DESCRIPTION
+ "A date-time specification.
+
+ field octets contents range
+ ----- ------ -------- -----
+ 1 1-2 year 0..65536
+ 2 3 month 1..12
+ 3 4 day 1..31
+ 4 5 hour 0..23
+ 5 6 minutes 0..59
+ 6 7 seconds 0..60
+ (use 60 for leap-second)
+ 7 8 deci-seconds 0..9
+ 8 9 direction from UTC '+' / '-'
+ 9 10 hours from UTC 0..11
+ 10 11 minutes from UTC 0..59
+
+ For example, Tuesday May 26, 1992 at 1:30:15 PM EDT would be displayed as:
+
+ 1992-5-26,13:30:15.0,-4:0
+
+ Note that if only local time is known, then timezone information (fields 8-10) is not present."
+
+ SYNTAX OCTET STRING (SIZE (8 | 11))
+
+
+StorageType ::= TEXTUAL-CONVENTION
+
+ STATUS current
+ DESCRIPTION
+ "Describes the memory realization of a conceptual row. A
+ row which is volatile(2) is lost upon reboot. A row which
+ is either nonVolatile(3), permanent(4) or readOnly(5), is
+ backed up by stable storage. A row which is permanent(4)
+ can be changed but not deleted. A row which is readOnly(5)
+ cannot be changed nor deleted.
+
+ If the value of an object with this syntax is either permanent(4) or readOnly(5), it cannot be modified. Conversely, if the value is either other(1), volatile(2) or nonVolatile(3), it cannot be modified to be permanent(4) or readOnly(5).
+
+ Every usage of this textual convention is required to specify the columnar objects which a permanent(4) row must at a minimum allow to be writable."
+
+ SYNTAX INTEGER {
+ other(1), -- eh?
+ volatile(2), -- e.g., in RAM
+ nonVolatile(3), -- e.g., in NVRAM
+ permanent(4), -- e.g., partially in ROM
+ readOnly(5) -- e.g., completely in ROM
+ }
+
+
+TDomain ::= TEXTUAL-CONVENTION
+
+ STATUS current
+ DESCRIPTION
+ "Denotes a kind of transport service.
+
+ Some possible values, such as snmpUDPDomain, are defined in 'Transport Mappings for Version 2 of the Simple Network Management Protocol (SNMPv2)'."
+
+ SYNTAX OBJECT IDENTIFIER
+
+
+TAddress ::= TEXTUAL-CONVENTION
+
+ STATUS current
+ DESCRIPTION
+ "Denotes a transport service address.
+
+ For snmpUDPDomain, a TAddress is 6 octets long, the initial 4 octets containing the IP-address in network-byte order and the last 2 containing the UDP port in network-byte order. Consult 'Transport Mappings for Version 2 of the Simple Network Management Protocol (SNMPv2)' for further information on snmpUDPDomain."
+
+ SYNTAX OCTET STRING (SIZE (1..255))
+
+END
diff --git a/lib/snmp/mibs/SNMPv2-TM.mib b/lib/snmp/mibs/SNMPv2-TM.mib
new file mode 100644
index 0000000000..6884ea98d8
--- /dev/null
+++ b/lib/snmp/mibs/SNMPv2-TM.mib
@@ -0,0 +1,151 @@
+SNMPv2-TM DEFINITIONS ::= BEGIN
+
+IMPORTS
+ MODULE-IDENTITY, OBJECT-IDENTITY, snmpDomains, snmpProxys, snmpModules
+ FROM SNMPv2-SMI
+ TEXTUAL-CONVENTION
+ FROM SNMPv2-TC;
+
+snmpv2TM MODULE-IDENTITY
+ LAST-UPDATED "9709250900Z"
+ ORGANIZATION "IETF SNMPv2 Working Group"
+ CONTACT-INFO
+ " Marshall T. Rose
+
+ Postal: Dover Beach Consulting, Inc.
+ 420 Whisman Court
+ Mountain View, CA 94043-2186
+ US
+
+ Tel: +1 415 968 1052
+
+ DESCRIPTION
+ "The MIB module for SNMPv2 Transport Mappings."
+ REVISION "9709250900Z"
+ DESCRIPTION
+ "This MIB module is extracted from RFC 1906. It is
+ modified by [email protected] to be
+ compilable. The MODULE-IDENTITY specification was
+ added."
+ ::= { snmpModules 0 } -- dummy
+
+-- SNMPv2 over UDP over IPv4
+
+snmpUDPDomain OBJECT-IDENTITY
+ STATUS current
+ DESCRIPTION
+ "The SNMPv2 over UDP transport domain. The corresponding
+ transport address is of type SnmpUDPAddress."
+ ::= { snmpDomains 1 }
+
+SnmpUDPAddress ::= TEXTUAL-CONVENTION
+ DISPLAY-HINT "1d.1d.1d.1d/2d"
+ STATUS current
+ DESCRIPTION
+ "Represents a UDP address:
+
+ octets contents encoding
+ 1-4 IP-address network-byte order
+ 5-6 UDP-port network-byte order
+ "
+ SYNTAX OCTET STRING (SIZE (6))
+
+
+-- SNMPv2 over OSI
+
+snmpCLNSDomain OBJECT-IDENTITY
+ STATUS current
+ DESCRIPTION
+ "The SNMPv2 over CLNS transport domain. The corresponding
+ transport address is of type SnmpOSIAddress."
+ ::= { snmpDomains 2 }
+
+snmpCONSDomain OBJECT-IDENTITY
+ STATUS current
+ DESCRIPTION
+ "The SNMPv2 over CONS transport domain. The corresponding
+ transport address is of type SnmpOSIAddress."
+ ::= { snmpDomains 3 }
+
+SnmpOSIAddress ::= TEXTUAL-CONVENTION
+ DISPLAY-HINT "*1x:/1x:"
+ STATUS current
+ DESCRIPTION
+ "Represents an OSI transport-address:
+
+ octets contents encoding
+ 1 length of NSAP 'n' as an unsigned-integer
+ (either 0 or from 3 to 20)
+ 2..(n+1) NSAP concrete binary representation
+ (n+2)..m TSEL string of (up to 64) octets
+ "
+ SYNTAX OCTET STRING (SIZE (1 | 4..85))
+
+
+-- SNMPv2 over DDP
+
+snmpDDPDomain OBJECT-IDENTITY
+ STATUS current
+ DESCRIPTION
+ "The SNMPv2 over DDP transport domain. The corresponding
+ transport address is of type SnmpNBPAddress."
+ ::= { snmpDomains 4 }
+
+SnmpNBPAddress ::= TEXTUAL-CONVENTION
+ STATUS current
+ DESCRIPTION
+ "Represents an NBP name:
+
+ octets contents encoding
+ 1 length of object 'n' as an unsigned integer
+ 2..(n+1) object string of (up to 32) octets
+ n+2 length of type 'p' as an unsigned integer
+ (n+3)..(n+2+p) type string of (up to 32) octets
+ n+3+p length of zone 'q' as an unsigned integer
+ (n+4+p)..(n+3+p+q) zone string of (up to 32) octets
+
+ For comparison purposes, strings are case-insensitive All
+ strings may contain any octet other than 255 (hex ff)."
+ SYNTAX OCTET STRING (SIZE (3..99))
+
+
+-- SNMPv2 over IPX
+
+snmpIPXDomain OBJECT-IDENTITY
+ STATUS current
+ DESCRIPTION
+ "The SNMPv2 over IPX transport domain. The corresponding
+ transport address is of type SnmpIPXAddress."
+ ::= { snmpDomains 5 }
+
+SnmpIPXAddress ::= TEXTUAL-CONVENTION
+ DISPLAY-HINT "4x.1x:1x:1x:1x:1x:1x.2d"
+ STATUS current
+ DESCRIPTION
+ "Represents an IPX address:
+
+ octets contents encoding
+ 1-4 network-number network-byte order
+ 5-10 physical-address network-byte order
+ 11-12 socket-number network-byte order
+ "
+ SYNTAX OCTET STRING (SIZE (12))
+
+
+-- for proxy to SNMPv1 (RFC 1157)
+
+rfc1157Proxy OBJECT IDENTIFIER ::= { snmpProxys 1 }
+
+rfc1157Domain OBJECT-IDENTITY
+ STATUS current
+ DESCRIPTION
+ "The transport domain for SNMPv1 over UDP. The
+ corresponding transport address is of type SnmpUDPAddress."
+ ::= { rfc1157Proxy 1 }
+
+-- ::= { rfc1157Proxy 2 } this OID is obsolete
+
+
+END
+
diff --git a/lib/snmp/mibs/STANDARD-MIB.funcs b/lib/snmp/mibs/STANDARD-MIB.funcs
new file mode 100644
index 0000000000..908497b4f8
--- /dev/null
+++ b/lib/snmp/mibs/STANDARD-MIB.funcs
@@ -0,0 +1,36 @@
+{sysUpTime, {snmp_standard_mib, sys_up_time, []}}.
+{sysDescr, {snmp_generic, variable_func, [{sysDescr, persistent}]}}.
+{sysObjectID, {snmp_generic, variable_func, [{sysObjectID, persistent}]}}.
+{sysContact, {snmp_generic, variable_func, [{sysContact, persistent}]}}.
+{sysName, {snmp_generic, variable_func, [{sysName, persistent}]}}.
+{sysLocation, {snmp_generic, variable_func, [{sysLocation, persistent}]}}.
+{sysServices, {snmp_generic, variable_func, [{sysServices, persistent}]}}.
+{snmpEnableAuthenTraps, {snmp_standard_mib, snmp_enable_authen_traps, []}}.
+
+{snmpInPkts, {snmp_standard_mib, variable_func, [snmpInPkts]}}.
+{snmpOutPkts, {snmp_standard_mib, variable_func, [snmpOutPkts]}}.
+{snmpInBadVersions, {snmp_standard_mib, variable_func, [snmpInBadVersions]}}.
+{snmpInBadCommunityNames, {snmp_standard_mib, variable_func, [snmpInBadCommunityNames]}}.
+{snmpInBadCommunityUses, {snmp_standard_mib, variable_func, [snmpInBadCommunityUses]}}.
+{snmpInASNParseErrs, {snmp_standard_mib, variable_func, [snmpInASNParseErrs]}}.
+{snmpInTooBigs, {snmp_standard_mib, variable_func, [snmpInTooBigs]}}.
+{snmpInNoSuchNames, {snmp_standard_mib, variable_func, [snmpInNoSuchNames]}}.
+{snmpInBadValues, {snmp_standard_mib, variable_func, [snmpInBadValues]}}.
+{snmpInReadOnlys, {snmp_standard_mib, variable_func, [snmpInReadOnlys]}}.
+{snmpInGenErrs, {snmp_standard_mib, variable_func, [snmpInGenErrs]}}.
+{snmpInTotalReqVars, {snmp_standard_mib, variable_func, [snmpInTotalReqVars]}}.
+{snmpInTotalSetVars, {snmp_standard_mib, variable_func, [snmpInTotalSetVars]}}.
+{snmpInGetRequests, {snmp_standard_mib, variable_func, [snmpInGetRequests]}}.
+{snmpInGetNexts, {snmp_standard_mib, variable_func, [snmpInGetNexts]}}.
+{snmpInSetRequests, {snmp_standard_mib, variable_func, [snmpInSetRequests]}}.
+{snmpInGetResponses, {snmp_standard_mib, variable_func, [snmpInGetResponses]}}.
+{snmpInTraps, {snmp_standard_mib, variable_func, [snmpInTraps]}}.
+{snmpOutTooBigs, {snmp_standard_mib, variable_func, [snmpOutTooBigs]}}.
+{snmpOutNoSuchNames, {snmp_standard_mib, variable_func, [snmpOutNoSuchNames]}}.
+{snmpOutBadValues, {snmp_standard_mib, variable_func, [snmpOutBadValues]}}.
+{snmpOutGenErrs, {snmp_standard_mib, variable_func, [snmpOutGenErrs]}}.
+{snmpOutGetRequests, {snmp_standard_mib, variable_func, [snmpOutGetRequests]}}.
+{snmpOutGetNexts, {snmp_standard_mib, variable_func, [snmpOutGetNexts]}}.
+{snmpOutSetRequests, {snmp_standard_mib, variable_func, [snmpOutSetRequests]}}.
+{snmpOutGetResponses, {snmp_standard_mib, variable_func, [snmpOutGetResponses]}}.
+{snmpOutTraps, {snmp_standard_mib, variable_func, [snmpOutTraps]}}.
diff --git a/lib/snmp/mibs/STANDARD-MIB.mib b/lib/snmp/mibs/STANDARD-MIB.mib
new file mode 100644
index 0000000000..552b8a3e48
--- /dev/null
+++ b/lib/snmp/mibs/STANDARD-MIB.mib
@@ -0,0 +1,528 @@
+STANDARD-MIB DEFINITIONS ::= BEGIN
+
+ IMPORTS
+ Counter, TimeTicks
+ FROM RFC1155-SMI
+ OBJECT-TYPE
+ FROM RFC-1212
+ DisplayString, mib-2
+ FROM RFC1213-MIB
+ ;
+
+
+-- Standard Datatypes
+
+-- From SNMPv2 (rfc1903)
+TruthValue ::=
+-- Represents a boolean value
+ INTEGER { true(1), false(2) }
+
+-- From SNMPv2 (rfc1903)
+DateAndTime ::=
+-- DESCRIPTION
+-- "A date-time specification.
+--
+-- field octets contents range
+-- 1 1-2 year 0..65536
+-- 2 3 month 1..12
+-- 3 4 day 1..31
+-- 4 5 hour 0..23
+-- 5 6 minutes 0..59
+-- 6 7 seconds 0..60
+-- (use 60 for leap-second)
+-- 7 8 deci-seconds 0..9
+-- 8 9 direction from UTC '+' / '-'
+-- 9 10 hours from UTC 0..11
+-- 10 11 minutes from UTC 0..59
+--
+-- For example, Tuesday May 26, 1992 at 1:30:15 PM EDT would be
+-- displayed as:
+--
+-- 1992-5-26,13:30:15.0,-4:0
+--
+-- Note that if only local time is known, then timezone
+-- information (fields 8-10) is not present."
+ OCTET STRING (SIZE (8 | 11))
+
+-- From SNMPv2 (rfc1903)
+RowStatus ::=
+ INTEGER {
+ -- the following two values are states:
+ -- these values may be read or written
+ active(1),
+ notInService(2),
+
+ -- the following value is a state:
+ -- this value may be read, but not written
+ notReady(3),
+
+ -- the following three values are
+ -- actions: these values may be written,
+ -- but are never read
+ createAndGo(4),
+ createAndWait(5),
+ destroy(6)
+ }
+
+
+system OBJECT IDENTIFIER ::= { mib-2 1 }
+snmp OBJECT IDENTIFIER ::= { mib-2 11 }
+
+
+-- the System group
+
+-- Implementation of the System group is mandatory for all
+-- systems. If an agent is not configured to have a value
+-- for any of these variables, a string of length 0 is
+-- returned.
+
+sysDescr OBJECT-TYPE
+ SYNTAX DisplayString (SIZE (0..255))
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "A textual description of the entity. This value
+ should include the full name and version
+ identification of the system's hardware type,
+ software operating-system, and networking
+ software. It is mandatory that this only contain
+ printable ASCII characters."
+ ::= { system 1 }
+
+sysObjectID OBJECT-TYPE
+ SYNTAX OBJECT IDENTIFIER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The vendor's authoritative identification of the
+ network management subsystem contained in the
+ entity. This value is allocated within the SMI
+ enterprises subtree (1.3.6.1.4.1) and provides an
+ easy and unambiguous means for determining `what
+ kind of box' is being managed. For example, if
+ vendor `Flintstones, Inc.' was assigned the
+ subtree 1.3.6.1.4.1.4242, it could assign the
+ identifier 1.3.6.1.4.1.4242.1.1 to its `Fred
+ Router'."
+ ::= { system 2 }
+
+sysUpTime OBJECT-TYPE
+ SYNTAX TimeTicks
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The time (in hundredths of a second) since the
+ network management portion of the system was last
+ re-initialized."
+ ::= { system 3 }
+
+sysContact OBJECT-TYPE
+ SYNTAX DisplayString (SIZE (0..255))
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The textual identification of the contact person
+ for this managed node, together with information
+ on how to contact this person."
+ ::= { system 4 }
+
+sysName OBJECT-TYPE
+ SYNTAX DisplayString (SIZE (0..255))
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "An administratively-assigned name for this
+ managed node. By convention, this is the node's
+ fully-qualified domain name."
+ ::= { system 5 }
+
+sysLocation OBJECT-TYPE
+ SYNTAX DisplayString (SIZE (0..255))
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The physical location of this node (e.g.,
+ `telephone closet, 3rd floor')."
+ ::= { system 6 }
+
+sysServices OBJECT-TYPE
+ SYNTAX INTEGER (0..127)
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "A value which indicates the set of services that
+ this entity primarily offers.
+
+ The value is a sum. This sum initially takes the
+ value zero, Then, for each layer, L, in the range
+ 1 through 7, that this node performs transactions
+ for, 2 raised to (L - 1) is added to the sum. For
+ example, a node which performs primarily routing
+ functions would have a value of 4 (2^(3-1)). In
+ contrast, a node which is a host offering
+ application services would have a value of 72
+ (2^(4-1) + 2^(7-1)). Note that in the context of
+ the Internet suite of protocols, values should be
+ calculated accordingly:
+
+ layer functionality
+ 1 physical (e.g., repeaters)
+ 2 datalink/subnetwork (e.g., bridges)
+ 3 internet (e.g., IP gateways)
+ 4 end-to-end (e.g., IP hosts)
+ 7 applications (e.g., mail relays)
+
+ For systems including OSI protocols, layers 5 and
+ 6 may also be counted."
+ ::= { system 7 }
+
+
+ -- the SNMP group
+
+ -- Implementation of the SNMP group is mandatory for all
+ -- systems which support an SNMP protocol entity. Some of
+ -- the objects defined below will be zero-valued in those
+ -- SNMP implementations that are optimized to support only
+ -- those functions specific to either a management agent or
+ -- a management station. In particular, it should be
+ -- observed that the objects below refer to an SNMP entity,
+ -- and there may be several SNMP entities residing on a
+ -- managed node (e.g., if the node is hosting acting as
+ -- a management station).
+
+snmpInPkts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of Messages delivered to the
+ SNMP entity from the transport service."
+ ::= { snmp 1 }
+
+snmpOutPkts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Messages which were
+ passed from the SNMP protocol entity to the
+ transport service."
+ ::= { snmp 2 }
+
+snmpInBadVersions OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Messages which were
+ delivered to the SNMP protocol entity and were for
+ an unsupported SNMP version."
+ ::= { snmp 3 }
+
+snmpInBadCommunityNames OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Messages delivered to
+ the SNMP protocol entity which used a SNMP
+ community name not known to said entity."
+ ::= { snmp 4 }
+
+snmpInBadCommunityUses OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Messages delivered to
+ the SNMP protocol entity which represented an SNMP
+ operation which was not allowed by the SNMP
+ community named in the Message."
+ ::= { snmp 5 }
+
+snmpInASNParseErrs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of ASN.1 or BER errors
+ encountered by the SNMP protocol entity when
+ decoding received SNMP Messages."
+ ::= { snmp 6 }
+
+ -- { snmp 7 } is not used
+
+snmpInTooBigs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP PDUs which were
+ delivered to the SNMP protocol entity and for
+ which the value of the error-status field is
+ `tooBig'."
+ ::= { snmp 8 }
+
+snmpInNoSuchNames OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP PDUs which were
+ delivered to the SNMP protocol entity and for
+ which the value of the error-status field is
+ `noSuchName'."
+ ::= { snmp 9 }
+
+snmpInBadValues OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP PDUs which were
+ delivered to the SNMP protocol entity and for
+ which the value of the error-status field is
+ `badValue'."
+ ::= { snmp 10 }
+
+snmpInReadOnlys OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number valid SNMP PDUs which were
+ delivered to the SNMP protocol entity and for
+ which the value of the error-status field is
+ `readOnly'. It should be noted that it is a
+ protocol error to generate an SNMP PDU which
+ contains the value `readOnly' in the error-status
+ field, as such this object is provided as a means
+ of detecting incorrect implementations of the
+ SNMP."
+ ::= { snmp 11 }
+
+snmpInGenErrs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP PDUs which were
+ delivered to the SNMP protocol entity and for
+ which the value of the error-status field is
+ `genErr'."
+ ::= { snmp 12 }
+
+snmpInTotalReqVars OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of MIB objects which have been
+ retrieved successfully by the SNMP protocol entity
+ as the result of receiving valid SNMP Get-Request
+ and Get-Next PDUs."
+ ::= { snmp 13 }
+
+snmpInTotalSetVars OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of MIB objects which have been
+ altered successfully by the SNMP protocol entity
+ as the result of receiving valid SNMP Set-Request
+ PDUs."
+ ::= { snmp 14 }
+
+snmpInGetRequests OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Get-Request PDUs which
+ have been accepted and processed by the SNMP
+ protocol entity."
+ ::= { snmp 15 }
+
+snmpInGetNexts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Get-Next PDUs which have
+ been accepted and processed by the SNMP protocol
+ entity."
+ ::= { snmp 16 }
+
+snmpInSetRequests OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Set-Request PDUs which
+ have been accepted and processed by the SNMP
+ protocol entity."
+ ::= { snmp 17 }
+
+snmpInGetResponses OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Get-Response PDUs which
+ have been accepted and processed by the SNMP
+ protocol entity."
+ ::= { snmp 18 }
+
+snmpInTraps OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Trap PDUs which have
+ been accepted and processed by the SNMP protocol
+ entity."
+ ::= { snmp 19 }
+
+snmpOutTooBigs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP PDUs which were
+ generated by the SNMP protocol entity and for
+ which the value of the error-status field is
+ `tooBig.'"
+ ::= { snmp 20 }
+
+snmpOutNoSuchNames OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP PDUs which were
+ generated by the SNMP protocol entity and for
+ which the value of the error-status is
+ `noSuchName'."
+ ::= { snmp 21 }
+
+snmpOutBadValues OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP PDUs which were
+ generated by the SNMP protocol entity and for
+ which the value of the error-status field is
+ `badValue'."
+ ::= { snmp 22 }
+
+ -- { snmp 23 } is not used
+
+snmpOutGenErrs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP PDUs which were
+ generated by the SNMP protocol entity and for
+ which the value of the error-status field is
+ `genErr'."
+ ::= { snmp 24 }
+
+snmpOutGetRequests OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Get-Request PDUs which
+ have been generated by the SNMP protocol entity."
+ ::= { snmp 25 }
+
+snmpOutGetNexts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Get-Next PDUs which have
+ been generated by the SNMP protocol entity."
+ ::= { snmp 26 }
+
+snmpOutSetRequests OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Set-Request PDUs which
+ have been generated by the SNMP protocol entity."
+ ::= { snmp 27 }
+
+snmpOutGetResponses OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Get-Response PDUs which
+ have been generated by the SNMP protocol entity."
+ ::= { snmp 28 }
+
+snmpOutTraps OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Trap PDUs which have
+ been generated by the SNMP protocol entity."
+ ::= { snmp 29 }
+
+snmpEnableAuthenTraps OBJECT-TYPE
+ SYNTAX INTEGER { enabled(1), disabled(2) }
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "Indicates whether the SNMP agent process is
+ permitted to generate authentication-failure
+ traps. The value of this object overrides any
+ configuration information; as such, it provides a
+ means whereby all authentication-failure traps may
+ be disabled.
+
+ Note that it is strongly recommended that this
+ object be stored in non-volatile memory so that it
+ remains constant between re-initializations of the
+ network management system."
+ ::= { snmp 30 }
+
+coldStart TRAP-TYPE
+ ENTERPRISE snmp
+ DESCRIPTION
+ "A coldStart trap signifies that the sending
+ protocol entity is reinitializing itself such
+ that the agent's configuration or the rotocol
+ entity implementation may be altered."
+ ::= 0
+
+warmStart TRAP-TYPE
+ ENTERPRISE snmp
+ DESCRIPTION
+ "A warmStart trap signifies that the sending
+ protocol entity is reinitializing itself such
+ that neither the agent configuration nor the
+ protocol entity implementation is altered."
+ ::= 1
+
+authenticationFailure TRAP-TYPE
+ ENTERPRISE snmp
+ DESCRIPTION
+ "An authenticationFailure trap signifies that
+ the sending protocol entity is the addressee
+ of a protocol message that is not properly
+ authenticated. While implementations of the
+ SNMP must be capable of generating this trap,
+ they must also be capable of suppressing the
+ emission of such traps via an implementation-
+ specific mechanism."
+ ::= 4
+
+END
+
diff --git a/lib/snmp/mibs/prebuild.skip b/lib/snmp/mibs/prebuild.skip
new file mode 100644
index 0000000000..f3c7a7c5da
--- /dev/null
+++ b/lib/snmp/mibs/prebuild.skip
@@ -0,0 +1 @@
+Makefile
diff --git a/lib/snmp/mibs/v1/.gitignore b/lib/snmp/mibs/v1/.gitignore
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/lib/snmp/mibs/v1/.gitignore
diff --git a/lib/snmp/priv/conf/Makefile b/lib/snmp/priv/conf/Makefile
new file mode 100644
index 0000000000..341107ce30
--- /dev/null
+++ b/lib/snmp/priv/conf/Makefile
@@ -0,0 +1,35 @@
+#-*-makefile-*- ; force emacs to enter makefile-mode
+
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2004-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%
+
+include $(ERL_TOP)/make/target.mk
+include $(ERL_TOP)/make/$(TARGET)/otp.mk
+
+# ----------------------------------------------------
+# Common Macros
+# ----------------------------------------------------
+
+include subdirs.mk
+
+SPECIAL_TARGETS =
+
+# ----------------------------------------------------
+# Default Subdir Targets
+# ----------------------------------------------------
+include $(ERL_TOP)/make/otp_subdir.mk
+
diff --git a/lib/snmp/priv/conf/agent/Makefile b/lib/snmp/priv/conf/agent/Makefile
new file mode 100644
index 0000000000..ee3a915c2b
--- /dev/null
+++ b/lib/snmp/priv/conf/agent/Makefile
@@ -0,0 +1,63 @@
+#-*-makefile-*- ; force emacs to enter makefile-mode
+
+# %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%
+
+include $(ERL_TOP)/make/target.mk
+include $(ERL_TOP)/make/$(TARGET)/otp.mk
+
+# ----------------------------------------------------
+# Application version
+# ----------------------------------------------------
+include ../../../vsn.mk
+
+VSN = $(SNMP_VSN)
+
+# ----------------------------------------------------
+# Release directory specification
+# ----------------------------------------------------
+RELSYSDIR = $(RELEASE_PATH)/lib/snmp-$(VSN)
+
+# ----------------------------------------------------
+# Common macros
+# ----------------------------------------------------
+
+include files.mk
+
+
+# ----------------------------------------------------
+# Targets
+# ----------------------------------------------------
+
+debug opt:
+
+clean:
+
+docs:
+
+# ----------------------------------------------------
+# Release Target
+# ----------------------------------------------------
+include $(ERL_TOP)/make/otp_release_targets.mk
+
+release_spec: opt
+ $(INSTALL_DIR) $(RELSYSDIR)/priv/conf
+ $(INSTALL_DIR) $(RELSYSDIR)/priv/conf/agent
+ $(INSTALL_DATA) $(CONF_FILES) $(RELSYSDIR)/priv/conf/agent
+
+release_docs_spec:
+
diff --git a/lib/snmp/priv/conf/agent/agent.conf b/lib/snmp/priv/conf/agent/agent.conf
new file mode 100644
index 0000000000..582be65fdc
--- /dev/null
+++ b/lib/snmp/priv/conf/agent/agent.conf
@@ -0,0 +1,17 @@
+%% This file was generated by snmp_config (v1.1) 1996-5-29 15:38:48
+%% This files defines the Agent address info
+%% The data is inserted into the intAgent* variables defined
+%% in INTERNAL-MIB.
+%% Each row is a 2-tuple:
+%% {IntAgentVariable, Value}.
+%% For example
+%% {intAgentUDPPort, 4000}.
+%% The ip address for the agent is sent as id in traps.
+%% {intAgentIpAddress, [127,42,17,5]}.
+%% {intAgentMaxPacketSize, 484}.
+
+{intAgentUDPPort, 4000}.
+{intAgentIpAddress, [141,213,11,24]}.
+{snmpEngineID, "mbj's engine"}.
+{snmpEngineMaxMessageSize, 484}.
+
diff --git a/lib/snmp/priv/conf/agent/community.conf b/lib/snmp/priv/conf/agent/community.conf
new file mode 100644
index 0000000000..a7457191a4
--- /dev/null
+++ b/lib/snmp/priv/conf/agent/community.conf
@@ -0,0 +1,14 @@
+%% This file was generated by snmp_config (v3.0) 2001-04-04 14:29:04
+%% This files defines the community info which maps to VACM parameters.
+%% The data is inserted into the snmpCommunityTable defined
+%% in SNMP-COMMUNITY-MIB.
+%% Each row is a 5-tuple:
+%% {CommunityIndex, CommunityName, SecurityName, ContextName, TransportTag}.
+%% For example
+%% {1, "public", "initial", "", ""}.
+%% {2, "secret", "secret_name", "", "tag"}.
+%% {3, "bridge1", "initial", "bridge1", ""}.
+%%
+{"public", "public", "initial", "", ""}.
+{"all-rights", "all-rights", "all-rights", "", ""}.
+{"standard trap", "standard trap", "initial", "", ""}.
diff --git a/lib/snmp/priv/conf/agent/context.conf b/lib/snmp/priv/conf/agent/context.conf
new file mode 100644
index 0000000000..1dcba35643
--- /dev/null
+++ b/lib/snmp/priv/conf/agent/context.conf
@@ -0,0 +1,13 @@
+%% This file was generated by snmp_config (v3.0) 2001-04-04 14:29:04
+%% This files defines the contexts known to the agent.
+%% The data is inserted into the vacmContextTable defined
+%% in SNMP-VIEW-BASED-ACM-MIB.
+%% Each row is a string:
+%% ContextName.
+%%
+%% The empty string is the default context.
+%% For example
+%% "bridge1".
+%% "bridge2".
+%%
+"".
diff --git a/lib/snmp/priv/conf/agent/files.mk b/lib/snmp/priv/conf/agent/files.mk
new file mode 100644
index 0000000000..2f81515af9
--- /dev/null
+++ b/lib/snmp/priv/conf/agent/files.mk
@@ -0,0 +1,22 @@
+#-*-makefile-*- ; force emacs to enter makefile-mode
+
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2001-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%
+
+CONF_FILES = agent.conf community.conf context.conf \
+ notify.conf standard.conf target_addr.conf \
+ target_params.conf usm.conf vacm.conf
diff --git a/lib/snmp/priv/conf/agent/notify.conf b/lib/snmp/priv/conf/agent/notify.conf
new file mode 100644
index 0000000000..96155f5963
--- /dev/null
+++ b/lib/snmp/priv/conf/agent/notify.conf
@@ -0,0 +1,12 @@
+%% This file was generated by snmp_config (v3.0) 2001-04-04 14:29:04
+%% This files defines the notification parameters.
+%% The data is inserted into the snmpNotifyTable defined
+%% in SNMP-NOTIFICATION-MIB.
+%% The Name is used as CommunityString for v1 and v2c.
+%% Each row is a 3-tuple:
+%% {Name, Tag, Type}.
+%% For example
+%% {"standard trap", "std_trap", trap}.
+%% {"standard inform", "std_inform", inform}.
+%%
+{"standard trap", "std_trap", trap}.
diff --git a/lib/snmp/priv/conf/agent/standard.conf b/lib/snmp/priv/conf/agent/standard.conf
new file mode 100644
index 0000000000..c0070508e6
--- /dev/null
+++ b/lib/snmp/priv/conf/agent/standard.conf
@@ -0,0 +1,20 @@
+%% This file was generated by snmp_config (v1.1) 1996-5-29 15:38:48
+%% This files defines the STANDARD-MIB info.
+%% Each row is a 2-tuple:
+%% {StandardVariable, Value}.
+%% For example
+%% {sysDescr, "Erlang SNMPv1 agent"}.
+%% {sysObjectID, [1,2,3]}.
+%% {sysContact, "(mbj,eklas)@erlang.ericsson.se"}.
+%% {sysName, "test"}.
+%% {sysLocation, "erlang"}.
+%% {sysServices, 72}.
+%% {snmpEnableAuthenTraps, enabled}.
+%%
+{sysDescr, "Erlang SNMPv1 agent"}.
+{sysObjectID, [1,2,3]}.
+{sysContact, "(mbj,eklas)@erlang.ericsson.se"}.
+{sysLocation, "erlang"}.
+{sysServices, 72}.
+{snmpEnableAuthenTraps, enabled}.
+{sysName, "My own foo agent"}.
diff --git a/lib/snmp/priv/conf/agent/target_addr.conf b/lib/snmp/priv/conf/agent/target_addr.conf
new file mode 100644
index 0000000000..33a5d0d4c4
--- /dev/null
+++ b/lib/snmp/priv/conf/agent/target_addr.conf
@@ -0,0 +1,18 @@
+%% This file was generated by snmp_config (v3.0) 2001-04-04 14:29:04
+%% This files defines the target address parameters.
+%% The data is inserted into the snmpTargetAddrTable defined
+%% in SNMP-TARGET-MIB, and in the snmpTargeAddrExtTabke defined
+%% in SNMP-COMMUNITY-MIB.
+%% Each row is a 9-tuple:
+%% {Name, Ip, Udp, Timeout, RetryCount, TagList, ParamsName, EngineId,
+%% TMask, MaxMessageSize}.
+%% The EngineId value is only used if Inform-Requests are sent to this
+%% target. If Informs are not sent, this value is ignored, and can be
+%% e.g. an empty string. However, if Informs are sent, it is essential
+%% that the value of EngineId matches the value of the target's
+%% actual snmpEngineID.
+%% For example
+%% {"1.2.3.4 v1", [1,2,3,4], 162, 1500, 3, "std_inform", "otp_v2", "",
+%% [127,0,0,0], 2048}.
+%%
+{"141,213,11,24 v3", [141,213,11,24], 5000, 1500, 3, "std_trap", "target_v3", "", [], 2048}.
diff --git a/lib/snmp/priv/conf/agent/target_params.conf b/lib/snmp/priv/conf/agent/target_params.conf
new file mode 100644
index 0000000000..5ad3363f6d
--- /dev/null
+++ b/lib/snmp/priv/conf/agent/target_params.conf
@@ -0,0 +1,10 @@
+%% This file was generated by snmp_config (v3.0) 2001-04-04 14:29:04
+%% This files defines the target parameters.
+%% The data is inserted into the snmpTargetParamsTable defined
+%% in SNMP-TARGET-MIB.
+%% Each row is a 5-tuple:
+%% {Name, MPModel, SecurityModel, SecurityName, SecurityLevel}.
+%% For example
+%% {"target_v3", v3, usm, "", noAuthNoPriv}.
+%%
+{"target_v3", v3, usm, "initial", noAuthNoPriv}.
diff --git a/lib/snmp/priv/conf/agent/usm.conf b/lib/snmp/priv/conf/agent/usm.conf
new file mode 100644
index 0000000000..f379f47264
--- /dev/null
+++ b/lib/snmp/priv/conf/agent/usm.conf
@@ -0,0 +1,15 @@
+%% This file was generated by snmp_config (v3.0) 2001-04-04 14:29:04
+%% This files defines the security parameters for the user-based
+%% security model.
+%% The data is inserted into the usmUserTable defined
+%% in SNMP-USER-BASED-SM-MIB.
+%% Each row is a 14-tuple:
+%% {EngineID, UserName, SecName, Clone, AuthP, AuthKeyC, OwnAuthKeyC,
+%% PrivP, PrivKeyC, OwnPrivKeyC, Public, AuthKey, PrivKey}.
+%% For example
+%% {"agentEngine", "initial", "initial", zeroDotZero,
+%% usmNoAuthProtocol, "", "", usmNoPrivProtocol, "", "", "",
+%% "", ""}.
+%%
+
+{"mbj's engine", "initial", "initial", zeroDotZero, usmNoAuthProtocol, "", "", usmNoPrivProtocol, "", "", "", "", ""}.
diff --git a/lib/snmp/priv/conf/agent/vacm.conf b/lib/snmp/priv/conf/agent/vacm.conf
new file mode 100644
index 0000000000..31499ee811
--- /dev/null
+++ b/lib/snmp/priv/conf/agent/vacm.conf
@@ -0,0 +1,31 @@
+%% This file was generated by snmp_config (v3.0) 2001-04-04 14:29:04
+%% This files defines the Mib Views.
+%% The data is inserted into the vacm* tables defined
+%% in SNMP-VIEW-BASED-ACM-MIB.
+%% Each row is one of 3 tuples; one for each table in the MIB:
+%% {vacmSecurityToGroup, SecModel, SecName, GroupName}.
+%% {vacmAccess, GroupName, Prefix, SecModel, SecLevel, Match, RV, WV, NV}.
+%% {vacmViewTreeFamily, ViewIndex, ViewSubtree, ViewStatus, ViewMask}.
+%% For example
+%% {vacmSecurityToGroup, v2c, "initial", "initial"}.
+%% {vacmSecurityToGroup, usm, "initial", "initial"}.
+%% read/notify access to system
+%% {vacmAccess, "initial", "", any, noAuthNoPriv, exact,
+%% "system", "", "system"}.
+%% {vacmViewTreeFamily, "system", [1,3,6,1,2,1,1], included, null}.
+%% {vacmViewTreeFamily, "exmib", [1,3,6,1,3], included, null}. % for EX1-MIB
+%% {vacmViewTreeFamily, "internet", [1,3,6,1], included, null}.
+%%
+
+{vacmSecurityToGroup, usm, "initial", "initial"}.
+{vacmSecurityToGroup, usm, "all-rights", "all-rights"}.
+
+{vacmAccess, "initial", "", any, noAuthNoPriv, exact, "restricted", "", "restricted"}.
+{vacmAccess, "initial", "", usm, authNoPriv, exact, "internet", "internet", "internet"}.
+{vacmAccess, "initial", "", usm, authPriv, exact, "internet", "internet", "internet"}.
+
+{vacmAccess, "all-rights", "", any, noAuthNoPriv, exact, "internet", "internet", "internet"}.
+
+{vacmViewTreeFamily, "internet", [1,3,6,1], included, null}.
+{vacmViewTreeFamily, "restricted", [1,3,6,1], included, null}.
+
diff --git a/lib/snmp/priv/conf/manager/Makefile b/lib/snmp/priv/conf/manager/Makefile
new file mode 100644
index 0000000000..16355f0ff3
--- /dev/null
+++ b/lib/snmp/priv/conf/manager/Makefile
@@ -0,0 +1,63 @@
+#-*-makefile-*- ; force emacs to enter makefile-mode
+
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2004-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%
+
+include $(ERL_TOP)/make/target.mk
+include $(ERL_TOP)/make/$(TARGET)/otp.mk
+
+# ----------------------------------------------------
+# Application version
+# ----------------------------------------------------
+include ../../../vsn.mk
+
+VSN = $(SNMP_VSN)
+
+# ----------------------------------------------------
+# Release directory specification
+# ----------------------------------------------------
+RELSYSDIR = $(RELEASE_PATH)/lib/snmp-$(VSN)
+
+# ----------------------------------------------------
+# Common macros
+# ----------------------------------------------------
+
+include files.mk
+
+
+# ----------------------------------------------------
+# Targets
+# ----------------------------------------------------
+
+debug opt:
+
+clean:
+
+docs:
+
+# ----------------------------------------------------
+# Release Target
+# ----------------------------------------------------
+include $(ERL_TOP)/make/otp_release_targets.mk
+
+release_spec: opt
+ $(INSTALL_DIR) $(RELSYSDIR)/priv/conf
+ $(INSTALL_DIR) $(RELSYSDIR)/priv/conf/manager
+ $(INSTALL_DATA) $(CONF_FILES) $(RELSYSDIR)/priv/conf/manager
+
+release_docs_spec:
+
diff --git a/lib/snmp/priv/conf/manager/agents.conf b/lib/snmp/priv/conf/manager/agents.conf
new file mode 100644
index 0000000000..7f9b3d60ab
--- /dev/null
+++ b/lib/snmp/priv/conf/manager/agents.conf
@@ -0,0 +1,40 @@
+%% agents.conf
+%%
+%% Configuration for each agent the manager shall handle.
+%% (Relevant parts of the snmpTargetAddrTable and snmpTargetParamsTable)
+%%
+%% {UserId,
+%% TargetName, Comm, Ip, Port, EngineID, Timeout, MaxMessageSize,
+%% Version, SecModel, SecName, SecLevel}
+%%
+%% UserId -> User identity of "manager entity" responsible for this
+%% agent: term()
+%% TargetName -> string(), length > 0 (Name associated with the agent)
+%% Comm -> string(), length > 0 (Community string)
+%% Ip -> [integer()] (Host address as a list of integers)
+%% Port -> integer() > 0
+%% EngineID -> string()
+%% Timeout -> infinity (no retransmission) | integer() > 0 |
+%% incr_timer()
+%% (Can be overridden when sending a sync message)
+%% MaxMessageSize -> integer() >= 484
+%% Version -> v1 | v2 | v3
+%% SecModel -> any | v1 | v2c | usm
+%% SecName -> string()
+%% SecLevel -> noAuthNoPriv | authNoPriv | authPriv
+%%
+%% incr_timer() -> {wait_for(), factor(). incr(), retry()}
+%% wait_for() -> integer() (Initial timeout (milli seconds))
+%% factor() -> integer() (Factor to multiply with at timeout)
+%% incr() -> integer() (Milli seconds to add at timeout)
+%% retry() -> integer() (Number of retransmissions)
+
+%% Example:
+{user_id_1,
+ "targ-hobbes", "comm1", [192,168,0,100], 162, "hobbe's agent",
+ 1500, 484,
+ v1, any, "initial", noAuthNoPriv}.
+{"user_id_2",
+ "targ-calvin", "comm2", [192,168,0,101], 162, "calvin's agent",
+ {1500, 1, 0, 0}, 484,
+ v1, any, "initial", noAuthNoPriv}.
diff --git a/lib/snmp/priv/conf/manager/files.mk b/lib/snmp/priv/conf/manager/files.mk
new file mode 100644
index 0000000000..61dde77d93
--- /dev/null
+++ b/lib/snmp/priv/conf/manager/files.mk
@@ -0,0 +1,20 @@
+#-*-makefile-*- ; force emacs to enter makefile-mode
+
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2004-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%
+
+CONF_FILES = manager.conf agents.conf users.conf
diff --git a/lib/snmp/priv/conf/manager/manager.conf b/lib/snmp/priv/conf/manager/manager.conf
new file mode 100644
index 0000000000..624ad4310e
--- /dev/null
+++ b/lib/snmp/priv/conf/manager/manager.conf
@@ -0,0 +1,16 @@
+%% manager.conf
+%%
+%% General SNMP-related configuration parameters for the SNMP manager
+%%
+%% Default values:
+%% address local host
+%% port 5000
+%% engine_id "mgrEngine"
+%% max_message_size 484
+%%
+
+%% Examples:
+{address, [192,168,0,100]}.
+{port, 5000}.
+{engine_id, "mgrEngine"}.
+{max_message_size, 484}.
diff --git a/lib/snmp/priv/conf/manager/users.conf b/lib/snmp/priv/conf/manager/users.conf
new file mode 100644
index 0000000000..8f3abe74d2
--- /dev/null
+++ b/lib/snmp/priv/conf/manager/users.conf
@@ -0,0 +1,14 @@
+%% users.conf
+%%
+%% Configuration for each user the manager shall handle.
+%%
+%% {UserId, UserMod, UserData}
+%%
+%% UserId -> User identity of "manager entity" responsible for this
+%% agent: term()
+%% UserMod -> Module implementing the snmpm_user behaviour: atom()
+%% UserData -> Generic data passed on to the user when calling any
+%% of the callback functions: term()
+%%
+{user_id_1, snmpm_user_default, undefined}.
+{"user_id_2", snmpm_user_default, []}.
diff --git a/lib/snmp/priv/conf/manager/usm.conf b/lib/snmp/priv/conf/manager/usm.conf
new file mode 100644
index 0000000000..5eb78791ca
--- /dev/null
+++ b/lib/snmp/priv/conf/manager/usm.conf
@@ -0,0 +1,30 @@
+%% usm.conf
+%% The data corresponds to the relevant parts of the usmUserTable
+%% defined in SNMP-USER-BASED-SM-MIB.
+%%
+%% {EngineID, UserName, AuthP, AuthKey, PrivP, PrivKey}.
+%% {EngineID, UserName, SecName, AuthP, AuthKey, PrivP, PrivKey}.
+%%
+%% The first case is when we have the identity-function (SecName = UserName)!
+%%
+%% EngineID -> string()
+%% UserName -> string()
+%% SecName -> string()
+%% AuthP -> usmNoAuthProtocol | usmHMACSHAAuthProtocol |
+%% usmHMACMD5AuthProtocol
+%% AuthKey -> string() (The user's secret localized authentication key)
+%% length depends on AuthP:
+%% usmNoAuthProtocol - any
+%% usmHMACSHAAuthProtocol - 16
+%% usmHMACMD5AuthProtocol - 20
+%% PrivP -> usmNoPrivProtocol | usmDESPrivProtocol
+%% PrivKey -> string() (The user's secret localized encryption key)
+%% length depends on PrivP:
+%% usmNoPrivProtocol - any
+%% usmDESPrivProtocol - 16
+%%
+
+%% example
+{"manager engine", "initial", "initial",
+ usmNoAuthProtocol, "",
+ usmNoPrivProtocol, ""}.
diff --git a/lib/snmp/priv/conf/subdirs.mk b/lib/snmp/priv/conf/subdirs.mk
new file mode 100644
index 0000000000..b3e159b0e4
--- /dev/null
+++ b/lib/snmp/priv/conf/subdirs.mk
@@ -0,0 +1,21 @@
+#-*-makefile-*- ; force emacs to enter makefile-mode
+
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2004-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%
+
+SUB_DIRECTORIES = agent manager
+
diff --git a/lib/snmp/priv/mibs/.gitignore b/lib/snmp/priv/mibs/.gitignore
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/lib/snmp/priv/mibs/.gitignore
diff --git a/lib/snmp/src/Makefile b/lib/snmp/src/Makefile
new file mode 100644
index 0000000000..341107ce30
--- /dev/null
+++ b/lib/snmp/src/Makefile
@@ -0,0 +1,35 @@
+#-*-makefile-*- ; force emacs to enter makefile-mode
+
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2004-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%
+
+include $(ERL_TOP)/make/target.mk
+include $(ERL_TOP)/make/$(TARGET)/otp.mk
+
+# ----------------------------------------------------
+# Common Macros
+# ----------------------------------------------------
+
+include subdirs.mk
+
+SPECIAL_TARGETS =
+
+# ----------------------------------------------------
+# Default Subdir Targets
+# ----------------------------------------------------
+include $(ERL_TOP)/make/otp_subdir.mk
+
diff --git a/lib/snmp/src/agent/Makefile b/lib/snmp/src/agent/Makefile
new file mode 100644
index 0000000000..a67fe4d17c
--- /dev/null
+++ b/lib/snmp/src/agent/Makefile
@@ -0,0 +1,142 @@
+#-*-makefile-*- ; force emacs to enter makefile-mode
+
+# %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%
+
+include $(ERL_TOP)/make/target.mk
+
+EBIN = ../../ebin
+
+include $(ERL_TOP)/make/$(TARGET)/otp.mk
+
+# ----------------------------------------------------
+# Application version
+# ----------------------------------------------------
+include ../../vsn.mk
+
+VSN = $(SNMP_VSN)
+
+# ----------------------------------------------------
+# Release directory specification
+# ----------------------------------------------------
+RELSYSDIR = $(RELEASE_PATH)/lib/snmp-$(VSN)
+
+
+# ----------------------------------------------------
+# Target Specs
+# ----------------------------------------------------
+
+include modules.mk
+
+ERL_FILES = $(MODULES:%=%.erl)
+
+HRL_FILES = $(INTERNAL_HRL_FILES:%=%.hrl)
+
+TARGET_FILES = $(MODULES:%=$(EBIN)/%.$(EMULATOR))
+
+
+# ----------------------------------------------------
+# SNMP FLAGS
+# ----------------------------------------------------
+ifeq ($(SNMP_DEFAULT_VERBOSITY),)
+ SNMP_FLAGS = -Ddefault_verbosity=silence
+else
+ SNMP_FLAGS = -Ddefault_verbosity=$(SNMP_DEFAULT_VERBOSITY)
+endif
+
+# ifeq ($(SNMP_DEBUG),)
+# SNMP_DEBUG = d
+# endif
+
+ifeq ($(SNMP_DEBUG),d)
+ SNMP_FLAGS += -Dsnmp_debug
+endif
+
+ifeq ($(SNMP_QC),true)
+ SNMP_FLAGS += -Dsnmp_qc
+endif
+
+ifeq ($(SNMP_EXT_VERBOSITY),true)
+ SNMP_FLAGS += -Dsnmp_extended_verbosity
+endif
+
+
+# ----------------------------------------------------
+# FLAGS
+# ----------------------------------------------------
+ERL_COMPILE_FLAGS += -pa $(ERL_TOP)/lib/snmp/ebin
+
+ifeq ($(WARN_UNUSED_VARS),true)
+ERL_COMPILE_FLAGS += +warn_unused_vars
+endif
+
+ERL_COMPILE_FLAGS += -I../../include \
+ -I../misc \
+ -Dversion=\"$(VSN)$(PRE_VSN)\" \
+ +'{parse_transform,sys_pre_attributes}' \
+ +'{attribute,insert,app_vsn,$(APP_VSN)}' \
+ -I$(ERL_TOP)/lib/stdlib \
+ $(SNMP_FLAGS)
+
+
+# ----------------------------------------------------
+# Targets
+# ----------------------------------------------------
+
+debug:
+ @$(MAKE) TYPE=debug opt
+
+opt: $(TARGET_FILES)
+
+
+clean:
+ rm -f $(TARGET_FILES)
+ rm -f core *~
+
+docs:
+
+info:
+ @echo "SNMP_FLAGS: $(SNMP_FLAGS)"
+ @echo "ERL_COMPILE_FLAGS: $(ERL_COMPILE_FLAGS)"
+ @echo ""
+ @echo "TARGET_FILES: $(TARGET_FILES)"
+ @echo ""
+
+
+# ----------------------------------------------------
+# Special Build Targets
+# ----------------------------------------------------
+
+
+# ----------------------------------------------------
+# Release Target
+# ----------------------------------------------------
+include $(ERL_TOP)/make/otp_release_targets.mk
+
+release_spec: opt
+ $(INSTALL_DIR) $(RELSYSDIR)/src
+ $(INSTALL_DIR) $(RELSYSDIR)/src/agent
+ $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) $(RELSYSDIR)/src/agent
+ $(INSTALL_DIR) $(RELSYSDIR)/ebin
+ $(INSTALL_DATA) $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) \
+ $(RELSYSDIR)/ebin
+# $(INSTALL_DIR) $(RELSYSDIR)/include
+# $(INSTALL_DATA) $(EXT_HRL_FILES) $(RELSYSDIR)/include
+
+release_docs_spec:
+
+include depend.mk
diff --git a/lib/snmp/src/agent/depend.mk b/lib/snmp/src/agent/depend.mk
new file mode 100644
index 0000000000..bc39e1fa35
--- /dev/null
+++ b/lib/snmp/src/agent/depend.mk
@@ -0,0 +1,249 @@
+#-*-makefile-*- ; force emacs to enter makefile-mode
+
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2004-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%
+
+$(EBIN)/snmpa_authentication_service.$(EMULATOR): \
+ snmpa_authentication_service.erl
+
+$(EBIN)/snmpa_error_report.$(EMULATOR): \
+ snmpa_error_report.erl
+
+$(EBIN)/snmpa_network_interface.$(EMULATOR): \
+ snmpa_network_interface.erl
+
+$(EBIN)/snmpa_network_interface_filter.$(EMULATOR): \
+ snmpa_network_interface_filter.erl
+
+$(EBIN)/snmpa_notification_filter.$(EMULATOR): \
+ snmpa_notification_filter.erl
+
+$(EBIN)/snmpa_notification_delivery_info_receiver.$(EMULATOR): \
+ snmpa_notification_delivery_info_receiver.erl
+
+$(EBIN)/snmpa_set_mechanism.$(EMULATOR): \
+ snmpa_set_mechanism.erl
+
+$(EBIN)/snmpa.$(EMULATOR): \
+ snmpa.erl
+
+$(EBIN)/snmpa_acm.$(EMULATOR): \
+ snmpa_authentication_service.erl \
+ snmpa_acm.erl \
+ ../misc/snmp_verbosity.hrl \
+ ../../include/snmp_types.hrl \
+ ../../include/STANDARD-MIB.hrl \
+ ../../include/SNMP-FRAMEWORK-MIB.hrl \
+ ../../include/SNMPv2-TM.hrl
+
+$(EBIN)/snmpa_agent.$(EMULATOR): \
+ snmpa_agent.erl \
+ ../misc/snmp_debug.hrl \
+ ../misc/snmp_verbosity.hrl \
+ ../../include/snmp_types.hrl
+
+$(EBIN)/snmpa_agent_sup.$(EMULATOR): \
+ snmpa_agent_sup.erl \
+ ../misc/snmp_debug.hrl
+
+$(EBIN)/snmpa_app.$(EMULATOR): \
+ snmpa_app.erl \
+ ../misc/snmp_debug.hrl
+
+$(EBIN)/snmpa_error.$(EMULATOR): \
+ snmpa_error_report.erl \
+ snmpa_error.erl
+
+$(EBIN)/snmpa_error_io.$(EMULATOR): \
+ snmpa_error_report.erl \
+ snmpa_error_io.erl
+
+$(EBIN)/snmpa_error_logger.$(EMULATOR): \
+ snmpa_error_report.erl \
+ snmpa_error_logger.erl
+
+$(EBIN)/snmpa_general_db.$(EMULATOR): \
+ snmpa_general_db.erl \
+ ../misc/snmp_verbosity.hrl
+
+$(EBIN)/snmpa_local_db.$(EMULATOR): \
+ snmpa_local_db.erl \
+ ../misc/snmp_debug.hrl \
+ ../misc/snmp_verbosity.hrl \
+ ../../include/snmp_types.hrl \
+ ../../include/STANDARD-MIB.hrl
+
+$(EBIN)/snmpa_mib.$(EMULATOR): \
+ snmpa_mib.erl \
+ ../misc/snmp_debug.hrl \
+ ../misc/snmp_verbosity.hrl \
+ ../../include/snmp_types.hrl
+
+$(EBIN)/snmpa_mib_data.$(EMULATOR): \
+ snmpa_mib_data.erl \
+ ../misc/snmp_debug.hrl \
+ ../misc/snmp_verbosity.hrl \
+ ../../include/snmp_types.hrl
+
+$(EBIN)/snmpa_mib_lib.$(EMULATOR): \
+ snmpa_mib_lib.erl \
+ ../misc/snmp_verbosity.hrl \
+ ../../include/snmp_types.hrl
+
+$(EBIN)/snmpa_misc_sup.$(EMULATOR): \
+ snmpa_misc_sup.erl \
+ ../misc/snmp_debug.hrl
+
+$(EBIN)/snmpa_mpd.$(EMULATOR): \
+ snmpa_mpd.erl \
+ ../misc/snmp_verbosity.hrl \
+ ../../include/snmp_types.hrl \
+ ../../include/SNMP-MPD-MIB.hrl \
+ ../../include/SNMPv2-TM.hrl
+
+$(EBIN)/snmpa_net_if.$(EMULATOR): \
+ snmpa_net_if.erl \
+ ../misc/snmp_debug.hrl \
+ ../misc/snmp_verbosity.hrl \
+ ../../include/snmp_types.hrl
+
+$(EBIN)/snmpa_net_if_filter.$(EMULATOR): \
+ snmpa_net_if_filter.erl
+
+$(EBIN)/snmpa_set.$(EMULATOR): \
+ snmpa_set_mechanism.erl \
+ snmpa_set.erl \
+ ../misc/snmp_verbosity.hrl
+
+$(EBIN)/snmpa_set_lib.$(EMULATOR): \
+ snmpa_set_lib.erl \
+ ../misc/snmp_verbosity.hrl \
+ ../../include/snmp_types.hrl
+
+$(EBIN)/snmpa_supervisor.$(EMULATOR): \
+ snmpa_supervisor.erl \
+ ../misc/snmp_debug.hrl \
+ ../misc/snmp_verbosity.hrl
+
+$(EBIN)/snmpa_svbl.$(EMULATOR): \
+ snmpa_svbl.erl \
+ ../../include/snmp_types.hrl
+
+$(EBIN)/snmpa_symbolic_store.$(EMULATOR): \
+ snmpa_symbolic_store.erl \
+ ../misc/snmp_debug.hrl \
+ ../misc/snmp_verbosity.hrl \
+ ../../include/snmp_types.hrl
+
+$(EBIN)/snmpa_target_cache.$(EMULATOR): \
+ snmpa_target_cache.erl \
+ ../misc/snmp_verbosity.hrl \
+ ../misc/snmp_debug.hrl \
+ snmpa_internal.hrl \
+ ../app/snmp_internal.hrl
+
+$(EBIN)/snmpa_trap.$(EMULATOR): \
+ snmpa_trap.erl \
+ ../misc/snmp_verbosity.hrl \
+ ../../include/snmp_types.hrl \
+ ../../include/SNMPv2-MIB.hrl \
+ ../../include/SNMP-FRAMEWORK-MIB.hrl
+
+$(EBIN)/snmpa_usm.$(EMULATOR): \
+ snmpa_usm.erl \
+ ../misc/snmp_verbosity.hrl \
+ ../../include/snmp_types.hrl \
+ ../../include/SNMP-USER-BASED-SM-MIB.hrl \
+ ../../include/SNMPv2-TC.hrl
+
+$(EBIN)/snmpa_vacm.$(EMULATOR): \
+ snmpa_vacm.erl \
+ snmpa_vacm.hrl \
+ ../misc/snmp_verbosity.hrl \
+ ../../include/snmp_types.hrl \
+ ../../include/SNMP-VIEW-BASED-ACM-MIB.hrl \
+ ../../include/SNMPv2-TC.hrl \
+ ../../include/SNMP-FRAMEWORK-MIB.hrl
+
+$(EBIN)/snmp_community_mib.$(EMULATOR): \
+ snmp_community_mib.erl \
+ ../misc/snmp_verbosity.hrl \
+ ../../include/SNMP-COMMUNITY-MIB.hrl \
+ ../../include/SNMP-TARGET-MIB.hrl \
+ ../../include/SNMPv2-TC.hrl
+
+$(EBIN)/snmp_framework_mib.$(EMULATOR): \
+ snmp_framework_mib.erl \
+ ../misc/snmp_verbosity.hrl \
+ ../../include/snmp_types.hrl \
+ ../../include/STANDARD-MIB.hrl
+
+$(EBIN)/snmp_generic.$(EMULATOR): \
+ snmp_generic.erl \
+ ../misc/snmp_verbosity.hrl \
+ ../../include/snmp_types.hrl \
+ ../../include/STANDARD-MIB.hrl
+
+$(EBIN)/snmp_generic_mnesia.$(EMULATOR): \
+ snmp_generic_mnesia.erl \
+ ../../include/snmp_types.hrl \
+ ../../include/STANDARD-MIB.hrl
+
+$(EBIN)/snmp_index.$(EMULATOR): \
+ snmp_index.erl
+
+$(EBIN)/snmp_notification_mib.$(EMULATOR): \
+ snmp_notification_mib.erl \
+ ../misc/snmp_verbosity.hrl \
+ ../../include/snmp_tables.hrl \
+ ../../include/SNMP-NOTIFICATION-MIB.hrl \
+ ../../include/SNMPv2-TC.hrl
+
+$(EBIN)/snmp_shadow_table.$(EMULATOR): \
+ snmp_shadow_table.erl
+
+$(EBIN)/snmp_standard_mib.$(EMULATOR): \
+ snmp_standard_mib.erl \
+ ../misc/snmp_verbosity.hrl \
+ ../../include/snmp_types.hrl \
+ ../../include/STANDARD-MIB.hrl
+
+$(EBIN)/snmp_target_mib.$(EMULATOR): \
+ snmp_target_mib.erl \
+ ../misc/snmp_verbosity.hrl \
+ ../../include/snmp_types.hrl \
+ ../../include/snmp_tables.hrl \
+ ../../include/SNMP-TARGET-MIB.hrl \
+ ../../include/SNMPv2-TC.hrl \
+ ../../include/SNMPv2-TM.hrl
+
+$(EBIN)/snmp_user_based_sm_mib.$(EMULATOR): \
+ snmp_user_based_sm_mib.erl \
+ ../misc/snmp_verbosity.hrl \
+ ../../include/snmp_types.hrl \
+ ../../include/SNMP-USER-BASED-SM-MIB.hrl \
+ ../../include/SNMPv2-TC.hrl
+
+$(EBIN)/snmp_view_based_acm_mib.$(EMULATOR): \
+ snmp_view_based_acm_mib.erl \
+ snmpa_vacm.hrl \
+ ../misc/snmp_verbosity.hrl \
+ ../../include/snmp_types.hrl \
+ ../../include/SNMP-VIEW-BASED-ACM-MIB.hrl \
+ ../../include/SNMPv2-TC.hrl
+
+
diff --git a/lib/snmp/src/agent/modules.mk b/lib/snmp/src/agent/modules.mk
new file mode 100644
index 0000000000..33ab41b434
--- /dev/null
+++ b/lib/snmp/src/agent/modules.mk
@@ -0,0 +1,78 @@
+#-*-makefile-*- ; force emacs to enter makefile-mode
+
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2004-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%
+
+BEHAVIOUR_MODULES = \
+ snmpa_authentication_service \
+ snmpa_discovery_handler \
+ snmpa_error_report \
+ snmpa_network_interface \
+ snmpa_network_interface_filter \
+ snmpa_notification_delivery_info_receiver \
+ snmpa_notification_filter \
+ snmpa_set_mechanism
+
+MODULES = \
+ $(BEHAVIOUR_MODULES) \
+ snmpa \
+ snmpa_acm \
+ snmpa_agent \
+ snmpa_agent_sup \
+ snmpa_app \
+ snmpa_conf \
+ snmpa_discovery_handler_default \
+ snmpa_error \
+ snmpa_error_io \
+ snmpa_error_logger \
+ snmpa_general_db \
+ snmpa_local_db \
+ snmpa_mib \
+ snmpa_mib_data \
+ snmpa_mib_lib \
+ snmpa_misc_sup \
+ snmpa_mpd \
+ snmpa_net_if \
+ snmpa_net_if_filter \
+ snmpa_set \
+ snmpa_set_lib \
+ snmpa_supervisor \
+ snmpa_svbl \
+ snmpa_symbolic_store \
+ snmpa_target_cache \
+ snmpa_trap \
+ snmpa_usm \
+ snmpa_vacm \
+ snmp_community_mib \
+ snmp_framework_mib \
+ snmp_generic \
+ snmp_generic_mnesia \
+ snmp_index \
+ snmp_notification_mib \
+ snmp_shadow_table \
+ snmp_standard_mib \
+ snmp_target_mib \
+ snmp_user_based_sm_mib \
+ snmp_view_based_acm_mib
+
+
+INTERNAL_HRL_FILES = \
+ snmpa_vacm \
+ snmpa_atl \
+ snmpa_internal
+
+EXT_HRL_FILES =
diff --git a/lib/snmp/src/agent/snmp_community_mib.erl b/lib/snmp/src/agent/snmp_community_mib.erl
new file mode 100644
index 0000000000..a2ee7bf0c9
--- /dev/null
+++ b/lib/snmp/src/agent/snmp_community_mib.erl
@@ -0,0 +1,590 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1999-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%
+%%
+-module(snmp_community_mib).
+
+-export([configure/1, reconfigure/1,
+ snmpCommunityTable/1, snmpCommunityTable/3,
+ snmpTargetAddrExtTable/3,
+ community2vacm/2, vacm2community/2,
+ get_target_addr_ext_mms/2]).
+-export([add_community/5, delete_community/1]).
+-export([check_community/1]).
+
+-include("SNMP-COMMUNITY-MIB.hrl").
+-include("SNMP-TARGET-MIB.hrl").
+-include("SNMPv2-TC.hrl").
+-include("snmp_types.hrl").
+
+-define(VMODULE,"COMMUNITY-MIB").
+-include("snmp_verbosity.hrl").
+
+-ifndef(default_verbosity).
+-define(default_verbosity,silence).
+-endif.
+
+
+%%%-----------------------------------------------------------------
+%%% Implements the instrumentation functions and additional
+%%% functions for the SNMP-COMMUNITY-MIB.
+%%% This MIB contains objects that makes it possible to use VACM
+%%% with SNMPv1 and SNMPv2c.
+%%%-----------------------------------------------------------------
+%%-----------------------------------------------------------------
+%% Func: configure/1
+%% Args: Dir is the directory where the configuration files are found.
+%% Purpose: If the tables doesn't exist, this function reads
+%% the config-files for the community mib tables, and
+%% inserts the data. This means that the data in the tables
+%% survive a reboot. However, the StorageType column is
+%% checked for each row. If volatile, the row is deleted.
+%% Returns: ok
+%% Fails: exit(configuration_error)
+%%-----------------------------------------------------------------
+configure(Dir) ->
+ set_sname(),
+ case db(snmpCommunityTable) of
+ {_, mnesia} ->
+ ?vlog("community table in mnesia: cleanup",[]),
+ gc_tabs();
+ TabDb ->
+ case snmpa_local_db:table_exists(TabDb) of
+ true ->
+ ?vlog("community table exist: cleanup",[]),
+ gc_tabs();
+ false ->
+ ?vlog("community table does not exist: reconfigure",[]),
+ reconfigure(Dir)
+ end
+ end.
+
+%%-----------------------------------------------------------------
+%% Func: reconfigure/1
+%% Args: Dir is the directory where the configuration files are found.
+%% Purpose: Reads the config-files for the community mib tables, and
+%% inserts the data. Makes sure that all old data in
+%% the tables are deleted, and the new data inserted.
+%% This function makes sure that all (and only)
+%% config-file-data are in the tables.
+%% Returns: ok
+%% Fails: exit(configuration_error)
+%%-----------------------------------------------------------------
+reconfigure(Dir) ->
+ set_sname(),
+ case (catch do_reconfigure(Dir)) of
+ ok ->
+ ok;
+ {error, Reason} ->
+ ?vinfo("reconfigure error: ~p", [Reason]),
+ config_err("reconfigure failed: ~p", [Reason]),
+ exit(configuration_error);
+ Error ->
+ ?vinfo("reconfigure failed: ~p", [Error]),
+ config_err("reconfigure failed: ~p", [Error]),
+ exit(configuration_error)
+ end.
+
+do_reconfigure(Dir) ->
+ ?vdebug("read community config files",[]),
+ Comms = read_community_config_files(Dir),
+ ?vdebug("initiate tables",[]),
+ init_tabs(Comms),
+ ok.
+
+init_tabs(Comms) ->
+ ?vdebug("create community table",[]),
+ snmpa_local_db:table_delete(db(snmpCommunityTable)),
+ snmpa_local_db:table_create(db(snmpCommunityTable)),
+ ?vdebug("invalidate cache",[]),
+ invalidate_cache(),
+ ?vdebug("initiate community table",[]),
+ init_comm_table(Comms).
+
+
+read_community_config_files(Dir) ->
+ ?vdebug("read community config file",[]),
+ Gen = fun(_) -> ok end,
+ Filter = fun(Comms) -> Comms end,
+ Check = fun(Entry) -> check_community(Entry) end,
+ [Comms] =
+ snmp_conf:read_files(Dir, [{Gen, Filter, Check, "community.conf"}]),
+ Comms.
+
+check_community({Index, CommunityName, SecName, CtxName, TransportTag}) ->
+ snmp_conf:check_string(Index,{gt,0}),
+ snmp_conf:check_string(CommunityName),
+ snmp_conf:check_string(SecName),
+ snmp_conf:check_string(CtxName),
+ snmp_conf:check_string(TransportTag),
+ EngineID = get_engine_id(),
+ Comm = {Index, CommunityName, SecName, EngineID, CtxName, TransportTag,
+ ?'StorageType_nonVolatile', ?'RowStatus_active'},
+ {ok, Comm};
+check_community(X) ->
+ error({invalid_community, X}).
+
+%% This is for the case when check_community is called from the
+%% snmp_config module (to generate community config file) and
+%% the agent is not started. The actual return value is not
+%% checked, as long as it is '{ok, _}'.
+get_engine_id() ->
+ case (catch snmp_framework_mib:get_engine_id()) of
+ {'EXIT', _} ->
+ "agentEngine";
+ EngineID ->
+ EngineID
+ end.
+
+init_comm_table([Row | T]) ->
+ ?vtrace("init_comm_table -> entry with"
+ "~n Row: ~p", [Row]),
+ Key = element(1, Row),
+ snmpa_local_db:table_create_row(db(snmpCommunityTable), Key, Row),
+ update_cache(Key),
+ init_comm_table(T);
+init_comm_table([]) ->
+ ?vtrace("init_comm_table -> entry when done", []),
+ true.
+
+table_cre_row(Tab, Key, Row) ->
+ snmpa_mib_lib:table_cre_row(db(Tab), Key, Row).
+
+table_del_row(Tab, Key) ->
+ snmpa_mib_lib:table_del_row(db(Tab), Key).
+
+
+%% FIXME: does not work with mnesia
+add_community(Idx, CommName, SecName, CtxName, TransportTag) ->
+ Community = {Idx, CommName, SecName, CtxName, TransportTag},
+ case (catch check_community(Community)) of
+ {ok, Row} ->
+ Key = element(1, Row),
+ case table_cre_row(snmpCommunityTable, Key, Row) of
+ true ->
+ update_cache(Key),
+ {ok, Key};
+ false ->
+ {error, create_failed}
+ end;
+ {error, Reason} ->
+ {error, Reason};
+ Error ->
+ {error, Error}
+ end.
+
+%% FIXME: does not work with mnesia
+delete_community(Key) ->
+ invalidate_cache(Key),
+ case table_del_row(snmpCommunityTable, Key) of
+ true ->
+ ok;
+ false ->
+ {error, delete_failed}
+ end.
+
+
+gc_tabs() ->
+ DB = db(snmpCommunityTable),
+ STC = stc(snmpCommunityTable),
+ FOI = foi(snmpCommunityTable),
+ IR = fun(RowIndex) -> invalidate_cache(RowIndex) end,
+ UR = fun(RowIndex) -> update_cache(RowIndex) end,
+ snmpa_mib_lib:gc_tab(DB, STC, FOI, IR, UR),
+ ok.
+
+
+%%-----------------------------------------------------------------
+%% API functions
+%%-----------------------------------------------------------------
+%%-----------------------------------------------------------------
+%% We keep two caches for mapping;
+%% one that maps CommunityName to CommunityIndex, and
+%% one that maps
+%% {SecName, ContextEngineId, ContextName} to {CommunityName, Tag}
+%% Name -> Index instead of Name -> Vacm allows us to save a
+%% few bytes of memory, although it introduces an extra level of
+%% indirection.
+%%-----------------------------------------------------------------
+community2vacm(Community, Addr) ->
+ Idxs = ets:lookup(snmp_community_cache, Community),
+ loop_c2v_rows(lists:keysort(2, Idxs), Addr).
+
+loop_c2v_rows([{_, CommunityIndex} | T], Addr) ->
+ ?vtrace("loop_c2v_rows -> entry with"
+ "~n CommunityIndex: ~p", [CommunityIndex]),
+ case get_row(CommunityIndex) of
+ {_Community, VacmParams, Tag} ->
+ {TDomain, TAddr} = Addr,
+ case snmp_target_mib:is_valid_tag(Tag, TDomain, TAddr) of
+ true ->
+ ?vdebug("loop_c2v_rows -> "
+ "~p valid tag for community index ~p",
+ [Tag, CommunityIndex]),
+ VacmParams;
+ false ->
+ ?vtrace("loop_c2v_rows -> "
+ "~p not valid tag community index ~p",
+ [Tag, CommunityIndex]),
+ loop_c2v_rows(T, Addr)
+ end;
+ undefined ->
+ loop_c2v_rows(T, Addr)
+ end;
+loop_c2v_rows([], _Addr) ->
+ undefined.
+
+
+%%-----------------------------------------------------------------
+%% Func: vacm2community(Vacm, {TDomain, TAddr}) ->
+%% {ok, Community} | undefined
+%% Types: Vacm = {SecName, ContextEngineId, ContextName}
+%% Purpose: Follows the steps in RFC 2576 section
+%% 5.2.3 in order to find a community string to be used
+%% in a notification.
+%%-----------------------------------------------------------------
+vacm2community(Vacm, Addr) ->
+ Names = ets:lookup(snmp_community_cache, Vacm),
+ loop_v2c_rows(lists:keysort(2, Names), Addr).
+
+loop_v2c_rows([{_, {CommunityName, Tag}} | T], Addr) ->
+ ?vtrace("loop_v2c_rows -> entry with"
+ "~n CommunityName: ~p"
+ "~n Tag: ~p", [CommunityName, Tag]),
+ {TDomain, TAddr} = Addr,
+ case snmp_target_mib:is_valid_tag(Tag, TDomain, TAddr) of
+ true ->
+ ?vdebug("loop_v2c_rows -> "
+ "~p valid tag for community name ~p",
+ [Tag, CommunityName]),
+ {ok, CommunityName};
+ false ->
+ loop_v2c_rows(T, Addr)
+ end;
+loop_v2c_rows([], _Addr) ->
+ undefined.
+
+
+
+get_row(RowIndex) ->
+ case snmp_generic:table_get_row(db(snmpCommunityTable), RowIndex,
+ foi(snmpCommunityTable)) of
+ {_, CommunityName, SecName, ContextEngineId, ContextName,
+ TransportTag, _StorageType, ?'RowStatus_active'} ->
+ {CommunityName, {SecName, ContextEngineId, ContextName},
+ TransportTag};
+ _ ->
+ undefined
+ end.
+
+invalidate_cache(RowIndex) ->
+ case get_row(RowIndex) of
+ {CommunityName, VacmParams, TransportTag} ->
+ ets:match_delete(snmp_community_cache,
+ {CommunityName, RowIndex}),
+ ets:match_delete(snmp_community_cache,
+ {VacmParams, {CommunityName, TransportTag}});
+ undefined ->
+ ok
+ end.
+
+update_cache(RowIndex) ->
+ case get_row(RowIndex) of
+ {CommunityName, VacmParams, TransportTag} ->
+ ets:insert(snmp_community_cache,
+ {CommunityName, RowIndex}), % CommunityIndex
+ ets:insert(snmp_community_cache,
+ {VacmParams, {CommunityName, TransportTag}});
+ undefined ->
+ ok
+ end.
+
+invalidate_cache() ->
+ ets:match_delete(snmp_community_cache, {'_', '_'}).
+
+
+get_target_addr_ext_mms(TDomain, TAddress) ->
+ get_target_addr_ext_mms(TDomain, TAddress, []).
+get_target_addr_ext_mms(TDomain, TAddress, Key) ->
+ case snmp_target_mib:table_next(snmpTargetAddrTable, Key) of
+ endOfTable ->
+ false;
+ NextKey ->
+ case snmp_target_mib:get(
+ snmpTargetAddrTable, NextKey, [?snmpTargetAddrTDomain,
+ ?snmpTargetAddrTAddress,
+ 12]) of
+ [{value, TDomain}, {value, TAddress}, {value, MMS}] ->
+ {ok, MMS};
+ _ ->
+ get_target_addr_ext_mms(TDomain, TAddress, NextKey)
+ end
+ end.
+%%-----------------------------------------------------------------
+%% Instrumentation Functions
+%%-----------------------------------------------------------------
+%% Op = print - Used for debugging purposes
+snmpCommunityTable(print) ->
+ Table = snmpCommunityTable,
+ DB = db(Table),
+ FOI = foi(Table),
+ PrintRow =
+ fun(Prefix, Row) ->
+ lists:flatten(
+ io_lib:format("~sIndex: ~p"
+ "~n~sName: ~p"
+ "~n~sSecurityName: ~p"
+ "~n~sContextEngineID: ~p"
+ "~n~sContextName: ~p"
+ "~n~sTransportTag: ~p"
+ "~n~sStorageType: ~p (~w)"
+ "~n~sStatus: ~p (~w)",
+ [Prefix, element(?snmpCommunityIndex, Row),
+ Prefix, element(?snmpCommunityName, Row),
+ Prefix, element(?snmpCommunitySecurityName, Row),
+ Prefix, element(?snmpCommunityContextEngineID, Row),
+ Prefix, element(?snmpCommunityContextName, Row),
+ Prefix, element(?snmpCommunityTransportTag, Row),
+ Prefix, element(?snmpCommunityStorageType, Row),
+ case element(?snmpCommunityStorageType, Row) of
+ ?'snmpCommunityStorageType_readOnly' -> readOnly;
+ ?'snmpCommunityStorageType_permanent' -> permanent;
+ ?'snmpCommunityStorageType_nonVolatile' -> nonVolatile;
+ ?'snmpCommunityStorageType_volatile' -> volatile;
+ ?'snmpCommunityStorageType_other' -> other;
+ _ -> undefined
+ end,
+ Prefix, element(?snmpCommunityStatus, Row),
+ case element(?snmpCommunityStatus, Row) of
+ ?'snmpCommunityStatus_destroy' -> destroy;
+ ?'snmpCommunityStatus_createAndWait' -> createAndWait;
+ ?'snmpCommunityStatus_createAndGo' -> createAndGo;
+ ?'snmpCommunityStatus_notReady' -> notReady;
+ ?'snmpCommunityStatus_notInService' -> notInService;
+ ?'snmpCommunityStatus_active' -> active;
+ _ -> undefined
+ end]))
+ end,
+ snmpa_mib_lib:print_table(Table, DB, FOI, PrintRow);
+%% Op == new | delete
+snmpCommunityTable(Op) ->
+ snmp_generic:table_func(Op, db(snmpCommunityTable)).
+
+%% Op == get | is_set_ok | set | get_next
+snmpCommunityTable(get, RowIndex, Cols) ->
+ get(snmpCommunityTable, RowIndex, Cols);
+snmpCommunityTable(get_next, RowIndex, Cols) ->
+ next(snmpCommunityTable, RowIndex, Cols);
+snmpCommunityTable(is_set_ok, RowIndex, Cols0) ->
+ case (catch verify_snmpCommunityTable_is_set_ok(Cols0)) of
+ {ok, Cols1} ->
+ case (catch verify_snmpCommunityTable_cols(Cols1, [])) of
+ {ok, Cols} ->
+ Db = db(snmpCommunityTable),
+ snmp_generic:table_func(is_set_ok, RowIndex, Cols, Db);
+ Error ->
+ Error
+ end;
+ Error ->
+ Error
+ end;
+snmpCommunityTable(set, RowIndex, Cols0) ->
+ case (catch verify_snmpCommunityTable_cols(Cols0, [])) of
+ {ok, Cols} ->
+ invalidate_cache(RowIndex),
+ Db = db(snmpCommunityTable),
+ Res = snmp_generic:table_func(set, RowIndex, Cols, Db),
+ snmpa_agent:invalidate_ca_cache(),
+ update_cache(RowIndex),
+ Res;
+ Error ->
+ Error
+ end;
+snmpCommunityTable(Op, Arg1, Arg2) ->
+ snmp_generic:table_func(Op, Arg1, Arg2, db(snmpCommunityTable)).
+
+
+verify_snmpCommunityTable_is_set_ok(Cols) ->
+ LocalEngineID = snmp_framework_mib:get_engine_id(),
+ case lists:keysearch(?snmpCommunityContextEngineID, 1, Cols) of
+ {value, {_, LocalEngineID}} ->
+ {ok, Cols};
+ {value, _} ->
+ {inconsistentValue, ?snmpCommunityContextEngineID};
+ false ->
+ {ok, kinsert(Cols, LocalEngineID)}
+ end.
+
+verify_snmpCommunityTable_cols([], Cols) ->
+ {ok, lists:reverse(Cols)};
+verify_snmpCommunityTable_cols([{Col, Val0}|Cols], Acc) ->
+ Val = verify_snmpCommunityTable_col(Col, Val0),
+ verify_snmpCommunityTable_cols(Cols, [{Col, Val}|Acc]).
+
+verify_snmpCommunityTable_col(?snmpCommunityIndex, Index) ->
+ case (catch snmp_conf:check_string(Index,{gt,0})) of
+ ok ->
+ Index;
+ _ ->
+ wrongValue(?snmpCommunityIndex)
+ end;
+verify_snmpCommunityTable_col(?snmpCommunityName, Name) ->
+ case (catch snmp_conf:check_string(Name)) of
+ ok ->
+ Name;
+ _ ->
+ wrongValue(?snmpCommunityName)
+ end;
+verify_snmpCommunityTable_col(?snmpCommunitySecurityName, Name) ->
+ case (catch snmp_conf:check_string(Name)) of
+ ok ->
+ Name;
+ _ ->
+ wrongValue(?snmpCommunitySecurityName)
+ end;
+verify_snmpCommunityTable_col(?snmpCommunityContextName, Name) ->
+ case (catch snmp_conf:check_string(Name)) of
+ ok ->
+ Name;
+ _ ->
+ wrongValue(?snmpCommunityContextName)
+ end;
+verify_snmpCommunityTable_col(?snmpCommunityTransportTag, Tag) ->
+ case (catch snmp_conf:check_string(Tag)) of
+ ok ->
+ Tag;
+ _ ->
+ wrongValue(?snmpCommunityTransportTag)
+ end;
+verify_snmpCommunityTable_col(_, Val) ->
+ Val.
+
+
+
+%% Op == get | is_set_ok | set | get_next
+snmpTargetAddrExtTable(get, RowIndex, Cols) ->
+ NCols = conv1(Cols),
+ get(snmpTargetAddrExtTable, RowIndex, NCols);
+snmpTargetAddrExtTable(get_next, RowIndex, Cols) ->
+ NCols = conv1(Cols),
+ conv2(next(snmpTargetAddrExtTable, RowIndex, NCols));
+snmpTargetAddrExtTable(set, RowIndex, Cols0) ->
+ case (catch verify_snmpTargetAddrExtTable_cols(Cols0, [])) of
+ {ok, Cols} ->
+ NCols = conv3(Cols),
+ snmp_generic:table_func(set, RowIndex, NCols,
+ db(snmpTargetAddrExtTable));
+ Error ->
+ Error
+ end;
+snmpTargetAddrExtTable(is_set_ok, RowIndex, Cols0) ->
+ case (catch verify_snmpTargetAddrExtTable_cols(Cols0, [])) of
+ {ok, Cols} ->
+ NCols = conv3(Cols),
+ snmp_generic:table_func(is_set_ok, RowIndex, NCols,
+ db(snmpTargetAddrExtTable));
+ Error ->
+ Error
+ end.
+
+
+verify_snmpTargetAddrExtTable_cols([], Cols) ->
+ {ok, lists:reverse(Cols)};
+verify_snmpTargetAddrExtTable_cols([{Col, Val0}|Cols], Acc) ->
+ Val = verify_snmpTargetAddrExtTable_col(Col, Val0),
+ verify_snmpTargetAddrExtTable_cols(Cols, [{Col, Val}|Acc]).
+
+verify_snmpTargetAddrExtTable_col(?snmpTargetAddrTMask, []) ->
+ [];
+verify_snmpTargetAddrExtTable_col(?snmpTargetAddrTMask, TMask) ->
+ case (catch snmp_conf:check_taddress(TMask)) of
+ ok ->
+ TMask;
+ _ ->
+ wrongValue(?snmpTargetAddrTMask)
+ end;
+verify_snmpTargetAddrExtTable_col(?snmpTargetAddrMMS, MMS) ->
+ case (catch snmp_conf:check_packet_size(MMS)) of
+ ok ->
+ MMS;
+ _ ->
+ wrongValue(?snmpTargetAddrMMS)
+ end;
+verify_snmpTargetAddrExtTable_col(_, Val) ->
+ Val.
+
+db(snmpTargetAddrExtTable) -> db(snmpTargetAddrTable);
+db(X) -> snmpa_agent:db(X).
+
+fa(snmpCommunityTable) -> ?snmpCommunityName;
+fa(snmpTargetAddrExtTable) -> 11.
+
+foi(snmpCommunityTable) -> ?snmpCommunityIndex;
+foi(snmpTargetAddrExtTable) -> 11.
+
+noc(snmpCommunityTable) -> 8;
+noc(snmpTargetAddrExtTable) -> 12.
+
+stc(snmpCommunityTable) -> ?snmpCommunityStorageType.
+
+next(Name, RowIndex, Cols) ->
+ snmp_generic:handle_table_next(db(Name), RowIndex, Cols,
+ fa(Name), foi(Name), noc(Name)).
+
+conv1([Col | T]) -> [Col + 10 | conv1(T)];
+conv1([]) -> [].
+
+
+conv2([{[Col | Oid], Val} | T]) ->
+ [{[Col - 10 | Oid], Val} | conv2(T)];
+conv2([X | T]) ->
+ [X | conv2(T)];
+conv2(X) -> X.
+
+
+conv3([{Idx, Val}|T]) -> [{Idx+10, Val} | conv3(T)];
+conv3([]) -> [].
+
+
+get(Name, RowIndex, Cols) ->
+ snmp_generic:handle_table_get(db(Name), RowIndex, Cols, foi(Name)).
+
+kinsert([H | T], EngineID) when element(1, H) < ?snmpCommunityContextEngineID ->
+ [H | kinsert(T, EngineID)];
+kinsert(Cols, EngineID) ->
+ [{?snmpCommunityContextEngineID, EngineID} | Cols].
+
+
+wrongValue(V) -> throw({wrongValue, V}).
+
+
+%% -----
+
+set_sname() ->
+ set_sname(get(sname)).
+
+set_sname(undefined) ->
+ put(sname,conf);
+set_sname(_) -> %% Keep it, if already set.
+ ok.
+
+
+error(Reason) ->
+ throw({error, Reason}).
+
+config_err(F, A) ->
+ snmpa_error:config_err("[COMMUNITY-MIB]: " ++ F, A).
diff --git a/lib/snmp/src/agent/snmp_framework_mib.erl b/lib/snmp/src/agent/snmp_framework_mib.erl
new file mode 100644
index 0000000000..0916e2ec74
--- /dev/null
+++ b/lib/snmp/src/agent/snmp_framework_mib.erl
@@ -0,0 +1,440 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1999-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%
+%%
+-module(snmp_framework_mib).
+
+-include("snmp_types.hrl").
+-include("STANDARD-MIB.hrl").
+
+-define(VMODULE,"FRAMEWORK-MIB").
+-include("snmp_verbosity.hrl").
+
+-ifndef(default_verbosity).
+-define(default_verbosity,silence).
+-endif.
+
+
+%%%-----------------------------------------------------------------
+%%% This module implements the init- configure- and instrumentation-
+%%% functions for the SNMP-FRAMEWORK-MIB.
+%%%
+%%% We also keep internal datastructures here, e.g. a table
+%%% over all known contexts.
+%%%-----------------------------------------------------------------
+%% External exports
+-export([init/0, configure/1]).
+-export([intContextTable/1, intContextTable/3,
+ intAgentUDPPort/1, intAgentIpAddress/1,
+ snmpEngineID/1,
+ snmpEngineBoots/1,
+ snmpEngineTime/1,
+ snmpEngineMaxMessageSize/1,
+ get_engine_id/0, get_engine_max_message_size/0,
+ get_engine_boots/0, get_engine_time/0,
+ set_engine_boots/1, set_engine_time/1,
+ table_next/2, check_status/3]).
+-export([add_context/1, delete_context/1]).
+-export([check_agent/1, check_context/1]).
+
+
+%%-----------------------------------------------------------------
+%% Func: init/0
+%% Purpose: Creates the tables and variables necessary for the SNMP
+%% mechanism to work properly.
+%% Note that this function won't destroy any old values.
+%% This function should be called only once.
+%%-----------------------------------------------------------------
+init() ->
+ maybe_create_table(intContextTable),
+ init_engine().
+
+
+%%-----------------------------------------------------------------
+%% Func: configure/1
+%% Args: Dir is the directory with trailing dir_separator where
+%% the configuration files can be found.
+%% Purpose: Reads the config-files for the internal tables, and
+%% inserts the data. Makes sure that all old data in
+%% the tables are deleted, and the new data inserted.
+%% This function makes sure that all (and only)
+%% config-file-data are in the tables.
+%% Returns: ok
+%% Fails: exit(configuration_error)
+%% PRE: init/1 has been successfully called
+%%-----------------------------------------------------------------
+configure(Dir) ->
+ set_sname(),
+ case snmpa_agent:get_agent_mib_storage() of
+ mnesia ->
+ ok;
+ _ ->
+ case (catch do_configure(Dir)) of
+ ok ->
+ ok;
+ {error, Reason} ->
+ ?vinfo("configure error: ~p", [Reason]),
+ config_err("configure failed: ~p", [Reason]),
+ exit(configuration_error);
+ Error ->
+ ?vinfo("configure failed: ~p", [Error]),
+ config_err("configure failed: ~p", [Error]),
+ exit(configuration_error)
+ end
+ end,
+ ok.
+
+do_configure(Dir) ->
+ ?vdebug("read internal config files",[]),
+ Contexts = read_internal_config_files(Dir),
+ ?vdebug("read agent config files",[]),
+ Agent = read_agent(Dir),
+ ?vdebug("initiate vars",[]),
+ init_vars(Agent),
+ %% Add default context, if not present.
+ NContexts = [{""} | lists:delete({""}, Contexts)],
+ ?vdebug("initiate tables",[]),
+ init_tabs(NContexts),
+ ok.
+
+read_internal_config_files(Dir) ->
+ ?vdebug("read context config file",[]),
+ Gen = fun(D) -> convert_context(D) end,
+ Filter = fun(Contexts) -> Contexts end,
+ Check = fun(Entry) -> check_context(Entry) end,
+ [Ctxs] = snmp_conf:read_files(Dir, [{Gen, Filter, Check, "context.conf"}]),
+ Ctxs.
+
+
+read_agent(Dir) ->
+ ?vdebug("read agent config file",[]),
+ Check = fun(Entry) -> check_agent(Entry) end,
+ File = filename:join(Dir, "agent.conf"),
+ Agent = snmp_conf:read(File, Check),
+ sort_agent(Agent).
+
+
+%%-----------------------------------------------------------------
+%% Make sure that each mandatory agent attribute is present, and
+%% provide default values for the other non-present attributes.
+%%-----------------------------------------------------------------
+sort_agent(L) ->
+ Mand = [{intAgentIpAddress, mandatory},
+ {intAgentUDPPort, mandatory},
+ {snmpEngineMaxMessageSize, mandatory},
+ {snmpEngineID, mandatory}],
+ {ok, L2} = snmp_conf:check_mandatory(L, Mand),
+ lists:keysort(1, L2).
+
+
+%%-----------------------------------------------------------------
+%% Generate a context.conf file.
+%%-----------------------------------------------------------------
+convert_context(Dir) ->
+ config_err("missing context.conf file => generating a default file", []),
+ File = filename:join(Dir,"context.conf"),
+ case file:open(File, [write]) of
+ {ok, Fid} ->
+ ok = io:format(Fid, "~s\n", [context_header()]),
+ ok = io:format(Fid, "%% The default context\n\"\".\n", []),
+ file:close(Fid);
+ {error, Reason} ->
+ file:delete(File),
+ error({failed_creating_file, File, Reason})
+ end.
+
+context_header() ->
+ {Y,Mo,D} = date(),
+ {H,Mi,S} = time(),
+ io_lib:format("%% This file was automatically generated by "
+ "snmp_config v~s ~w-~2.2.0w-~2.2.0w "
+ "~2.2.0w:~2.2.0w:~2.2.0w\n",
+ [?version,Y,Mo,D,H,Mi,S]).
+
+
+%%-----------------------------------------------------------------
+%% Context
+%% Context.
+%%-----------------------------------------------------------------
+check_context(Context) ->
+ ?vtrace("check_context -> entry with"
+ "~n Context: ~p", [Context]),
+ case (catch snmp_conf:check_string(Context)) of
+ ok ->
+ {ok, {Context}};
+ _ ->
+ error({invalid_context, Context})
+ end.
+
+
+%%-----------------------------------------------------------------
+%% Agent
+%% {Name, Value}.
+%%-----------------------------------------------------------------
+check_agent({intAgentIpAddress, Value}) ->
+ snmp_conf:check_ip(Value);
+check_agent({intAgentUDPPort, Value}) ->
+ snmp_conf:check_integer(Value);
+%% This one is kept for backwards compatibility
+check_agent({intAgentMaxPacketSize, Value}) ->
+ snmp_conf:check_packet_size(Value);
+check_agent({snmpEngineMaxMessageSize, Value}) ->
+ snmp_conf:check_packet_size(Value);
+check_agent({snmpEngineID, Value}) ->
+ snmp_conf:check_string(Value);
+check_agent(X) ->
+ error({invalid_agent_attribute, X}).
+
+
+maybe_create_table(Name) ->
+ case snmpa_local_db:table_exists(db(Name)) of
+ true ->
+ ok;
+ _ ->
+ ?vtrace("create table: ~w",[Name]),
+ snmpa_local_db:table_create(db(Name))
+ end.
+
+init_vars(Vars) ->
+ lists:map(fun init_var/1, Vars).
+
+init_var({Var, Val}) ->
+ ?vtrace("init var: "
+ "~n set ~w to ~w",[Var, Val]),
+ snmp_generic:variable_set(db(Var), Val).
+
+init_tabs(Contexts) ->
+ ?vdebug("create context table",[]),
+ snmpa_local_db:table_delete(db(intContextTable)),
+ snmpa_local_db:table_create(db(intContextTable)),
+ init_context_table(Contexts).
+
+init_context_table([Row | T]) ->
+ Context = element(1, Row),
+ Key = [length(Context) | Context],
+ ?vtrace("create intContextTable table row for: ~w",[Key]),
+ snmpa_local_db:table_create_row(db(intContextTable), Key, Row),
+ init_context_table(T);
+init_context_table([]) -> true.
+
+
+table_cre_row(Tab, Key, Row) ->
+ snmpa_mib_lib:table_cre_row(db(Tab), Key, Row).
+
+table_del_row(Tab, Key) ->
+ snmpa_mib_lib:table_del_row(db(Tab), Key).
+
+
+%% FIXME: does not work with mnesia
+add_context(Ctx) ->
+ case (catch check_context(Ctx)) of
+ {ok, Row} ->
+ Context = element(1, Row),
+ Key = [length(Context) | Context],
+ case table_cre_row(intContextTable, Key, Row) of
+ true ->
+ {ok, Key};
+ false ->
+ {error, create_failed}
+ end;
+ {error, Reason} ->
+ {error, Reason};
+ Error ->
+ {error, Error}
+ end.
+
+%% FIXME: does not work with mnesia
+delete_context(Key) ->
+ case table_del_row(intContextTable, Key) of
+ true ->
+ ok;
+ false ->
+ {error, delete_failed}
+ end.
+
+
+%%-----------------------------------------------------------------
+%% Instrumentation functions
+%% Retreive functions are also used internally by the agent, so
+%% don't change the interface without changing those functions.
+%% Note that if these functions implementations are changed,
+%% an error can make the agent crash, as no error detection is
+%% performed for the internal data.
+%% These functions cannot use the default functions as is, because
+%% the default functions rely on that the mib is loaded, and
+%% these functions must work even if the OTP-FRAMEWORK-MIB isn't loaded.
+%% So we hardcode the information necessary for the functions
+%% called by the default functions in snmp_generic. This info is
+%% normally provided by the mib compiler, and inserted into
+%% snmpa_symbolic_store at load mib time.
+%%-----------------------------------------------------------------
+
+%%-----------------------------------------------------------------
+%% None if the int* objects are defined in any MIB.
+%%
+%% intContextTable keeps all
+%% known contexts internally, but is ordered as an SNMP table. It
+%% could be defined as:
+%% intContextTable OBJECT-TYPE
+%% SYNTAX SEQUENCE OF IntContextEntry
+%% MAX-ACCESS not-accessible
+%% STATUS current
+%% DESCRIPTION "A table of locally available contexts."
+%% ::= { xx }
+%%
+%% intContextEntry OBJECT-TYPE
+%% SYNTAX IntContextEntry
+%% MAX-ACCESS not-accessible
+%% STATUS current
+%% DESCRIPTION "Information about a particular context."
+%% INDEX {
+%% intContextName
+%% }
+%% ::= { intContextTable 1 }
+%%
+%% IntContextEntry ::= SEQUENCE
+%% {
+%% intContextName SnmpAdminString
+%% }
+%%
+%% intContextName OBJECT-TYPE
+%% SYNTAX SnmpAdminString (SIZE(0..32))
+%% MAX-ACCESS read-only
+%% STATUS current
+%% DESCRIPTION "A human readable name identifying a particular
+%% context at a particular SNMP entity.
+%%
+%% The empty contextName (zero length) represents the
+%% default context.
+%% "
+%% ::= { intContextEntry 1 }
+%%-----------------------------------------------------------------
+
+%% Op == new | delete
+intContextTable(Op) ->
+ snmp_generic:table_func(Op, db(intContextTable)).
+
+%% Op == get get_next -- READ only table
+intContextTable(get, RowIndex, Cols) ->
+ get(intContextTable, RowIndex, Cols);
+intContextTable(get_next, RowIndex, Cols) ->
+ next(intContextTable, RowIndex, Cols);
+intContextTable(Op, Arg1, Arg2) ->
+ snmp_generic:table_func(Op, Arg1, Arg2, db(intContextTable)).
+
+%% FIXME: exported, not used by agent, not documented - remove?
+table_next(Name, RestOid) ->
+ snmp_generic:table_next(db(Name), RestOid).
+
+%% FIXME: exported, not used by agent, not documented - remove?
+%% FIXME: does not work with mnesia
+check_status(Name, Indexes, StatusNo) ->
+ case snmpa_local_db:table_get_element(db(Name), Indexes, StatusNo) of
+ {value, ?'RowStatus_active'} -> true;
+ _ -> false
+ end.
+
+db(intContextTable) -> {intContextTable, volatile};
+db(X) -> snmpa_agent:db(X).
+
+fa(intContextTable) -> 1.
+
+foi(intContextTable) -> 1.
+
+noc(intContextTable) -> 1.
+
+next(Name, RowIndex, Cols) ->
+ snmp_generic:handle_table_next(db(Name), RowIndex, Cols,
+ fa(Name), foi(Name), noc(Name)).
+
+get(Name, RowIndex, Cols) ->
+ snmp_generic:handle_table_get(db(Name), RowIndex, Cols, foi(Name)).
+
+%% Op == new | delete | get
+intAgentUDPPort(Op) ->
+ snmp_generic:variable_func(Op, db(intAgentUDPPort)).
+
+intAgentIpAddress(Op) ->
+ snmp_generic:variable_func(Op, db(intAgentIpAddress)).
+
+snmpEngineID(Op) ->
+ snmp_generic:variable_func(Op, db(snmpEngineID)).
+
+snmpEngineMaxMessageSize(Op) ->
+ snmp_generic:variable_func(Op, db(snmpEngineMaxMessageSize)).
+
+snmpEngineBoots(Op) ->
+ snmp_generic:variable_func(Op, db(snmpEngineBoots)).
+
+snmpEngineTime(get) ->
+ {value, get_engine_time()}.
+
+init_engine() ->
+ case snmp_generic:variable_get(db(snmpEngineBoots)) of
+ {value, Val} when Val < 2147483647 ->
+ snmp_generic:variable_set(db(snmpEngineBoots), Val+1);
+ {value, _} ->
+ ok;
+ undefined ->
+ snmp_generic:variable_set(db(snmpEngineBoots), 1)
+ end,
+ reset_engine_base().
+
+
+reset_engine_base() ->
+ ets:insert(snmp_agent_table, {snmp_engine_base, snmp_misc:now(sec)}).
+
+get_engine_id() ->
+ {value, EngineID} = snmpEngineID(get),
+ EngineID.
+
+get_engine_max_message_size() ->
+ {value, MPS} = snmpEngineMaxMessageSize(get),
+ MPS.
+
+get_engine_time() ->
+ [{_, EngineBase}] = ets:lookup(snmp_agent_table, snmp_engine_base),
+ snmp_misc:now(sec) - EngineBase.
+
+get_engine_boots() ->
+ {value, Val} = snmpEngineBoots(get),
+ Val.
+
+set_engine_boots(Boots) ->
+ snmp_generic:variable_func(set, Boots, db(snmpEngineBoots)).
+
+set_engine_time(Time) ->
+ Base = snmp_misc:now(sec) - Time,
+ ets:insert(snmp_agent_table, {snmp_engine_base, Base}).
+
+
+set_sname() ->
+ set_sname(get(sname)).
+
+set_sname(undefined) ->
+ put(sname,conf);
+set_sname(_) -> %% Keep it, if already set.
+ ok.
+
+%% ------------------------------------------------------------------
+
+error(Reason) ->
+ throw({error, Reason}).
+
+config_err(F, A) ->
+ snmpa_error:config_err("[FRAMEWORK-MIB]: " ++ F, A).
+
diff --git a/lib/snmp/src/agent/snmp_generic.erl b/lib/snmp/src/agent/snmp_generic.erl
new file mode 100644
index 0000000000..508aa090d9
--- /dev/null
+++ b/lib/snmp/src/agent/snmp_generic.erl
@@ -0,0 +1,891 @@
+%%
+%% %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%
+%%
+-module(snmp_generic).
+
+-export([variable_func/2, variable_func/3, variable_get/1, variable_set/2]).
+-export([table_func/2, table_func/4,
+ table_set_row/5, table_set_cols/3, table_set_cols/4,
+ table_row_exists/2, table_foreach/2, table_foreach/3,
+ table_try_row/4, table_get_row/2, table_get_row/3,
+ table_get_elements/3, table_get_elements/4, table_get_element/3,
+ table_set_element/4, table_set_elements/3,
+ table_next/2, handle_table_next/6,
+ table_try_make_consistent/3, table_max_col/2,
+ find_col/2, table_check_status/5,
+ table_find/3,split_index_to_keys/2, init_defaults/2, init_defaults/3,
+ table_info/1,
+ try_apply/2, get_own_indexes/2, table_create_rest/6,
+ handle_table_get/4, variable_inc/2,
+ get_status_col/2, get_table_info/2, get_index_types/1]).
+
+-include("STANDARD-MIB.hrl").
+-include("snmp_types.hrl").
+
+-define(VMODULE,"GENERIC").
+-include("snmp_verbosity.hrl").
+
+-ifndef(default_verbosity).
+-define(default_verbosity,silence).
+-endif.
+
+
+%%%-----------------------------------------------------------------
+%%% Generic functions for implementing software tables
+%%% and variables.
+%%%-----------------------------------------------------------------
+%% NameDb is {TableName, Db} where Db is volatile | persistent | mnesia
+
+%%------------------------------------------------------------------
+%% Access functions to the database.
+%%------------------------------------------------------------------
+variable_get({Name, mnesia}) ->
+ snmp_generic_mnesia:variable_get(Name);
+variable_get(NameDb) -> % ret {value, Val} | undefined
+ snmpa_local_db:variable_get(NameDb).
+variable_set({Name, mnesia}, Val) ->
+ snmp_generic_mnesia:variable_set(Name, Val);
+variable_set(NameDb, Val) -> % ret true
+ snmpa_local_db:variable_set(NameDb, Val).
+
+variable_inc({Name, mnesia}, N) ->
+ snmp_generic_mnesia:variable_inc(Name, N);
+variable_inc(NameDb, N) -> % ret true
+ snmpa_local_db:variable_inc(NameDb, N).
+
+%%-----------------------------------------------------------------
+%% Returns: {value, Val} | undefined
+%%
+%% snmpa_local_db overloads (for performance reasons? (mbj?))
+%%-----------------------------------------------------------------
+table_get_element({Name, volatile}, RowIndex, Col) ->
+ snmpa_local_db:table_get_element({Name, volatile}, RowIndex, Col);
+table_get_element({Name, persistent}, RowIndex, Col) ->
+ snmpa_local_db:table_get_element({Name, persistent}, RowIndex, Col);
+table_get_element(NameDb, RowIndex, Col) ->
+ TableInfo = table_info(NameDb),
+ case handle_table_get(NameDb,RowIndex,[Col],
+ TableInfo#table_info.first_own_index) of
+ [{value, Val}] -> {value, Val};
+ _ -> undefined
+ end.
+
+table_get_elements(NameDb, RowIndex, Cols) ->
+ TableInfo = snmp_generic:table_info(NameDb),
+ table_get_elements(NameDb, RowIndex, Cols,
+ TableInfo#table_info.first_own_index).
+
+%%----------------------------------------------------------------------
+%% Returns: list of vals | undefined
+%%----------------------------------------------------------------------
+table_get_elements({Name, mnesia}, RowIndex, Cols, FirstOwnIndex) ->
+ ?vtrace("table_get_elements(mnesia) -> entry with"
+ "~n Name: ~p"
+ "~n RowIndex: ~p"
+ "~n Cols: ~p"
+ "~n FirstOwnIndex: ~p", [Name, RowIndex, Cols, FirstOwnIndex]),
+ snmp_generic_mnesia:table_get_elements(Name, RowIndex, Cols, FirstOwnIndex);
+table_get_elements(NameDb, RowIndex, Cols, FirstOwnIndex) ->
+ ?vtrace("table_get_elements -> entry with"
+ "~n NameDb: ~p"
+ "~n RowIndex: ~p"
+ "~n Cols: ~p"
+ "~n FirstOwnIndex: ~p", [NameDb, RowIndex, Cols, FirstOwnIndex]),
+ snmpa_local_db:table_get_elements(NameDb, RowIndex, Cols, FirstOwnIndex).
+
+
+%% ret true
+table_set_element({Name,mnesia}, RowIndex, Col, NewVal) ->
+ snmp_generic_mnesia:table_set_elements(Name, RowIndex,
+ [{Col, NewVal}]);
+table_set_element(NameDb, RowIndex, Col, NewVal) ->
+ snmpa_local_db:table_set_elements(NameDb, RowIndex, [{Col, NewVal}]).
+
+table_set_elements({Name, mnesia}, RowIndex, Cols) ->
+ snmp_generic_mnesia:table_set_elements(Name, RowIndex, Cols);
+table_set_elements(NameDb, RowIndex, Cols) -> % ret true
+ snmpa_local_db:table_set_elements(NameDb, RowIndex, Cols).
+
+table_next({Name, mnesia}, RestOid) ->
+ snmp_generic_mnesia:table_next(Name, RestOid);
+table_next(NameDb, RestOid) -> % ret RRestOid | endOfTable
+ snmpa_local_db:table_next(NameDb, RestOid).
+table_max_col(NameDb, Col) -> % ret largest element in Col
+ % in the table NameDb.
+ snmpa_local_db:table_max_col(NameDb, Col).
+
+
+%%------------------------------------------------------------------
+%% Theses functions could be in the MIB for simple
+%% variables or tables, i.e. vars without complex
+%% set-operations. If there are complex set op, an
+%% extra layer-function should be added, and that
+%% function should be in the MIB, and it can call these
+%% functions.
+%% The MIB functions just provide the table name, column
+%% and a list of the keys for the table.
+%%------------------------------------------------------------------
+
+%%------------------------------------------------------------------
+%% Variables
+%%------------------------------------------------------------------
+%%------------------------------------------------------------------
+%% This is the default function for variables.
+%%------------------------------------------------------------------
+
+variable_func(new, NameDb) ->
+ case variable_get(NameDb) of
+ {value, _} -> ok;
+ undefined ->
+ #variable_info{defval = Defval} = variable_info(NameDb),
+ variable_set(NameDb, Defval)
+ end;
+
+variable_func(delete, _NameDb) ->
+ ok;
+
+variable_func(get, NameDb) ->
+ case variable_get(NameDb) of
+ {value, Val} -> {value, Val};
+ _ -> genErr
+ end.
+
+variable_func(is_set_ok, _Val, _NameDb) ->
+ noError;
+variable_func(set, Val, NameDb) ->
+ case variable_set(NameDb, Val) of
+ true -> noError;
+ false -> commitFailed
+ end;
+variable_func(undo, _Val, _NameDb) ->
+ noError.
+
+%%------------------------------------------------------------------
+%% Tables
+%% Assumes the RowStatus is the last column in the
+%% table.
+%%------------------------------------------------------------------
+%%------------------------------------------------------------------
+%% This is the default function for tables.
+%%
+%% NameDb is the name of the table (atom)
+%% RowIndex is a flat list of the indexes for the row.
+%% Col is the column number.
+%%------------------------------------------------------------------
+%% Each database implements its own table_func
+%%------------------------------------------------------------------
+table_func(Op, {Name, mnesia}) ->
+ snmp_generic_mnesia:table_func(Op, Name);
+
+table_func(Op, NameDb) ->
+ snmpa_local_db:table_func(Op, NameDb).
+
+table_func(Op, RowIndex, Cols, {Name, mnesia}) ->
+ snmp_generic_mnesia:table_func(Op, RowIndex, Cols, Name);
+
+table_func(Op, RowIndex, Cols, NameDb) ->
+ snmpa_local_db:table_func(Op, RowIndex, Cols, NameDb).
+
+%%----------------------------------------------------------------------
+%% DB independent.
+%%----------------------------------------------------------------------
+handle_table_get(NameDb, RowIndex, Cols, FirstOwnIndex) ->
+ case table_get_elements(NameDb, RowIndex, Cols, FirstOwnIndex) of
+ undefined ->
+ ?vdebug("handle_table_get -> undefined", []),
+ make_list(length(Cols), {noValue, noSuchInstance});
+ Res ->
+ ?vtrace("handle_table_get -> Res: ~n ~p", [Res]),
+ validate_get(Cols, Res)
+ end.
+
+validate_get([_Col | Cols], [Res | Ress]) ->
+ NewVal =
+ case Res of
+ noinit -> {noValue, unSpecified};
+ noacc -> {noAccess, unSpecified};
+ Val -> {value, Val}
+ end,
+ [NewVal | validate_get(Cols, Ress)];
+validate_get([], []) -> [].
+
+make_list(N, X) when N > 0 -> [X | make_list(N-1, X)];
+make_list(_, _) -> [].
+
+table_foreach(Tab, Fun) ->
+ ?vdebug("apply fun to all in table ~w",[Tab]),
+ table_foreach(Tab, Fun, undefined, []).
+table_foreach(Tab, Fun, FOI) ->
+ ?vdebug("apply fun to all in table ~w",[Tab]),
+ table_foreach(Tab, Fun, FOI, []).
+table_foreach(Tab, Fun, FOI, Oid) ->
+ case table_next(Tab, Oid) of
+ endOfTable ->
+ ?vdebug("end of table",[]),
+ ok;
+ Oid ->
+ %% OOUPS, circular ref, major db fuckup
+ ?vinfo("cyclic reference: ~w -> ~w",[Oid,Oid]),
+ exit({cyclic_db_reference,Oid});
+ NextOid ->
+ ?vtrace("get row for oid ~w",[NextOid]),
+ case table_get_row(Tab, NextOid, FOI) of
+ undefined -> ok;
+ Row ->
+ ?vtrace("row: ~w",[Row]),
+ Fun(NextOid, Row)
+ end,
+ table_foreach(Tab, Fun, FOI, NextOid)
+ end.
+
+%%------------------------------------------------------------------
+%% Used to implement next, and to find next entry's
+%% keys in a table when not all of the keys are known.
+%%
+%% FirstCol is the first column in the search.
+%% LastCol is the last column.
+%% Col is the current column.
+%% If Col is less than FirstCol, (or not present), the
+%% search shall begin in the first row (no indexes) of
+%% column FirstCol.
+%% Returns: List of endOfTable | {NextOid, Value}
+%%------------------------------------------------------------------
+handle_table_next(_NameDb, _RowIndex, [], _FirstCol, _FOI, _LastCol) ->
+ [];
+handle_table_next(NameDb, RowIndex, OrgCols, FirstCol, FOI, LastCol) ->
+ FirstVals =
+ case split_cols(OrgCols, FirstCol, LastCol) of
+ {[], Cols, LastCols} ->
+ [];
+ {FirstCols, Cols, LastCols} ->
+ handle_table_next(NameDb, [], FirstCols, FirstCol, FOI, LastCol)
+ end,
+ NextVals =
+ case table_next(NameDb, RowIndex) of
+ endOfTable ->
+ {NewCols, EndOfTabs} = make_new_cols(Cols, LastCol),
+ NewVals =
+ handle_table_next(NameDb, [], NewCols,FirstCol,FOI,LastCol),
+ lists:append(NewVals, EndOfTabs);
+ NextIndex ->
+ % We found next Row; check if all Cols are initialized.
+ Row = table_get_elements(NameDb, NextIndex, Cols, FOI),
+ check_all_initalized(Row,Cols,NameDb,NextIndex,
+ FirstCol, FOI, LastCol)
+ end,
+ lists:append([FirstVals, NextVals, LastCols]).
+
+%% Split into three parts A,B,C; A < FirstCol =< B =< LastCol < C
+split_cols([Col | Cols], FirstCol, LastCol) when Col < FirstCol ->
+ {A, B, C} = split_cols(Cols, FirstCol, LastCol),
+ {[FirstCol | A], B, C};
+split_cols([Col | Cols], FirstCol, LastCol) when Col > LastCol ->
+ {A, B, C} = split_cols(Cols, FirstCol, LastCol),
+ {A, B, [endOfTable | C]};
+split_cols([Col | Cols], FirstCol, LastCol) ->
+ {A, B, C} = split_cols(Cols, FirstCol, LastCol),
+ {A, [Col | B], C};
+split_cols([], _FirstCol, _LastCol) ->
+ {[], [], []}.
+
+%% Add 1 to each col < lastcol. Otherwise make it into
+%% endOfTable.
+make_new_cols([Col | Cols], LastCol) when Col < LastCol ->
+ {NewCols, Ends} = make_new_cols(Cols, LastCol),
+ {[Col+1 | NewCols], Ends};
+make_new_cols([_Col | Cols], LastCol) ->
+ {NewCols, Ends} = make_new_cols(Cols, LastCol),
+ {NewCols, [endOfTable | Ends]};
+make_new_cols([], _LastCol) ->
+ {[], []}.
+
+check_all_initalized([noinit|Vals],[Col|Cols],Name,RowIndex,
+ FirstCol, FOI, LastCol) ->
+ [NextValForThisCol] =
+ handle_table_next(Name, RowIndex, [Col], FirstCol, FOI, LastCol),
+ [NextValForThisCol |
+ check_all_initalized(Vals, Cols, Name, RowIndex, FirstCol, FOI, LastCol)];
+check_all_initalized([noacc|Vals],[Col|Cols],Name,RowIndex,
+ FirstCol, FOI, LastCol) ->
+ [NextValForThisCol] =
+ handle_table_next(Name, RowIndex, [Col], FirstCol, FOI, LastCol),
+ [NextValForThisCol |
+ check_all_initalized(Vals, Cols, Name, RowIndex, FirstCol, FOI, LastCol)];
+check_all_initalized([Val | Vals], [Col | Cols], Name, RowIndex,
+ FirstCol, FOI, LastCol) ->
+ [{[Col | RowIndex], Val} |
+ check_all_initalized(Vals, Cols, Name, RowIndex, FirstCol, FOI, LastCol)];
+check_all_initalized([], [], _Name, _RowIndex, _FirstCol, _FOI, _LastCol) ->
+ [].
+
+
+%%------------------------------------------------------------------
+%% Implements is_set_ok.
+%%------------------------------------------------------------------
+%% TryChangeStatusFunc is a function that will be
+%% called if the rowstatus column is changed.
+%% Arguments: (StatusVal, RowIndex, Cols)
+%% Two cases:
+%% 1) Last col is RowStatus - check status
+%% 2) No modification to RowStatus - check that row exists.
+%%------------------------------------------------------------------
+table_try_row(_NameDb, _TryChangeStatusFunc, _RowIndex, []) -> {noError, 0};
+table_try_row(NameDb, TryChangeStatusFunc, RowIndex, Cols) ->
+ #table_info{status_col = StatusCol} = table_info(NameDb),
+ case lists:keysearch(StatusCol, 1, Cols) of
+ {value, {StatusCol, Val}} ->
+ case table_check_status(NameDb, StatusCol,
+ Val, RowIndex, Cols) of
+ {noError, 0} ->
+ try_apply(TryChangeStatusFunc, [NameDb, Val,
+ RowIndex, Cols]);
+ Error -> Error
+ end;
+ _ ->
+ case table_row_exists(NameDb, RowIndex) of
+ true -> {noError, 0};
+ false ->
+ [{ColNo, _Val}|_] = Cols,
+ {inconsistentName, ColNo}
+ end
+ end.
+
+%%------------------------------------------------------------------
+%% table_check_status can be used by the is_set_ok
+%% procedure of all tables, to check the
+%% status variable, if present in Cols.
+%% table_check_status(NameDb, Col, Val, RowIndex, Cols) ->
+%% NameDb : the name of the table
+%% Col : the columnnumber of RowStatus
+%% Val : the value of the RowStatus Col
+%%------------------------------------------------------------------
+
+%% Try to make the row active. Ok if status != notReady
+%% If it is notReady, make sure no row has value noinit.
+table_check_status(NameDb, Col, ?'RowStatus_active', RowIndex, Cols) ->
+ case table_get_row(NameDb, RowIndex) of
+ Row when is_tuple(Row) andalso
+ (element(Col, Row) =:= ?'RowStatus_notReady') ->
+ case is_any_noinit(Row, Cols) of
+ false -> {noError, 0};
+ true -> {inconsistentValue, Col}
+ end;
+ undefined -> {inconsistentValue, Col};
+ _Else -> {noError, 0}
+ end;
+
+%% Try to make the row inactive. Ok if status != notReady
+table_check_status(NameDb, Col, ?'RowStatus_notInService', RowIndex, Cols) ->
+ case table_get_row(NameDb, RowIndex) of
+ Row when is_tuple(Row) andalso
+ (element(Col, Row) =:= ?'RowStatus_notReady') ->
+ case is_any_noinit(Row, Cols) of
+ false -> {noError, 0};
+ true -> {inconsistentValue, Col}
+ end;
+ undefined -> {inconsistentValue, Col};
+ _Else -> {noError, 0}
+ end;
+
+%% Try to createAndGo
+%% Ok if values are provided, or default values can be used for
+%% all columns.
+table_check_status(NameDb, Col, ?'RowStatus_createAndGo', RowIndex, Cols) ->
+ case table_row_exists(NameDb, RowIndex) of
+ false ->
+ % it's ok to use snmpa_local_db:table_construct_row since it's
+ % side effect free and we only use the result temporary.
+ case catch snmpa_local_db:table_construct_row(
+ NameDb, RowIndex, ?'RowStatus_createAndGo', Cols) of
+ {'EXIT', _} ->
+ {noCreation, Col}; % Bad RowIndex
+ Row ->
+ case lists:member(noinit, tuple_to_list(Row)) of
+ false -> {noError, 0};
+ _Found -> {inconsistentValue, Col}
+ end
+ end;
+ true -> {inconsistentValue, Col}
+ end;
+
+%% Try to createAndWait - ok if row doesn't exist.
+table_check_status(NameDb, Col, ?'RowStatus_createAndWait', RowIndex, Cols) ->
+ case table_row_exists(NameDb, RowIndex) of
+ false ->
+ case catch snmpa_local_db:table_construct_row(
+ NameDb, RowIndex, ?'RowStatus_createAndGo', Cols) of
+ {'EXIT', _} ->
+ {noCreation, Col}; % Bad RowIndex
+ _Row ->
+ {noError, 0}
+ end;
+ true -> {inconsistentValue, Col}
+ end;
+
+%% Try to destroy
+table_check_status(_NameDb, _Col, ?'RowStatus_destroy', _RowIndex, _Cols) ->
+ {noError, 0};
+
+%% Otherwise, notReady. It isn't possible to set a row to notReady.
+table_check_status(_NameDb, Col, _, _RowIndex, _Cols) ->
+ {inconsistentValue, Col}.
+
+is_any_noinit(Row, Cols) ->
+ is_any_noinit(tuple_to_list(Row), Cols, 1).
+is_any_noinit([noinit | Vals], [{N, _Value} | Cols], N) ->
+ is_any_noinit(Vals, Cols, N+1);
+is_any_noinit([noinit | _Vals], _Cols, _N) ->
+ true;
+is_any_noinit([_ | Vals], [{N, _Value} | Cols], N) ->
+ is_any_noinit(Vals, Cols, N+1);
+is_any_noinit([_ | Vals], Cols, N) ->
+ is_any_noinit(Vals, Cols, N+1);
+is_any_noinit([], _, _) ->
+ false.
+
+%%------------------------------------------------------------------
+%% Implements set.
+%% ChangedStatusFunc is a function that will be
+%% called if the rowstatus column is changed.
+%% The function is called *after* the row is created or
+%% otherwise modified, but *before* it is deleted.
+%% Arguments: (StatusVal, RowIndex, Cols)
+%% ConsFunc is a consistency-check function which will
+%% be called with the RowIndex of this row, if
+%% no operation on the row is made, when
+%% all columns are set, OR when row is createAndWait:ed.
+%% This is useful when the RowStatus
+%% could change, e.g. if the manager has provided all
+%% mandatory columns in this set operation.
+%% If it is nofunc, no function will be called after all
+%% sets.
+%%------------------------------------------------------------------
+table_set_row(_NameDb, _, _, _RowIndex, []) -> {noError, 0};
+table_set_row(NameDb, ChangedStatusFunc, ConsFunc, RowIndex, Cols) ->
+ #table_info{status_col = StatusCol} = table_info(NameDb),
+ case lists:keysearch(StatusCol, 1, Cols) of
+ {value, {StatusCol, Val}} ->
+ table_set_status(NameDb, RowIndex, Val, StatusCol,
+ Cols, ChangedStatusFunc, ConsFunc);
+ _ -> table_set_cols(NameDb, RowIndex, Cols, ConsFunc)
+ end.
+
+%%----------------------------------------------------------------------
+%% Mnesia overloads for performance reasons.
+%%----------------------------------------------------------------------
+table_set_status({Name, mnesia}, RowIndex, Status, StatusCol, Cols,
+ ChangedStatusFunc, ConsFunc) ->
+ snmp_generic_mnesia:table_set_status(Name, RowIndex,
+ Status, StatusCol, Cols,
+ ChangedStatusFunc, ConsFunc);
+
+table_set_status(NameDb,RowIndex, Status, StatusCol, Cols,
+ ChangedStatusFunc,ConsFunc) ->
+ snmpa_local_db:table_set_status(NameDb, RowIndex,
+ Status, StatusCol, Cols,
+ ChangedStatusFunc, ConsFunc).
+
+init_defaults(Defs, InitRow) ->
+ table_defaults(InitRow, Defs).
+init_defaults(Defs, InitRow, StartCol) ->
+ table_defaults(InitRow, StartCol, Defs).
+%%-----------------------------------------------------------------
+%% Get, from a list of Keys, the Keys defined in this table.
+%% (e.g. if INDEX { ifIndex, myOwnIndex }, the Keys is a list
+%% of two elements, and returned from this func is a list of
+%% the last of the two.)
+%%-----------------------------------------------------------------
+get_own_indexes(0, _Keys) -> [];
+get_own_indexes(1, Keys) -> Keys;
+get_own_indexes(Index, [_Key | Keys]) ->
+ get_own_indexes(Index - 1, Keys).
+
+%%-----------------------------------------------------------------
+%% Creates everything but the INDEX columns.
+%% Pre: The StatusColumn is present
+%% Four cases:
+%% 0) If a column is 'not-accessible' => use noacc
+%% 1) If no value is provided for the column and column is
+%% not StatusCol => use noinit
+%% 2) If column is not StatusCol, use the provided value
+%% 3) If column is StatusCol, use Status
+%%-----------------------------------------------------------------
+table_create_rest(Col, Max, _ , _ , [], _NoAcc) when Col > Max -> [];
+table_create_rest(Col,Max,StatusCol,Status,[{Col,_Val}|Defs],[Col|NoAccs]) ->
+ % case 0
+ [noacc | table_create_rest(Col+1, Max, StatusCol, Status, Defs, NoAccs)];
+table_create_rest(Col,Max,StatusCol,Status,Defs,[Col|NoAccs]) ->
+ % case 0
+ [noacc | table_create_rest(Col+1, Max, StatusCol, Status, Defs, NoAccs)];
+table_create_rest(StatCol, Max, StatCol, Status, [{_Col, _Val} |Defs], NoAccs) ->
+ % case 3
+ [Status | table_create_rest(StatCol+1, Max, StatCol, Status,Defs,NoAccs)];
+table_create_rest(Col, Max, StatusCol, Status, [{Col, Val} |Defs],NoAccs) ->
+ % case 2
+ [Val | table_create_rest(Col+1, Max, StatusCol, Status,Defs,NoAccs)];
+table_create_rest(StatCol, Max, StatCol, Status, Cols, NoAccs) ->
+ % case 3
+ [Status | table_create_rest(StatCol+1, Max, StatCol, Status, Cols, NoAccs)];
+table_create_rest(Col, Max, StatusCol, Status, Cols, NoAccs) when Col =< Max->
+ % case 1
+ [noinit | table_create_rest(Col+1, Max, StatusCol, Status, Cols, NoAccs)].
+
+%%------------------------------------------------------------------
+%% Sets default values to a row.
+%% InitRow is a list of values.
+%% Defs is a list of {Col, DefVal}, in Column order.
+%% Returns a new row (a list of values) with the same values as
+%% InitRow, except if InitRow has value noinit in a column, and
+%% the corresponing Col has a DefVal in Defs, then the DefVal
+%% will be the new value.
+%%------------------------------------------------------------------
+table_defaults(InitRow, Defs) -> table_defaults(InitRow, 1, Defs).
+
+table_defaults([], _, _Defs) -> [];
+table_defaults([noinit | T], CurIndex, [{CurIndex, DefVal} | Defs]) ->
+ [DefVal | table_defaults(T, CurIndex+1, Defs)];
+%% 'not-accessible' columns don't get a value
+table_defaults([noacc | T], CurIndex, [{CurIndex, _DefVal} | Defs]) ->
+ [noacc | table_defaults(T, CurIndex+1, Defs)];
+table_defaults([Val | T], CurIndex, [{CurIndex, _DefVal} | Defs]) ->
+ [Val | table_defaults(T, CurIndex+1, Defs)];
+table_defaults([Val | T], CurIndex, Defs) ->
+ [Val | table_defaults(T, CurIndex+1, Defs)].
+
+
+%%------------------------------------------------------------------
+%% table_set_cols/3,4
+%% can be used by the set procedure of all tables
+%% to set all columns in Cols, one at a time.
+%% ConsFunc is a check-consistency function, which will
+%% be called with the RowIndex of this row, when
+%% all columns are set. This is useful when the RowStatus
+%% could change, e.g. if the manager has provided all
+%% mandatory columns in this set operation.
+%% If ConsFunc is nofunc, no function will be called after all
+%% sets.
+%% Returns: {noError, 0} | {Error, Col}
+%%------------------------------------------------------------------
+%% mnesia uses its own for performance reasons.
+%% -----------------------------------------------------------------
+table_set_cols({Name,mnesia}, RowIndex, Cols, ConsFunc) ->
+ snmp_generic_mnesia:table_set_cols(Name, RowIndex,Cols,ConsFunc);
+table_set_cols(NameDb, RowIndex, Cols, ConsFunc) ->
+ case table_set_cols(NameDb, RowIndex, Cols) of
+ {noError, 0} -> try_apply(ConsFunc, [NameDb, RowIndex, Cols]);
+ Error -> Error
+ end.
+
+table_set_cols(_NameDb, _RowIndex, []) ->
+ {noError, 0};
+table_set_cols(NameDb, RowIndex, [{Col, Val} | Cols]) ->
+ case catch table_set_element(NameDb, RowIndex, Col, Val) of
+ true ->
+ table_set_cols(NameDb, RowIndex, Cols);
+ X ->
+ user_err("snmp_generic:table_set_cols set ~w to"
+ " ~w returned ~w",
+ [{NameDb, RowIndex}, {Col, Val}, X]),
+ {undoFailed, Col}
+ end.
+
+%%------------------------------------------------------------------
+%% This function splits RowIndex which is part
+%% of a OID, into a list of the indexes for the
+%% table. So a table with indexes {integer, octet string},
+%% and a RowIndex [4,3,5,6,7], will be split into
+%% [4, [5,6,7]].
+%%------------------------------------------------------------------
+split_index_to_keys(Indexes, RowIndex) ->
+ collect_keys(Indexes, RowIndex).
+
+collect_keys([#asn1_type{bertype = 'INTEGER'} | Indexes], [IntKey | Keys]) ->
+ [IntKey | collect_keys(Indexes, Keys)];
+collect_keys([#asn1_type{bertype = 'Unsigned32'} | Indexes], [IntKey | Keys]) ->
+ [IntKey | collect_keys(Indexes, Keys)];
+collect_keys([#asn1_type{bertype = 'Counter32'} | Indexes], [IntKey | Keys]) ->
+ %% Should we allow this - counter in INDEX is strange!
+ [IntKey | collect_keys(Indexes, Keys)];
+collect_keys([#asn1_type{bertype = 'TimeTicks'} | Indexes], [IntKey | Keys]) ->
+ %% Should we allow this - timeticks in INDEX is strange!
+ [IntKey | collect_keys(Indexes, Keys)];
+collect_keys([#asn1_type{bertype = 'IpAddress'} | Indexes],
+ [A, B, C, D | Keys]) ->
+ [[A, B, C, D] | collect_keys(Indexes, Keys)];
+%% Otherwise, check if it has constant size
+collect_keys([#asn1_type{lo = X, hi = X} | Indexes], Keys)
+ when is_integer(X) andalso (length(Keys) >= X) ->
+ {StrKey, Rest} = collect_length(X, Keys, []),
+ [StrKey | collect_keys(Indexes, Rest)];
+collect_keys([#asn1_type{lo = X, hi = X} | _Indexes], Keys)
+ when is_integer(X) ->
+ exit({error, {size_mismatch, X, Keys}});
+%% Otherwise, its a dynamic-length type => its a list
+%% OBJECT IDENTIFIER, OCTET STRING or BITS (or derivatives)
+%% Check if it is IMPLIED (only last element can be IMPLIED)
+collect_keys([#asn1_type{implied = true}], Keys) ->
+ [Keys];
+collect_keys([_Type | Indexes], [Length | Keys]) when length(Keys) >= Length ->
+ {StrKey, Rest} = collect_length(Length, Keys, []),
+ [StrKey | collect_keys(Indexes, Rest)];
+collect_keys([_Type | _Indexes], [Length | Keys]) ->
+ exit({error, {size_mismatch, Length, Keys}});
+collect_keys([], []) -> [];
+collect_keys([], Keys) ->
+ exit({error, {bad_keys, Keys}});
+collect_keys(_Any, Key) -> [Key].
+
+collect_length(0, Rest, Rts) ->
+ {lists:reverse(Rts), Rest};
+collect_length(N, [El | Rest], Rts) ->
+ collect_length(N-1, Rest, [El | Rts]).
+
+%%------------------------------------------------------------------
+%% Checks if a certain row exists.
+%% Returns true or false.
+%%------------------------------------------------------------------
+table_row_exists(NameDb, RowIndex) ->
+ case table_get_element(NameDb, RowIndex, 1) of
+ undefined -> false;
+ _ -> true
+ end.
+
+%%------------------------------------------------------------------
+%% table_find(NameDb, Col, Value)
+%% Finds a row (if one exists) in table NameDb
+%% with column Col equals to Value.
+%% Returns the RowIndex of the row, or false
+%% if no row exists.
+%%------------------------------------------------------------------
+table_find(NameDb, Col, Value) -> table_find(NameDb, Col, Value, []).
+table_find(NameDb, Col, Value, Indexes) ->
+ case table_next(NameDb, Indexes) of
+ endOfTable ->
+ false;
+ NewIndexes ->
+ case table_get_element(NameDb, NewIndexes, Col) of
+ {value, Value} -> NewIndexes;
+ _Else -> table_find(NameDb, Col, Value, NewIndexes)
+ end
+ end.
+
+
+%%------------------------------------------------------------------
+%% find_col(Col, Cols)
+%% undefined if a Col for column Col doesn't exist.
+%% {value, Val} if a Col for Col with value Val exists.
+%%------------------------------------------------------------------
+find_col(_Col, []) -> undefined;
+find_col(Col, [{Col, Val} | _T]) -> {value, Val};
+find_col(Col, [_H | T]) -> find_col(Col, T).
+
+%%------------------------------------------------------------------
+%% check_mandatory_cols(ListOfCols, Cols)
+%% {noError 0}if all columns in ListOfCols are present in Cols.
+%% {inconsistentValue 0} otherwise. (Index = 0. It's hard to tell
+%% which Col is wrong, when the problem is that one is missing!)
+%%------------------------------------------------------------------
+% check_mandatory_cols([], _) -> {noError, 0};
+% check_mandatory_cols(_, []) -> {inconsistentValue, 0};
+% check_mandatory_cols([Col | Cols], [{Col, Val} | T]) ->
+% check_mandatory_cols(Cols, T);
+% check_mandatory_cols([Col | Cols], [{Col2, Val} | T]) ->
+% check_mandatory_cols([Col | Cols], T).
+
+
+try_apply(nofunc, _) -> {noError, 0};
+try_apply(F, Args) -> apply(F, Args).
+
+table_info({Name, _Db}) ->
+ case snmpa_symbolic_store:table_info(Name) of
+ {value, TI} ->
+ TI;
+ false ->
+ error({table_not_found, Name})
+ end;
+table_info(Name) ->
+ case snmpa_symbolic_store:table_info(Name) of
+ {value, TI} ->
+ TI;
+ false ->
+ error({table_not_found, Name})
+ end.
+
+variable_info({Name, _Db}) ->
+ case snmpa_symbolic_store:variable_info(Name) of
+ {value, VI} ->
+ VI;
+ false ->
+ error({variable_not_found, Name})
+ end;
+variable_info(Name) ->
+ case snmpa_symbolic_store:variable_info(Name) of
+ {value, VI} ->
+ VI;
+ false ->
+ error({variable_not_found, Name})
+ end.
+
+
+%%------------------------------------------------------------------
+%% This function is a simple consistency check
+%% function which could be used by the user-defined
+%% table functions.
+%% Check if the row has all information needed to
+%% make row notInService (from notReady). This is
+%% a simple check, which just checks if some col
+%% in the row has the value 'noinit'.
+%% If it has the information, the status is changed
+%% to notInService.
+%%------------------------------------------------------------------
+table_try_make_consistent(Name, RowIndex, _Cols) ->
+ TableInfo = table_info(Name),
+ case TableInfo#table_info.status_col of
+ StatusCol when is_integer(StatusCol) ->
+ {value, StatusVal} = table_get_element(Name, RowIndex, StatusCol),
+ table_try_make_consistent(Name, RowIndex, StatusVal, TableInfo);
+ _ ->
+ {noError, 0}
+ end.
+
+table_try_make_consistent(Name, RowIndex, ?'RowStatus_notReady', TableInfo) ->
+ %% this *should* be a generic function,
+ %% but since mnesia got its own try_mk_cons
+ %% and I don't have time to impl table_get_row
+ %% for mnesia I call snmpa_local_db:
+ Row = snmpa_local_db:table_get_row(Name, RowIndex),
+ case lists:member(noinit, tuple_to_list(Row)) of
+ true -> {noError, 0};
+ false ->
+ case catch table_set_element(Name, RowIndex,
+ TableInfo#table_info.status_col,
+ ?'RowStatus_notInService') of
+ true -> {noError, 0};
+ X ->
+ user_err("snmp_generic:table_try_make_consistent "
+ "set ~w to notInService returned ~w",
+ [{Name, RowIndex}, X]),
+ {commitFailed, TableInfo#table_info.status_col}
+ end
+ end;
+
+table_try_make_consistent(_Name, _RowIndex, _StatusVal, _TableInfo) ->
+ {noError, 0}.
+
+table_get_row({Name, mnesia}, RowIndex) ->
+ snmp_generic_mnesia:table_get_row(Name, RowIndex);
+table_get_row(NameDb, RowIndex) ->
+ snmpa_local_db:table_get_row(NameDb, RowIndex).
+
+table_get_row(NameDb, RowIndex, undefined) ->
+ table_get_row(NameDb, RowIndex);
+table_get_row({Name, mnesia}, RowIndex, FOI) ->
+ snmp_generic_mnesia:table_get_row(Name, RowIndex, FOI);
+table_get_row(NameDb, RowIndex, _FOI) ->
+ snmpa_local_db:table_get_row(NameDb, RowIndex).
+
+
+%%-----------------------------------------------------------------
+%% Purpose: These functions can be used by the user's instrum func
+%% to retrieve various table info.
+%%-----------------------------------------------------------------
+
+%%-----------------------------------------------------------------
+%% Description:
+%% Used by user's instrum func to check if mstatus column is
+%% modified.
+%%-----------------------------------------------------------------
+get_status_col(Name, Cols) ->
+ #table_info{status_col = StatusCol} = table_info(Name),
+ case lists:keysearch(StatusCol, 1, Cols) of
+ {value, {StatusCol, Val}} -> {ok, Val};
+ _ -> false
+ end.
+
+
+%%-----------------------------------------------------------------
+%% Description:
+%% Used by user's instrum func to get the table info. Specific parts
+%% or all of it. If all is selected then the result will be a tagged
+%% list of values.
+%%-----------------------------------------------------------------
+get_table_info(Name, nbr_of_cols) ->
+ get_nbr_of_cols(Name);
+get_table_info(Name, defvals) ->
+ get_defvals(Name);
+get_table_info(Name, status_col) ->
+ get_status_col(Name);
+get_table_info(Name, not_accessible) ->
+ get_not_accessible(Name);
+get_table_info(Name, index_types) ->
+ get_index_types(Name);
+get_table_info(Name, first_accessible) ->
+ get_first_accessible(Name);
+get_table_info(Name, first_own_index) ->
+ get_first_own_index(Name);
+get_table_info(Name, all) ->
+ TableInfo = table_info(Name),
+ [{nbr_of_cols, TableInfo#table_info.nbr_of_cols},
+ {defvals, TableInfo#table_info.defvals},
+ {status_col, TableInfo#table_info.status_col},
+ {not_accessible, TableInfo#table_info.not_accessible},
+ {index_types, TableInfo#table_info.index_types},
+ {first_accessible, TableInfo#table_info.first_accessible},
+ {first_own_index, TableInfo#table_info.first_own_index}].
+
+
+%%-----------------------------------------------------------------
+%% Description:
+%% Used by user's instrum func to get the index types.
+%%-----------------------------------------------------------------
+get_index_types(Name) ->
+ #table_info{index_types = IndexTypes} = table_info(Name),
+ IndexTypes.
+
+get_nbr_of_cols(Name) ->
+ #table_info{nbr_of_cols = NumberOfCols} = table_info(Name),
+ NumberOfCols.
+
+get_defvals(Name) ->
+ #table_info{defvals = DefVals} = table_info(Name),
+ DefVals.
+
+get_status_col(Name) ->
+ #table_info{status_col = StatusCol} = table_info(Name),
+ StatusCol.
+
+get_not_accessible(Name) ->
+ #table_info{not_accessible = NotAcc} = table_info(Name),
+ NotAcc.
+
+get_first_accessible(Name) ->
+ #table_info{first_accessible = FirstAcc} = table_info(Name),
+ FirstAcc.
+
+get_first_own_index(Name) ->
+ #table_info{first_own_index = FirstOwnIdx} = table_info(Name),
+ FirstOwnIdx.
+
+
+%%-----------------------------------------------------------------
+
+error(Reason) ->
+ throw({error, Reason}).
+
+user_err(F, A) ->
+ snmpa_error:user_err(F, A).
diff --git a/lib/snmp/src/agent/snmp_generic_mnesia.erl b/lib/snmp/src/agent/snmp_generic_mnesia.erl
new file mode 100644
index 0000000000..a73aad5b33
--- /dev/null
+++ b/lib/snmp/src/agent/snmp_generic_mnesia.erl
@@ -0,0 +1,400 @@
+%%
+%% %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%
+%%
+-module(snmp_generic_mnesia).
+
+-export([variable_get/1, variable_set/2, variable_inc/2]).
+-export([table_func/2, table_func/4,
+ table_set_cols/4, table_set_element/4, table_set_elements/3,
+ table_get_elements/4, table_get_row/2, table_get_row/3,
+ table_next/2,table_set_status/7,
+ table_try_make_consistent/2,
+ table_delete_row/2]).
+
+-include("STANDARD-MIB.hrl").
+-include("snmp_types.hrl").
+%% -include("snmp_generic.hrl").
+
+%%%-----------------------------------------------------------------
+%%% Generic functions for implementing software tables
+%%% and variables. Mnesia is used.
+%%%-----------------------------------------------------------------
+
+%%------------------------------------------------------------------
+%% Theses functions could be in the MIB for simple
+%% variables or tables, i.e. vars without complex
+%% set-operations. If there are complex set op, an
+%% extra layer-function should be added, and that
+%% function should be in the MIB, and it can call these
+%% functions.
+%%------------------------------------------------------------------
+
+%%------------------------------------------------------------------
+%% Variables
+%%------------------------------------------------------------------
+%%------------------------------------------------------------------
+%% This is the default function for variables.
+%%------------------------------------------------------------------
+variable_get(Name) ->
+ case mnesia:dirty_read({snmp_variables, Name}) of
+ [{_Db, _Name, Val}] -> {value, Val};
+ _ -> undefined
+ end.
+
+variable_set(Name, Val) ->
+ mnesia:dirty_write({snmp_variables, Name, Val}),
+ true.
+
+variable_inc(Name, N) ->
+ case mnesia:dirty_update_counter({snmp_variables, Name}, N) of
+ NewVal when NewVal < 4294967296 ->
+ ok;
+ NewVal ->
+ mnesia:dirty_write({snmp_variables, Name, NewVal rem 4294967296})
+ end.
+
+%%------------------------------------------------------------------
+%% Tables
+%% Assumes the RowStatus is the last column in the
+%% table.
+%%------------------------------------------------------------------
+%%------------------------------------------------------------------
+%% This is the default function for tables.
+%%
+%% Name is the name of the table (atom)
+%% RowIndex is a flat list of the indexes for the row.
+%% Cols is a list of column numbers.
+%%------------------------------------------------------------------
+table_func(new, _Name) ->
+ ok;
+
+table_func(delete, _Name) ->
+ ok.
+
+table_func(get, RowIndex, Cols, Name) ->
+ TableInfo = snmp_generic:table_info(Name),
+ snmp_generic:handle_table_get({Name, mnesia}, RowIndex, Cols,
+ TableInfo#table_info.first_own_index);
+
+%%------------------------------------------------------------------
+%% Returns: List of endOfTable | {NextOid, Value}.
+%% Implements the next operation, with the function
+%% handle_table_next. Next should return the next accessible
+%% instance, which cannot be a key (well, it could, but it
+%% shouldn't).
+%%------------------------------------------------------------------
+table_func(get_next, RowIndex, Cols, Name) ->
+ #table_info{first_accessible = FirstCol, first_own_index = FOI,
+ nbr_of_cols = LastCol} = snmp_generic:table_info(Name),
+ snmp_generic:handle_table_next({Name,mnesia},RowIndex,Cols,
+ FirstCol, FOI, LastCol);
+
+table_func(is_set_ok, RowIndex, Cols, Name) ->
+ snmp_generic:table_try_row({Name, mnesia}, nofunc, RowIndex, Cols);
+
+%%------------------------------------------------------------------
+%% Cols is here a list of {ColumnNumber, NewValue}
+%% This function must only be used by tables with a RowStatus col!
+%% Other tables should use table_set_cols/4.
+%% All set functionality is handled within a transaction.
+%%
+%% GenericMnesia uses its own table_set_status and own table_try_make_consistent
+%% for performance reasons.
+%%------------------------------------------------------------------
+table_func(set, RowIndex, Cols, Name) ->
+ case mnesia:transaction(
+ fun() ->
+ snmp_generic:table_set_row(
+ {Name, mnesia}, nofunc,
+ {snmp_generic_mnesia, table_try_make_consistent},
+ RowIndex, Cols)
+ end) of
+ {atomic, Value} ->
+ Value;
+ {aborted, Reason} ->
+ user_err("set transaction aborted. Tab ~w, RowIndex"
+ " ~w, Cols ~w. Reason ~w",
+ [Name, RowIndex, Cols, Reason]),
+ {Col, _Val} = hd(Cols),
+ {commitFailed, Col}
+ end;
+
+table_func(undo, _RowIndex, _Cols, _Name) ->
+ {noError, 0}.
+
+
+table_get_row(Name, RowIndex) ->
+ case mnesia:snmp_get_row(Name, RowIndex) of
+ {ok, DbRow} ->
+ TableInfo = snmp_generic:table_info(Name),
+ make_row(DbRow, TableInfo#table_info.first_own_index);
+ undefined ->
+ undefined
+ end.
+table_get_row(Name, RowIndex, FOI) ->
+ case mnesia:snmp_get_row(Name, RowIndex) of
+ {ok, DbRow} ->
+ make_row(DbRow, FOI);
+ undefined ->
+ undefined
+ end.
+
+%%-----------------------------------------------------------------
+%% Returns: [Val | noacc | noinit] | undefined
+%%-----------------------------------------------------------------
+table_get_elements(Name, RowIndex, Cols, FirstOwnIndex) ->
+ case mnesia:snmp_get_row(Name, RowIndex) of
+ {ok, DbRow} ->
+ Row = make_row(DbRow, FirstOwnIndex),
+ get_elements(Cols, Row);
+ undefined ->
+ undefined
+ end.
+
+get_elements([Col | Cols], Row) ->
+ [element(Col, Row) | get_elements(Cols, Row)];
+get_elements([], _Row) -> [].
+
+%%-----------------------------------------------------------------
+%% Args: DbRow is a mnesia row ({name, Keys, Cols, ...}).
+%% Returns: A tuple with a SNMP-table row. Each SNMP-col is one
+%% element, list or int.
+%%-----------------------------------------------------------------
+make_row(DbRow, 0) ->
+ [_Name, _Keys | Cols] = tuple_to_list(DbRow),
+ list_to_tuple(Cols);
+make_row(DbRow, FirstOwnIndex) ->
+ list_to_tuple(make_row2(make_row_list(DbRow), FirstOwnIndex)).
+make_row2(RowList, 1) -> RowList;
+make_row2([_OtherIndex | RowList], N) ->
+ make_row2(RowList, N-1).
+
+make_row_list(Row) ->
+ make_row_list(size(Row), Row, []).
+make_row_list(N, Row, Acc) when N > 2 ->
+ make_row_list(N-1, Row, [element(N, Row) | Acc]);
+make_row_list(2, Row, Acc) ->
+ case element(2, Row) of
+ Keys when is_tuple(Keys) ->
+ lists:append(tuple_to_list(Keys), Acc);
+ Key ->
+ [Key | Acc]
+ end.
+
+%% createAndGo
+table_set_status(Name, RowIndex, ?'RowStatus_createAndGo', _StatusCol, Cols,
+ ChangedStatusFunc, _ConsFunc) ->
+ Row = table_construct_row(Name, RowIndex, ?'RowStatus_active', Cols),
+ mnesia:write(Row),
+ snmp_generic:try_apply(ChangedStatusFunc, [Name, ?'RowStatus_createAndGo',
+ RowIndex, Cols]);
+
+%%------------------------------------------------------------------
+%% createAndWait - set status to notReady, and try to
+%% make row consistent.
+%%------------------------------------------------------------------
+table_set_status(Name, RowIndex, ?'RowStatus_createAndWait', _StatusCol,
+ Cols, ChangedStatusFunc, ConsFunc) ->
+ Row = table_construct_row(Name, RowIndex, ?'RowStatus_notReady', Cols),
+ mnesia:write(Row),
+ case snmp_generic:try_apply(ConsFunc, [RowIndex, Row]) of
+ {noError, 0} -> snmp_generic:try_apply(ChangedStatusFunc,
+ [Name, ?'RowStatus_createAndWait',
+ RowIndex, Cols]);
+ Error -> Error
+ end;
+
+%% destroy
+table_set_status(Name, RowIndex, ?'RowStatus_destroy', _StatusCol, Cols,
+ ChangedStatusFunc, _ConsFunc) ->
+ case snmp_generic:try_apply(ChangedStatusFunc,
+ [Name, ?'RowStatus_destroy', RowIndex, Cols]) of
+ {noError, 0} ->
+ #table_info{index_types = Indexes} = snmp_generic:table_info(Name),
+ Key =
+ case snmp_generic:split_index_to_keys(Indexes, RowIndex) of
+ [Key1] -> Key1;
+ KeyList -> list_to_tuple(KeyList)
+ end,
+ mnesia:delete({Name, Key}),
+ {noError, 0};
+ Error -> Error
+ end;
+
+%% Otherwise, active or notInService
+table_set_status(Name, RowIndex, Val, _StatusCol, Cols,
+ ChangedStatusFunc, ConsFunc) ->
+ table_set_cols(Name, RowIndex, Cols, ConsFunc),
+ snmp_generic:try_apply(ChangedStatusFunc, [Name, Val, RowIndex, Cols]).
+
+table_delete_row(Name, RowIndex) ->
+ case mnesia:snmp_get_mnesia_key(Name, RowIndex) of
+ {ok, Key} ->
+ mnesia:delete({Name, Key});
+ undefined ->
+ ok
+ end.
+
+
+%%------------------------------------------------------------------
+%% This function is a simple consistency check
+%% function which could be used by the user-defined
+%% table functions.
+%% Check if the row has all information needed to
+%% make row notInService (from notReady). This is
+%% a simple check, which just checks if some col
+%% in the row has the value 'noinit'.
+%% If it has the information, the status is changed
+%% to notInService.
+%%------------------------------------------------------------------
+table_try_make_consistent(RowIndex, NewDbRow) ->
+ Name = element(1, NewDbRow),
+ #table_info{first_own_index = FirstOwnIndex,
+ status_col = StatusCol, index_types = IT} =
+ snmp_generic:table_info(Name),
+ if
+ is_integer(StatusCol) ->
+ NewRow = make_row(NewDbRow, FirstOwnIndex),
+ StatusVal = element(StatusCol, NewRow),
+ AddCol = if
+ FirstOwnIndex == 0 -> 2;
+ true -> 1 + FirstOwnIndex - length(IT)
+ end,
+ table_try_make_consistent(Name, RowIndex, NewRow, NewDbRow,
+ AddCol, StatusCol, StatusVal);
+ true ->
+ {noError, 0}
+ end.
+
+
+table_try_make_consistent(Name, RowIndex, NewRow, NewDbRow,
+ AddCol, StatusCol, ?'RowStatus_notReady') ->
+ case lists:member(noinit, tuple_to_list(NewRow)) of
+ true -> {noError, 0};
+ false ->
+ table_set_element(Name, RowIndex, StatusCol,
+ ?'RowStatus_notInService'),
+ NewDbRow2 = set_new_row([{StatusCol, ?'RowStatus_notInService'}],
+ AddCol, NewDbRow),
+ mnesia:write(NewDbRow2),
+ {noError, 0}
+ end;
+
+table_try_make_consistent(_Name, _RowIndex, _NewRow, _NewDBRow,
+ _AddCol, _StatusCol, _StatusVal) ->
+ {noError, 0}.
+
+%%------------------------------------------------------------------
+%% Constructs a row that is to be stored in Mnesia, i.e.
+%% {Name, Key, Col1, ...} |
+%% {Name, {Key1, Key2, ..}, ColN, ColN+1...}
+%% dynamic key values are stored without length first.
+%% RowIndex is a list of the first elements. RowStatus is needed,
+%% because the provided value may not be stored, e.g. createAndGo
+%% should be active. If a value isn't specified in the Col list,
+%% then the corresponding value will be noinit.
+%%------------------------------------------------------------------
+table_construct_row(Name, RowIndex, Status, Cols) ->
+ #table_info{nbr_of_cols = LastCol, index_types = Indexes,
+ defvals = Defs, status_col = StatusCol,
+ first_own_index = FirstOwnIndex, not_accessible = NoAccs} =
+ snmp_generic:table_info(Name),
+ KeyList = snmp_generic:split_index_to_keys(Indexes, RowIndex),
+ OwnKeyList = snmp_generic:get_own_indexes(FirstOwnIndex, KeyList),
+ StartCol = length(OwnKeyList) + 1,
+ RowList = snmp_generic:table_create_rest(StartCol, LastCol,
+ StatusCol, Status, Cols, NoAccs),
+ L = snmp_generic:init_defaults(Defs, RowList, StartCol),
+ Keys = case KeyList of
+ [H] -> H;
+ _ -> list_to_tuple(KeyList)
+ end,
+ list_to_tuple([Name, Keys | L]).
+
+%%------------------------------------------------------------------
+%% table_set_cols/4
+%% can be used by the set procedure of all tables
+%% to set all columns in Cols, one at a time.
+%% ConsFunc is a check-consistency function, which will
+%% be called with the RowIndex of this row, when
+%% all columns are set. This is useful when the RowStatus
+%% could change, e.g. if the manager has provided all
+%% mandatory columns in this set operation.
+%% If ConsFunc is nofunc, no function will be called after all
+%% sets.
+%% Returns: {noError, 0} | {Error, Col}
+%%------------------------------------------------------------------
+table_set_cols(Name, RowIndex, Cols, ConsFunc) ->
+ table_set_elements(Name, RowIndex, Cols, ConsFunc).
+
+%%-----------------------------------------------------------------
+%% Col is _not_ a key column. A row in the db is stored as
+%% {Name, {Key1, Key2,...}, Col1, Col2, ...}
+%%-----------------------------------------------------------------
+table_set_element(Name, RowIndex, Col, NewVal) ->
+ #table_info{index_types = Indexes, first_own_index = FirstOwnIndex} =
+ snmp_generic:table_info(Name),
+ DbCol = if
+ FirstOwnIndex == 0 -> Col + 2;
+ true -> 1 + FirstOwnIndex - length(Indexes) + Col
+ end,
+ case mnesia:snmp_get_row(Name, RowIndex) of
+ {ok, DbRow} ->
+ NewDbRow = setelement(DbCol, DbRow, NewVal),
+ mnesia:write(NewDbRow),
+ true;
+ undefined ->
+ false
+ end.
+
+table_set_elements(Name, RowIndex, Cols) ->
+ case table_set_elements(Name, RowIndex, Cols, nofunc) of
+ {noError, 0} -> true;
+ _ -> false
+ end.
+table_set_elements(Name, RowIndex, Cols, ConsFunc) ->
+ #table_info{index_types = Indexes, first_own_index = FirstOwnIndex} =
+ snmp_generic:table_info(Name),
+ AddCol = if
+ FirstOwnIndex == 0 -> 2;
+ true -> 1 + FirstOwnIndex - length(Indexes)
+ end,
+ case mnesia:snmp_get_row(Name, RowIndex) of
+ {ok, DbRow} ->
+ NewDbRow = set_new_row(Cols, AddCol, DbRow),
+ mnesia:write(NewDbRow),
+ snmp_generic:try_apply(ConsFunc, [RowIndex, NewDbRow]);
+ undefined ->
+ {Col, _Val} = hd(Cols),
+ {commitFailed, Col}
+ end.
+
+set_new_row([{Col, Val} | Cols], AddCol, Row) ->
+ set_new_row(Cols, AddCol, setelement(Col+AddCol, Row, Val));
+set_new_row([], _AddCol, Row) ->
+ Row.
+
+table_next(Name, RestOid) ->
+ case mnesia:snmp_get_next_index(Name, RestOid) of
+ {ok, NextIndex} -> NextIndex;
+ endOfTable -> endOfTable
+ end.
+
+
+user_err(F, A) ->
+ snmpa_error:user_err(F, A).
diff --git a/lib/snmp/src/agent/snmp_index.erl b/lib/snmp/src/agent/snmp_index.erl
new file mode 100644
index 0000000000..1902fe2613
--- /dev/null
+++ b/lib/snmp/src/agent/snmp_index.erl
@@ -0,0 +1,163 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1997-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%
+%%
+-module(snmp_index).
+
+-export([new/1, new/2,
+ insert/3,
+ delete/1, delete/2,
+ get/2, get_next/2,
+ get_last/1,
+ key_to_oid/2]).
+
+
+-define(VMODULE,"IDX").
+-include("snmp_verbosity.hrl").
+
+-record(tab, {id, keys}).
+
+-define(badarg(F, A), exit({badarg, {?MODULE, F, A}})).
+-define(bad_new(A), ?badarg(new, A)).
+-define(bad_get(A), ?badarg(get, A)).
+
+
+%%%-----------------------------------------------------------------
+%%% This module implements an SNMP index structure as an ADT.
+%%% It is supposed to be used as a separate structure which implements
+%%% the SNMP ordering of the keys in the SNMP table. The advantage
+%%% with this is that the get-next operation is automatically
+%%% taken care of.
+%%%-----------------------------------------------------------------
+
+%%-----------------------------------------------------------------
+%% Args: KeyTypes = key() | {key(), ...}
+%% key() = integer | string | fix_string
+%% Returns: handle()
+%%-----------------------------------------------------------------
+
+new(KeyTypes) ->
+ ?vlog("new -> entry with"
+ "~n KeyTypes: ~p", [KeyTypes]),
+ do_new(KeyTypes, ?MODULE, [public, ordered_set]).
+
+new(KeyTypes, Name) when is_atom(Name) ->
+ ?vlog("new -> entry with"
+ "~n KeyTypes: ~p"
+ "~n Name: ~p", [KeyTypes, Name]),
+ do_new(KeyTypes, Name, [public, ordered_set, named_table]);
+new(KeyTypes, Name) ->
+ ?vinfo("new -> bad data"
+ "~n KeyTypes: ~p"
+ "~n Name: ~p", [KeyTypes, Name]),
+ ?bad_new([KeyTypes, Name]).
+
+do_new(KeyTypes, EtsName, EtsOpts) ->
+ ?vdebug("do_new -> entry with"
+ "~n KeyTypes: ~p"
+ "~n EtsName: ~p"
+ "~n EtsOpts: ~p", [KeyTypes, EtsName, EtsOpts]),
+ case is_snmp_type(to_list(KeyTypes)) of
+ true ->
+ Tab = #tab{id = ets:new(EtsName, EtsOpts), keys = KeyTypes},
+ ?vtrace("do_new -> "
+ "~n Tab: ~p", [Tab]),
+ Tab;
+ false ->
+ ?bad_new([KeyTypes, EtsName])
+ end.
+
+
+get(#tab{id = OrdSet}, KeyOid) ->
+ ?vlog("get -> entry with"
+ "~n OrdSet: ~p"
+ "~n KeyOid: ~p", [OrdSet, KeyOid]),
+ case ets:lookup(OrdSet, KeyOid) of
+ [X] ->
+ {ok, X};
+ _ ->
+ undefined
+ end.
+
+
+
+get_next(#tab{id = OrdSet} = Tab, KeyOid) ->
+ ?vlog("get_next -> entry with"
+ "~n Tab: ~p"
+ "~n KeyOid: ~p", [Tab, KeyOid]),
+ case ets:next(OrdSet, KeyOid) of
+ '$end_of_table' ->
+ undefined;
+ Key ->
+ get(Tab, Key)
+ end.
+
+get_last(#tab{id = OrdSet} = Tab) ->
+ ?vlog("get_last -> entry with"
+ "~n Tab: ~p", [Tab]),
+ case ets:last(OrdSet) of
+ '$end_of_table' ->
+ undefined;
+ Key ->
+ get(Tab, Key)
+ end.
+
+insert(#tab{id = OrdSet, keys = KeyTypes} = Tab, Key, Val) ->
+ ets:insert(OrdSet, {key_to_oid_i(Key, KeyTypes), Val}),
+ Tab.
+
+delete(#tab{id = OrdSet, keys = KeyTypes} = Tab, Key) ->
+ ets:delete(OrdSet, key_to_oid_i(Key, KeyTypes)),
+ Tab.
+
+delete(#tab{id = OrdSet}) ->
+ ets:delete(OrdSet).
+
+key_to_oid(#tab{keys = KeyTypes}, Key) ->
+ key_to_oid_i(Key, KeyTypes).
+
+to_list(Tuple) when is_tuple(Tuple) -> tuple_to_list(Tuple);
+to_list(X) -> [X].
+
+is_snmp_type([integer | T]) -> is_snmp_type(T);
+is_snmp_type([string | T]) -> is_snmp_type(T);
+is_snmp_type([fix_string | T]) -> is_snmp_type(T);
+is_snmp_type([]) -> true;
+is_snmp_type(_) -> false.
+
+
+%%-----------------------------------------------------------------
+%% Args: Key = key()
+%% key() = int() | string() | {int() | string(), ...}
+%% Type = {fix_string | term()}
+%% Make an OBJECT IDENTIFIER out of it.
+%% Variable length objects are prepended by their length.
+%% Ex. Key = {"pelle", 42} AND Type = {string, integer} =>
+%% OID [5, $p, $e, $l, $l, $e, 42]
+%% Key = {"pelle", 42} AND Type = {fix_string, integer} =>
+%% OID [$p, $e, $l, $l, $e, 42]
+%%-----------------------------------------------------------------
+key_to_oid_i(Key, _Type) when is_integer(Key) -> [Key];
+key_to_oid_i(Key, fix_string) -> Key;
+key_to_oid_i(Key, _Type) when is_list(Key) -> [length(Key) | Key];
+key_to_oid_i(Key, Types) -> keys_to_oid(size(Key), Key, [], Types).
+
+keys_to_oid(0, _Key, Oid, _Types) -> Oid;
+keys_to_oid(N, Key, Oid, Types) ->
+ Oid2 = lists:append(key_to_oid_i(element(N, Key), element(N, Types)), Oid),
+ keys_to_oid(N-1, Key, Oid2, Types).
+
diff --git a/lib/snmp/src/agent/snmp_notification_mib.erl b/lib/snmp/src/agent/snmp_notification_mib.erl
new file mode 100644
index 0000000000..16e43f05d7
--- /dev/null
+++ b/lib/snmp/src/agent/snmp_notification_mib.erl
@@ -0,0 +1,457 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1998-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%
+%%
+-module(snmp_notification_mib).
+
+-export([configure/1, reconfigure/1, invalidate_cache/0,
+ snmpNotifyTable/1, snmpNotifyTable/3,
+ snmpNotifyFilterTable/3, snmpNotifyFilterProfileTable/3,
+ get_targets/0, get_targets/1]).
+-export([add_notify/3, delete_notify/1]).
+-export([check_notify/1]).
+
+-include("SNMP-NOTIFICATION-MIB.hrl").
+-include("SNMPv2-TC.hrl").
+-include("snmp_tables.hrl").
+
+-define(VMODULE,"NOTIFICATION-MIB").
+-include("snmp_verbosity.hrl").
+
+-ifndef(default_verbosity).
+-define(default_verbosity,silence).
+-endif.
+
+
+%%-----------------------------------------------------------------
+%% Func: configure/1
+%% Args: Dir is the directory where the configuration files are found.
+%% Purpose: If the tables doesn't exist, this function reads
+%% the config-files for the notify tables, and
+%% inserts the data. This means that the data in the tables
+%% survive a reboot. However, the StorageType column is
+%% checked for each row. If volatile, the row is deleted.
+%% Returns: ok
+%% Fails: exit(configuration_error)
+%%-----------------------------------------------------------------
+configure(Dir) ->
+ set_sname(),
+ case db(snmpNotifyTable) of
+ {_, mnesia} ->
+ ?vlog("notification table in mnesia: cleanup",[]),
+ gc_tabs();
+ TabDb ->
+ case snmpa_local_db:table_exists(TabDb) of
+ true ->
+ ?vlog("notification table exist: cleanup",[]),
+ gc_tabs();
+ false ->
+ ?vlog("notification table does not exist: reconfigure",[]),
+ reconfigure(Dir)
+ end
+ end.
+
+%%-----------------------------------------------------------------
+%% Func: reconfigure/1
+%% Args: Dir is the directory where the configuration files are found.
+%% Purpose: Reads the config-files for the notify tables, and
+%% inserts the data. Makes sure that all old data in
+%% the tables are deleted, and the new data inserted.
+%% This function makes sure that all (and only)
+%% config-file-data are in the tables.
+%% Returns: ok
+%% Fails: exit(configuration_error)
+%%-----------------------------------------------------------------
+reconfigure(Dir) ->
+ set_sname(),
+ case (catch do_reconfigure(Dir)) of
+ ok ->
+ ok;
+ {error, Reason} ->
+ ?vinfo("reconfigure error: ~p", [Reason]),
+ config_err("reconfigure failed: ~p", [Reason]),
+ exit(configuration_error);
+ Error ->
+ ?vinfo("reconfigure failed: ~p", [Error]),
+ config_err("reconfigure failed: ~p", [Error]),
+ exit(configuration_error)
+ end.
+
+do_reconfigure(Dir) ->
+ ?vdebug("read notify config files",[]),
+ Notifs = read_notify_config_files(Dir),
+ init_tabs(Notifs),
+ ?vdebug("invalidate cache",[]),
+ invalidate_cache(),
+ ok.
+
+
+read_notify_config_files(Dir) ->
+ ?vdebug("read notify config file",[]),
+ Gen = fun(_) -> ok end,
+ Filter = fun(Notifs) -> Notifs end,
+ Check = fun(Entry) -> check_notify(Entry) end,
+ [Notifs] =
+ snmp_conf:read_files(Dir, [{Gen, Filter, Check, "notify.conf"}]),
+ Notifs.
+
+check_notify({Name, Tag, Type}) ->
+ snmp_conf:check_string(Name,{gt,0}),
+ snmp_conf:check_string(Tag),
+ {ok, Val} = snmp_conf:check_atom(Type, [{trap, 1}, {inform, 2}]),
+ Notify = {Name, Tag, Val,
+ ?'StorageType_nonVolatile', ?'RowStatus_active'},
+ {ok, Notify};
+check_notify(X) ->
+ error({invalid_notify, X}).
+
+
+init_tabs(Notifs) ->
+ ?vdebug("create notify table",[]),
+ snmpa_local_db:table_delete(db(snmpNotifyTable)),
+ snmpa_local_db:table_create(db(snmpNotifyTable)),
+ ?vdebug("initiate notify table",[]),
+ init_notify_table(Notifs).
+
+init_notify_table([Row | T]) ->
+ Key = element(1, Row),
+ snmpa_local_db:table_create_row(db(snmpNotifyTable), Key, Row),
+ init_notify_table(T);
+init_notify_table([]) -> true.
+
+table_cre_row(Tab, Key, Row) ->
+ snmpa_mib_lib:table_cre_row(db(Tab), Key, Row).
+
+table_del_row(Tab, Key) ->
+ snmpa_mib_lib:table_del_row(db(Tab), Key).
+
+
+%% FIXME: does not work with mnesia
+add_notify(Name, Tag, Type) ->
+ Notif = {Name, Tag, Type},
+ case (catch check_notify(Notif)) of
+ {ok, Row} ->
+ Key = element(1, Row),
+ case table_cre_row(snmpNotifyTable, Key, Row) of
+ true ->
+ {ok, Key};
+ false ->
+ {error, create_failed}
+ end;
+ {error, Reason} ->
+ {error, Reason};
+ Error ->
+ {error, Error}
+ end.
+
+%% FIXME: does not work with mnesia
+delete_notify(Key) ->
+ case table_del_row(snmpNotifyTable, Key) of
+ true ->
+ ok;
+ false ->
+ {error, delete_failed}
+ end.
+
+gc_tabs() ->
+ DB = db(snmpNotifyTable),
+ STC = stc(snmpNotifyTable),
+ FOI = foi(snmpNotifyTable),
+ snmpa_mib_lib:gc_tab(DB, STC, FOI),
+ ok.
+
+
+%%-----------------------------------------------------------------
+%% Func: get_targets()
+%% get_targets(NotifyName) -> [Target]
+%% Types: Target = {DestAddr, TargetName, TargetParams, NotifyType}
+%% NotifyName = string() - the INDEX
+%% DestAddr = {TDomain, TAddr}
+%% TagrgetName = string()
+%% TargetParams = {MpModel, SecModel, SecName, SecLevel}
+%% NotifyType = trap | {inform, Timeout, Retry}
+%% Purpose: Returns a list of all targets. Called by snmpa_trap
+%% when a trap should be sent.
+%% If a NotifyName is specified, the targets for that
+%% name is returned.
+%%-----------------------------------------------------------------
+get_targets() ->
+ TargetsFun = fun find_targets/0,
+ snmpa_target_cache:targets(TargetsFun).
+
+get_targets(NotifyName) ->
+ TargetsFun = fun find_targets/0,
+ snmpa_target_cache:targets(TargetsFun, NotifyName).
+
+
+%%-----------------------------------------------------------------
+%% We use a cache of targets to avoid searching the tables each
+%% time a trap is sent. When some of the 3 tables (notify,
+%% targetAddr, targetParams) is modified, the cache is invalidated.
+%%-----------------------------------------------------------------
+
+invalidate_cache() ->
+ snmpa_target_cache:invalidate().
+
+
+%% Ret: [{NotifyName, {DestAddr, TargetName, TargetParams, NotifyType}}]
+%% NotifyType = trap | {inform, Timeout. Retry}
+%% DestAddr = {Domain, Addr} ; e.g. {snmpUDPDomain, {IPasList, UdpPort}}
+
+find_targets() ->
+ TargAddrs = snmp_target_mib:get_target_addrs(),
+ %% TargAddrs = [{TagList,DestAddr,TargetName,TargetParams,Timeout,Retry}]
+ {_, Db} = db(snmpNotifyTable),
+ find_targets([], TargAddrs, Db, []).
+find_targets(Key, TargAddrs, Db, Res) ->
+ case table_next(snmpNotifyTable, Key) of
+ endOfTable ->
+ Res;
+ NextKey when Db == mnesia ->
+ case mnesia:snmp_get_row(snmpNotifyTable, NextKey) of
+ {ok, #snmpNotifyTable{
+ snmpNotifyTag = Tag,
+ snmpNotifyType = Type,
+ snmpNotifyRowStatus = ?'RowStatus_active'}} ->
+ ?vtrace("found notify entry for ~w"
+ "~n Tag: ~w"
+ "~n Type: ~w", [NextKey, Tag, Type]),
+ Targs = get_targets(TargAddrs, Tag, Type, NextKey),
+ find_targets(NextKey, TargAddrs, Db, Targs ++ Res);
+ {ok, #snmpNotifyTable{
+ snmpNotifyTag = Tag,
+ snmpNotifyType = Type,
+ snmpNotifyRowStatus = RowStatus}} ->
+ ?vtrace("found invalid notify entry for ~w"
+ "~n Tag: ~w"
+ "~n Type: ~w"
+ "~n RowStatus: ~p",
+ [NextKey, Tag, Type, RowStatus]),
+ find_targets(NextKey, TargAddrs, Db, Res);
+ _ ->
+ ?vtrace("notify entry not found for ~w", [NextKey]),
+ find_targets(NextKey, TargAddrs, Db, Res)
+ end;
+ NextKey ->
+ Elements = [?snmpNotifyTag, ?snmpNotifyType, ?snmpNotifyRowStatus],
+ case snmpNotifyTable(get, NextKey, Elements) of
+ [{value, Tag}, {value, Type}, {value, ?'RowStatus_active'}] ->
+ ?vtrace("found notify entry for ~w"
+ "~n Tag: ~w"
+ "~n Type: ~w", [NextKey, Tag, Type]),
+ Targs = get_targets(TargAddrs, Tag, Type, NextKey),
+ find_targets(NextKey, TargAddrs, Db, Targs ++ Res);
+ [{value, Tag1}, {value, Type1}, {value, RowStatus}] ->
+ ?vtrace("found invalid notify entry for ~w"
+ "~n Tag: ~w"
+ "~n Type: ~w"
+ "~n RowStatus: ~w",
+ [NextKey, Tag1, Type1, RowStatus]),
+ find_targets(NextKey, TargAddrs, Db, Res);
+ _ ->
+ ?vtrace("notify entry not found for ~w", [NextKey]),
+ find_targets(NextKey, TargAddrs, Db, Res)
+ end
+ end.
+
+get_targets([{TagList, Addr, TargetName, Params, Timeout, Retry}|T],
+ Tag, Type, Name) ->
+ case snmp_misc:is_tag_member(Tag, TagList) of
+ true -> [{Name, {Addr, TargetName, Params, type(Type, Timeout, Retry)}}|
+ get_targets(T, Tag, Type, Name)];
+ false ->
+ get_targets(T, Tag, Type, Name)
+ end;
+get_targets([], _Tag, _Type, _Name) ->
+ [].
+
+type(trap, _, _) -> trap;
+type(1, _, _) -> trap; %% OTP-4329
+type(inform, Timeout, Retry) -> {inform, Timeout, Retry};
+type(2, Timeout, Retry) -> {inform, Timeout, Retry}. %% OTP-4329
+
+
+%%-----------------------------------------------------------------
+%% Instrumentation Functions
+%%-----------------------------------------------------------------
+%% Op = print - Used for debugging purposes
+snmpNotifyTable(print) ->
+ Table = snmpNotifyTable,
+ DB = db(Table),
+ FOI = foi(Table),
+ PrintRow =
+ fun(Prefix, Row) ->
+ lists:flatten(
+ io_lib:format("~sName: ~p"
+ "~n~sTag: ~p"
+ "~n~sType: ~p (~w)"
+ "~n~sStorageType: ~p (~w)"
+ "~n~sStatus: ~p (~w)",
+ [Prefix, element(?snmpNotifyName, Row),
+ Prefix, element(?snmpNotifyTag, Row),
+ Prefix, element(?snmpNotifyType, Row),
+ case element(?snmpNotifyType, Row) of
+ ?snmpNotifyType_inform -> inform;
+ ?snmpNotifyType_trap -> trap;
+ _ -> undefined
+ end,
+ Prefix, element(?snmpNotifyStorageType, Row),
+ case element(?snmpNotifyStorageType, Row) of
+ ?'snmpNotifyStorageType_readOnly' -> readOnly;
+ ?'snmpNotifyStorageType_permanent' -> permanent;
+ ?'snmpNotifyStorageType_nonVolatile' -> nonVolatile;
+ ?'snmpNotifyStorageType_volatile' -> volatile;
+ ?'snmpNotifyStorageType_other' -> other;
+ _ -> undefined
+ end,
+ Prefix, element(?snmpNotifyRowStatus, Row),
+ case element(?snmpNotifyRowStatus, Row) of
+ ?'snmpNotifyRowStatus_destroy' -> destroy;
+ ?'snmpNotifyRowStatus_createAndWait' -> createAndWait;
+ ?'snmpNotifyRowStatus_createAndGo' -> createAndGo;
+ ?'snmpNotifyRowStatus_notReady' -> notReady;
+ ?'snmpNotifyRowStatus_notInService' -> notInService;
+ ?'snmpNotifyRowStatus_active' -> active;
+ _ -> undefined
+ end]))
+ end,
+ snmpa_mib_lib:print_table(Table, DB, FOI, PrintRow);
+%% Op == new | delete
+snmpNotifyTable(Op) ->
+ snmp_generic:table_func(Op, db(snmpNotifyTable)).
+
+%% Op == get | is_set_ok | set | get_next
+snmpNotifyTable(get, RowIndex, Cols) ->
+ %% BMK BMK BMK BMK
+ get(snmpNotifyTable, RowIndex, Cols);
+snmpNotifyTable(get_next, RowIndex, Cols) ->
+ %% BMK BMK BMK BMK
+ next(snmpNotifyTable, RowIndex, Cols);
+snmpNotifyTable(set, RowIndex, Cols0) ->
+ %% BMK BMK BMK BMK
+ case (catch verify_snmpNotifyTable_cols(Cols0, [])) of
+ {ok, Cols} ->
+ invalidate_cache(),
+ %% invalidate_cache(RowIndex),
+ Db = db(snmpNotifyTable),
+ snmp_generic:table_func(set, RowIndex, Cols, Db);
+ Error ->
+ Error
+ end;
+snmpNotifyTable(is_set_ok, RowIndex, Cols0) ->
+ case (catch verify_snmpNotifyTable_cols(Cols0, [])) of
+ {ok, Cols} ->
+ Db = db(snmpNotifyTable),
+ snmp_generic:table_func(is_set_ok, RowIndex, Cols, Db);
+ Error ->
+ Error
+ end;
+snmpNotifyTable(Op, Arg1, Arg2) ->
+ snmp_generic:table_func(Op, Arg1, Arg2, db(snmpNotifyTable)).
+
+
+verify_snmpNotifyTable_cols([], Cols) ->
+ {ok, lists:reverse(Cols)};
+verify_snmpNotifyTable_cols([{Col, Val0}|Cols], Acc) ->
+ Val = verify_snmpNotifyTable_col(Col, Val0),
+ verify_snmpNotifyTable_cols(Cols, [{Col, Val}|Acc]).
+
+verify_snmpNotifyTable_col(?snmpNotifyName, Name) ->
+ case (catch snmp_conf:check_string(Name, {gt, 0})) of
+ ok ->
+ Name;
+ _ ->
+ wrongValue(?snmpNotifyName)
+ end;
+verify_snmpNotifyTable_col(?snmpNotifyTag, Tag) ->
+ case (catch snmp_conf:check_string(Tag)) of
+ ok ->
+ Tag;
+ _ ->
+ wrongValue(?snmpNotifyTag)
+ end;
+verify_snmpNotifyTable_col(?snmpNotifyType, Type) ->
+ case Type of
+ trap -> 1;
+ inform -> 2;
+ 1 -> 1;
+ 2 -> 2;
+ _ -> wrongValue(?snmpNotifyType)
+ end;
+verify_snmpNotifyTable_col(_, Val) ->
+ Val.
+
+
+%%-----------------------------------------------------------------
+%% In this version of the agent, we don't support notification
+%% filters.
+%%-----------------------------------------------------------------
+snmpNotifyFilterTable(get, _RowIndex, Cols) ->
+ lists:map(fun(_Col) -> {noValue, noSuchObject} end, Cols);
+snmpNotifyFilterTable(get_next, _RowIndex, Cols) ->
+ lists:map(fun(_Col) -> endOfTable end, Cols);
+snmpNotifyFilterTable(is_set_ok, _RowIndex, Cols) ->
+ {notWritable, element(1, hd(Cols))}.
+
+snmpNotifyFilterProfileTable(get, _RowIndex, Cols) ->
+ lists:map(fun(_Col) -> {noValue, noSuchObject} end, Cols);
+snmpNotifyFilterProfileTable(get_next, _RowIndex, Cols) ->
+ lists:map(fun(_Col) -> endOfTable end, Cols);
+snmpNotifyFilterProfileTable(is_set_ok, _RowIndex, Cols) ->
+ {notWritable, element(1, hd(Cols))}.
+
+
+db(X) -> snmpa_agent:db(X).
+
+fa(snmpNotifyTable) -> ?snmpNotifyTag.
+
+foi(snmpNotifyTable) -> ?snmpNotifyName.
+
+noc(snmpNotifyTable) -> 5.
+
+stc(snmpNotifyTable) -> ?snmpNotifyStorageType.
+
+next(Name, RowIndex, Cols) ->
+ snmp_generic:handle_table_next(db(Name), RowIndex, Cols,
+ fa(Name), foi(Name), noc(Name)).
+
+table_next(Name, RestOid) ->
+ snmp_generic:table_next(db(Name), RestOid).
+
+
+get(Name, RowIndex, Cols) ->
+ snmp_generic:handle_table_get(db(Name), RowIndex, Cols, foi(Name)).
+
+
+wrongValue(V) -> throw({wrongValue, V}).
+
+
+%% -----
+
+set_sname() ->
+ set_sname(get(sname)).
+
+set_sname(undefined) ->
+ put(sname,conf);
+set_sname(_) -> %% Keep it, if already set.
+ ok.
+
+error(Reason) ->
+ throw({error, Reason}).
+
+config_err(F, A) ->
+ snmpa_error:config_err("[NOTIFICATION-MIB]: " ++ F, A).
diff --git a/lib/snmp/src/agent/snmp_shadow_table.erl b/lib/snmp/src/agent/snmp_shadow_table.erl
new file mode 100644
index 0000000000..34543d542b
--- /dev/null
+++ b/lib/snmp/src/agent/snmp_shadow_table.erl
@@ -0,0 +1,187 @@
+%%
+%% %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%
+%%
+-module(snmp_shadow_table).
+
+-export([table_func/2, table_func/4]).
+
+-include("snmpa_internal.hrl").
+
+-record(time_stamp, {key, data}).
+
+-define(verify(Expr, Error), verify(catch Expr, Error, ?FILE, ?LINE)).
+
+verify(Res, Error, File, Line) ->
+ case Res of
+ {atomic, _} ->
+ Res;
+ ok ->
+ Res;
+ _ ->
+ error_msg("~s(~w): crashed ~p -> ~p ~p~n",
+ [File, Line, Error, Res, process_info(self())]),
+ Res
+ end.
+
+
+%%%-----------------------------------------------------------------
+%%% This module contains generic functions for implementing an SNMP
+%%% table as a 'shadow'-table in Mnesia. This means that for the
+%%% SNMP table, there exists one Mnesia table with all information
+%%% of the table.
+%%% The Mnesia table is updated whenever an SNMP request is issued
+%%% for the table and a specified amount of time has past since the
+%%% last update.
+%%% This is implemented as instrumentation functions to be used
+%%% for the table.
+%%%-----------------------------------------------------------------
+
+create_time_stamp_table() ->
+ Props = [{type, set},
+ {attributes, record_info(fields, time_stamp)}],
+ create_table(time_stamp, Props, ram_copies, false),
+ NRef =
+ case mnesia:dirty_read({time_stamp, ref_count}) of
+ [] -> 1;
+ [#time_stamp{data = Ref}] -> Ref + 1
+ end,
+ ok = mnesia:dirty_write(#time_stamp{key = ref_count, data = NRef}).
+
+delete_time_stamp_table() ->
+ Tab = time_stamp,
+ case catch mnesia:dirty_read({Tab, ref_count}) of
+ {'EXIT', _Reason} ->
+ delete_table(Tab);
+ [] ->
+ delete_table(Tab);
+ [#time_stamp{data = 1}] ->
+ delete_table(Tab);
+ [#time_stamp{data = Ref}] ->
+ ok = mnesia:dirty_write(#time_stamp{key = ref_count, data = Ref - 1})
+ end.
+
+update(Name, UpdateFunc, Interval) ->
+ CurrentTime = get_time(),
+ case mnesia:dirty_read({time_stamp, Name}) of
+ [#time_stamp{data = Expire}] when CurrentTime =< Expire -> ok;
+ _ ->
+ UpdateFunc(),
+ ok = mnesia:dirty_write(#time_stamp{key = Name,
+ data = CurrentTime + Interval})
+ end.
+
+
+%%-----------------------------------------------------------------
+%% Func: table_func(Op, Extra)
+%% table_func(Op, RowIndex, Cols, Extra)
+%% Args: Extra = {Name, SnmpKey, Attributes, Interval, UpdateFunc}
+%% Purpose: Instrumentation function for the table.
+%% Name is the name of the table
+%% SnmpKey is the snmpkey as it should be specifed in order
+%% to create the Mnesia table as an SNMP table
+%% Attributes is the attributes as it should be specifed in order
+%% to create the Mnesia table as an SNMP table
+%% Interval is the minimum time in milliseconds between two
+%% updates of the table
+%% UpdateFunc is a function with no arguments that is called
+%% whenever the table must be updated
+%% Returns: As specified for an SNMP table instrumentation function.
+%%-----------------------------------------------------------------
+table_func(new, {Name, SnmpKey, Attribs, _Interval, _UpdateFunc}) ->
+ create_time_stamp_table(),
+ Props = [{type, set},
+ {snmp, [{key, SnmpKey}]},
+ {attributes, Attribs}],
+ create_table(Name, Props, ram_copies, true);
+table_func(delete, {Name, _SnmpKey, _Attribs, _Interval, _UpdateFunc}) ->
+ delete_time_stamp_table(),
+ delete_table(Name).
+
+table_func(Op, RowIndex, Cols,
+ {Name, _SnmpKey, _Attribs, Interval, UpdateFunc}) ->
+ update(Name, UpdateFunc, Interval),
+ snmp_generic:table_func(Op, RowIndex, Cols, {Name, mnesia}).
+
+get_time() ->
+ {M,S,U} = erlang:now(),
+ 1000000000 * M + 1000 * S + (U div 1000).
+
+%%-----------------------------------------------------------------
+%% Urrk.
+%% We want named tables, without schema info; the tables should
+%% be locally named, but if the node crashes, info about the
+%% table shouldn't be kept. We could use ets tables for this.
+%% BUT, we also want the snmp functionality, therefore we must
+%% use mnesia.
+%% The problem arises when the node that implements these tables
+%% crashes, and another node takes over the MIB-implementations.
+%% That node cannot create the shadow tables again, because they
+%% already exist (according to mnesia...). Therefore, we must
+%% check if we maybe must delete the table first, and then create
+%% it again.
+%%-----------------------------------------------------------------
+create_table(Tab, Props, Storage, DeleteAll) ->
+ case lists:member(Tab, mnesia:system_info(tables)) of
+ true ->
+ case mnesia:table_info(Tab, storage_type) of
+ unknown ->
+ ?verify(mnesia:add_table_copy(Tab, node(), Storage),
+ [add_table_copy, Tab, node(), Storage]);
+ Storage when DeleteAll == true ->
+ delete_all(Tab);
+ _ ->
+ ignore
+ end;
+ false ->
+ Nodes = [node()],
+ Props2 = [{local_content, true}, {Storage, Nodes}] ++ Props,
+ ?verify(mnesia:create_table(Tab, Props2),
+ [create_table, Tab, Props2])
+ end.
+
+delete_all(Tab) ->
+ delete_all(mnesia:dirty_first(Tab), Tab).
+
+delete_all('$end_of_table', _Tab) ->
+ ok;
+delete_all(Key, Tab) ->
+ ok = mnesia:dirty_delete({Tab, Key}),
+ delete_all(mnesia:dirty_next(Tab, Key), Tab).
+
+delete_table(Tab) ->
+ case lists:member(Tab, mnesia:system_info(tables)) of
+ true ->
+ case ?verify(mnesia:del_table_copy(Tab, node()),
+ [del_table_copy, Tab, node()]) of
+ {atomic, ok} ->
+ ok;
+ {aborted, _Reason} ->
+ catch delete_all(Tab),
+ ok
+ end;
+ false ->
+ ok
+ end.
+
+
+%%-----------------------------------------------------------------
+
+error_msg(F, A) ->
+ ?snmpa_error(F, A).
+
+
diff --git a/lib/snmp/src/agent/snmp_standard_mib.erl b/lib/snmp/src/agent/snmp_standard_mib.erl
new file mode 100644
index 0000000000..3928a8afe6
--- /dev/null
+++ b/lib/snmp/src/agent/snmp_standard_mib.erl
@@ -0,0 +1,316 @@
+%%
+%% %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%
+%%
+-module(snmp_standard_mib).
+
+%%%-----------------------------------------------------------------
+%%% This module implements the configure- and reinit-functions
+%%% for the STANDARD-MIB and SNMPv2-MIB.
+%%%-----------------------------------------------------------------
+
+-include("snmp_types.hrl").
+-include("STANDARD-MIB.hrl").
+
+-define(VMODULE,"STANDARD-MIB").
+-include("snmp_verbosity.hrl").
+
+-define(enabled, 1).
+-define(disabled, 2).
+
+%% External exports
+-export([configure/1, reconfigure/1, reset/0, sys_up_time/0, sys_up_time/1,
+ snmp_enable_authen_traps/1, snmp_enable_authen_traps/2,
+ sys_object_id/1, sys_object_id/2, sys_or_table/3,
+ variable_func/1, variable_func/2,
+ inc/1, inc/2]).
+-export([dummy/1, snmp_set_serial_no/1, snmp_set_serial_no/2]).
+-export([add_agent_caps/2, del_agent_caps/1, get_agent_caps/0]).
+-export([check_standard/1]).
+
+
+%%-----------------------------------------------------------------
+%% Func: configure/1
+%% Args: Dir is the directory with trailing dir_separator where
+%% the configuration files can be found.
+%% Purpose: Reads the config-files for the standard mib, and
+%% inserts the data. Persistent data that is already
+%% present is *not* changed! (use reconfigure for that)
+%% Returns: ok
+%% Fails: exit(configuration_error)
+%%-----------------------------------------------------------------
+configure(Dir) ->
+ case (catch do_configure(Dir)) of
+ ok ->
+ ok;
+ {error, Reason} ->
+ ?vinfo("configure error: ~p", [Reason]),
+ config_err("configure failed: ~p", [Reason]),
+ exit(configuration_error);
+ Error ->
+ ?vinfo("configure failed: ~p", [Error]),
+ config_err("configure failed: ~p", [Error]),
+ exit(configuration_error)
+ end.
+
+do_configure(Dir) ->
+ case snmpa_agent:get_agent_mib_storage() of
+ mnesia ->
+ ok;
+ _ ->
+ Standard = read_standard(Dir),
+ lists:map(fun maybe_create_persistent_var/1, Standard)
+ end,
+ snmpa_local_db:variable_set({next_sys_or_index, volatile}, 1),
+ %% sysORTable is always volatile
+ snmp_generic:table_func(new, {sysORTable, volatile}),
+ ok.
+
+
+%%-----------------------------------------------------------------
+%% Func: reconfigure/1
+%% Args: Dir is the directory with trailing dir_separator where
+%% the configuration files can be found.
+%% Purpose: Reads the config-files for the standard mib, and
+%% inserts the data. Persistent data that is already
+%% present is deleted. Makes sure the config file
+%% data is used.
+%% Returns: ok
+%% Fails: exit(configuration_error)
+%%-----------------------------------------------------------------
+reconfigure(Dir) ->
+ set_sname(),
+ case (catch do_reconfigure(Dir)) of
+ ok ->
+ ok;
+ {error, Reason} ->
+ ?vinfo("reconfigure error: ~p", [Reason]),
+ config_err("reconfigure failed: ~p", [Reason]),
+ exit(configuration_error);
+ Error ->
+ ?vinfo("reconfigure failed: ~p", [Error]),
+ config_err("reconfigure failed: ~p", [Error]),
+ exit(configuration_error)
+ end.
+
+do_reconfigure(Dir) ->
+ Standard = read_standard(Dir),
+ lists:map(fun create_persistent_var/1, Standard),
+ snmpa_local_db:variable_set({next_sys_or_index, volatile}, 1),
+ snmp_generic:table_func(new, {sysORTable, volatile}),
+ ok.
+
+
+%%-----------------------------------------------------------------
+%% Func: read_standard/1
+%% Args: Dir is the directory with trailing dir_separator where
+%% the configuration files can be found.
+%% Purpose: Reads th standard configuration file.
+%% Returns: A list of standard variables
+%% Fails: If an error occurs, the process will die with Reason
+%% configuration_error.
+%%-----------------------------------------------------------------
+read_standard(Dir) ->
+ ?vdebug("check standard config file",[]),
+ Gen = fun(_) -> ok end,
+ Filter = fun(Standard) -> sort_standard(Standard) end,
+ Check = fun(Entry) -> check_standard(Entry) end,
+ [Standard] =
+ snmp_conf:read_files(Dir, [{Gen, Filter, Check, "standard.conf"}]),
+ Standard.
+
+
+%%-----------------------------------------------------------------
+%% Make sure that each mandatory standard attribute is present, and
+%% provide default values for the other non-present attributes.
+%%-----------------------------------------------------------------
+sort_standard(L) ->
+ Mand = [{sysContact, {value, ""}},
+ {sysDescr, {value, ""}},
+ {sysLocation, {value, ""}},
+ {sysName, {value, ""}},
+ {sysObjectID, mandatory},
+ {sysServices, mandatory},
+ {snmpEnableAuthenTraps, mandatory}],
+ {ok, L2} = snmp_conf:check_mandatory(L, Mand),
+ lists:keysort(1, L2).
+
+
+%%-----------------------------------------------------------------
+%% Standard
+%% {Name, Value}.
+%%-----------------------------------------------------------------
+check_standard({sysDescr, Value}) -> snmp_conf:check_string(Value);
+check_standard({sysObjectID, Value}) -> snmp_conf:check_oid(Value);
+check_standard({sysContact, Value}) -> snmp_conf:check_string(Value);
+check_standard({sysName, Value}) -> snmp_conf:check_string(Value);
+check_standard({sysLocation, Value}) -> snmp_conf:check_string(Value);
+check_standard({sysServices, Value}) -> snmp_conf:check_integer(Value);
+check_standard({snmpEnableAuthenTraps, Value}) ->
+ Atoms = [{enabled, ?snmpEnableAuthenTraps_enabled},
+ {disabled, ?snmpEnableAuthenTraps_disabled}],
+ {ok, Val} = snmp_conf:check_atom(Value, Atoms),
+ {ok, {snmpEnableAuthenTraps, Val}};
+check_standard({Attrib, _Value}) -> error({unknown_attribute, Attrib});
+check_standard(X) -> error({invalid_standard_specification, X}).
+
+
+%%-----------------------------------------------------------------
+%% Func: reset/0
+%% Purpose: Resets all counters (sets them to 0).
+%%-----------------------------------------------------------------
+reset() ->
+ snmpa_mpd:reset().
+
+maybe_create_persistent_var({Var, Val}) ->
+ VarDB = db(Var),
+ case snmp_generic:variable_get(VarDB) of
+ {value, _} -> ok;
+ _ -> snmp_generic:variable_set(VarDB, Val)
+ end.
+
+create_persistent_var({Var, Val}) ->
+ snmp_generic:variable_set(db(Var), Val).
+
+variable_func(_Op) -> ok.
+
+variable_func(get, Name) ->
+ [{_, Val}] = ets:lookup(snmp_agent_table, Name),
+ {value, Val}.
+
+
+%%-----------------------------------------------------------------
+%% inc(VariableName) increments the variable (Counter) in
+%% the local mib. (e.g. snmpInPkts)
+%%-----------------------------------------------------------------
+inc(Name) -> inc(Name, 1).
+inc(Name, N) -> ets:update_counter(snmp_agent_table, Name, N).
+
+%%-----------------------------------------------------------------
+%% This is the instrumentation function for sysUpTime.
+%%-----------------------------------------------------------------
+sys_up_time() ->
+ snmpa:sys_up_time().
+
+sys_up_time(get) ->
+ {value, snmpa:sys_up_time()}.
+
+%%-----------------------------------------------------------------
+%% This is the instrumentation function for snmpEnableAuthenTraps
+%%-----------------------------------------------------------------
+snmp_enable_authen_traps(new) ->
+ snmp_generic:variable_func(new, db(snmpEnableAuthenTraps));
+
+snmp_enable_authen_traps(delete) ->
+ ok;
+
+snmp_enable_authen_traps(get) ->
+ snmp_generic:variable_func(get, db(snmpEnableAuthenTraps)).
+
+snmp_enable_authen_traps(set, NewVal) ->
+ snmp_generic:variable_func(set, NewVal, db(snmpEnableAuthenTraps)).
+
+%%-----------------------------------------------------------------
+%% This is the instrumentation function for sysObjectId
+%%-----------------------------------------------------------------
+sys_object_id(new) ->
+ snmp_generic:variable_func(new, db(sysObjectID));
+
+sys_object_id(delete) ->
+ ok;
+
+sys_object_id(get) ->
+ snmp_generic:variable_func(get, db(sysObjectID)).
+
+sys_object_id(set, NewVal) ->
+ snmp_generic:variable_func(set, NewVal, db(sysObjectID)).
+
+%%-----------------------------------------------------------------
+%% This is a dummy instrumentation function for objects like
+%% snmpTrapOID, that is accessible-for-notify, with different
+%% values each time. This function will only be called with
+%% new/delete.
+%%-----------------------------------------------------------------
+dummy(_Op) -> ok.
+
+%%-----------------------------------------------------------------
+%% This is the instrumentation function for snmpSetSerialNo.
+%% It is always volatile.
+%%-----------------------------------------------------------------
+snmp_set_serial_no(new) ->
+ snmp_generic:variable_func(new, {snmpSetSerialNo, volatile}),
+ {A1,A2,A3} = erlang:now(),
+ random:seed(A1,A2,A3),
+ Val = random:uniform(2147483648) - 1,
+ snmp_generic:variable_func(set, Val, {snmpSetSerialNo, volatile});
+
+snmp_set_serial_no(delete) ->
+ ok;
+
+snmp_set_serial_no(get) ->
+ snmp_generic:variable_func(get, {snmpSetSerialNo, volatile}).
+
+snmp_set_serial_no(is_set_ok, NewVal) ->
+ case snmp_generic:variable_func(get, {snmpSetSerialNo, volatile}) of
+ {value, NewVal} -> noError;
+ _ -> inconsistentValue
+ end;
+snmp_set_serial_no(set, NewVal) ->
+ snmp_generic:variable_func(set, (NewVal + 1) rem 2147483648,
+ {snmpSetSerialNo, volatile}).
+
+%%-----------------------------------------------------------------
+%% This is the instrumentation function for sysOrTable
+%%-----------------------------------------------------------------
+sys_or_table(Op, RowIndex, Cols) ->
+ snmp_generic:table_func(Op, RowIndex, Cols, {sysORTable, volatile}).
+
+add_agent_caps(Oid, Descr) when is_list(Oid) andalso is_list(Descr) ->
+ {value, Next} = snmpa_local_db:variable_get({next_sys_or_index, volatile}),
+ snmpa_local_db:variable_set({next_sys_or_index, volatile}, Next+1),
+ SysUpTime = sys_up_time(),
+ Row = {Next, Oid, Descr, SysUpTime},
+ snmpa_local_db:table_create_row({sysORTable, volatile}, [Next], Row),
+ snmpa_local_db:variable_set({sysORLastChange, volatile}, SysUpTime),
+ Next.
+
+del_agent_caps(Index) ->
+ snmpa_local_db:table_delete_row({sysORTable, volatile}, [Index]),
+ snmpa_local_db:variable_set({sysORLastChange, volatile}, sys_up_time()).
+
+get_agent_caps() ->
+ snmpa_local_db:match({sysORTable, volatile}, {'$1', '$2', '$3', '$4'}).
+
+
+db(Var) -> snmpa_agent:db(Var).
+
+
+%% -----
+
+set_sname() ->
+ set_sname(get(sname)).
+
+set_sname(undefined) ->
+ put(sname,conf);
+set_sname(_) -> %% Keep it, if already set.
+ ok.
+
+error(Reason) ->
+ throw({error, Reason}).
+
+config_err(F, A) ->
+ snmpa_error:config_err("[STANDARD-MIB]: " ++ F, A).
diff --git a/lib/snmp/src/agent/snmp_target_mib.erl b/lib/snmp/src/agent/snmp_target_mib.erl
new file mode 100644
index 0000000000..a3ac67b533
--- /dev/null
+++ b/lib/snmp/src/agent/snmp_target_mib.erl
@@ -0,0 +1,888 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1998-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%
+%%
+-module(snmp_target_mib).
+
+-export([configure/1, reconfigure/1,
+ snmpTargetSpinLock/1, snmpTargetSpinLock/2,
+ snmpTargetAddrTable/1, snmpTargetAddrTable/3,
+ snmpTargetParamsTable/1, snmpTargetParamsTable/3,
+ get_target_addrs/0, get_target_engine_id/1, set_target_engine_id/2,
+ is_valid_tag/3, get/3, table_next/2]).
+-export([add_addr/10, delete_addr/1,
+ add_params/5, delete_params/1]).
+-export([check_target_addr/1, check_target_params/1]).
+
+-include("snmp_types.hrl").
+-include("snmp_tables.hrl").
+-include("SNMP-TARGET-MIB.hrl").
+-include("SNMPv2-TC.hrl").
+-include("SNMPv2-TM.hrl").
+-include("SNMP-FRAMEWORK-MIB.hrl").
+
+-define(VMODULE,"TARGET-MIB").
+-include("snmp_verbosity.hrl").
+
+
+%% Column not accessible via SNMP - needed when the agent sends informs
+-define(snmpTargetAddrEngineId, 10).
+%% Extra comlumns for the augmented table snmpTargetAddrExtTable
+-define(snmpTargetAddrTMask, 11).
+-define(snmpTargetAddrMMS, 12).
+
+
+%%-----------------------------------------------------------------
+%% Func: configure/1
+%% Args: Dir is the directory where the configuration files are found.
+%% Purpose: If the tables doesn't exist, this function reads
+%% the config-files for the target tables, and
+%% inserts the data. This means that the data in the tables
+%% survive a reboot. However, the StorageType column is
+%% checked for each row. If volatile, the row is deleted.
+%% Returns: ok
+%% Fails: exit(configuration_error)
+%%-----------------------------------------------------------------
+configure(Dir) ->
+ set_sname(),
+ case db(snmpTargetParamsTable) of
+ {_, mnesia} ->
+ ?vdebug("tables in mnesia: init vars & cleanup",[]),
+ init_vars(),
+ gc_tabs();
+ TabDb ->
+ case snmpa_local_db:table_exists(TabDb) of
+ true ->
+ ?vdebug("tables already exist: init vars & cleanup",[]),
+ init_vars(),
+ gc_tabs();
+ false ->
+ ?vdebug("no tables: reconfigure",[]),
+ reconfigure(Dir)
+ end
+ end.
+
+
+%%-----------------------------------------------------------------
+%% Func: reconfigure/1
+%% Args: Dir is the directory where the configuration files are found.
+%% Purpose: Reads the config-files for the target tables, and
+%% inserts the data. Makes sure that all old data in
+%% the tables are deleted, and the new data inserted.
+%% This function makes sure that all (and only)
+%% config-file-data are in the tables.
+%% Returns: ok
+%% Fails: exit(configuration_error)
+%%-----------------------------------------------------------------
+reconfigure(Dir) ->
+ set_sname(),
+ case (catch do_reconfigure(Dir)) of
+ ok ->
+ ok;
+ {error, Reason} ->
+ ?vinfo("reconfigure error: ~p", [Reason]),
+ config_err("reconfigure failed: ~p", [Reason]),
+ exit(configuration_error);
+ Error ->
+ ?vinfo("reconfigure failed: ~p", [Error]),
+ config_err("reconfigure failed: ~p", [Error]),
+ exit(configuration_error)
+ end.
+
+do_reconfigure(Dir) ->
+ ?vdebug("read target configuration files",[]),
+ {Addrs, Params} = read_target_config_files(Dir),
+ ?vdebug("initiate tables",[]),
+ init_tabs(Addrs, Params),
+ ?vdebug("initiate vars",[]),
+ init_vars(),
+ ?vdebug("invalidate cache for notification mib",[]),
+ snmp_notification_mib:invalidate_cache(),
+ ok.
+
+
+read_target_config_files(Dir) ->
+ ?vdebug("check target address config file",[]),
+ TAGen = fun(_D) -> ok end,
+ TAFilter = fun(Addr) -> Addr end,
+ TACheck = fun(Entry) -> check_target_addr(Entry) end,
+
+ TPGen = fun(_D) -> ok end,
+ TPFilter = fun(Params) -> Params end,
+ TPCheck = fun(Entry) -> check_target_params(Entry) end,
+
+ [Addrs, Params] =
+ snmp_conf:read_files(Dir,
+ [{TAGen, TAFilter, TACheck, "target_addr.conf"},
+ {TPGen, TPFilter, TPCheck, "target_params.conf"}]),
+ {Addrs, Params}.
+
+
+%%-----------------------------------------------------------------
+%% TargetAddr
+%% {Name, Ip, Udp, Timeout, RetryCount, TagList, Params, EngineId,
+%% TMask, MMS}
+%%-----------------------------------------------------------------
+check_target_addr({Name, Ip, Udp, Timeout, RetryCount, TagList,
+ Params, EngineId, TMask, MMS}) ->
+ ?vtrace("check target address with:"
+ "~n Name: ~s"
+ "~n Ip: ~p"
+ "~n Udp: ~p"
+ "~n Timeout: ~p"
+ "~n RetryCount: ~p"
+ "~n TagList: ~p"
+ "~n Params: ~p"
+ "~n EngineId: ~p"
+ "~n TMask: ~p"
+ "~n MMS: ~p",
+ [Name,Ip,Udp,Timeout,RetryCount,
+ TagList,Params,EngineId,TMask,MMS]),
+ snmp_conf:check_string(Name,{gt,0}),
+ snmp_conf:check_ip(Ip),
+ snmp_conf:check_integer(Udp, {gt, 0}),
+ snmp_conf:check_integer(Timeout, {gte, 0}),
+ snmp_conf:check_integer(RetryCount, {gte,0}),
+ snmp_conf:check_string(TagList),
+ snmp_conf:check_string(Params),
+ check_engine_id(EngineId),
+ TAddr = Ip ++ [Udp div 256, Udp rem 256],
+ check_mask(TMask, TAddr),
+ snmp_conf:check_packet_size(MMS),
+ ?vtrace("check target address done",[]),
+
+ Addr = {Name, ?snmpUDPDomain, TAddr, Timeout,
+ RetryCount, TagList, Params,
+ ?'StorageType_nonVolatile', ?'RowStatus_active', EngineId,
+ TMask, MMS}, % Values for Augmenting table in SNMP-COMMUNITY-MIB
+ {ok, Addr};
+check_target_addr({Name, Ip, Udp, Timeout, RetryCount, TagList, Params,
+ EngineId}) ->
+ check_target_addr({Name, Ip, Udp, Timeout, RetryCount, TagList,
+ Params, EngineId, [], 2048});
+%% Use dummy engine id if the old style is found
+check_target_addr({Name, Ip, Udp, Timeout, RetryCount, TagList, Params}) ->
+ check_target_addr({Name, Ip, Udp, Timeout, RetryCount, TagList,
+ Params, "dummy", [], 2048});
+%% Use dummy engine id if the old style is found
+check_target_addr({Name, Ip, Udp, Timeout, RetryCount, TagList, Params,
+ TMask, MMS}) ->
+ check_target_addr({Name, Ip, Udp, Timeout, RetryCount, TagList,
+ Params, "dummy", TMask, MMS});
+check_target_addr(X) ->
+ error({invalid_target_addr, X}).
+
+
+check_engine_id(discovery) ->
+ ok;
+check_engine_id(EngineId) ->
+ snmp_conf:check_string(EngineId).
+
+check_mask([], _TAddr) ->
+ ok;
+check_mask(TMask, TAddr) when length(TMask) == length(TAddr) ->
+ snmp_conf:check_taddress(TMask);
+check_mask(TMask, _TAddr) ->
+ throw({error, {invalid_mask, TMask}}).
+
+
+%%-----------------------------------------------------------------
+%% TargetParams
+%% {Name, MPModel, SecurityModel, SecurityName, SecurityLevel}
+%%-----------------------------------------------------------------
+check_target_params({Name, MPModel, SecModel, SecName, SecLevel}) ->
+ snmp_conf:check_string(Name,{gt,0}),
+ {ok, MP} = snmp_conf:check_atom(MPModel, [{v1, ?MP_V1},
+ {v2c, ?MP_V2C},
+ {v3, ?MP_V3}]),
+ {ok, SecM} = snmp_conf:check_sec_model(SecModel, [any]),
+ snmp_conf:check_string(SecName),
+ {ok, SecL} = snmp_conf:check_sec_level(SecLevel),
+ Params = {Name, MP, SecM, SecName, SecL,
+ ?'StorageType_nonVolatile', ?'RowStatus_active'},
+ {ok, Params};
+check_target_params(X) ->
+ error({invalid_target_params, X}).
+
+
+
+%% maybe_create_table(Name) ->
+%% case snmpa_local_db:table_exists(db(Name)) of
+%% true -> ok;
+%% _ -> snmpa_local_db:table_create(db(Name))
+%% end.
+
+init_tabs(Addrs, Params) ->
+ ?vdebug("create target address table",[]),
+ AddrDB = db(snmpTargetAddrTable),
+ snmpa_local_db:table_delete(AddrDB),
+ snmpa_local_db:table_create(AddrDB),
+ init_addr_table(Addrs),
+ ?vdebug("create target params table",[]),
+ ParmDB = db(snmpTargetParamsTable),
+ snmpa_local_db:table_delete(ParmDB),
+ snmpa_local_db:table_create(ParmDB),
+ init_params_table(Params).
+
+init_addr_table([Row | T]) ->
+ Key = element(1, Row),
+ snmpa_local_db:table_create_row(db(snmpTargetAddrTable), Key, Row),
+ init_addr_table(T);
+init_addr_table([]) -> true.
+
+init_params_table([Row | T]) ->
+ Key = element(1, Row),
+ snmpa_local_db:table_create_row(db(snmpTargetParamsTable), Key, Row),
+ init_params_table(T);
+init_params_table([]) -> true.
+
+table_cre_row(Tab, Key, Row) ->
+ snmpa_mib_lib:table_cre_row(db(Tab), Key, Row).
+
+table_del_row(Tab, Key) ->
+ snmpa_mib_lib:table_del_row(db(Tab), Key).
+
+
+add_addr(Name, Ip, Port, Timeout, Retry, TagList,
+ Params, EngineId, TMask, MMS) ->
+ Addr = {Name, Ip, Port, Timeout, Retry, TagList,
+ Params, EngineId, TMask, MMS},
+ case (catch check_target_addr(Addr)) of
+ {ok, Row} ->
+ Key = element(1, Row),
+ case table_cre_row(snmpTargetAddrTable, Key, Row) of
+ true ->
+ {ok, Key};
+ false ->
+ {error, create_failed}
+ end;
+ {error, Reason} ->
+ {error, Reason};
+ Error ->
+ {error, Error}
+ end.
+
+delete_addr(Key) ->
+ case table_del_row(snmpTargetAddrTable, Key) of
+ true ->
+ ok;
+ false ->
+ {error, delete_failed}
+ end.
+
+
+add_params(Name, MPModel, SecModel, SecName, SecLevel) ->
+ Params = {Name, MPModel, SecModel, SecName, SecLevel},
+ case (catch check_target_params(Params)) of
+ {ok, Row} ->
+ Key = element(1, Row),
+ case table_cre_row(snmpTargetParamsTable, Key, Row) of
+ true ->
+ {ok, Key};
+ false ->
+ {create_failed}
+ end;
+ {error, Reason} ->
+ {error, Reason};
+ Error ->
+ {error, Error}
+ end.
+
+delete_params(Key) ->
+ case table_del_row(snmpTargetParamsTable, Key) of
+ true ->
+ ok;
+ false ->
+ {error, delete_failed}
+ end.
+
+
+gc_tabs() ->
+ AddrDB = db(snmpTargetAddrTable),
+ AddrSTC = stc(snmpTargetAddrTable),
+ AddrFOI = foi(snmpTargetAddrTable),
+ snmpa_mib_lib:gc_tab(AddrDB, AddrSTC, AddrFOI),
+ ParmDB = db(snmpTargetParamsTable),
+ ParmSTC = stc(snmpTargetParamsTable),
+ ParmFOI = foi(snmpTargetParamsTable),
+ snmpa_mib_lib:gc_tab(ParmDB, ParmSTC, ParmFOI),
+ ok.
+
+
+%%-----------------------------------------------------------------
+%% Counter functions
+%%-----------------------------------------------------------------
+init_vars() ->
+ ?vtrace("initiate vars",[]),
+ lists:map(fun maybe_create_var/1, vars()).
+
+maybe_create_var(Var) ->
+ case ets:lookup(snmp_agent_table, Var) of
+ [_] -> ok;
+ _ -> init_var(Var)
+ end.
+
+init_var(Var) -> ets:insert(snmp_agent_table, {Var, 0}).
+
+vars() ->
+ [snmpUnavailableContexts,
+ snmpUnknownContexts].
+
+%%-----------------------------------------------------------------
+%% API functions
+%%-----------------------------------------------------------------
+is_valid_tag("", _TDomain, _TAddress) ->
+ true;
+is_valid_tag(Tag, TDomain, TAddress) ->
+ is_valid_tag(TDomain, TAddress, Tag, []).
+
+is_valid_tag(TDomain, TAddress, Tag, Key) ->
+ case table_next(snmpTargetAddrTable, Key) of
+ endOfTable ->
+ false;
+ NextKey ->
+ case get(snmpTargetAddrTable, NextKey, [?snmpTargetAddrTDomain,
+ ?snmpTargetAddrTAddress,
+ ?snmpTargetAddrTagList,
+ ?snmpTargetAddrTMask]) of
+ [{value, TDomain}, % must match exactly
+ {value, TAddress}, % RFC2576: chapters 5.2.1 & 5.3
+ {value, TagList},
+ {value, []}] ->
+ case snmp_misc:is_tag_member(Tag, TagList) of
+ true ->
+ ?vtrace("is_valid_tag -> exact: "
+ "tag IS member of taglist", []),
+ true;
+ false ->
+ ?vtrace("is_valid_tag -> exact: "
+ "tag is NOT member of taglist", []),
+ is_valid_tag(TDomain, TAddress,
+ Tag, NextKey)
+ end;
+ [{value, TDomain}, % must match exactly
+ {value, TAddress2},
+ {value, TagList},
+ {value, TMask}] when TMask =/= [] ->
+ case snmp_misc:is_tmask_match(TAddress, TAddress2,
+ TMask) of
+ true ->
+ case snmp_misc:is_tag_member(Tag, TagList) of
+ true ->
+ ?vtrace("is_valid_tag -> masked: "
+ "tag IS member of taglist", []),
+ true;
+ false ->
+ ?vtrace("is_valid_tag -> masked: "
+ "tag is NOT member of taglist",[]),
+ is_valid_tag(TDomain, TAddress,
+ Tag, NextKey)
+ end;
+ false ->
+ is_valid_tag(TDomain, TAddress,
+ Tag, NextKey)
+ end;
+ _ ->
+ is_valid_tag(TDomain, TAddress, Tag, NextKey)
+ end
+ end.
+
+
+%% TargAddrs =
+%% [{TagList, TargetAddr, TargetAddrName, TargetParams, Timeout, Retry}]
+%% TargetAddr = {TDomain, TAddr}; e.g. {?snmpUDPDomain, IpAndUdpPortAsList}
+get_target_addrs() ->
+ get_target_addrs([], db(snmpTargetAddrTable), []).
+
+
+get_target_addrs(Key, {Tab, _} = TabDb, Acc) ->
+ case table_next(Tab, Key) of
+ endOfTable ->
+ Acc;
+ NextKey ->
+ case get_target_addr(TabDb, NextKey) of
+ {ok, Targ} ->
+ get_target_addrs(NextKey, TabDb, [Targ| Acc]);
+ {error, Reason} ->
+ ?vlog("failed getting target address: "
+ "~n Reason: ~p", [Reason]),
+ get_target_addrs(NextKey, TabDb, Acc)
+ end
+ end.
+
+get_target_addr({Tab, mnesia}, Key) ->
+ case mnesia:snmp_get_row(Tab, Key) of
+ {ok, #snmpTargetAddrTable{
+ snmpTargetAddrTDomain = TDomain,
+ snmpTargetAddrTAddress = TAddress,
+ snmpTargetAddrTimeout = Timeout,
+ snmpTargetAddrRetryCount = RetryCount,
+ snmpTargetAddrTagList = TagList,
+ snmpTargetAddrParams = Params,
+ snmpTargetAddrRowStatus = ?'RowStatus_active'}} ->
+ case get_target_params(Params) of
+ undefined ->
+ config_err("Failed retreiving target params [~p]"
+ "~n for ~p [~p]", [Params, Key, TAddress]),
+ {error, {not_found, {target_params, Key, Params}}};
+ TargetParams ->
+ Targ = {TagList, {TDomain, TAddress}, Key,
+ TargetParams, Timeout, RetryCount},
+ {ok, Targ}
+ end;
+ _ ->
+ {error, {not_found, {target_addr, Key}}}
+ end;
+get_target_addr(TabDb, Key) ->
+ case snmpa_local_db:table_get_row(TabDb, Key) of
+ {_Key, TDomain, TAddress, Timeout, RetryCount, TagList, Params,
+ _Storage, ?'RowStatus_active', _TargetEngineId,_TMask,_MMS} ->
+ case get_target_params(Params) of
+ undefined ->
+ config_err("Failed retreiving target params [~p]"
+ "~n for target ~p [~p]",
+ [Params, Key, TAddress]),
+ {error, {not_found, {target_params, Key, Params}}};
+ TargetParams ->
+ Targ = {TagList, {TDomain, TAddress}, Key,
+ TargetParams, Timeout, RetryCount},
+ {ok, Targ}
+ end;
+ _ ->
+ {error, {not_found, {target_addr, Key}}}
+ end.
+
+
+get_target_params(Params) ->
+ case snmpTargetParamsTable(get, Params, [?snmpTargetParamsMPModel,
+ ?snmpTargetParamsSecurityModel,
+ ?snmpTargetParamsSecurityName,
+ ?snmpTargetParamsSecurityLevel,
+ ?snmpTargetParamsRowStatus]) of
+ [{value, MpModel},
+ {value, SecModel}, {value, SecName}, {value, SecLevel},
+ {value, ?'RowStatus_active'}] ->
+ {MpModel, SecModel, SecName, SecLevel};
+ _ ->
+ undefined
+ end.
+
+get_target_engine_id(TargetAddrName) ->
+ case db(snmpTargetAddrTable) of
+ {_, mnesia} ->
+ case mnesia:snmp_get_row(snmpTargetAddrTable, TargetAddrName) of
+ {ok, T} ->
+ {ok, T#snmpTargetAddrTable.snmpTargetAddrEngineId};
+ _ ->
+ undefined
+ end;
+ TabDb ->
+ case snmpa_local_db:table_get_element(TabDb,
+ TargetAddrName,
+ ?snmpTargetAddrEngineId) of
+ {value, Val} ->
+ {ok, Val};
+ _ ->
+ undefined
+ end
+ end.
+
+set_target_engine_id(TargetAddrName, EngineId) ->
+ snmp_generic:table_set_elements(db(snmpTargetAddrTable),
+ TargetAddrName,
+ [{?snmpTargetAddrEngineId, EngineId}]).
+
+%%-----------------------------------------------------------------
+%% Instrumentation Functions
+%%-----------------------------------------------------------------
+snmpTargetSpinLock(new) ->
+ snmp_generic:variable_func(new, {snmpTargetSpinLock, volatile}),
+ {A1,A2,A3} = erlang:now(),
+ random:seed(A1,A2,A3),
+ Val = random:uniform(2147483648) - 1,
+ snmp_generic:variable_func(set, Val, {snmpTargetSpinLock, volatile});
+
+snmpTargetSpinLock(delete) ->
+ ok;
+
+snmpTargetSpinLock(get) ->
+ snmp_generic:variable_func(get, {snmpTargetSpinLock, volatile}).
+
+snmpTargetSpinLock(is_set_ok, NewVal) ->
+ case snmp_generic:variable_func(get, {snmpTargetSpinLock, volatile}) of
+ {value, NewVal} -> noError;
+ _ -> inconsistentValue
+ end;
+snmpTargetSpinLock(set, NewVal) ->
+ snmp_generic:variable_func(set, (NewVal + 1) rem 2147483648,
+ {snmpTargetSpinLock, volatile}).
+
+
+%% Op = print - Used for debugging purposes
+snmpTargetAddrTable(print) ->
+ Table = snmpTargetAddrTable,
+ DB = db(Table),
+ FOI = foi(Table),
+ PrintRow =
+ fun(Prefix, Row) ->
+ lists:flatten(
+ io_lib:format("~sName: ~p"
+ "~n~sTDomain: ~p (~w)"
+ "~n~sTAddress: ~p (~s)"
+ "~n~sTimeout: ~p"
+ "~n~sRetryCount: ~p"
+ "~n~sTagList: ~p"
+ "~n~sParams: ~p"
+ "~n~sStorageType: ~p (~w)"
+ "~n~sStatus: ~p (~w)"
+ "~n~s[NonAcc] EngineID: ~p"
+ "~n~s[Ext] TMask: ~p"
+ "~n~s[Ext] MMS: ~p",
+ [Prefix, element(?snmpTargetAddrName, Row),
+ Prefix, element(?snmpTargetAddrTDomain, Row),
+ case element(?snmpTargetAddrTDomain, Row) of
+ ?snmpUDPDomain -> udp;
+ _ -> undefined
+ end,
+ Prefix, element(?snmpTargetAddrTAddress, Row),
+ case element(?snmpTargetAddrTAddress, Row) of
+ [A,B,C,D,U1,U2] ->
+ lists:flatten(
+ io_lib:format("~w.~w.~w.~w:~w",
+ [A, B, C, D, U1 bsl 8 + U2]));
+ _ -> "-"
+ end,
+ Prefix, element(?snmpTargetAddrTimeout, Row),
+ Prefix, element(?snmpTargetAddrRetryCount, Row),
+ Prefix, element(?snmpTargetAddrTagList, Row),
+ Prefix, element(?snmpTargetAddrParams, Row),
+ Prefix, element(?snmpTargetAddrStorageType, Row),
+ case element(?snmpTargetAddrStorageType, Row) of
+ ?'snmpTargetAddrStorageType_readOnly' -> readOnly;
+ ?'snmpTargetAddrStorageType_permanent' -> permanent;
+ ?'snmpTargetAddrStorageType_nonVolatile' -> nonVolatile;
+ ?'snmpTargetAddrStorageType_volatile' -> volatile;
+ ?'snmpTargetAddrStorageType_other' -> other;
+ _ -> undefined
+ end,
+ Prefix, element(?snmpTargetAddrRowStatus, Row),
+ case element(?snmpTargetAddrRowStatus, Row) of
+ ?'snmpTargetAddrRowStatus_destroy' -> destroy;
+ ?'snmpTargetAddrRowStatus_createAndWait' -> createAndWait;
+ ?'snmpTargetAddrRowStatus_createAndGo' -> createAndGo;
+ ?'snmpTargetAddrRowStatus_notReady' -> notReady;
+ ?'snmpTargetAddrRowStatus_notInService' -> notInService;
+ ?'snmpTargetAddrRowStatus_active' -> active;
+ _ -> undefined
+ end,
+ Prefix,
+ element(?snmpTargetAddrEngineId, Row),
+ Prefix,
+ element(?snmpTargetAddrTMask, Row),
+ Prefix,
+ element(?snmpTargetAddrMMS, Row)]))
+ end,
+ snmpa_mib_lib:print_table(Table, DB, FOI, PrintRow);
+%% Op == new | delete
+snmpTargetAddrTable(Op) ->
+ snmp_generic:table_func(Op, db(snmpTargetAddrTable)).
+
+%% Op == get | is_set_ok | set | get_next
+snmpTargetAddrTable(get, RowIndex, Cols) ->
+ get(snmpTargetAddrTable, RowIndex, Cols);
+snmpTargetAddrTable(get_next, RowIndex, Cols) ->
+ next(snmpTargetAddrTable, RowIndex, Cols);
+snmpTargetAddrTable(set, RowIndex, Cols0) ->
+ %% BMK BMK BMK
+ case (catch verify_targetAddrTable_cols(Cols0, [])) of
+ {ok, Cols} ->
+ snmp_notification_mib:invalidate_cache(),
+ %% Add columns for augmenting table snmpTargetAddrExtTable and for
+ %% target engine ID. Target engine ID is set to "". The function
+ %% get_target_engine_id will return "" unless a value is set using
+ %% set_target_engine_id. If it is "" Informs can't be sent to the
+ %% target.
+ NCols = Cols ++ [{?snmpTargetAddrEngineId, ""},
+ {?snmpTargetAddrTMask, []},
+ {?snmpTargetAddrMMS, 2048}],
+ Db = db(snmpTargetAddrTable),
+ snmp_generic:table_func(set, RowIndex, NCols, Db);
+ Error ->
+ Error
+ end;
+snmpTargetAddrTable(is_set_ok, RowIndex, Cols0) ->
+ case (catch verify_targetAddrTable_cols(Cols0, [])) of
+ {ok, Cols} ->
+ %% Add columns for augmenting table snmpTargetAddrExtTable and for
+ %% target engine ID. Target engine ID is set to "". The function
+ %% get_target_engine_id will return "" unless a value is set using
+ %% set_target_engine_id. If it is "" Informs can't be sent to the
+ %% target.
+ NCols = Cols ++ [{?snmpTargetAddrEngineId, ""},
+ {?snmpTargetAddrTMask, []},
+ {?snmpTargetAddrMMS, 2048}],
+ Db = db(snmpTargetAddrTable),
+ snmp_generic:table_func(is_set_ok, RowIndex, NCols, Db);
+ Error ->
+ Error
+ end;
+snmpTargetAddrTable(Op, Arg1, Arg2) ->
+ Db = db(snmpTargetAddrTable),
+ snmp_generic:table_func(Op, Arg1, Arg2, Db).
+
+verify_targetAddrTable_cols([], Cols) ->
+ {ok, lists:reverse(Cols)};
+verify_targetAddrTable_cols([{Col, Val0}|Cols], Acc) ->
+ Val = verify_targetAddrTable_col(Col, Val0),
+ verify_targetAddrTable_cols(Cols, [{Col, Val}|Acc]).
+
+verify_targetAddrTable_col(?snmpTargetAddrName, Name) ->
+ case (catch snmp_conf:check_string(Name)) of
+ ok ->
+ Name;
+ _ ->
+ wrongValue(?snmpTargetAddrName)
+ end;
+verify_targetAddrTable_col(?snmpTargetAddrTAddress, TAddr) ->
+ case (catch snmp_conf:check_taddress(TAddr)) of
+ ok ->
+ TAddr;
+ _ ->
+ wrongValue(?snmpTargetAddrTAddress)
+ end;
+verify_targetAddrTable_col(?snmpTargetAddrTimeout, Timeout) ->
+ case (catch snmp_conf:check_integer(Timeout)) of
+ ok when Timeout >= 0 ->
+ Timeout;
+ _ ->
+ wrongValue(?snmpTargetAddrTimeout)
+ end;
+verify_targetAddrTable_col(?snmpTargetAddrRetryCount, Retry) ->
+ case (catch snmp_conf:check_integer(Retry)) of
+ ok when Retry >= 0 ->
+ Retry;
+ _ ->
+ wrongValue(?snmpTargetAddrRetryCount)
+ end;
+verify_targetAddrTable_col(?snmpTargetAddrTagList, TagList) ->
+ case (catch snmp_conf:check_string(TagList)) of
+ ok ->
+ TagList;
+ _ ->
+ wrongValue(?snmpTargetAddrTagList)
+ end;
+verify_targetAddrTable_col(?snmpTargetAddrParams, Params) ->
+ case (catch snmp_conf:check_string(Params)) of
+ ok ->
+ Params;
+ _ ->
+ wrongValue(?snmpTargetAddrParams)
+ end;
+verify_targetAddrTable_col(_, Val) ->
+ Val.
+
+
+%% Op = print - Used for debugging purposes
+snmpTargetParamsTable(print) ->
+ Table = snmpTargetParamsTable,
+ DB = db(Table),
+ FOI = foi(Table),
+ PrintRow =
+ fun(Prefix, Row) ->
+ lists:flatten(
+ io_lib:format("~sName: ~p"
+ "~n~sMPModel: ~p (~w)"
+ "~n~sSecurityModel: ~p (~w)"
+ "~n~sSecurityName: ~p"
+ "~n~sSecurityLevel: ~p (~w)"
+ "~n~sStorageType: ~p (~w)"
+ "~n~sStatus: ~p (~w)",
+ [Prefix,
+ element(?snmpTargetParamsName, Row),
+ Prefix,
+ element(?snmpTargetParamsMPModel, Row),
+ case element(?snmpTargetParamsMPModel, Row) of
+ ?MP_V1 -> v1;
+ ?MP_V2C -> v2c;
+ ?MP_V3 -> v3;
+ _ -> undefined
+ end,
+ Prefix,
+ element(?snmpTargetParamsSecurityModel, Row),
+ case element(?snmpTargetParamsSecurityModel, Row) of
+ ?SEC_ANY -> any;
+ ?SEC_V1 -> v1;
+ ?SEC_V2C -> v2c;
+ ?SEC_USM -> usm;
+ _ -> undefined
+ end,
+ Prefix,
+ element(?snmpTargetParamsSecurityName, Row),
+ Prefix,
+ element(?snmpTargetParamsSecurityLevel, Row),
+ case element(?snmpTargetParamsSecurityLevel, Row) of
+ ?'SnmpSecurityLevel_noAuthNoPriv' -> noAuthNoPriv;
+ ?'SnmpSecurityLevel_authNoPriv' -> authNoPriv;
+ ?'SnmpSecurityLevel_authPriv' -> authPriv;
+ _ -> undefined
+ end,
+ Prefix,
+ element(?snmpTargetParamsStorageType, Row),
+ case element(?snmpTargetParamsStorageType, Row) of
+ ?'snmpTargetParamsStorageType_readOnly' -> readOnly;
+ ?'snmpTargetParamsStorageType_permanent' -> permanent;
+ ?'snmpTargetParamsStorageType_nonVolatile' -> nonVolatile;
+ ?'snmpTargetParamsStorageType_volatile' -> volatile;
+ ?'snmpTargetParamsStorageType_other' -> other;
+ _ -> undefined
+ end,
+ Prefix,
+ element(?snmpTargetParamsRowStatus, Row),
+ case element(?snmpTargetParamsRowStatus, Row) of
+ ?'snmpTargetParamsRowStatus_destroy' -> destroy;
+ ?'snmpTargetParamsRowStatus_createAndWait' -> createAndWait;
+ ?'snmpTargetParamsRowStatus_createAndGo' -> createAndGo;
+ ?'snmpTargetParamsRowStatus_notReady' -> notReady;
+ ?'snmpTargetParamsRowStatus_notInService' -> notInService;
+ ?'snmpTargetParamsRowStatus_active' -> active;
+ _ -> undefined
+ end]))
+ end,
+ snmpa_mib_lib:print_table(Table, DB, FOI, PrintRow);
+%% Op == new | delete
+snmpTargetParamsTable(Op) ->
+ snmp_generic:table_func(Op, db(snmpTargetParamsTable)).
+
+%% Op == get | is_set_ok | set | get_next
+snmpTargetParamsTable(get, RowIndex, Cols) ->
+ %% BMK BMK BMK
+ get(snmpTargetParamsTable, RowIndex, Cols);
+snmpTargetParamsTable(get_next, RowIndex, Cols) ->
+ %% BMK BMK BMK
+ next(snmpTargetParamsTable, RowIndex, Cols);
+snmpTargetParamsTable(set, RowIndex, Cols0) ->
+ %% BMK BMK BMK
+ case (catch verify_snmpTargetParamsTable_cols(Cols0, [])) of
+ {ok, Cols} ->
+ snmp_notification_mib:invalidate_cache(),
+ snmp_generic:table_func(set, RowIndex, Cols,
+ db(snmpTargetParamsTable));
+ Error ->
+ Error
+ end;
+snmpTargetParamsTable(Op, Arg1, Arg2) ->
+ snmp_generic:table_func(Op, Arg1, Arg2, db(snmpTargetParamsTable)).
+
+verify_snmpTargetParamsTable_cols([], Cols) ->
+ {ok, lists:reverse(Cols)};
+verify_snmpTargetParamsTable_cols([{Col, Val0}|Cols], Acc) ->
+ Val = verify_snmpTargetParamsTable_col(Col, Val0),
+ verify_snmpTargetParamsTable_cols(Cols, [{Col, Val}|Acc]).
+
+verify_snmpTargetParamsTable_col(?snmpTargetParamsName, Name) ->
+ case (catch snmp_conf:check_string(Name)) of
+ ok ->
+ Name;
+ _ ->
+ wrongValue(?snmpTargetParamsName)
+ end;
+verify_snmpTargetParamsTable_col(?snmpTargetParamsMPModel, Model) ->
+ case Model of
+ v1 -> ?MP_V1;
+ v2c -> ?MP_V2C;
+ v3 -> ?MP_V3;
+ ?MP_V1 -> ?MP_V1;
+ ?MP_V2C -> ?MP_V2C;
+ ?MP_V3 -> ?MP_V3;
+ _ -> wrongValue(?snmpTargetParamsMPModel)
+ end;
+verify_snmpTargetParamsTable_col(?snmpTargetParamsSecurityModel, Model) ->
+ case Model of
+ v1 -> ?SEC_V1;
+ v2c -> ?SEC_V2C;
+ usm -> ?SEC_USM;
+ ?SEC_V1 -> ?SEC_V1;
+ ?SEC_V2C -> ?SEC_V2C;
+ ?SEC_USM -> ?SEC_USM;
+ _ -> wrongValue(?snmpTargetParamsSecurityModel)
+ end;
+verify_snmpTargetParamsTable_col(?snmpTargetParamsSecurityName, Name) ->
+ case (catch snmp_conf:check_string(Name)) of
+ ok ->
+ Name;
+ _ ->
+ wrongValue(?snmpTargetParamsSecurityName)
+ end;
+verify_snmpTargetParamsTable_col(?snmpTargetParamsSecurityLevel, Level) ->
+ case Level of
+ noAuthNoPriv -> 1;
+ authNoPriv -> 2;
+ authPriv -> 3;
+ 1 -> 1;
+ 2 -> 2;
+ 3 -> 3;
+ _ -> wrongValue(?snmpTargetParamsSecurityLevel)
+ end;
+verify_snmpTargetParamsTable_col(_, Val) ->
+ Val.
+
+db(X) -> snmpa_agent:db(X).
+
+fa(snmpTargetAddrTable) -> ?snmpTargetAddrTDomain;
+fa(snmpTargetParamsTable) -> ?snmpTargetParamsMPModel.
+
+foi(snmpTargetAddrTable) -> ?snmpTargetAddrName;
+foi(snmpTargetParamsTable) -> ?snmpTargetParamsName.
+
+noc(snmpTargetAddrTable) -> 9;
+noc(snmpTargetParamsTable) -> 7.
+
+stc(snmpTargetAddrTable) -> ?snmpTargetAddrStorageType;
+stc(snmpTargetParamsTable) -> ?snmpTargetParamsStorageType.
+
+next(Name, RowIndex, Cols) ->
+ snmp_generic:handle_table_next(db(Name), RowIndex, Cols,
+ fa(Name), foi(Name), noc(Name)).
+
+table_next(Name, RestOid) ->
+ snmp_generic:table_next(db(Name), RestOid).
+
+
+get(Name, RowIndex, Cols) ->
+ snmp_generic:handle_table_get(db(Name), RowIndex, Cols, foi(Name)).
+
+
+wrongValue(V) -> throw({wrongValue, V}).
+
+
+%% -----
+
+set_sname() ->
+ set_sname(get(sname)).
+
+set_sname(undefined) ->
+ put(sname,conf);
+set_sname(_) -> %% Keep it, if already set.
+ ok.
+
+error(Reason) ->
+ throw({error, Reason}).
+
+config_err(F, A) ->
+ snmpa_error:config_err("[TARGET-MIB]: " ++ F, A).
+
+
diff --git a/lib/snmp/src/agent/snmp_user_based_sm_mib.erl b/lib/snmp/src/agent/snmp_user_based_sm_mib.erl
new file mode 100644
index 0000000000..7b881f888c
--- /dev/null
+++ b/lib/snmp/src/agent/snmp_user_based_sm_mib.erl
@@ -0,0 +1,1182 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1999-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%
+%%
+-module(snmp_user_based_sm_mib).
+
+-export([configure/1, reconfigure/1,
+ usmUserSpinLock/1, usmUserSpinLock/2,
+ usmUserTable/1, usmUserTable/3,
+ table_next/2,
+ is_engine_id_known/1, get_user/2, get_user_from_security_name/2,
+ mk_key_change/3, mk_key_change/5, extract_new_key/3, mk_random/1]).
+-export([add_user/1, add_user/13, delete_user/1]).
+
+%% Internal
+-export([check_usm/1]).
+
+-include("SNMP-USER-BASED-SM-MIB.hrl").
+-include("SNMP-USM-AES-MIB.hrl").
+-include("SNMPv2-TC.hrl").
+-include("snmpa_internal.hrl").
+-include("snmp_types.hrl").
+
+-define(VMODULE,"USM_MIB").
+-include("snmp_verbosity.hrl").
+
+-ifndef(default_verbosity).
+-define(default_verbosity,silence).
+-endif.
+
+
+%% Columns not accessible via SNMP
+-define(usmUserAuthKey, 14).
+-define(usmUserPrivKey, 15).
+
+
+%%%-----------------------------------------------------------------
+%%% Utility functions
+%%%-----------------------------------------------------------------
+
+%%%-----------------------------------------------------------------
+%%% Implements the instrumentation functions and additional
+%%% functions for the SNMP-USER-BASED-SM-MIB.
+%%%-----------------------------------------------------------------
+
+%%-----------------------------------------------------------------
+%% Func: configure/1
+%% Args: Dir is the directory where the configuration files are found.
+%% Purpose: If the tables doesn't exist, this function reads
+%% the config-files for the USM tables, and
+%% inserts the data. This means that the data in the tables
+%% survive a reboot. However, the StorageType column is
+%% checked for each row. If volatile, the row is deleted.
+%% Returns: ok
+%% Fails: exit(configuration_error)
+%%-----------------------------------------------------------------
+configure(Dir) ->
+ set_sname(),
+ case db(usmUserTable) of
+ {_, mnesia} ->
+ ?vdebug("usm user table in mnesia: init vars & cleanup",[]),
+ init_vars(),
+ gc_tabs();
+ TabDb ->
+ case snmpa_local_db:table_exists(TabDb) of
+ true ->
+ ?vdebug("usm user table exists: init vars & cleanup",[]),
+ init_vars(),
+ gc_tabs();
+ false ->
+ ?vdebug("usm user table does not exist: reconfigure",[]),
+ reconfigure(Dir)
+ end
+ end.
+
+%%-----------------------------------------------------------------
+%% Func: reconfigure/1
+%% Args: Dir is the directory where the configuration files are found.
+%% Purpose: Reads the config-files for the USM tables, and
+%% inserts the data. Makes sure that all old data in
+%% the tables are deleted, and the new data inserted.
+%% This function makes sure that all (and only)
+%% config-file-data are in the tables.
+%% Returns: ok
+%% Fails: exit(configuration_error) |
+%% exit({unsupported_crypto, Function})
+%%-----------------------------------------------------------------
+reconfigure(Dir) ->
+ set_sname(),
+ case (catch do_reconfigure(Dir)) of
+ ok ->
+ ok;
+ {error, Reason} ->
+ ?vinfo("reconfigure error: ~p", [Reason]),
+ config_err("reconfigure failed: ~p", [Reason]),
+ exit(configuration_error);
+ Error ->
+ ?vinfo("reconfigure failed: ~p", [Error]),
+ config_err("reconfigure failed: ~p", [Error]),
+ exit(configuration_error)
+ end.
+
+do_reconfigure(Dir) ->
+ ?vdebug("read usm configuration files",[]),
+ Users = read_usm_config_files(Dir),
+ ?vdebug("check users",[]),
+ check_users(Users),
+ ?vdebug("initiate tables",[]),
+ init_tabs(Users),
+ ?vdebug("initiate vars",[]),
+ init_vars(),
+ ok.
+
+
+read_usm_config_files(Dir) ->
+ ?vdebug("read usm config file",[]),
+ Gen = fun(D) -> generate_usm(D) end,
+ Filter = fun(Usms) -> Usms end,
+ Check = fun(Entry) -> check_usm(Entry) end,
+ [Usms] =
+ snmp_conf:read_files(Dir, [{Gen, Filter, Check, "usm.conf"}]),
+ Usms.
+
+
+generate_usm(Dir) ->
+ info_msg("Incomplete configuration. Generating empty usm.conf.", []),
+ USMFile = filename:join(Dir, "usm.conf"),
+ ok = file:write_file(USMFile, list_to_binary([])).
+
+
+check_usm({EngineID, Name, SecName, Clone, AuthP, AuthKeyC, OwnAuthKeyC,
+ PrivP, PrivKeyC, OwnPrivKeyC, Public, AuthKey, PrivKey}) ->
+ snmp_conf:check_string(EngineID),
+ snmp_conf:check_string(Name),
+ snmp_conf:check_string(SecName),
+ CloneVal =
+ case catch snmp_conf:check_atom(Clone,[{zeroDotZero,?zeroDotZero}]) of
+ {error, _} ->
+ snmp_conf:check_oid(Clone),
+ Clone;
+ {ok, X} ->
+ X
+ end,
+ AuthProtoAlt = [{usmNoAuthProtocol, ?usmNoAuthProtocol},
+ {usmHMACSHAAuthProtocol, ?usmHMACSHAAuthProtocol},
+ {usmHMACMD5AuthProtocol, ?usmHMACMD5AuthProtocol}],
+ {ok, AuthProto} = snmp_conf:check_atom(AuthP, AuthProtoAlt),
+ snmp_conf:check_string(AuthKeyC),
+ snmp_conf:check_string(OwnAuthKeyC),
+ PrivProtoAlt = [{usmNoPrivProtocol, ?usmNoPrivProtocol},
+ {usmDESPrivProtocol, ?usmDESPrivProtocol},
+ {usmAesCfb128Protocol, ?usmAesCfb128Protocol}],
+ {ok, PrivProto} = snmp_conf:check_atom(PrivP, PrivProtoAlt),
+ snmp_conf:check_string(PrivKeyC),
+ snmp_conf:check_string(OwnPrivKeyC),
+ snmp_conf:check_string(Public),
+ snmp_conf:check_string(AuthKey, alen(AuthP)),
+ snmp_conf:check_string(PrivKey, plen(PrivP)),
+
+ User = {EngineID, Name, SecName,
+ CloneVal, AuthProto, AuthKeyC, OwnAuthKeyC,
+ PrivProto, PrivKeyC, OwnPrivKeyC, Public,
+ ?'StorageType_nonVolatile', ?'RowStatus_active', AuthKey, PrivKey},
+ {ok, User};
+check_usm(X) ->
+ error({invalid_user, X}).
+
+alen(usmNoAuthProtocol) -> any;
+alen(usmHMACMD5AuthProtocol) -> 16;
+alen(usmHMACSHAAuthProtocol) -> 20.
+
+plen(usmNoPrivProtocol) -> any;
+plen(usmDESPrivProtocol) -> 16;
+plen(usmAesCfb128Protocol) -> 16.
+
+
+%%-----------------------------------------------------------------
+%% This function loops through all users, and check that the
+%% definition is constistent with the support for crypto on
+%% the system. Thus, it is not possible to define a user that
+%% uses authentication if 'crypto' is not started, or a user that
+%% uses DES if 'crypto' doesn't support DES.
+%%-----------------------------------------------------------------
+check_users([User | Users]) ->
+ check_user(User),
+ check_users(Users);
+check_users([]) ->
+ ok.
+
+check_user(User) ->
+ case element(?usmUserAuthProtocol, User) of
+ ?usmNoAuthProtocol -> ok;
+ ?usmHMACMD5AuthProtocol ->
+ case is_crypto_supported(md5_mac_96) of
+ true -> ok;
+ false -> exit({unsupported_crypto, md5_mac_96})
+ end;
+ ?usmHMACSHAAuthProtocol ->
+ case is_crypto_supported(sha_mac_96) of
+ true -> ok;
+ false -> exit({unsupported_crypto, sha_mac_96})
+ end
+ end,
+ case element(?usmUserPrivProtocol, User) of
+ ?usmNoPrivProtocol -> ok;
+ ?usmDESPrivProtocol ->
+ case is_crypto_supported(des_cbc_decrypt) of
+ true -> ok;
+ false -> exit({unsupported_crypto, des_cbc_decrypt})
+ end;
+ ?usmAesCfb128Protocol ->
+ case is_crypto_supported(aes_cfb_128_decrypt) of
+ true -> ok;
+ false -> exit({unsupported_crypto, aes_cfb_128_decrypt})
+ end
+ end.
+
+
+init_tabs(Users) ->
+ ?vdebug("create usm user table",[]),
+ snmpa_local_db:table_delete(db(usmUserTable)),
+ snmpa_local_db:table_create(db(usmUserTable)),
+ init_user_table(Users).
+
+init_user_table([Row | T]) ->
+ Key = mk_user_table_key(Row),
+ snmpa_local_db:table_create_row(db(usmUserTable), Key, Row),
+ init_user_table(T);
+init_user_table([]) -> true.
+
+mk_user_table_key(Row) ->
+ Key1 = element(1, Row),
+ Key2 = element(2, Row),
+ [length(Key1) | Key1] ++ [length(Key2) | Key2].
+
+table_cre_row(Tab, Key, Row) ->
+ snmpa_mib_lib:table_cre_row(db(Tab), Key, Row).
+
+table_del_row(Tab, Key) ->
+ snmpa_mib_lib:table_del_row(db(Tab), Key).
+
+
+add_user(EngineID, Name, SecName, Clone, AuthP, AuthKeyC, OwnAuthKeyC,
+ PrivP, PrivKeyC, OwnPrivKeyC, Public, AuthKey, PrivKey) ->
+ User = {EngineID, Name, SecName, Clone, AuthP, AuthKeyC, OwnAuthKeyC,
+ PrivP, PrivKeyC, OwnPrivKeyC, Public, AuthKey, PrivKey},
+ add_user(User).
+
+add_user(User) ->
+ case (catch check_usm(User)) of
+ {ok, Row} ->
+ case (catch check_user(Row)) of
+ {'EXIT', Reason} ->
+ {error, Reason};
+ _ ->
+ Key = mk_user_table_key(Row),
+ case table_cre_row(usmUserTable, Key, Row) of
+ true ->
+ {ok, Key};
+ false ->
+ {error, create_failed}
+ end
+ end;
+ {error, Reason} ->
+ {error, Reason};
+ Error ->
+ {error, Error}
+ end.
+
+delete_user(Key) ->
+ case table_del_row(usmUserTable, Key) of
+ true ->
+ ok;
+ false ->
+ {error, delete_failed}
+ end.
+
+
+gc_tabs() ->
+ DB = db(usmUserTable),
+ STC = stc(usmUserTable),
+ FOI = foi(usmUserTable),
+ snmpa_mib_lib:gc_tab(DB, STC, FOI),
+ ok.
+
+
+%%-----------------------------------------------------------------
+%% Counter functions
+%%-----------------------------------------------------------------
+init_vars() -> lists:map(fun maybe_create_var/1, vars()).
+
+maybe_create_var(Var) ->
+ case ets:lookup(snmp_agent_table, Var) of
+ [_] -> ok;
+ _ -> init_var(Var)
+ end.
+
+init_var(Var) -> ets:insert(snmp_agent_table, {Var, 0}).
+
+vars() ->
+ [
+ usmStatsUnsupportedSecLevels,
+ usmStatsNotInTimeWindows,
+ usmStatsUnknownUserNames,
+ usmStatsUnknownEngineIDs,
+ usmStatsWrongDigests,
+ usmStatsDecryptionErrors
+ ].
+
+%%-----------------------------------------------------------------
+%% API functions
+%%-----------------------------------------------------------------
+is_engine_id_known(EngineID) ->
+ EngineKey = [length(EngineID) | EngineID],
+ ?vtrace("is_engine_id_known -> EngineKey: ~w", [EngineKey]),
+ case table_next(usmUserTable, EngineKey) of
+ endOfTable -> false;
+ Key ->
+ ?vtrace("is_engine_id_known -> Key: ~w", [Key]),
+ lists:prefix(EngineKey, Key)
+ end.
+
+get_user(EngineID, UserName) ->
+ Key = [length(EngineID) | EngineID] ++ [length(UserName) | UserName],
+ snmp_generic:table_get_row(db(usmUserTable), Key, foi(usmUserTable)).
+
+get_user_from_security_name(EngineID, SecName) ->
+ %% Since the normal mapping between UserName and SecName is the
+ %% identityfunction, we first try to use the SecName as UserName,
+ %% and check the resulting row. If it doesn't match, we'll have to
+ %% loop through the entire table.
+ Key = [length(EngineID) | EngineID] ++ [length(SecName) | SecName],
+ case snmp_generic:table_get_row(db(usmUserTable), Key,
+ foi(usmUserTable)) of
+ Row when is_tuple(Row) ->
+ ?vtrace("get_user_from_security_name -> "
+ "found user using the identity function", []),
+ Row;
+ undefined ->
+ ?vtrace("get_user_from_security_name -> "
+ "user *not* found using the identity function", []),
+ F = fun(_, Row) when (
+ (element(?usmUserEngineID,Row) =:= EngineID) andalso
+ (element(?usmUserSecurityName,Row) =:= SecName)) ->
+ throw({ok, Row});
+ (_, _) ->
+ ok
+ end,
+ case catch snmp_generic:table_foreach(db(usmUserTable), F) of
+ {ok, Row} ->
+ Row;
+ _Else ->
+ undefined
+ end
+ end.
+
+
+%%-----------------------------------------------------------------
+%% Instrumentation Functions
+%%-----------------------------------------------------------------
+usmUserSpinLock(new) ->
+ snmp_generic:variable_func(new, {usmUserSpinLock, volatile}),
+ {A1,A2,A3} = erlang:now(),
+ random:seed(A1,A2,A3),
+ Val = random:uniform(2147483648) - 1,
+ snmp_generic:variable_func(set, Val, {usmUserSpinLock, volatile});
+
+usmUserSpinLock(delete) ->
+ ok;
+
+usmUserSpinLock(get) ->
+ snmp_generic:variable_func(get, {usmUserSpinLock, volatile}).
+
+usmUserSpinLock(is_set_ok, NewVal) ->
+ case snmp_generic:variable_func(get, {usmUserSpinLock, volatile}) of
+ {value, NewVal} -> noError;
+ _ -> inconsistentValue
+ end;
+usmUserSpinLock(set, NewVal) ->
+ snmp_generic:variable_func(set, (NewVal + 1) rem 2147483648,
+ {usmUserSpinLock, volatile}).
+
+
+%% Op = print - Used for debugging purposes
+usmUserTable(print) ->
+ Table = usmUserTable,
+ DB = db(Table),
+ FOI = foi(Table),
+ %% TableInfo = snmpa_mib_lib:get_table(db(Table), foi(Table)),
+ PrintRow =
+ fun(Prefix, Row) ->
+ lists:flatten(
+ io_lib:format("~sEngineID: ~p"
+ "~n~sName: ~p"
+ "~n~sSecurityName: ~p"
+ "~n~sCloneFrom: ~p"
+ "~n~sAuthProtocol: ~p (~w)"
+ "~n~sAuthKeyChange: ~p"
+ "~n~sOwnAuthKeyChange: ~p"
+ "~n~sPrivProtocol: ~p (~w)"
+ "~n~sPrivKeyChange: ~p"
+ "~n~sOwnPrivKeyChange: ~p"
+ "~n~sPublic: ~p"
+ "~n~sStorageType: ~p (~w)"
+ "~n~sStatus: ~p (~w)",
+ [Prefix, element(?usmUserEngineID, Row),
+ Prefix, element(?usmUserName, Row),
+ Prefix, element(?usmUserSecurityName, Row),
+ Prefix, element(?usmUserCloneFrom, Row),
+ Prefix, element(?usmUserAuthProtocol, Row),
+ case element(?usmUserAuthProtocol, Row) of
+ ?usmNoAuthProtocol -> none;
+ ?usmHMACMD5AuthProtocol -> md5;
+ ?usmHMACSHAAuthProtocol -> sha;
+ md5 -> md5;
+ sha -> sha;
+ _ -> undefined
+ end,
+ Prefix, element(?usmUserAuthKeyChange, Row),
+ Prefix, element(?usmUserOwnAuthKeyChange, Row),
+ Prefix, element(?usmUserPrivProtocol, Row),
+ case element(?usmUserPrivProtocol, Row) of
+ ?usmNoPrivProtocol -> none;
+ ?usmDESPrivProtocol -> des;
+ ?usmAesCfb128Protocol -> aes;
+ des -> des;
+ aes -> aes;
+ _ -> undefined
+ end,
+ Prefix, element(?usmUserPrivKeyChange, Row),
+ Prefix, element(?usmUserOwnPrivKeyChange, Row),
+ Prefix, element(?usmUserPublic, Row),
+ Prefix, element(?usmUserStorageType, Row),
+ case element(?usmUserStorageType, Row) of
+ ?'usmUserStorageType_readOnly' -> readOnly;
+ ?'usmUserStorageType_permanent' -> permanent;
+ ?'usmUserStorageType_nonVolatile' -> nonVolatile;
+ ?'usmUserStorageType_volatile' -> volatile;
+ ?'usmUserStorageType_other' -> other;
+ _ -> undefined
+ end,
+ Prefix, element(?usmUserStatus, Row),
+ case element(?usmUserStatus, Row) of
+ ?'usmUserStatus_destroy' -> destroy;
+ ?'usmUserStatus_createAndWait' -> createAndWait;
+ ?'usmUserStatus_createAndGo' -> createAndGo;
+ ?'usmUserStatus_notReady' -> notReady;
+ ?'usmUserStatus_notInService' -> notInService;
+ ?'usmUserStatus_active' -> active;
+ _ -> undefined
+ end]))
+ end,
+ snmpa_mib_lib:print_table(Table, DB, FOI, PrintRow);
+%% Op == new | delete
+usmUserTable(Op) ->
+ snmp_generic:table_func(Op, db(usmUserTable)).
+
+%% Op == get | is_set_ok | set | get_next
+usmUserTable(get, RowIndex, Cols) ->
+ get_patch(Cols, get(usmUserTable, RowIndex, Cols));
+usmUserTable(get_next, RowIndex, Cols) ->
+ next_patch(next(usmUserTable, RowIndex, Cols));
+usmUserTable(is_set_ok, RowIndex, Cols0) ->
+ ?vtrace("usmUserTable(is_set_ok) -> entry with"
+ "~n RowIndex: ~p"
+ "~n Cols0: ~p", [RowIndex, Cols0]),
+ case (catch verify_usmUserTable_cols(Cols0, [])) of
+ {ok, Cols} ->
+ ?vtrace("usmUserTable(is_set_ok) -> verified: "
+ "~n Cols: ~p", [Cols]),
+ %% Add a dummy value for securityName; otherwise snmp_generic will
+ %% think that a value is missing, so the row can't be created.
+ %% Note: this value is only added for is_set_ok, not for set!
+ NCols = [{?usmUserSecurityName, ""} | Cols],
+ IsSetOkRes = snmp_generic:table_func(is_set_ok, RowIndex,
+ NCols, db(usmUserTable)),
+ ?vtrace("usmUserTable(is_set_ok) -> tested: "
+ "~n IsSetOkRes: ~p", [IsSetOkRes]),
+ validate_is_set_ok(IsSetOkRes, RowIndex, Cols);
+ Error ->
+ Error
+ end;
+usmUserTable(set, RowIndex, Cols0) ->
+ ?vtrace("usmUserTable(set) -> entry with"
+ "~n RowIndex: ~p"
+ "~n Cols0: ~p", [RowIndex, Cols0]),
+ case (catch verify_usmUserTable_cols(Cols0, [])) of
+ {ok, Cols} ->
+ ?vtrace("usmUserTable(set) -> verified"
+ "~n Cols: ~p", [Cols]),
+ NCols = pre_set(RowIndex, Cols),
+ ?vtrace("usmUserTable(set) -> pre-set: "
+ "~n NCols: ~p", [NCols]),
+ %% NOTE: The NCols parameter is sent to snmp_generic, but not to
+ %% validate_set! The reason is that the columns from pre_set are
+ %% set in snmp_generic, but not used by validate_set.
+ validate_set(snmp_generic:table_func(set, RowIndex,
+ NCols, db(usmUserTable)),
+ RowIndex, Cols);
+ Error ->
+ Error
+ end;
+usmUserTable(Op, Arg1, Arg2) ->
+ snmp_generic:table_func(Op, Arg1, Arg2, db(usmUserTable)).
+
+
+verify_usmUserTable_cols([], Cols) ->
+ ?vtrace("verify_usmUserTable_cols -> entry when done with"
+ "~n Cols: ~p", [Cols]),
+ {ok, lists:reverse(Cols)};
+verify_usmUserTable_cols([{Col, Val0}|Cols], Acc) ->
+ ?vtrace("verify_usmUserTable_cols -> entry with"
+ "~n Col: ~p"
+ "~n Val0: ~p", [Col, Val0]),
+ Val = verify_usmUserTable_col(Col, Val0),
+ ?vtrace("verify_usmUserTable_cols -> verified: "
+ "~n Val: ~p", [Val]),
+ verify_usmUserTable_cols(Cols, [{Col, Val}|Acc]).
+
+verify_usmUserTable_col(?usmUserEngineID, EngineID) ->
+ case (catch snmp_conf:check_string(EngineID)) of
+ ok ->
+ EngineID;
+ _ ->
+ wrongValue(?usmUserEngineID)
+ end;
+verify_usmUserTable_col(?usmUserName, Name) ->
+ case (catch snmp_conf:check_string(Name)) of
+ ok ->
+ Name;
+ _ ->
+ wrongValue(?usmUserName)
+ end;
+verify_usmUserTable_col(?usmUserSecurityName, Name) ->
+ case (catch snmp_conf:check_string(Name)) of
+ ok ->
+ Name;
+ _ ->
+ wrongValue(?usmUserSecurityName)
+ end;
+verify_usmUserTable_col(?usmUserCloneFrom, Clone) ->
+ case Clone of
+ zeroDotZero -> ?zeroDotZero;
+ ?zeroDotZero -> ?zeroDotZero;
+ _ ->
+ case (catch snmp_conf:check_oid(Clone)) of
+ ok ->
+ Clone;
+ _ ->
+ wrongValue(?usmUserCloneFrom)
+ end
+ end;
+verify_usmUserTable_col(?usmUserAuthProtocol, AuthP) ->
+ case AuthP of
+ usmNoAuthProtocol -> ?usmNoAuthProtocol;
+ usmHMACSHAAuthProtocol -> ?usmHMACSHAAuthProtocol;
+ usmHMACMD5AuthProtocol -> ?usmHMACMD5AuthProtocol;
+ ?usmNoAuthProtocol -> ?usmNoAuthProtocol;
+ ?usmHMACSHAAuthProtocol -> ?usmHMACSHAAuthProtocol;
+ ?usmHMACMD5AuthProtocol -> ?usmHMACMD5AuthProtocol;
+ _ ->
+ wrongValue(?usmUserAuthProtocol)
+ end;
+verify_usmUserTable_col(?usmUserAuthKeyChange, AKC) ->
+ case (catch snmp_conf:check_string(AKC)) of
+ ok ->
+ AKC;
+ _ ->
+ wrongValue(?usmUserAuthKeyChange)
+ end;
+verify_usmUserTable_col(?usmUserOwnAuthKeyChange, OAKC) ->
+ case (catch snmp_conf:check_string(OAKC)) of
+ ok ->
+ OAKC;
+ _ ->
+ wrongValue(?usmUserOwnAuthKeyChange)
+ end;
+verify_usmUserTable_col(?usmUserPrivProtocol, PrivP) ->
+ case PrivP of
+ usmNoPrivProtocol -> ?usmNoPrivProtocol;
+ usmDESPrivProtocol -> ?usmDESPrivProtocol;
+ usmAesCfb128Protocol -> ?usmAesCfb128Protocol;
+ ?usmNoPrivProtocol -> ?usmNoPrivProtocol;
+ ?usmDESPrivProtocol -> ?usmDESPrivProtocol;
+ ?usmAesCfb128Protocol -> ?usmAesCfb128Protocol;
+ _ ->
+ wrongValue(?usmUserPrivProtocol)
+ end;
+verify_usmUserTable_col(?usmUserPrivKeyChange, PKC) ->
+ case (catch snmp_conf:check_string(PKC)) of
+ ok ->
+ PKC;
+ _ ->
+ wrongValue(?usmUserPrivKeyChange)
+ end;
+verify_usmUserTable_col(?usmUserOwnPrivKeyChange, OPKC) ->
+ case (catch snmp_conf:check_string(OPKC)) of
+ ok ->
+ OPKC;
+ _ ->
+ wrongValue(?usmUserOwnPrivKeyChange)
+ end;
+verify_usmUserTable_col(?usmUserPublic, Public) ->
+ case (catch snmp_conf:check_string(Public)) of
+ ok ->
+ Public;
+ _ ->
+ wrongValue(?usmUserPublic)
+ end;
+verify_usmUserTable_col(_, Val) ->
+ Val.
+
+
+%% Patch the values stored in the DB with other values for some
+%% objects.
+get_patch([?usmUserCloneFrom | Cols], [{value, _Val} | Vals]) ->
+ [{value, ?zeroDotZero} | get_patch(Cols, Vals)];
+get_patch([?usmUserAuthKeyChange | Cols], [{value, _Val} | Vals]) ->
+ [{value, ""} | get_patch(Cols, Vals)];
+get_patch([?usmUserOwnAuthKeyChange | Cols], [{value, _Val} | Vals]) ->
+ [{value, ""} | get_patch(Cols, Vals)];
+get_patch([?usmUserPrivKeyChange | Cols], [{value, _Val} | Vals]) ->
+ [{value, ""} | get_patch(Cols, Vals)];
+get_patch([?usmUserOwnPrivKeyChange | Cols], [{value, _Val} | Vals]) ->
+ [{value, ""} | get_patch(Cols, Vals)];
+get_patch([_Col | Cols], [Val | Vals]) ->
+ [Val | get_patch(Cols, Vals)];
+get_patch(_Cols, Result) ->
+ Result.
+
+next_patch([{[?usmUserCloneFrom | Idx], _Val} | Vals]) ->
+ [{[?usmUserCloneFrom | Idx], ?zeroDotZero} | next_patch(Vals)];
+next_patch([{[?usmUserAuthKeyChange | Idx], _Val} | Vals]) ->
+ [{[?usmUserAuthKeyChange | Idx], ""} | next_patch(Vals)];
+next_patch([{[?usmUserOwnAuthKeyChange | Idx], _Val} | Vals]) ->
+ [{[?usmUserOwnAuthKeyChange | Idx], ""} | next_patch(Vals)];
+next_patch([{[?usmUserPrivKeyChange | Idx], _Val} | Vals]) ->
+ [{[?usmUserPrivKeyChange | Idx], ""} | next_patch(Vals)];
+next_patch([{[?usmUserOwnPrivKeyChange | Idx], _Val} | Vals]) ->
+ [{[?usmUserOwnPrivKeyChange | Idx], ""} | next_patch(Vals)];
+next_patch([Val | Vals]) ->
+ [Val | next_patch(Vals)];
+next_patch(Result) -> Result.
+
+
+validate_is_set_ok({noError, 0}, RowIndex, Cols) ->
+ case (catch do_validate_is_set_ok(RowIndex, Cols)) of
+ ok ->
+ {noError, 0};
+ Error ->
+ Error
+ end;
+validate_is_set_ok(Error, _RowIndex, _Cols) ->
+ Error.
+
+do_validate_is_set_ok(RowIndex, Cols) ->
+ validate_clone_from(RowIndex, Cols),
+ validate_auth_protocol(RowIndex, Cols),
+ validate_auth_key_change(RowIndex, Cols),
+ validate_own_auth_key_change(RowIndex, Cols),
+ validate_priv_protocol(RowIndex, Cols),
+ validate_priv_key_change(RowIndex, Cols),
+ validate_own_priv_key_change(RowIndex, Cols),
+ ok.
+
+pre_set(RowIndex, Cols) ->
+ %% Possibly initialize the usmUserSecurityName and privacy keys
+ case snmp_generic:table_row_exists(db(usmUserTable), RowIndex) of
+ true -> Cols;
+ false ->
+ SecName = get_user_name(RowIndex),
+ [{?usmUserSecurityName, SecName} | Cols] ++
+ [{?usmUserAuthKey, ""},
+ {?usmUserPrivKey, ""}]
+ end.
+
+validate_set({noError, 0}, RowIndex, Cols) ->
+ %% Now, all is_set_ok validation steps have been executed. So
+ %% everything is ready for the set.
+ set_clone_from(RowIndex, Cols),
+ set_auth_key_change(RowIndex, Cols),
+ set_own_auth_key_change(RowIndex, Cols),
+ set_priv_key_change(RowIndex, Cols),
+ set_own_priv_key_change(RowIndex, Cols),
+ {noError, 0};
+validate_set(Error, _RowIndex, _Cols) ->
+ Error.
+
+%%-----------------------------------------------------------------
+%% Here's the alg: If this is the first time the CloneFrom is written,
+%% we must check that the CloneFrom row exists, so we can invoke the
+%% clone process in the set phase. Otherwise, the set succed, with
+%% no further checks.
+%%-----------------------------------------------------------------
+validate_clone_from(RowIndex, Cols) ->
+ case lists:keysearch(?usmUserCloneFrom, 1, Cols) of
+ {value, {_Col, RowPointer}} ->
+ RowIndex2 = extract_row(RowPointer),
+ OldCloneFrom = snmp_generic:table_get_element(db(usmUserTable),
+ RowIndex,
+ ?usmUserCloneFrom),
+ case OldCloneFrom of
+ {value, Val} when Val /= noinit ->
+ %% This means that the cloning is already done...
+ ok;
+ _ ->
+ %% Otherwise, we must check the CloneFrom value
+ case snmp_generic:table_get_element(db(usmUserTable),
+ RowIndex2,
+ ?usmUserStatus) of
+ {value, ?'RowStatus_active'} -> ok;
+ _ -> inconsistentName(?usmUserCloneFrom)
+ end
+ end;
+ false ->
+ ok
+ end.
+
+
+validate_auth_protocol(RowIndex, Cols) ->
+ case lists:keysearch(?usmUserAuthProtocol, 1, Cols) of
+ {value, {_Col, AuthProtocol}} ->
+ %% Check if the row has been cloned; we can't check the
+ %% old value of authProtocol, because if the row was
+ %% createAndWaited, the default value would have been
+ %% written (usmNoAuthProtocol).
+ OldCloneFrom = snmp_generic:table_get_element(db(usmUserTable),
+ RowIndex,
+ ?usmUserCloneFrom),
+ case OldCloneFrom of
+ {value, Val} when Val /= noinit ->
+ %% This means that the cloning is already done; set is ok
+ %% if new protocol is usmNoAuthProtocol
+ case AuthProtocol of
+ ?usmNoAuthProtocol ->
+ %% Check that the Priv protocl is noPriv
+ case get_priv_proto(RowIndex, Cols) of
+ ?usmNoPrivProtocol -> ok;
+ _ -> inconsistentValue(?usmUserAuthProtocol)
+ end;
+ ?usmHMACMD5AuthProtocol ->
+ inconsistentValue(?usmUserAuthProtocol);
+ ?usmHMACSHAAuthProtocol ->
+ inconsistentValue(?usmUserAuthProtocol);
+ _ ->
+ wrongValue(?usmUserAuthProtocol)
+ end;
+ _ ->
+ %% Otherwise, check that the new protocol is known,
+ %% and that the system we're running supports the
+ %% hash function.
+ case AuthProtocol of
+ ?usmNoAuthProtocol ->
+ %% Check that the Priv protocl is noPriv
+ case get_priv_proto(RowIndex, Cols) of
+ ?usmNoPrivProtocol -> ok;
+ _ -> inconsistentValue(?usmUserAuthProtocol)
+ end;
+ ?usmHMACMD5AuthProtocol ->
+ case is_crypto_supported(md5_mac_96) of
+ true -> ok;
+ false ->
+ wrongValue(?usmUserAuthProtocol)
+ end;
+ ?usmHMACSHAAuthProtocol ->
+ case is_crypto_supported(sha_mac_96) of
+ true -> ok;
+ false ->
+ wrongValue(?usmUserAuthProtocol)
+ end;
+ _ -> wrongValue(?usmUserAuthProtocol)
+ end
+ end;
+ false ->
+ ok
+ end.
+
+validate_auth_key_change(RowIndex, Cols) ->
+ validate_key_change(RowIndex, Cols, ?usmUserAuthKeyChange, auth).
+
+validate_own_auth_key_change(RowIndex, Cols) ->
+ validate_requester(RowIndex, Cols, ?usmUserOwnAuthKeyChange),
+ validate_key_change(RowIndex, Cols, ?usmUserOwnAuthKeyChange, auth).
+
+validate_priv_key_change(RowIndex, Cols) ->
+ validate_key_change(RowIndex, Cols, ?usmUserPrivKeyChange, priv).
+
+validate_own_priv_key_change(RowIndex, Cols) ->
+ validate_requester(RowIndex, Cols, ?usmUserOwnPrivKeyChange),
+ validate_key_change(RowIndex, Cols, ?usmUserOwnPrivKeyChange, priv).
+
+%% Check that the requesting user is the same as the modified user
+validate_requester(RowIndex, Cols, KeyChangeCol) ->
+ case lists:keysearch(KeyChangeCol, 1, Cols) of
+ {value, _} ->
+ case get(sec_model) of % Check the securityModel in the request
+ ?SEC_USM -> ok;
+ _ -> noAccess(KeyChangeCol)
+ end,
+ %% The SecurityName may not be set yet. First, check if it is set.
+ SecNameForUser =
+ case snmp_generic:table_get_element(db(usmUserTable),
+ RowIndex,
+ ?usmUserSecurityName) of
+ {value, Val} when Val /= noinit -> Val;
+ _ -> get_user_name(RowIndex)
+ end,
+ case get(sec_name) of % Check the securityName in the request
+ SecNameForUser -> ok;
+ _ -> noAccess(KeyChangeCol)
+ end;
+ false ->
+ ok
+ end.
+
+validate_key_change(RowIndex, Cols, KeyChangeCol, Type) ->
+ case lists:keysearch(KeyChangeCol, 1, Cols) of
+ {value, {_Col, KeyC}} ->
+ %% Check if the row has been cloned; or if it is cloned in
+ %% this set-operation.
+ OldCloneFrom = snmp_generic:table_get_element(db(usmUserTable),
+ RowIndex,
+ ?usmUserCloneFrom),
+ IsClonePresent = case lists:keysearch(?usmUserCloneFrom, 1, Cols) of
+ {value, _} -> true;
+ false -> false
+ end,
+ %% Set is ok if 1) the user already is created, 2) this is
+ %% a new user, which has been cloned, or is about to be
+ %% cloned.
+ case {OldCloneFrom, IsClonePresent} of
+ {{value, Val}, _} when Val /= noinit ->
+ %% The user exists, or has been cloned
+ ok;
+ {_, true} ->
+ %% The user is cloned in this operation
+ ok;
+ _ ->
+ %% The user doen't exist, or hasn't been cloned,
+ %% and is not cloned in this operation.
+ inconsistentName(KeyChangeCol)
+ end,
+ %% Check that the length makes sense
+ Len = length(KeyC),
+ case Type of
+ auth ->
+ case get_auth_proto(RowIndex, Cols) of
+ ?usmNoAuthProtocol -> ok;
+ ?usmHMACMD5AuthProtocol when Len =:= 32 -> ok;
+ ?usmHMACSHAAuthProtocol when Len =:= 40 -> ok;
+ _ -> wrongValue(KeyChangeCol)
+ end;
+ priv ->
+ case get_priv_proto(RowIndex, Cols) of
+ ?usmNoPrivProtocol -> ok;
+ ?usmDESPrivProtocol when Len == 32 -> ok;
+ ?usmAesCfb128Protocol when Len == 32 -> ok;
+ _ -> wrongValue(KeyChangeCol)
+ end
+ end;
+ false ->
+ ok
+ end.
+
+validate_priv_protocol(RowIndex, Cols) ->
+ case lists:keysearch(?usmUserPrivProtocol, 1, Cols) of
+ {value, {_Col, PrivProtocol}} ->
+ %% Check if the row has been cloned; we can't check the
+ %% old value of privhProtocol, because if the row was
+ %% createAndWaited, the default value would have been
+ %% written (usmNoPrivProtocol).
+ OldCloneFrom = snmp_generic:table_get_element(db(usmUserTable),
+ RowIndex,
+ ?usmUserCloneFrom),
+ case OldCloneFrom of
+ {value, Val} when Val /= noinit ->
+ %% This means that the cloning is already done; set is ok
+ %% if new protocol is usmNoPrivProtocol
+ case PrivProtocol of
+ ?usmNoPrivProtocol ->
+ ok;
+ ?usmDESPrivProtocol ->
+ inconsistentValue(?usmUserPrivProtocol);
+ ?usmAesCfb128Protocol ->
+ inconsistentValue(?usmUserPrivProtocol);
+ _ ->
+ wrongValue(?usmUserPrivProtocol)
+ end;
+ _ ->
+ %% Otherwise, check that the new protocol is known,
+ %% and that the system we're running supports the
+ %% crypto function.
+ case PrivProtocol of
+ ?usmNoPrivProtocol ->
+ ok;
+ ?usmDESPrivProtocol ->
+ %% The 'catch' handles the case when 'crypto' is
+ %% not present in the system.
+ case is_crypto_supported(des_cbc_decrypt) of
+ true ->
+ case get_auth_proto(RowIndex, Cols) of
+ ?usmNoAuthProtocol ->
+ inconsistentValue(?usmUserPrivProtocol);
+ _ ->
+ ok
+ end;
+ false ->
+ wrongValue(?usmUserPrivProtocol)
+ end;
+ ?usmAesCfb128Protocol ->
+ %% The 'catch' handles the case when 'crypto' is
+ %% not present in the system.
+ case is_crypto_supported(aes_cfb_128_decrypt) of
+ true ->
+ case get_auth_proto(RowIndex, Cols) of
+ ?usmNoAuthProtocol ->
+ inconsistentValue(?usmUserPrivProtocol);
+ _ ->
+ ok
+ end;
+ false ->
+ wrongValue(?usmUserPrivProtocol)
+ end;
+ _ -> wrongValue(?usmUserPrivProtocol)
+ end
+ end;
+ false ->
+ ok
+ end.
+
+
+set_clone_from(RowIndex, Cols) ->
+ %% If CloneFrom is modified, do the cloning.
+ case lists:keysearch(?usmUserCloneFrom, 1, Cols) of
+ {value, {_Col, RowPointer}} ->
+ RowIndex2 = extract_row(RowPointer), % won't fail
+ CloneRow = snmp_generic:table_get_row(db(usmUserTable), RowIndex2,
+ foi(usmUserTable)),
+ AuthP = element(?usmUserAuthProtocol, CloneRow),
+ PrivP = element(?usmUserPrivProtocol, CloneRow),
+ AuthK = element(?usmUserAuthKey, CloneRow),
+ PrivK = element(?usmUserPrivKey, CloneRow),
+ SCols = [{?usmUserAuthProtocol, AuthP},
+ {?usmUserPrivProtocol, PrivP},
+ {?usmUserAuthKey, AuthK},
+ {?usmUserPrivKey, PrivK}],
+ case snmp_generic:table_set_elements(db(usmUserTable),
+ RowIndex,
+ SCols) of
+ true -> ok;
+ false -> {commitFailed, ?usmUserCloneFrom}
+ end;
+ false ->
+ ok
+ end.
+
+set_auth_key_change(RowIndex, Cols) ->
+ set_key_change(RowIndex, Cols, ?usmUserAuthKeyChange, auth).
+
+set_own_auth_key_change(RowIndex, Cols) ->
+ set_key_change(RowIndex, Cols, ?usmUserOwnAuthKeyChange, auth).
+
+set_priv_key_change(RowIndex, Cols) ->
+ set_key_change(RowIndex, Cols, ?usmUserPrivKeyChange, priv).
+
+set_own_priv_key_change(RowIndex, Cols) ->
+ set_key_change(RowIndex, Cols, ?usmUserOwnPrivKeyChange, priv).
+
+set_key_change(RowIndex, Cols, KeyChangeCol, Type) ->
+ case lists:keysearch(KeyChangeCol, 1, Cols) of
+ {value, {_Col, KeyChange}} ->
+ KeyCol = case Type of
+ auth -> ?usmUserAuthKey;
+ priv -> ?usmUserPrivKey
+ end,
+ [AuthP, Key] =
+ snmp_generic:table_get_elements(db(usmUserTable),
+ RowIndex,
+ [?usmUserAuthProtocol,
+ KeyCol]),
+ NewKey = extract_new_key(AuthP, Key, KeyChange),
+ snmp_generic:table_set_element(db(usmUserTable), RowIndex,
+ KeyCol, NewKey);
+ false ->
+ ok
+ end.
+
+%% Extract the UserName part from a RowIndex.
+get_user_name([L1 | Rest]) -> get_user_name(L1, Rest).
+get_user_name(0, [_L2 | UserName]) -> UserName;
+get_user_name(N, [_H | T]) -> get_user_name(N-1, T).
+
+extract_row(RowPtr) -> extract_row(?usmUserEntry, RowPtr).
+extract_row([H | T], [H | T2]) -> extract_row(T, T2);
+extract_row([], [?usmUserSecurityName | T]) -> T;
+extract_row(_, _) -> wrongValue(?usmUserCloneFrom).
+
+%% Pre: the user exixt
+get_auth_proto(RowIndex, Cols) ->
+ %% The protocol can be chanegd by the request too, otherwise,
+ %% check the stored protocol.
+ case lists:keysearch(?usmUserAuthProtocol, 1, Cols) of
+ {value, {_, Protocol}} ->
+ Protocol;
+ false ->
+ %% OTP-3596
+ case snmp_generic:table_get_element(db(usmUserTable),
+ RowIndex,
+ ?usmUserAuthProtocol) of
+ {value, Protocol} ->
+ Protocol;
+ _ ->
+ undefined
+ end
+ end.
+
+%% Pre: the user exixt
+get_priv_proto(RowIndex, Cols) ->
+ %% The protocol can be chanegd by the request too, otherwise,
+ %% check the stored protocol.
+ case lists:keysearch(?usmUserPrivProtocol, 1, Cols) of
+ {value, {_, Protocol}} ->
+ Protocol;
+ false ->
+ %% OTP-3596
+ case snmp_generic:table_get_element(db(usmUserTable),
+ RowIndex,
+ ?usmUserPrivProtocol) of
+ {value, Protocol} ->
+ Protocol;
+ _ ->
+ undefined
+ end
+ end.
+
+
+db(X) -> snmpa_agent:db(X).
+
+fa(usmUserTable) -> ?usmUserSecurityName.
+
+foi(usmUserTable) -> ?usmUserEngineID.
+
+noc(usmUserTable) -> 13.
+
+stc(usmUserTable) -> ?usmUserStorageType.
+
+next(Name, RowIndex, Cols) ->
+ snmp_generic:handle_table_next(db(Name), RowIndex, Cols,
+ fa(Name), foi(Name), noc(Name)).
+
+table_next(Name, RestOid) ->
+ snmp_generic:table_next(db(Name), RestOid).
+
+
+get(Name, RowIndex, Cols) ->
+ snmp_generic:handle_table_get(db(Name), RowIndex, Cols, foi(Name)).
+
+%%-----------------------------------------------------------------
+%% Key change functions. The KeyChange Texual-Convention is
+%% defined in the SNMP-USER-BASED-SM-MIB.
+%% Note that this implementation supports md5 and sha, which
+%% both have fixed length requirements on the length of the key;
+%% thus the implementation can be (and is) simplified.
+%%-----------------------------------------------------------------
+mk_key_change(Hash, OldKey, NewKey) ->
+ KeyLen = length(NewKey),
+ Alg = case Hash of
+ ?usmHMACMD5AuthProtocol -> md5;
+ ?usmHMACSHAAuthProtocol -> sha;
+ md5 -> md5;
+ sha -> sha
+ end,
+ Random = mk_random(KeyLen),
+ mk_key_change(Alg, OldKey, NewKey, KeyLen, Random).
+
+%% This function is only exported for test purposes. There is a test
+%% case in the standard where Random is pre-defined.
+mk_key_change(Alg, OldKey, NewKey, KeyLen, Random) ->
+ %% OldKey and Random is of length KeyLen...
+ Digest = lists:sublist(binary_to_list(crypto:Alg(OldKey++Random)), KeyLen),
+ %% ... and so is Digest
+ Delta = snmp_misc:str_xor(Digest, NewKey),
+ Random ++ Delta.
+
+%% Extracts a new Key from a KeyChange value, sent by a manager.
+extract_new_key(?usmNoAuthProtocol, OldKey, _KeyChange) ->
+ OldKey;
+extract_new_key(Hash, OldKey, KeyChange) ->
+ KeyLen = length(OldKey),
+ Alg = case Hash of
+ ?usmHMACMD5AuthProtocol -> md5;
+ ?usmHMACSHAAuthProtocol -> sha;
+ md5 -> md5;
+ sha -> sha
+ end,
+ {Random, Delta} = split(KeyLen, KeyChange, []),
+ Digest = lists:sublist(binary_to_list(crypto:Alg(OldKey++Random)), KeyLen),
+ NewKey = snmp_misc:str_xor(Digest, Delta),
+ NewKey.
+
+-define(i16(Int), (Int bsr 8) band 255, Int band 255).
+-define(i8(Int), Int band 255).
+
+mk_random(Len) when Len =< 20 ->
+ %% Use of yield():
+ %% This will either schedule another process, or fail and invoke
+ %% the error_handler (in old versions). In either case, it is
+ %% safe to assume that now, reductions and garbage_collection have
+ %% changed in a non-deterministically way.
+ {_,_,A} = erlang:now(),
+ catch erlang:yield(),
+ {_,_,B} = erlang:now(),
+ catch erlang:yield(),
+ {_,_,C} = erlang:now(),
+ {D,_} = erlang:statistics(reductions),
+ {E,_} = erlang:statistics(runtime),
+ {F,_} = erlang:statistics(wall_clock),
+ {G,H,_} = erlang:statistics(garbage_collection),
+ catch erlang:yield(),
+ {_,_,C2} = erlang:now(),
+ {D2,_} = erlang:statistics(reductions),
+ {_,H2,_} = erlang:statistics(garbage_collection),
+ %% X(N) means we can use N bits from variable X:
+ %% A(16) B(16) C(16) D(16) E(8) F(16) G(8) H(16)
+ Rnd20 = [?i16(A),?i16(B),?i16(C),?i16(D),?i8(E),?i16(F),
+ ?i8(G),?i16(H),?i16(C2),?i16(D2),?i16(H2)],
+ lists:sublist(Rnd20, Len).
+
+split(0, Rest, FirstRev) ->
+ {lists:reverse(FirstRev), Rest};
+split(N, [H | T], FirstRev) when N > 0 ->
+ split(N-1, T, [H | FirstRev]).
+
+
+is_crypto_supported(Func) ->
+ %% The 'catch' handles the case when 'crypto' is
+ %% not present in the system (or not started).
+ case catch lists:member(Func, crypto:info()) of
+ true -> true;
+ _ -> false
+ end.
+
+inconsistentValue(V) -> throw({inconsistentValue, V}).
+inconsistentName(N) -> throw({inconsistentName, N}).
+wrongValue(V) -> throw({wrongValue, V}).
+noAccess(C) -> throw({noAccess, C}).
+
+set_sname() ->
+ set_sname(get(sname)).
+
+set_sname(undefined) ->
+ put(sname,conf);
+set_sname(_) -> %% Keep it, if already set.
+ ok.
+
+error(Reason) ->
+ throw({error, Reason}).
+
+%%-----------------------------------------------------------------
+
+info_msg(F, A) ->
+ ?snmpa_info("USM: " ++ F, A).
+
+%% ---
+
+config_err(F, A) ->
+ snmpa_error:config_err("[USER-BASED-SM-MIB]: " ++ F, A).
+
diff --git a/lib/snmp/src/agent/snmp_view_based_acm_mib.erl b/lib/snmp/src/agent/snmp_view_based_acm_mib.erl
new file mode 100644
index 0000000000..873ab00545
--- /dev/null
+++ b/lib/snmp/src/agent/snmp_view_based_acm_mib.erl
@@ -0,0 +1,832 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1999-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%
+%%
+-module(snmp_view_based_acm_mib).
+
+-export([configure/1, reconfigure/1, table_next/2, get/3]).
+
+-export([vacmAccessTable/1, vacmAccessTable/3,
+ vacmContextTable/1, vacmContextTable/3,
+ vacmSecurityToGroupTable/1, vacmSecurityToGroupTable/3,
+ vacmViewSpinLock/1, vacmViewSpinLock/2,
+ vacmViewTreeFamilyTable/1, vacmViewTreeFamilyTable/3]).
+-export([add_sec2group/3, delete_sec2group/1,
+ add_access/8, delete_access/1,
+ add_view_tree_fam/4, delete_view_tree_fam/1]).
+
+%% Internal exports
+-export([check_vacm/1]).
+
+
+-include("snmp_types.hrl").
+-include("SNMPv2-TC.hrl").
+-include("SNMP-VIEW-BASED-ACM-MIB.hrl").
+-include("snmpa_vacm.hrl").
+
+
+-define(VMODULE,"VACM-MIB").
+-include("snmp_verbosity.hrl").
+
+-ifndef(default_verbosity).
+-define(default_verbosity,silence).
+-endif.
+
+
+%%-----------------------------------------------------------------
+%% Func: configure/1
+%% Args: Dir is the directory where the configuration files are found.
+%% Purpose: If the tables doesn't exist, this function reads
+%% the config-files for the VACM tables, and
+%% inserts the data. This means that the data in the tables
+%% survive a reboot. However, the StorageType column is
+%% checked for each row. If volatile, the row is deleted.
+%% Returns: ok
+%% Fails: exit(configuration_error)
+%%-----------------------------------------------------------------
+configure(Dir) ->
+ set_sname(),
+ case db(vacmSecurityToGroupTable) of
+ {_, mnesia} ->
+ ?vdebug("vacm security-to-group table in mnesia: cleanup",[]),
+ gc_tabs(),
+ init_vacm_mnesia();
+ TabDb ->
+ case snmpa_local_db:table_exists(TabDb) of
+ true ->
+ ?vdebug("vacm security-to-group table already exist: "
+ "cleanup",[]),
+ gc_tabs();
+ false ->
+ ?vdebug("vacm security-to-group table does not exist: "
+ "reconfigure",[]),
+ reconfigure(Dir)
+ end
+ end.
+
+%%-----------------------------------------------------------------
+%% Func: reconfigure/1
+%% Args: Dir is the directory where the configuration files are found.
+%% Purpose: Reads the config-files for the VACM tables, and
+%% inserts the data. Makes sure that all old data in
+%% the tables are deleted, and the new data inserted.
+%% This function makes sure that all (and only)
+%% config-file-data are in the tables.
+%% Returns: ok
+%% Fails: exit(configuration_error)
+%%-----------------------------------------------------------------
+reconfigure(Dir) ->
+ set_sname(),
+ case (catch do_reconfigure(Dir)) of
+ ok ->
+ ok;
+ {error, Reason} ->
+ ?vinfo("reconfigure error: ~p", [Reason]),
+ config_err("reconfigure failed: ~p", [Reason]),
+ exit(configuration_error);
+ Error ->
+ ?vinfo("reconfigure failed: ~p", [Error]),
+ config_err("reconfigure failed: ~p", [Error]),
+ exit(configuration_error)
+ end.
+
+do_reconfigure(Dir) ->
+ ?vdebug("read vacm configuration files",[]),
+ {Sec2Group, Access, View} = read_vacm_config_files(Dir),
+ ?vdebug("initiate tables",[]),
+ init_tabs(Sec2Group, Access, View),
+ ok.
+
+read_vacm_config_files(Dir) ->
+ ?vdebug("read vacm config file",[]),
+ Gen = fun(_) -> ok end,
+ Filter = fun(Vacms) ->
+ Sec2Group = [X || {vacmSecurityToGroup, X} <- Vacms],
+ Access = [X || {vacmAccess, X} <- Vacms],
+ View = [X || {vacmViewTreeFamily, X} <- Vacms],
+ {Sec2Group, Access, View}
+ end,
+ Check = fun(Entry) -> check_vacm(Entry) end,
+ [Vacms] = snmp_conf:read_files(Dir, [{Gen, Filter, Check, "vacm.conf"}]),
+ Vacms.
+
+%%-----------------------------------------------------------------
+%% VACM tables
+%%-----------------------------------------------------------------
+check_vacm({vacmSecurityToGroup, SecModel, SecName, GroupName}) ->
+ {ok, SecM} = snmp_conf:check_sec_model(SecModel, []),
+ snmp_conf:check_string(SecName),
+ snmp_conf:check_string(GroupName),
+
+ Vacm = {SecM, SecName, GroupName,
+ ?'StorageType_nonVolatile', ?'RowStatus_active'},
+ {ok, {vacmSecurityToGroup, Vacm}};
+check_vacm({vacmAccess, GroupName, Prefix, SecModel, SecLevel,
+ Match, RV, WV, NV}) ->
+ snmp_conf:check_string(GroupName),
+ snmp_conf:check_string(Prefix),
+ {ok, SecM} = snmp_conf:check_sec_model(SecModel, []),
+ {ok, SecL} = snmp_conf:check_sec_level(SecLevel),
+ MatchAlt = [{exact, ?vacmAccessContextMatch_exact},
+ {prefix, ?vacmAccessContextMatch_prefix}],
+ {ok, M} = snmp_conf:check_atom(Match, MatchAlt),
+ snmp_conf:check_string(RV),
+ snmp_conf:check_string(WV),
+ snmp_conf:check_string(NV),
+
+ %% GN, Prefix, Model, Level, Row
+ Vacm = {GroupName, Prefix, SecM, SecL,
+ {M, RV, WV, NV,
+ ?'StorageType_nonVolatile', ?'RowStatus_active'}},
+ {ok, {vacmAccess, Vacm}};
+check_vacm({vacmViewTreeFamily, ViewName, Tree, Type, Mask}) ->
+ snmp_conf:check_string(ViewName),
+ snmp_conf:check_oid(Tree),
+ {ok, TypeVal} =
+ snmp_conf:check_atom(Type, [{included, ?view_included},
+ {excluded, ?view_excluded}]),
+ MaskVal =
+ case (catch snmp_conf:check_atom(Mask, [{null, []}])) of
+ {error, _} ->
+ snmp_conf:check_oid(Mask),
+ Mask;
+ {ok, X} ->
+ X
+ end,
+ Vacm = {ViewName, Tree, MaskVal, TypeVal,
+ ?'StorageType_nonVolatile', ?'RowStatus_active'},
+ {ok, {vacmViewTreeFamily, Vacm}};
+check_vacm(X) ->
+ error({invalid_vacm, X}).
+
+
+init_tabs(Sec2Group, Access, View) ->
+ ?vdebug("create vacm security-to-group table",[]),
+ snmpa_local_db:table_delete(db(vacmSecurityToGroupTable)),
+ snmpa_local_db:table_create(db(vacmSecurityToGroupTable)),
+ init_sec2group_table(Sec2Group),
+ init_access_table(Access),
+ ?vdebug("create vacm view-tree-family table",[]),
+ snmpa_local_db:table_delete(db(vacmViewTreeFamilyTable)),
+ snmpa_local_db:table_create(db(vacmViewTreeFamilyTable)),
+ init_view_table(View).
+
+init_sec2group_table([Row | T]) ->
+% ?vtrace("init security-to-group table: "
+% "~n Row: ~p",[Row]),
+ Key1 = element(1, Row),
+ Key2 = element(2, Row),
+ Key = [Key1, length(Key2) | Key2],
+ snmpa_local_db:table_create_row(db(vacmSecurityToGroupTable), Key, Row),
+ init_sec2group_table(T);
+init_sec2group_table([]) -> true.
+
+init_access_table([{GN, Prefix, Model, Level, Row} | T]) ->
+% ?vtrace("init access table: "
+% "~n GN: ~p"
+% "~n Prefix: ~p"
+% "~n Model: ~p"
+% "~n Level: ~p"
+% "~n Row: ~p",[GN, Prefix, Model, Level, Row]),
+ Key = [length(GN) | GN] ++ [length(Prefix) | Prefix] ++ [Model, Level],
+ snmpa_vacm:insert([{Key, Row}], false),
+ init_access_table(T);
+init_access_table([]) ->
+ snmpa_vacm:dump_table().
+
+init_view_table([Row | T]) ->
+% ?vtrace("init view table: "
+% "~n Row: ~p",[Row]),
+ Key1 = element(1, Row),
+ Key2 = element(2, Row),
+ Key = [length(Key1) | Key1] ++ [length(Key2) | Key2],
+ snmpa_local_db:table_create_row(db(vacmViewTreeFamilyTable), Key, Row),
+ init_view_table(T);
+init_view_table([]) -> true.
+
+
+table_cre_row(Tab, Key, Row) ->
+ snmpa_mib_lib:table_cre_row(db(Tab), Key, Row).
+
+table_del_row(Tab, Key) ->
+ snmpa_mib_lib:table_del_row(db(Tab), Key).
+
+
+%% add_sec2group(SecModel, SecName, GroupName) -> Result
+%% Result -> {ok, Key} | {error, Reason}
+%% Key -> term()
+%% Reason -> term()
+add_sec2group(SecModel, SecName, GroupName) ->
+ Sec2Grp = {vacmSecurityToGroup, SecModel, SecName, GroupName},
+ case (catch check_vacm(Sec2Grp)) of
+ {ok, {vacmSecurityToGroup, Row}} ->
+ Key1 = element(1, Row),
+ Key2 = element(2, Row),
+ Key = [Key1, length(Key2) | Key2],
+ case table_cre_row(vacmSecurityToGroupTable, Key, Row) of
+ true ->
+ {ok, Key};
+ false ->
+ {error, create_failed}
+ end;
+ {error, Reason} ->
+ {error, Reason};
+ Error ->
+ {error, Error}
+ end.
+
+delete_sec2group(Key) ->
+ case table_del_row(vacmSecurityToGroupTable, Key) of
+ true ->
+ ok;
+ false ->
+ {error, delete_failed}
+ end.
+
+%% NOTE: This function must be used in conjuction with
+%% snmpa_vacm:dump_table.
+%% That is, when all access has been added, call
+%% snmpa_vacm:dump_table/0
+add_access(GroupName, Prefix, SecModel, SecLevel, Match, RV, WV, NV) ->
+ Access = {vacmAccess, GroupName, Prefix, SecModel, SecLevel,
+ Match, RV, WV, NV},
+ case (catch check_vacm(Access)) of
+ {ok, {vacmAccess, {GN, Pref, SM, SL, Row}}} ->
+ Key1 = [length(GN) | GN],
+ Key2 = [length(Pref) | Pref],
+ Key3 = [SM, SL],
+ Key = Key1 ++ Key2 ++ Key3,
+ snmpa_vacm:insert([{Key, Row}], false),
+ {ok, Key};
+ {error, Reason} ->
+ {error, Reason};
+ Error ->
+ {error, Error}
+ end.
+
+delete_access(Key) ->
+ snmpa_vacm:delete(Key).
+
+
+add_view_tree_fam(ViewIndex, SubTree, Status, Mask) ->
+ VTF = {vacmViewTreeFamily, ViewIndex, SubTree, Status, Mask},
+ case (catch check_vacm(VTF)) of
+ {ok, {vacmViewTreeFamily, Row}} ->
+ Key1 = element(1, Row),
+ Key2 = element(2, Row),
+ Key = [length(Key1) | Key1] ++ [length(Key2) | Key2],
+ case table_cre_row(vacmViewTreeFamilyTable, Key, Row) of
+ true ->
+ {ok, Key};
+ false ->
+ {error, create_failed}
+ end;
+ {error, Reason} ->
+ {error, Reason};
+ Error ->
+ {error, Error}
+ end.
+
+delete_view_tree_fam(Key) ->
+ case table_del_row(vacmViewTreeFamilyTable, Key) of
+ true ->
+ ok;
+ false ->
+ {error, delete_failed}
+ end.
+
+
+gc_tabs() ->
+ SecDB = db(vacmSecurityToGroupTable),
+ SecSTC = stc(vacmSecurityToGroupTable),
+ SecFOI = foi(vacmSecurityToGroupTable),
+ snmpa_mib_lib:gc_tab(SecDB, SecSTC, SecFOI),
+ ViewDB = db(vacmViewTreeFamilyTable),
+ ViewSTC = stc(vacmViewTreeFamilyTable),
+ ViewFOI = foi(vacmViewTreeFamilyTable),
+ snmpa_mib_lib:gc_tab(ViewDB, ViewSTC, ViewFOI),
+ ok.
+
+init_vacm_mnesia() ->
+ F = fun(RowIndex, Row) ->
+ snmpa_vacm:insert([{RowIndex, Row}], false)
+ end,
+
+ %% The 5 is intentional: It is a trick to get a tuple with the
+ %% columns needed by the vacm ets-table (corresponding to the
+ %% tuple read from the config files). Therefor, 5 since it it
+ %% is not a real foi...
+ snmp_generic:table_foreach({vacmAccessTable, mnesia}, F, 5).
+
+
+%%-----------------------------------------------------------------
+%% The context table is actually implemented in an internal,
+%% non-snmp visible table intContextTable.
+%%-----------------------------------------------------------------
+vacmContextTable(_Op) ->
+ ok.
+vacmContextTable(set = Op, Arg1, Arg2) ->
+ snmpa_agent:invalidate_ca_cache(),
+ snmp_framework_mib:intContextTable(Op, Arg1, Arg2);
+vacmContextTable(Op, Arg1, Arg2) ->
+ snmp_framework_mib:intContextTable(Op, Arg1, Arg2).
+
+
+vacmSecurityToGroupTable(Op) ->
+ snmp_generic:table_func(Op, db(vacmSecurityToGroupTable)).
+
+vacmSecurityToGroupTable(get_next, RowIndex, Cols) ->
+ next(vacmSecurityToGroupTable, RowIndex, Cols);
+vacmSecurityToGroupTable(get, RowIndex, Cols) ->
+ get(vacmSecurityToGroupTable, RowIndex, Cols);
+vacmSecurityToGroupTable(set, RowIndex, Cols0) ->
+ ?vtrace("vacmSecurityToGroupTable(set) -> entry with"
+ "~n RowIndex: ~p"
+ "~n Cols0: ~p", [RowIndex, Cols0]),
+ case (catch verify_vacmSecurityToGroupTable_cols(Cols0, [])) of
+ {ok, Cols} ->
+ ?vtrace("vacmSecurityToGroupTable(set) -> verified: "
+ "~n Cols: ~p", [Cols]),
+ snmpa_agent:invalidate_ca_cache(),
+ snmp_generic:table_func(set, RowIndex, Cols,
+ db(vacmSecurityToGroupTable));
+ Error ->
+ Error
+ end;
+vacmSecurityToGroupTable(is_set_ok, RowIndex, Cols0) ->
+ ?vtrace("vacmSecurityToGroupTable(is_set_ok) -> entry with"
+ "~n RowIndex: ~p"
+ "~n Cols0: ~p", [RowIndex, Cols0]),
+ case (catch verify_vacmSecurityToGroupTable_cols(Cols0, [])) of
+ {ok, Cols} ->
+ ?vtrace("vacmSecurityToGroupTable(is_set_ok) -> verified: "
+ "~n Cols: ~p", [Cols]),
+ snmp_generic:table_func(is_set_ok, RowIndex, Cols,
+ db(vacmSecurityToGroupTable));
+ Error ->
+ Error
+ end;
+vacmSecurityToGroupTable(Op, Arg1, Arg2) ->
+ snmp_generic:table_func(Op, Arg1, Arg2, db(vacmSecurityToGroupTable)).
+
+
+verify_vacmSecurityToGroupTable_cols([], Cols) ->
+ ?vtrace("verify_vacmSecurityToGroupTable_cols -> entry when done with"
+ "~n Cols: ~p", [Cols]),
+ {ok, lists:reverse(Cols)};
+verify_vacmSecurityToGroupTable_cols([{Col, Val0}|Cols], Acc) ->
+ ?vtrace("verify_vacmSecurityToGroupTable_cols -> entry with"
+ "~n Col: ~p"
+ "~n Val0: ~p", [Col, Val0]),
+ Val = verify_vacmSecurityToGroupTable_col(Col, Val0),
+ ?vtrace("verify_vacmSecurityToGroupTable_cols -> verified: "
+ "~n Val: ~p", [Val]),
+ verify_vacmSecurityToGroupTable_cols(Cols, [{Col, Val}|Acc]).
+
+verify_vacmSecurityToGroupTable_col(?vacmSecurityModel, Model) ->
+ case Model of
+ any -> ?SEC_ANY;
+ v1 -> ?SEC_ANY;
+ v2c -> ?SEC_ANY;
+ usm -> ?SEC_ANY;
+ ?SEC_ANY -> ?SEC_ANY;
+ ?SEC_V1 -> ?SEC_ANY;
+ ?SEC_V2C -> ?SEC_ANY;
+ ?SEC_USM -> ?SEC_ANY;
+ _ ->
+ ?vlog("verification of vacmSecurityModel(~w) ~p failed",
+ [?vacmSecurityModel, Model]),
+ wrongValue(?vacmSecurityModel)
+ end;
+verify_vacmSecurityToGroupTable_col(?vacmSecurityName, Name) ->
+ case (catch snmp_conf:check_string(Name)) of
+ ok ->
+ Name;
+ Reason ->
+ ?vlog("verification of vacmSecurityName(~w) ~p failed: "
+ "~n Reason: ~p", [?vacmSecurityName, Name, Reason]),
+ wrongValue(?vacmSecurityName)
+ end;
+verify_vacmSecurityToGroupTable_col(?vacmGroupName, Name) ->
+ case (catch snmp_conf:check_string(Name)) of
+ ok ->
+ Name;
+ Reason ->
+ ?vlog("verification of vacmGroupName(~w) ~p failed: "
+ "~n Reason: ~p", [?vacmGroupName, Name, Reason]),
+ wrongValue(?vacmGroupName)
+ end;
+verify_vacmSecurityToGroupTable_col(_, Val) ->
+ Val.
+
+
+%%-----------------------------------------------------------------
+%% The vacmAccesTable is implemented as a bplus_tree in the
+%% snmpa_vacm_access_server process. That means that we'll have
+%% to implement everything by ourselves, most notably is_set_ok
+%% and set.
+%% Each row is stored in the bplus_tree as
+%% {RowIndex, {Col4, Col5, ..., Col9}}
+%%
+%%-----------------------------------------------------------------
+vacmAccessTable(_Op) ->
+ ok.
+vacmAccessTable(get, RowIndex, Cols) ->
+ %% For GET, Cols are guaranteed to be accessible columns.
+ case snmpa_vacm:get_row(RowIndex) of
+ {ok, Row} ->
+ lists:map(fun(Col) -> {value, element(Col-3, Row)} end, Cols);
+ false ->
+ {noValue, noSuchInstance}
+ end;
+vacmAccessTable(get_next, RowIndex, Cols) ->
+ %% For GET-NEXT, Cols can be anything, but they are sorted.
+ %% Thus, we translate each
+ %% Example: GET-NEXT -1.3.4.5
+ %% 4.3.4.5
+ %% 10.3.4.5
+ %% Table: Idx= 1.2.3 Col4= 1
+ %% Idx= 4.5.6. Col4= 2
+ %% Returns: 4.1.2.3 = 1, 4.4.5.6 = 2, endOfTable
+ {PreCols, ValidCols} = split_cols(Cols, []),
+ do_get_next([], PreCols) ++ do_get_next(RowIndex, ValidCols);
+%% vacmAccessContextMatch does not have a default value => we'll have
+%% to treat that col specially
+vacmAccessTable(is_set_ok, RowIndex, Cols0) ->
+ case (catch verify_vacmAccessTable_cols(Cols0, [])) of
+ {ok, Cols} ->
+ IsValidKey = is_valid_key(RowIndex),
+ case lists:keysearch(?vacmAccessStatus, 1, Cols) of
+ %% Ok, if contextMatch is init
+ {value, {Col, ?'RowStatus_active'}} ->
+ {ok, Row} = snmpa_vacm:get_row(RowIndex),
+ case element(?vacmAContextMatch, Row) of
+ noinit -> {inconsistentValue, Col};
+ _ -> {noError, 0}
+ end;
+ {value, {Col, ?'RowStatus_notInService'}} -> % Ok, if not notReady
+ {ok, Row} = snmpa_vacm:get_row(RowIndex),
+ case element(?vacmAStatus, Row) of
+ ?'RowStatus_notReady' -> {inconsistentValue, Col};
+ _ -> {noError, 0}
+ end;
+ {value, {Col, ?'RowStatus_notReady'}} -> % never ok!
+ {inconsistentValue, Col};
+ {value, {Col, ?'RowStatus_createAndGo'}} -> % ok, if it doesn't exist
+ Res = lists:keysearch(?vacmAccessContextMatch, 1, Cols),
+ case snmpa_vacm:get_row(RowIndex) of
+ false when (IsValidKey =:= true) andalso
+ is_tuple(Res) -> {noError, 0};
+ false -> {noCreation, Col}; % Bad RowIndex
+ _ -> {inconsistentValue, Col}
+ end;
+ {value, {Col, ?'RowStatus_createAndWait'}} -> % ok, if it doesn't exist
+ case snmpa_vacm:get_row(RowIndex) of
+ false when (IsValidKey =:= true) -> {noError, 0};
+ false -> {noCreation, Col}; % Bad RowIndex
+ _ -> {inconsistentValue, Col}
+ end;
+ {value, {_Col, ?'RowStatus_destroy'}} -> % always ok!
+ {noError, 0};
+ _ -> % otherwise, it's a change; it must exist
+ case snmpa_vacm:get_row(RowIndex) of
+ {ok, _} ->
+ {noError, 0};
+ false ->
+ {inconsistentName, element(1, hd(Cols))}
+ end
+ end;
+ Error ->
+ Error
+ end;
+vacmAccessTable(set, RowIndex, Cols0) ->
+ case (catch verify_vacmAccessTable_cols(Cols0, [])) of
+ {ok, Cols} ->
+ snmpa_agent:invalidate_ca_cache(),
+ do_vacmAccessTable_set(RowIndex, Cols);
+ Error ->
+ Error
+ end.
+
+verify_vacmAccessTable_cols([], Cols) ->
+ {ok, lists:reverse(Cols)};
+verify_vacmAccessTable_cols([{Col, Val0}|Cols], Acc) ->
+ Val = verify_vacmAccessTable_col(Col, Val0),
+ verify_vacmAccessTable_cols(Cols, [{Col, Val}|Acc]).
+
+verify_vacmAccessTable_col(?vacmAccessContextPrefix, Pref) ->
+ case (catch snmp_conf:check_string(Pref)) of
+ ok ->
+ Pref;
+ _ ->
+ wrongValue(?vacmAccessContextPrefix)
+ end;
+verify_vacmAccessTable_col(?vacmAccessSecurityModel, Model) ->
+ case Model of
+ any -> ?SEC_ANY;
+ v1 -> ?SEC_ANY;
+ v2c -> ?SEC_ANY;
+ usm -> ?SEC_ANY;
+ ?SEC_ANY -> ?SEC_ANY;
+ ?SEC_V1 -> ?SEC_ANY;
+ ?SEC_V2C -> ?SEC_ANY;
+ ?SEC_USM -> ?SEC_ANY;
+ _ ->
+ wrongValue(?vacmAccessSecurityModel)
+ end;
+verify_vacmAccessTable_col(?vacmAccessSecurityLevel, Level) ->
+ case Level of
+ noAuthNoPriv -> 1;
+ authNoPriv -> 2;
+ authPriv -> 3;
+ 1 -> 1;
+ 2 -> 2;
+ 3 -> 3;
+ _ -> wrongValue(?vacmAccessSecurityLevel)
+ end;
+verify_vacmAccessTable_col(?vacmAccessContextMatch, Match) ->
+ case Match of
+ exact -> ?vacmAccessContextMatch_exact;
+ prefix -> ?vacmAccessContextMatch_prefix;
+ ?vacmAccessContextMatch_exact -> ?vacmAccessContextMatch_exact;
+ ?vacmAccessContextMatch_prefix -> ?vacmAccessContextMatch_prefix;
+ _ ->
+ wrongValue(?vacmAccessContextMatch)
+ end;
+verify_vacmAccessTable_col(?vacmAccessReadViewName, RVN) ->
+ case (catch snmp_conf:check_string(RVN)) of
+ ok ->
+ RVN;
+ _ ->
+ wrongValue(?vacmAccessReadViewName)
+ end;
+verify_vacmAccessTable_col(?vacmAccessWriteViewName, WVN) ->
+ case (catch snmp_conf:check_string(WVN)) of
+ ok ->
+ WVN;
+ _ ->
+ wrongValue(?vacmAccessWriteViewName)
+ end;
+verify_vacmAccessTable_col(?vacmAccessNotifyViewName, NVN) ->
+ case (catch snmp_conf:check_string(NVN)) of
+ ok ->
+ NVN;
+ _ ->
+ wrongValue(?vacmAccessNotifyViewName)
+ end;
+verify_vacmAccessTable_col(_, Val) ->
+ Val.
+
+do_vacmAccessTable_set(RowIndex, Cols) ->
+ case lists:keysearch(?vacmAccessStatus, 1, Cols) of
+ {value, {_Col, ?'RowStatus_createAndGo'}} ->
+ Row = mk_row(Cols),
+ Row2 = setelement(?vacmAStatus, Row, ?'RowStatus_active'),
+ snmpa_vacm:insert([{RowIndex, Row2}]),
+ {noError, 0};
+ {value, {_Col, ?'RowStatus_createAndWait'}} ->
+ Row = mk_row(Cols),
+ Row2 = case element(?vacmAContextMatch, Row) of
+ noinit -> setelement(?vacmAStatus, Row,
+ ?'RowStatus_notReady');
+ _ -> setelement(?vacmAStatus, Row,
+ ?'RowStatus_notInService')
+ end,
+ snmpa_vacm:insert([{RowIndex, Row2}]),
+ {noError, 0};
+ {value, {_Col, ?'RowStatus_destroy'}} ->
+ snmpa_vacm:delete(RowIndex),
+ {noError, 0};
+ {value, {_Col, ?'RowStatus_active'}} ->
+ {ok, Row} = snmpa_vacm:get_row(RowIndex),
+ NRow = ch_row(Cols, Row),
+ NRow2 =
+ case element(?vacmAContextMatch, NRow) of
+ noinit -> setelement(?vacmAStatus, NRow,
+ ?'RowStatus_notReady');
+ _ -> setelement(?vacmAStatus, NRow,
+ ?'RowStatus_active')
+ end,
+ snmpa_vacm:insert([{RowIndex, NRow2}]),
+ {noError, 0};
+ _ ->
+ {ok, Row} = snmpa_vacm:get_row(RowIndex),
+ NRow = ch_row(Cols, Row),
+ NRow2 =
+ case element(?vacmAContextMatch, NRow) of
+ noinit -> setelement(?vacmAStatus, NRow,
+ ?'RowStatus_notReady');
+ _ -> setelement(?vacmAStatus, NRow,
+ ?'RowStatus_notInService')
+ end,
+ snmpa_vacm:insert([{RowIndex, NRow2}]),
+ {noError, 0}
+ end.
+
+
+%% Cols are sorted, and all columns are > 3.
+do_get_next(RowIndex, Cols) ->
+ case snmpa_vacm:get_next_row(RowIndex) of
+ {NextIndex, Row} ->
+ F1 = fun(Col) when Col < ?vacmAccessStatus ->
+ {[Col | NextIndex], element(Col-3, Row)};
+ (_) ->
+ endOfTable
+ end,
+ lists:map(F1, Cols);
+ false ->
+ case snmpa_vacm:get_next_row([]) of
+ {_NextIndex, Row} ->
+ F2 = fun(Col) when Col < ?vacmAccessStatus ->
+ {[Col+1 | RowIndex], element(Col-2, Row)};
+ (_) ->
+ endOfTable
+ end,
+ lists:map(F2, Cols);
+ false ->
+ lists:map(fun(_Col) -> endOfTable end, Cols)
+ end
+ end.
+
+%%-----------------------------------------------------------------
+%% Functions to manipulate vacmAccessRows.
+%%-----------------------------------------------------------------
+is_valid_key(RowIndex) ->
+ case catch mk_key(RowIndex) of
+ true -> true;
+ _ -> false
+ end.
+
+mk_key([L1 | T1]) ->
+ [L2 | T2] = spx(L1, T1),
+ [_SM, _SL] = spx(L2, T2),
+ true.
+
+spx(N, L) -> spx(N, [], L).
+spx(0, _L1, L2) -> L2;
+spx(N, L1, [H | L2]) -> spx(N-1, [H | L1], L2).
+
+mk_row(Cols) ->
+ ch_row(Cols, {noinit, "", "", "", ?'StorageType_nonVolatile', noinit}).
+
+ch_row([], Row) -> Row;
+ch_row([{Col, Val} | T], Row) -> ch_row(T, setelement(Col-3, Row, Val)).
+
+
+%% Split a list of columns in 2 lists - the first is all columns
+%% that are =< 3. For these, use the first accessible column number: 4.
+split_cols([Col | Cols], PreCols) when Col =< 3 ->
+ split_cols(Cols, [4 | PreCols]);
+split_cols(Cols, PreCols) ->
+ {PreCols, Cols}.
+
+vacmViewSpinLock(new) ->
+ snmp_generic:variable_func(new, {vacmViewSpinLock, volatile}),
+ {A1,A2,A3} = erlang:now(),
+ random:seed(A1,A2,A3),
+ Val = random:uniform(2147483648) - 1,
+ snmp_generic:variable_func(set, Val, {vacmViewSpinLock, volatile});
+
+vacmViewSpinLock(delete) ->
+ ok;
+
+vacmViewSpinLock(get) ->
+ snmp_generic:variable_func(get, {vacmViewSpinLock, volatile}).
+
+vacmViewSpinLock(is_set_ok, NewVal) ->
+ case snmp_generic:variable_func(get, {vacmViewSpinLock, volatile}) of
+ {value, NewVal} -> noError;
+ _ -> inconsistentValue
+ end;
+vacmViewSpinLock(set, NewVal) ->
+ snmp_generic:variable_func(set, (NewVal + 1) rem 2147483648,
+ {vacmViewSpinLock, volatile}).
+
+
+vacmViewTreeFamilyTable(Op) ->
+ snmp_generic:table_func(Op, db(vacmViewTreeFamilyTable)).
+vacmViewTreeFamilyTable(get_next, RowIndex, Cols) ->
+ next(vacmViewTreeFamilyTable, RowIndex, Cols);
+vacmViewTreeFamilyTable(get, RowIndex, Cols) ->
+ get(vacmViewTreeFamilyTable, RowIndex, Cols);
+vacmViewTreeFamilyTable(set, RowIndex, Cols0) ->
+ case (catch verify_vacmViewTreeFamilyTable_cols(Cols0, [])) of
+ {ok, Cols} ->
+ snmpa_agent:invalidate_ca_cache(),
+ snmp_generic:table_func(set, RowIndex, Cols,
+ db(vacmViewTreeFamilyTable));
+ Error ->
+ Error
+ end;
+vacmViewTreeFamilyTable(is_set_ok, RowIndex, Cols0) ->
+ case (catch verify_vacmViewTreeFamilyTable_cols(Cols0, [])) of
+ {ok, Cols} ->
+ snmp_generic:table_func(is_set_ok, RowIndex, Cols,
+ db(vacmViewTreeFamilyTable));
+ Error ->
+ Error
+ end;
+vacmViewTreeFamilyTable(Op, Arg1, Arg2) ->
+ snmp_generic:table_func(Op, Arg1, Arg2, db(vacmViewTreeFamilyTable)).
+
+
+verify_vacmViewTreeFamilyTable_cols([], Cols) ->
+ {ok, lists:reverse(Cols)};
+verify_vacmViewTreeFamilyTable_cols([{Col, Val0}|Cols], Acc) ->
+ Val = verify_vacmViewTreeFamilyTable_col(Col, Val0),
+ verify_vacmViewTreeFamilyTable_cols(Cols, [{Col, Val}|Acc]).
+
+verify_vacmViewTreeFamilyTable_col(?vacmViewTreeFamilyViewName, Name) ->
+ case (catch snmp_conf:check_string(Name)) of
+ ok ->
+ Name;
+ _ ->
+ wrongValue(?vacmViewTreeFamilyViewName)
+ end;
+verify_vacmViewTreeFamilyTable_col(?vacmViewTreeFamilySubtree, Tree) ->
+ case (catch snmp_conf:check_oid(Tree)) of
+ ok ->
+ Tree;
+ _ ->
+ wrongValue(?vacmViewTreeFamilySubtree)
+ end;
+verify_vacmViewTreeFamilyTable_col(?vacmViewTreeFamilyMask, Mask) ->
+ case Mask of
+ null -> [];
+ [] -> [];
+ _ ->
+ case (catch snmp_conf:check_oid(Mask)) of
+ ok ->
+ Mask;
+ _ ->
+ wrongValue(?vacmViewTreeFamilyMask)
+ end
+ end;
+verify_vacmViewTreeFamilyTable_col(?vacmViewTreeFamilyType, Type) ->
+ case Type of
+ included -> ?view_included;
+ excluded -> ?view_excluded;
+ ?view_included -> ?view_included;
+ ?view_excluded -> ?view_excluded;
+ _ ->
+ wrongValue(?vacmViewTreeFamilyType)
+ end;
+verify_vacmViewTreeFamilyTable_col(_, Val) ->
+ Val.
+
+
+table_next(Name, RestOid) ->
+ snmp_generic:table_next(db(Name), RestOid).
+
+
+db(X) -> snmpa_agent:db(X).
+
+fa(vacmSecurityToGroupTable) -> ?vacmGroupName;
+fa(vacmViewTreeFamilyTable) -> ?vacmViewTreeFamilyMask.
+
+foi(vacmSecurityToGroupTable) -> ?vacmSecurityModel;
+foi(vacmViewTreeFamilyTable) -> ?vacmViewTreeFamilyViewName.
+
+noc(vacmSecurityToGroupTable) -> 5;
+noc(vacmViewTreeFamilyTable) -> 6.
+
+stc(vacmSecurityToGroupTable) -> ?vacmSecurityToGroupStorageType;
+stc(vacmViewTreeFamilyTable) -> ?vacmViewTreeFamilyStorageType.
+
+next(Name, RowIndex, Cols) ->
+ snmp_generic:handle_table_next(db(Name), RowIndex, Cols,
+ fa(Name), foi(Name), noc(Name)).
+
+get(Name, RowIndex, Cols) ->
+ snmp_generic:handle_table_get(db(Name), RowIndex, Cols, foi(Name)).
+
+wrongValue(V) -> throw({wrongValue, V}).
+
+set_sname() ->
+ set_sname(get(sname)).
+
+set_sname(undefined) ->
+ put(sname,conf);
+set_sname(_) -> %% Keep it, if already set.
+ ok.
+
+error(Reason) ->
+ throw({error, Reason}).
+
+config_err(F, A) ->
+ snmpa_error:config_err("[VIEW-BASED-ACM-MIB]: " ++ F, A).
+
diff --git a/lib/snmp/src/agent/snmpa.erl b/lib/snmp/src/agent/snmpa.erl
new file mode 100644
index 0000000000..79493bd892
--- /dev/null
+++ b/lib/snmp/src/agent/snmpa.erl
@@ -0,0 +1,580 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2004-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%
+%%
+-module(snmpa).
+
+
+%%----------------------------------------------------------------------
+%% This module contains the user interface to the snmp agent toolkit.
+%%----------------------------------------------------------------------
+
+-export([verbosity/2,
+
+ current_request_id/0, current_community/0, current_address/0,
+ current_context/0, current_net_if_data/0,
+
+ get_symbolic_store_db/0,
+ which_aliasnames/0,
+ which_tables/0,
+ which_variables/0,
+ which_notifications/0,
+ name_to_oid/1, name_to_oid/2,
+ oid_to_name/1, oid_to_name/2,
+ int_to_enum/2, int_to_enum/3,
+ enum_to_int/2, enum_to_int/3,
+
+ info/0, info/1, old_info_format/1,
+ load_mibs/1, load_mibs/2,
+ unload_mibs/1, unload_mibs/2,
+ which_mibs/0, which_mibs/1,
+ whereis_mib/1, whereis_mib/2,
+ dump_mibs/0, dump_mibs/1,
+ mib_of/1, mib_of/2,
+ me_of/1, me_of/2,
+ invalidate_mibs_cache/0, invalidate_mibs_cache/1,
+ enable_mibs_cache/0, enable_mibs_cache/1,
+ disable_mibs_cache/0, disable_mibs_cache/1,
+ gc_mibs_cache/0, gc_mibs_cache/1, gc_mibs_cache/2, gc_mibs_cache/3,
+ enable_mibs_cache_autogc/0, enable_mibs_cache_autogc/1,
+ disable_mibs_cache_autogc/0, disable_mibs_cache_autogc/1,
+ update_mibs_cache_age/1, update_mibs_cache_age/2,
+ update_mibs_cache_gclimit/1, update_mibs_cache_gclimit/2,
+
+ get/2, get/3, get_next/2, get_next/3,
+
+ register_subagent/3, unregister_subagent/2,
+
+ send_notification/3, send_notification/4, send_notification/5,
+ send_notification/6,
+ send_trap/3, send_trap/4,
+
+ discovery/2, discovery/3, discovery/4, discovery/5, discovery/6,
+
+ sys_up_time/0, system_start_time/0,
+
+ backup/1, backup/2,
+
+ convert_config/1,
+
+ restart_worker/0, restart_worker/1,
+ restart_set_worker/0, restart_set_worker/1]).
+
+%% USM functions:
+-export([passwd2localized_key/3, localize_key/3]).
+
+%% Agent Capabilities functions
+-export([add_agent_caps/2, del_agent_caps/1, get_agent_caps/0]).
+
+%% Audit Trail Log functions
+-export([log_to_txt/2, log_to_txt/3, log_to_txt/4,
+ log_to_txt/5, log_to_txt/6, log_to_txt/7,
+ change_log_size/1,
+ get_log_type/0, get_log_type/1,
+ change_log_type/1, change_log_type/2,
+ set_log_type/1, set_log_type/2
+ ]).
+
+%% Message filter / load regulation functions
+-export([
+ register_notification_filter/3,
+ register_notification_filter/4,
+ register_notification_filter/5,
+ unregister_notification_filter/1,
+ unregister_notification_filter/2,
+ which_notification_filter/0,
+ which_notification_filter/1,
+
+ get_request_limit/0, get_request_limit/1,
+ set_request_limit/1, set_request_limit/2
+ ]).
+
+-include("snmpa_atl.hrl").
+
+-define(EXTRA_INFO, undefined).
+
+
+%%-----------------------------------------------------------------
+%% This utility function is used to convert an old SNMP application
+%% config (prior to snmp-4.0) to a SNMP agent config (as of
+%% snmp-4.0).
+%% This is the config structure of the SNMP application as of
+%% snmp-4.0:
+%% {snmp, snmp_config()}
+%% snmp_config() -> [snmp_config_item()]
+%% snmp_config_item() -> {agent, agent_config()} |
+%% {manager, manager_config()}
+%%-----------------------------------------------------------------
+
+convert_config(Opts) ->
+ snmpa_app:convert_config(Opts).
+
+
+%%-----------------------------------------------------------------
+%% Note that verbosity for the agents is actually only implemented
+%% (properly) for the master agent.
+%%-----------------------------------------------------------------
+
+verbosity(all,Verbosity) ->
+ catch snmpa_agent:verbosity(sub_agents,Verbosity),
+ catch snmpa_agent:verbosity(master_agent,Verbosity),
+ catch snmpa_agent:verbosity(net_if,Verbosity),
+ catch snmpa_agent:verbosity(mib_server,Verbosity),
+ catch snmpa_agent:verbosity(note_store,Verbosity),
+ catch snmpa_symbolic_store:verbosity(Verbosity),
+ catch snmpa_local_db:verbosity(Verbosity);
+verbosity(master_agent,Verbosity) ->
+ catch snmpa_agent:verbosity(master_agent,Verbosity);
+verbosity(net_if,Verbosity) ->
+ catch snmpa_agent:verbosity(net_if,Verbosity);
+verbosity(note_store,Verbosity) ->
+ catch snmpa_agent:verbosity(note_store, Verbosity);
+verbosity(mib_server,Verbosity) ->
+ catch snmpa_agent:verbosity(mib_server,Verbosity);
+verbosity(symbolic_store,Verbosity) ->
+ catch snmpa_symbolic_store:verbosity(Verbosity);
+verbosity(local_db,Verbosity) ->
+ catch snmpa_local_db:verbosity(Verbosity);
+verbosity(Agent,{subagents,Verbosity}) ->
+ catch snmpa_agent:verbosity(Agent,{sub_agents,Verbosity});
+verbosity(Agent,Verbosity) ->
+ catch snmpa_agent:verbosity(Agent,Verbosity).
+
+
+%%-----------------------------------------------------------------
+%%
+%% Some symbolic store (internal database) utility functions
+%%
+%%-----------------------------------------------------------------
+
+get_symbolic_store_db() ->
+ snmpa_symbolic_store:get_db().
+
+
+which_aliasnames() ->
+ snmpa_symbolic_store:which_aliasnames().
+
+which_tables() ->
+ snmpa_symbolic_store:which_tables().
+
+which_variables() ->
+ snmpa_symbolic_store:which_variables().
+
+which_notifications() ->
+ snmpa_symbolic_store:which_notifications().
+
+
+%%-----------------------------------------------------------------
+%% These 8 functions returns {value, Val} | false
+%%-----------------------------------------------------------------
+name_to_oid(Name) ->
+ snmpa_symbolic_store:aliasname_to_oid(Name).
+
+name_to_oid(Db, Name) ->
+ snmpa_symbolic_store:aliasname_to_oid(Db, Name).
+
+oid_to_name(OID) ->
+ snmpa_symbolic_store:oid_to_aliasname(OID).
+
+oid_to_name(Db, OID) ->
+ snmpa_symbolic_store:oid_to_aliasname(Db, OID).
+
+enum_to_int(Name, Enum) ->
+ snmpa_symbolic_store:enum_to_int(Name, Enum).
+
+enum_to_int(Db, Name, Enum) ->
+ snmpa_symbolic_store:enum_to_int(Db, Name, Enum).
+
+int_to_enum(Name, Int) ->
+ snmpa_symbolic_store:int_to_enum(Name, Int).
+
+int_to_enum(Db, Name, Int) ->
+ snmpa_symbolic_store:int_to_enum(Db, Name, Int).
+
+
+%%-----------------------------------------------------------------
+%% These functions must only be called in the process context
+%% where the instrumentation functions are called!
+%%-----------------------------------------------------------------
+current_request_id() -> current_get(snmp_request_id).
+current_context() -> current_get(snmp_context).
+current_community() -> current_get(snmp_community).
+current_address() -> current_get(snmp_address).
+current_net_if_data() -> current_get(net_if_data).
+
+current_get(Tag) ->
+ case get(Tag) of
+ undefined -> false;
+ X -> {value, X}
+ end.
+
+
+%% -
+
+get(Agent, Vars) -> snmpa_agent:get(Agent, Vars).
+get(Agent, Vars, Context) -> snmpa_agent:get(Agent, Vars, Context).
+
+get_next(Agent, Vars) -> snmpa_agent:get_next(Agent, Vars).
+get_next(Agent, Vars, Context) -> snmpa_agent:get_next(Agent, Vars, Context).
+
+
+info() -> info(snmp_master_agent).
+info(Agent) -> snmpa_agent:info(Agent).
+
+old_info_format(Info) when is_list(Info) ->
+ {value, Vsns} = lists:keysearch(vsns, 1, Info),
+ {value, {_, MibInfo}} = lists:keysearch(mib_server, 1, Info),
+ {value, SAa} = lists:keysearch(subagents, 1, MibInfo),
+ {value, LoadedMibs} = lists:keysearch(loaded_mibs, 1, MibInfo),
+ {value, TreeSz} = lists:keysearch(tree_size_bytes, 1, MibInfo),
+ {value, ProcMem} = lists:keysearch(process_memory, 1, MibInfo),
+ {value, DbMem} = lists:keysearch(db_memory, 1, MibInfo),
+ [Vsns, SAa, LoadedMibs, TreeSz, ProcMem, DbMem].
+
+
+%% -
+
+backup(BackupDir) ->
+ backup(snmp_master_agent, BackupDir).
+
+backup(Agent, BackupDir) ->
+ snmpa_agent:backup(Agent, BackupDir).
+
+
+%% -
+
+dump_mibs() -> snmpa_agent:dump_mibs(snmp_master_agent).
+dump_mibs(File) -> snmpa_agent:dump_mibs(snmp_master_agent, File).
+
+load_mibs(Mibs) ->
+ load_mibs(snmp_master_agent, Mibs).
+load_mibs(Agent, Mibs) when is_list(Mibs) ->
+ snmpa_agent:load_mibs(Agent, Mibs).
+
+unload_mibs(Mibs) ->
+ unload_mibs(snmp_master_agent, Mibs).
+unload_mibs(Agent, Mibs) when is_list(Mibs) ->
+ snmpa_agent:unload_mibs(Agent, Mibs).
+
+which_mibs() -> which_mibs(snmp_master_agent).
+which_mibs(Agent) -> snmpa_agent:which_mibs(Agent).
+
+whereis_mib(Mib) ->
+ whereis_mib(snmp_master_agent, Mib).
+whereis_mib(Agent, Mib) when is_atom(Mib) ->
+ snmpa_agent:whereis_mib(Agent, Mib).
+
+
+%% -
+
+mib_of(Oid) ->
+ snmpa_agent:mib_of(Oid).
+
+mib_of(Agent, Oid) ->
+ snmpa_agent:mib_of(Agent, Oid).
+
+me_of(Oid) ->
+ snmpa_agent:me_of(Oid).
+
+me_of(Agent, Oid) ->
+ snmpa_agent:me_of(Agent, Oid).
+
+
+invalidate_mibs_cache() ->
+ invalidate_mibs_cache(snmp_master_agent).
+
+invalidate_mibs_cache(Agent) ->
+ snmpa_agent:invalidate_mibs_cache(Agent).
+
+
+enable_mibs_cache() ->
+ enable_mibs_cache(snmp_master_agent).
+
+enable_mibs_cache(Agent) ->
+ snmpa_agent:enable_mibs_cache(Agent).
+
+
+disable_mibs_cache() ->
+ disable_mibs_cache(snmp_master_agent).
+
+disable_mibs_cache(Agent) ->
+ snmpa_agent:disable_mibs_cache(Agent).
+
+
+gc_mibs_cache() ->
+ gc_mibs_cache(snmp_master_agent).
+
+gc_mibs_cache(Agent) when is_atom(Agent) orelse is_pid(Agent) ->
+ snmpa_agent:gc_mibs_cache(Agent);
+gc_mibs_cache(Age) ->
+ gc_mibs_cache(snmp_master_agent, Age).
+
+gc_mibs_cache(Agent, Age) when is_atom(Agent) orelse is_pid(Agent) ->
+ snmpa_agent:gc_mibs_cache(Agent, Age);
+gc_mibs_cache(Age, GcLimit) ->
+ gc_mibs_cache(snmp_master_agent, Age, GcLimit).
+
+gc_mibs_cache(Agent, Age, GcLimit) when is_atom(Agent) orelse is_pid(Agent) ->
+ snmpa_agent:gc_mibs_cache(Agent, Age, GcLimit).
+
+
+enable_mibs_cache_autogc() ->
+ enable_mibs_cache_autogc(snmp_master_agent).
+
+enable_mibs_cache_autogc(Agent) ->
+ snmpa_agent:enable_mibs_cache_autogc(Agent).
+
+
+disable_mibs_cache_autogc() ->
+ disable_mibs_cache_autogc(snmp_master_agent).
+
+disable_mibs_cache_autogc(Agent) ->
+ snmpa_agent:disable_mibs_cache_autogc(Agent).
+
+
+update_mibs_cache_age(Age) ->
+ update_mibs_cache_age(snmp_master_agent, Age).
+
+update_mibs_cache_age(Agent, Age) ->
+ snmpa_agent:update_mibs_cache_age(Agent, Age).
+
+
+update_mibs_cache_gclimit(GcLimit) ->
+ update_mibs_cache_age(snmp_master_agent, GcLimit).
+
+update_mibs_cache_gclimit(Agent, GcLimit) ->
+ snmpa_agent:update_mibs_cache_gclimit(Agent, GcLimit).
+
+
+
+
+%% - message filter / load regulation
+
+register_notification_filter(Id, Mod, Data) when is_atom(Mod) ->
+ register_notification_filter(snmp_master_agent, Id, Mod, Data, last).
+
+register_notification_filter(Agent, Id, Mod, Data)
+ when is_atom(Agent) andalso is_atom(Mod) ->
+ register_notification_filter(Agent, Id, Mod, Data, last);
+register_notification_filter(Agent, Id, Mod, Data)
+ when is_pid(Agent) andalso is_atom(Mod) ->
+ register_notification_filter(Agent, Id, Mod, Data, last);
+register_notification_filter(Id, Mod, Data, Where) when is_atom(Mod) ->
+ register_notification_filter(snmp_master_agent, Id, Mod, Data, Where).
+
+register_notification_filter(Agent, Id, Mod, Data, Where) ->
+ snmpa_agent:register_notification_filter(Agent, Id, Mod, Data, Where).
+
+unregister_notification_filter(Id) ->
+ unregister_notification_filter(snmp_master_agent, Id).
+
+unregister_notification_filter(Agent, Id) ->
+ snmpa_agent:unregister_notification_filter(Agent, Id).
+
+which_notification_filter() ->
+ which_notification_filter(snmp_master_agent).
+
+which_notification_filter(Agent) ->
+ snmpa_agent:which_notification_filter(Agent).
+
+
+get_request_limit() ->
+ get_request_limit(snmp_master_agent).
+get_request_limit(Agent) ->
+ snmpa_agent:get_request_limit(Agent).
+
+set_request_limit(NewLimit) ->
+ set_request_limit(snmp_master_agent, NewLimit).
+set_request_limit(Agent, NewLimit) ->
+ snmpa_agent:set_request_limit(Agent, NewLimit).
+
+
+%% -
+
+send_notification(Agent, Notification, Recv) ->
+ send_notification(Agent, Notification, Recv, "", "", []).
+
+send_notification(Agent, Notification, Recv, Varbinds) ->
+ send_notification(Agent, Notification, Recv, "", "", Varbinds).
+
+send_notification(Agent, Notification, Recv, NotifyName, Varbinds) ->
+ send_notification(Agent, Notification, Recv, NotifyName, "", Varbinds).
+
+send_notification(Agent, Notification, Recv,
+ NotifyName, ContextName, Varbinds)
+ when (is_list(NotifyName) andalso
+ is_list(ContextName) andalso
+ is_list(Varbinds)) ->
+ snmpa_agent:send_trap(Agent, Notification, NotifyName,
+ ContextName, Recv, Varbinds).
+
+%% Kept for backwards compatibility
+send_trap(Agent, Trap, Community) ->
+ send_notification(Agent, Trap, no_receiver, Community, "", []).
+
+send_trap(Agent, Trap, Community, Varbinds) ->
+ send_notification(Agent, Trap, no_receiver, Community, "", Varbinds).
+
+
+%%%-----------------------------------------------------------------
+
+discovery(TargetName, Notification) ->
+ Varbinds = [],
+ discovery(TargetName, Notification, Varbinds).
+
+discovery(TargetName, Notification, Varbinds) when is_list(Varbinds) ->
+ ContextName = "",
+ discovery(TargetName, Notification, ContextName, Varbinds);
+discovery(TargetName, Notification, DiscoHandler)
+ when is_atom(DiscoHandler) ->
+ Varbinds = [],
+ discovery(TargetName, Notification, Varbinds, DiscoHandler).
+
+discovery(TargetName, Notification, ContextName, Varbinds)
+ when is_list(Varbinds) ->
+ DiscoHandler = snmpa_discovery_handler_default,
+ discovery(TargetName, Notification, ContextName, Varbinds,
+ DiscoHandler);
+discovery(TargetName, Notification, Varbinds, DiscoHandler)
+ when is_atom(DiscoHandler) ->
+ ContextName = "",
+ discovery(TargetName, Notification, ContextName, Varbinds, DiscoHandler).
+
+discovery(TargetName, Notification, ContextName, Varbinds, DiscoHandler) ->
+ ExtraInfo = ?EXTRA_INFO,
+ discovery(TargetName, Notification, ContextName, Varbinds, DiscoHandler,
+ ExtraInfo).
+
+discovery(TargetName, Notification, ContextName, Varbinds, DiscoHandler,
+ ExtraInfo)
+ when (is_list(TargetName) andalso (length(TargetName) > 0) andalso
+ is_atom(Notification) andalso
+ is_list(ContextName) andalso
+ is_list(Varbinds) andalso
+ is_atom(DiscoHandler)) ->
+ case (catch snmpa_discovery_handler:verify(DiscoHandler)) of
+ ok ->
+ snmpa_agent:discovery(TargetName, Notification, ContextName,
+ Varbinds, DiscoHandler, ExtraInfo);
+ Error ->
+ Error
+ end.
+
+
+%%%-----------------------------------------------------------------
+
+register_subagent(Agent, SubTree, SubAgent) ->
+ snmpa_agent:register_subagent(Agent, SubTree, SubAgent).
+
+unregister_subagent(Agent, SubOidOrPid) ->
+ snmpa_agent:unregister_subagent(Agent, SubOidOrPid).
+
+system_start_time() ->
+ [{_, Time}] = ets:lookup(snmp_agent_table, system_start_time),
+ Time.
+
+sys_up_time() ->
+ % time in 0.01 seconds.
+ StartTime = system_start_time(),
+ (snmp_misc:now(cs) - StartTime) rem (2 bsl 31).
+
+
+%%%-----------------------------------------------------------------
+
+restart_worker() ->
+ restart_worker(snmp_master_agent).
+
+restart_worker(Agent) ->
+ snmpa_agent:restart_worker(Agent).
+
+
+restart_set_worker() ->
+ restart_set_worker(snmp_master_agent).
+
+restart_set_worker(Agent) ->
+ snmpa_agent:restart_set_worker(Agent).
+
+
+%%%-----------------------------------------------------------------
+%%% USM functions
+%%%-----------------------------------------------------------------
+passwd2localized_key(Alg, Passwd, EngineID) ->
+ snmp_usm:passwd2localized_key(Alg, Passwd, EngineID).
+
+localize_key(Alg, Key, EngineID) ->
+ snmp_usm:localize_key(Alg, Key, EngineID).
+
+
+%%%-----------------------------------------------------------------
+%%% Agent Capabilities functions
+%%%-----------------------------------------------------------------
+add_agent_caps(Oid, Descr) ->
+ snmp_standard_mib:add_agent_caps(Oid, Descr).
+
+del_agent_caps(Index) ->
+ snmp_standard_mib:del_agent_caps(Index).
+
+get_agent_caps() ->
+ snmp_standard_mib:get_agent_caps().
+
+
+%%%-----------------------------------------------------------------
+%%% Audit Trail Log functions
+%%%-----------------------------------------------------------------
+log_to_txt(LogDir, Mibs) ->
+ OutFile = "snmpa_log.txt",
+ LogName = ?audit_trail_log_name,
+ LogFile = ?audit_trail_log_file,
+ snmp:log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile).
+log_to_txt(LogDir, Mibs, OutFile) ->
+ LogName = ?audit_trail_log_name,
+ LogFile = ?audit_trail_log_file,
+ snmp:log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile).
+log_to_txt(LogDir, Mibs, OutFile, LogName) ->
+ LogFile = ?audit_trail_log_file,
+ snmp:log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile).
+log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile) ->
+ snmp:log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile).
+log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Start) ->
+ snmp:log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Start).
+log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Start, Stop) ->
+ snmp:log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Start, Stop).
+
+
+change_log_size(NewSize) ->
+ LogName = ?audit_trail_log_name, % The old (agent) default
+ snmp:change_log_size(LogName, NewSize).
+
+
+get_log_type() ->
+ get_log_type(snmp_master_agent).
+
+get_log_type(Agent) ->
+ snmpa_agent:get_log_type(Agent).
+
+%% NewType -> atl_type()
+change_log_type(NewType) ->
+ set_log_type(NewType).
+
+change_log_type(Agent, NewType) ->
+ set_log_type(Agent, NewType).
+
+set_log_type(NewType) ->
+ set_log_type(snmp_master_agent, NewType).
+
+set_log_type(Agent, NewType) ->
+ snmpa_agent:set_log_type(Agent, NewType).
diff --git a/lib/snmp/src/agent/snmpa_acm.erl b/lib/snmp/src/agent/snmpa_acm.erl
new file mode 100644
index 0000000000..6ad4f0b442
--- /dev/null
+++ b/lib/snmp/src/agent/snmpa_acm.erl
@@ -0,0 +1,364 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1997-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%
+%%
+-module(snmpa_acm).
+
+-behaviour(snmpa_authentication_service).
+
+-export([init_check_access/2, get_root_mib_view/0,
+ error2status/1,
+ validate_mib_view/2, validate_all_mib_view/2,
+ is_definitely_not_in_mib_view/2,
+ invalidate_ca_cache/0]).
+
+-include("snmp_types.hrl").
+-include("STANDARD-MIB.hrl").
+-include("SNMP-FRAMEWORK-MIB.hrl").
+-include("SNMPv2-TM.hrl").
+
+-define(VMODULE,"ACM").
+-include("snmp_verbosity.hrl").
+
+
+%%%-----------------------------------------------------------------
+%%% This module implements the Access Control Model part of the
+%%% multi-lingual SNMP agent. It contains generic function not
+%%% tied to a specific model, but in this version it uses VACM.
+%%%
+%%% Note that we don't follow the isAccessAllowed Abstract Service
+%%% Interface defined in rfc2271. We implement an optimization
+%%% of that ASI. Since the mib view is the same for all variable
+%%% bindings in a PDU, there is no need to recalculate the mib
+%%% view for each variable. Therefore, one function
+%%% (init_check_access/2) is used to find the mib view, and then
+%%% each variable is checked against this mib view.
+%%%
+%%% Access checking is done in several steps. First, the version-
+%%% specific MPD (see snmpa_mpd) creates data used by VACM. This
+%%% means that the format of this data is known by both the MPD and
+%%% the ACM. When the master agent wants to check the access to a
+%%% Pdu, it first calls init_check_access/2, which returns a MibView
+%%% that can be used to check access of individual variables.
+%%%-----------------------------------------------------------------
+
+%%-----------------------------------------------------------------
+%% Func: init_check_access(Pdu, ACMData) ->
+%% {ok, MibView, ContextName} |
+%% {error, Reason} |
+%% {discarded, Variable, Reason}
+%% Types: Pdu = #pdu
+%% ACMData = acm_data() = {community, Community, Address} |
+%% {v3, MsgID, SecModel, SecName, SecLevel,
+%% ContextEngineID, ContextName, SecData}
+%% Community = string()
+%% Address = ip() ++ udp() (list)
+%% MsgID = integer() <not used>
+%% SecModel = ?SEC_* (see snmp_types.hrl)
+%% SecName = string()
+%% SecLevel = ?'SnmpSecurityLevel_*' (see SNMP-FRAMEWORK-MIB.hrl)
+%% ContextEngineID = string() <not used>
+%% ContextName = string()
+%% SecData = <not used>
+%% Variable = snmpInBadCommunityNames |
+%% snmpInBadCommunityUses |
+%% snmpInASNParseErrs
+%% Reason = snmp_message_decoding |
+%% {bad_community_name, Address, Community}} |
+%% {invalid_access, Access, Op}
+%%
+%% Purpose: Called once for each Pdu. Returns a MibView
+%% which is later used for each variable in the pdu.
+%% The authenticationFailure trap is sent (maybe) when the auth.
+%% procedure evaluates to unauthentic,
+%%
+%% NOTE: This function is executed in the Master agents's context
+%%-----------------------------------------------------------------
+init_check_access(Pdu, ACMData) ->
+ case init_ca(Pdu, ACMData) of
+ {ok, MibView, ContextName} ->
+ {ok, MibView, ContextName};
+ {discarded, Reason} ->
+ {error, Reason};
+ {authentication_failure, Variable, Reason} ->
+ handle_authentication_failure(),
+ {discarded, Variable, Reason}
+ end.
+
+error2status(noSuchView) -> authorizationError;
+error2status(noAccessEntry) -> authorizationError;
+error2status(noGroupName) -> authorizationError;
+error2status(_) -> genErr.
+
+%%-----------------------------------------------------------------
+%% Func: init_ca(Pdu, ACMData) ->
+%% {ok, MibView} |
+%% {discarded, Reason} |
+%% {authentication_failure, Variable, Reason}
+%%
+%% error: an error response will be sent
+%% discarded: no error response is sent
+%% authentication_failure: no error response is sent, a trap is generated
+%%-----------------------------------------------------------------
+init_ca(Pdu, {community, SecModel, Community, TAddr}) ->
+ %% This is a v1 or v2c request. Use SNMP-COMMUNITY-MIB to
+ %% map the community to vacm parameters.
+ ?vtrace("check access for ~n"
+ " Pdu: ~p~n"
+ " Security model: ~p~n"
+ " Community: ~s",[Pdu,SecModel,Community]),
+ ViewType = case Pdu#pdu.type of
+ 'set-request' -> write;
+ _ -> read
+ end,
+ ?vtrace("View type: ~p", [ViewType]),
+ CaCacheKey = {Community, SecModel, TAddr, ViewType},
+ case check_ca_cache(CaCacheKey) of
+ false ->
+ case snmp_community_mib:community2vacm(Community,
+ {?snmpUDPDomain,TAddr}) of
+ {SecName, _ContextEngineId, ContextName} ->
+ %% Maybe we should check that the contextEngineID
+ %% matches the local engineID?
+ %% It better, since we don't impl. proxy.
+ ?vtrace("get mib view"
+ "~n Security name: ~p"
+ "~n Context name: ~p",[SecName,ContextName]),
+ case snmpa_vacm:get_mib_view(ViewType, SecModel, SecName,
+ ?'SnmpSecurityLevel_noAuthNoPriv',
+ ContextName) of
+ {ok, MibView} ->
+ Res = {ok, MibView, ContextName},
+ upd_ca_cache({CaCacheKey, Res}),
+ put(sec_model, SecModel),
+ put(sec_name, SecName),
+ Res;
+ {discarded, Reason} ->
+ snmpa_mpd:inc(snmpInBadCommunityUses),
+ {discarded, Reason}
+ end;
+ undefined ->
+ {authentication_failure, snmpInBadCommunityNames,
+ {bad_community_name, TAddr, Community}}
+ end;
+ Res ->
+ Res
+ end;
+
+init_ca(Pdu, {v3, _MsgID, SecModel, SecName, SecLevel,
+ _ContextEngineID, ContextName, _SecData}) ->
+ ?vtrace("check v3 access for ~n"
+ " Pdu: ~p~n"
+ " Security model: ~p~n"
+ " Security name: ~p~n"
+ " Security level: ~p",[Pdu,SecModel,SecName,SecLevel]),
+ ViewType = case Pdu#pdu.type of
+ 'set-request' -> write;
+ _ -> read
+ end,
+ ?vtrace("View type: ~p",[ViewType]),
+ %% Convert the msgflag value to a ?'SnmpSecurityLevel*'
+ SL = case SecLevel of
+ 0 -> ?'SnmpSecurityLevel_noAuthNoPriv';
+ 1 -> ?'SnmpSecurityLevel_authNoPriv';
+ 3 -> ?'SnmpSecurityLevel_authPriv'
+ end,
+ put(sec_model, SecModel),
+ put(sec_name, SecName),
+ CaCacheKey = {ViewType, SecModel, SecName, SL, ContextName},
+ case check_ca_cache(CaCacheKey) of
+ false ->
+ case snmpa_vacm:get_mib_view(ViewType, SecModel, SecName,
+ SL, ContextName) of
+ {ok, MibView} ->
+ Res = {ok, MibView, ContextName},
+ upd_ca_cache({CaCacheKey, Res}),
+ Res;
+ Else ->
+ Else
+ end;
+ Res ->
+ Res
+ end.
+
+check_ca_cache(Key) ->
+ case get(ca_cache) of
+ undefined ->
+ put(ca_cache, []),
+ false;
+ L ->
+ check_ca_cache(L, Key)
+ end.
+
+check_ca_cache([{Key, Val} | _], Key) -> Val;
+check_ca_cache([_ | T], Key) -> check_ca_cache(T, Key);
+check_ca_cache([], _) -> false.
+
+upd_ca_cache(KeyVal) ->
+ case get(ca_cache) of
+ [A,B,C,_] -> % cache is full
+ put(ca_cache, [KeyVal,A,B,C]);
+ L ->
+ put(ca_cache, [KeyVal|L])
+ end.
+
+invalidate_ca_cache() ->
+ erase(ca_cache).
+
+%%-----------------------------------------------------------------
+%% Func: check(Res) -> {ok, MibView} | {discarded, Variable, Reason}
+%% Args: Res = {ok, AccessFunc} |
+%% {authentication_failure, Variable, Reason}
+%%-----------------------------------------------------------------
+
+%%-----------------------------------------------------------------
+%% NOTE: The do_get MUST be executed in the Master agents's
+%% context. Therefor, force master-agent to do a GET to
+%% retrieve the value for snmpEnableAuthenTraps.
+%% A user may have another impl. than default for this
+%% variable.
+%%-----------------------------------------------------------------
+handle_authentication_failure() ->
+ case snmpa_agent:do_get(get_root_mib_view(),
+ [#varbind{oid = ?snmpEnableAuthenTraps_instance}],
+ true, true) of
+ {noError, _, [#varbind{value = ?snmpEnableAuthenTraps_enabled}]} ->
+ ?vtrace("handle_authentication_failure -> enabled", []),
+ snmpa:send_notification(snmp_master_agent,
+ authenticationFailure,
+ no_receiver);
+ _ ->
+ ok
+ end.
+
+%%%-----------------------------------------------------------------
+%%% MIB View handling
+%%%-----------------------------------------------------------------
+
+get_root_mib_view() ->
+ [{[1], [], ?view_included}].
+
+%%-----------------------------------------------------------------
+%% Returns true if Oid is in the MibView, false
+%% otherwise.
+%% Alg: (defined in SNMP-VIEW-BASED-ACM-MIB)
+%% For each family (= {SubTree, Mask, Type}), check if Oid
+%% belongs to that family. For each family that Oid belong to,
+%% get the longest. If two or more are longest, get the
+%% lexicografically greatest. Check the type of this family. If
+%% included, then Oid belongs to the MibView, otherwise it
+%% does not.
+%% Optimisation: Do only one loop, and kepp the largest sofar.
+%% When we find a family that Oid belongs to, check if it is
+%% larger than the largest.
+%%-----------------------------------------------------------------
+validate_mib_view(Oid, MibView) ->
+ case get_largest_family(MibView, Oid, undefined) of
+ {_, _, ?view_included} -> true;
+ _ -> false
+ end.
+
+get_largest_family([{SubTree, Mask, Type} | T], Oid, Res) ->
+ case check_mask(Oid, SubTree, Mask) of
+ true -> get_largest_family(T, Oid, add_res(length(SubTree), SubTree,
+ Type, Res));
+ false -> get_largest_family(T, Oid, Res)
+ end;
+get_largest_family([], _Oid, Res) -> Res.
+
+%%-----------------------------------------------------------------
+%% We keep only the largest (first longest SubTree, and then
+%% lexicografically greatest) SubTree.
+%%-----------------------------------------------------------------
+add_res(Len, SubTree, Type, undefined) ->
+ {Len, SubTree, Type};
+add_res(Len, SubTree, Type, {MaxLen, _MaxS, _MaxT}) when Len > MaxLen ->
+ {Len, SubTree, Type};
+add_res(Len, SubTree, Type, {MaxLen, MaxS, MaxT}) when Len == MaxLen ->
+ if
+ SubTree > MaxS -> {Len, SubTree, Type};
+ true -> {MaxLen, MaxS, MaxT}
+ end;
+add_res(_Len, _SubTree, _Type, MaxRes) -> MaxRes.
+
+
+%% 1 in mask is exact match, 0 is wildcard.
+%% If mask is shorter than SubTree, its regarded
+%% as being all ones.
+check_mask(_Oid, [], _Mask) -> true;
+check_mask([X | Xs], [X | Ys], [1 | Ms]) ->
+ check_mask(Xs, Ys, Ms);
+check_mask([X | Xs], [X | Ys], []) ->
+ check_mask(Xs, Ys, []);
+check_mask([_X | Xs], [_Y | Ys], [0 | Ms]) ->
+ check_mask(Xs, Ys, Ms);
+check_mask(_, _, _) -> false.
+
+%%-----------------------------------------------------------------
+%% Validates all oids in the Varbinds list towards the MibView.
+%%-----------------------------------------------------------------
+validate_all_mib_view([#varbind{oid = Oid, org_index = Index} | Varbinds],
+ MibView) ->
+ ?vtrace("validate_all_mib_view -> entry with"
+ "~n Oid: ~p"
+ "~n Index: ~p", [Oid, Index]),
+ case validate_mib_view(Oid, MibView) of
+ true -> validate_all_mib_view(Varbinds, MibView);
+ false -> {false, Index}
+ end;
+validate_all_mib_view([], _MibView) ->
+ ?vtrace("validate_all_mib_view -> done", []),
+ true.
+
+%%-----------------------------------------------------------------
+%% This function is used to optimize the next operation in
+%% snmpa_mib_data. If we get to a node in the tree where we can
+%% determine that we are guaranteed to be outside the mibview,
+%% we don't have to continue the search in the that tree (Actually
+%% we will, because we only check this at leafs. But we won't
+%% go into tables or subagents, and that's the important
+%% optimization.) For now, this function isn't that sophisticated;
+%% it just checks that there is really no family in the mibview
+%% that the Oid (or any other oids with Oid as prefix) may be
+%% included in. Perhaps this function easily could be more
+%% intelligent.
+%%-----------------------------------------------------------------
+is_definitely_not_in_mib_view(Oid, [{SubTree, Mask,?view_included}|T]) ->
+ case check_maybe_mask(Oid, SubTree, Mask) of
+ true -> false;
+ false -> is_definitely_not_in_mib_view(Oid, T)
+ end;
+is_definitely_not_in_mib_view(Oid, [{_SubTree, _Mask,?view_excluded}|T]) ->
+ is_definitely_not_in_mib_view(Oid, T);
+is_definitely_not_in_mib_view(_Oid, []) ->
+ true.
+
+%%-----------------------------------------------------------------
+%% As check_mask, BUT if Oid < SubTree and sofar good, we
+%% return true. As Oid get larger we may decide.
+%%-----------------------------------------------------------------
+check_maybe_mask(_Oid, [], _Mask) -> true;
+check_maybe_mask([X | Xs], [X | Ys], [1 | Ms]) ->
+ check_maybe_mask(Xs, Ys, Ms);
+check_maybe_mask([X | Xs], [X | Ys], []) ->
+ check_maybe_mask(Xs, Ys, []);
+check_maybe_mask([_X | Xs], [_Y | Ys], [0 | Ms]) ->
+ check_maybe_mask(Xs, Ys, Ms);
+check_maybe_mask([_X | _Xs], [_Y | _Ys], _) ->
+ false;
+check_maybe_mask(_, _, _) ->
+ true.
diff --git a/lib/snmp/src/agent/snmpa_agent.erl b/lib/snmp/src/agent/snmpa_agent.erl
new file mode 100644
index 0000000000..508a1da514
--- /dev/null
+++ b/lib/snmp/src/agent/snmpa_agent.erl
@@ -0,0 +1,3964 @@
+%%
+%% %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%
+%%
+-module(snmpa_agent).
+
+-include_lib("kernel/include/file.hrl").
+-include("snmpa_internal.hrl").
+-include("snmp_types.hrl").
+-include("snmp_debug.hrl").
+-include("snmp_verbosity.hrl").
+-include("SNMP-FRAMEWORK-MIB.hrl").
+
+%% External exports
+-export([start_link/4, start_link/5, stop/1]).
+-export([subagent_set/2,
+ load_mibs/2, unload_mibs/2, which_mibs/1, whereis_mib/2, info/1,
+ register_subagent/3, unregister_subagent/2,
+ send_trap/6,
+ register_notification_filter/5,
+ unregister_notification_filter/2,
+ which_notification_filter/1,
+ get_net_if/1]).
+-export([
+ discovery/6,
+ is_originating_discovery_enabled/0,
+ is_terminating_discovery_enabled/0,
+ terminating_discovery_stage2/0,
+ terminating_trigger_username/0
+ ]).
+-export([verbosity/2, dump_mibs/1, dump_mibs/2]).
+-export([validate_err/3, make_value_a_correct_value/3,
+ do_get/3, do_get/4,
+ get/2, get/3, get_next/2, get_next/3]).
+-export([mib_of/1, mib_of/2, me_of/1, me_of/2,
+ invalidate_mibs_cache/1,
+ enable_mibs_cache/1, disable_mibs_cache/1,
+ gc_mibs_cache/1, gc_mibs_cache/2, gc_mibs_cache/3,
+ enable_mibs_cache_autogc/1, disable_mibs_cache_autogc/1,
+ update_mibs_cache_age/2,
+ update_mibs_cache_gclimit/2]).
+-export([get_agent_mib_storage/0, db/1,
+ backup/2]).
+-export([get_log_type/1, set_log_type/2]).
+-export([get_request_limit/1, set_request_limit/2]).
+-export([invalidate_ca_cache/0]).
+-export([restart_worker/1, restart_set_worker/1]).
+
+%% Internal exports
+-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
+ terminate/2, code_change/3, tr_var/2, tr_varbind/1,
+ handle_pdu/7, worker/2, worker_loop/1, do_send_trap/6]).
+
+-ifndef(default_verbosity).
+-define(default_verbosity,silence).
+-endif.
+
+-define(empty_pdu_size, 21).
+
+-ifdef(snmp_extended_verbosity).
+-define(vt(F,A), ?vtrace(F, A)).
+-else.
+-define(vt(_F, _A), ok).
+-endif.
+
+-define(DISCO_TERMINATING_TRIGGER_USERNAME, "").
+
+
+-ifdef(snmp_debug).
+-define(GS_START_LINK3(Prio, Parent, Ref, Opts),
+ gen_server:start_link(?MODULE, [Prio, Parent, Ref, Opts],
+ [{debug,[trace]}])).
+-define(GS_START_LINK4(Prio, Name, Parent, Ref, Opts),
+ gen_server:start_link({local, Name}, ?MODULE,
+ [Prio, Parent, Ref, Opts],
+ [{debug,[trace]}])).
+-else.
+-define(GS_START_LINK3(Prio, Parent, Ref, Opts),
+ gen_server:start_link(?MODULE, [Prio, Parent, Ref, Opts],[])).
+-define(GS_START_LINK4(Prio, Name, Parent, Ref, Opts),
+ gen_server:start_link({local, Name}, ?MODULE,
+ [Prio, Parent, Ref, Opts],[])).
+-endif.
+
+
+-record(notification_filter, {id, mod, data}).
+-record(disco,
+ {from, rec, sender, target, engine_id,
+ sec_level, ctx, ivbs, stage, handler, extra}).
+
+
+%%-----------------------------------------------------------------
+%% The agent is multi-threaded, i.e. each request is handled
+%% by a separate process. However, in the normal case, there
+%% is just one request handled at the time. In order to improve
+%% performance, there is always two worker processes alive. They are
+%% created at initialization time. There is always one worker
+%% dedicated to SET-handling. When a get*-request is received,
+%% it is sent to the worker, and the worker is marked as busy.
+%% If a request is received when the worker is busy, a new temporary
+%% worker is spawned.
+%% Code change
+%% ===========
+%% Note that the worker(s) execute the same module as the master
+%% agent. For code change we have two options - ignore the workers,
+%% or send them a code change message.
+%%-----------------------------------------------------------------
+-record(state, {type,
+ parent,
+ worker,
+ worker_state = ready,
+ set_worker,
+ multi_threaded,
+ ref,
+ vsns,
+ nfilters = [],
+ note_store,
+ mib_server, %% Currently unused
+ net_if, %% Currently unused
+ net_if_mod,
+ backup,
+ disco,
+ mibs_cache_request}).
+
+
+%%%-----------------------------------------------------------------
+%%% This module implements the agent machinery; both for the master
+%%% agent and the subagents.
+%%%-----------------------------------------------------------------
+%%% Table of contents
+%%% =================
+%%% 1. Interface
+%%% 2. Main loop
+%%% 3. GET REQUEST
+%%% 4. GET-NEXT REQUEST
+%%% 5. GET-BULK REQUEST
+%%% 6. SET REQUEST
+%%% 7. Misc functions
+%%%-----------------------------------------------------------------
+
+%%-----------------------------------------------------------------
+%% Parent is a Pid (of master_agent) or none
+%% Options is a list of Option, where Option is
+%% {mibs, Mibs}
+%% {net_if, NetIfModule}
+%% {priority, Prio}
+%% {verbosity, Verbosity}
+%% {multi_threaded, Bool} true means that SETs are serialized,
+%% while GETs are concurrent, even with a SET.
+%% {set_mechanism, SetModule} % undocumented feature
+%%
+%% The following options are now removed - they are not needed
+%% anymore when VACM is standard for authentication, and works
+%% with all versions, and trap sending is standardized too.
+%% {authentication_service, AuthModule} % undocumented feature
+%% {trap_mechanism, TrapModule} % undocumented feature
+%% Note: authentication_service is reintroduced for AXD301 (OTP-3324).
+%%-----------------------------------------------------------------
+start_link(Prio, Parent, Ref, Options) ->
+ ?d("start_link -> entry with"
+ "~n Prio: ~p"
+ "~n Parent: ~p"
+ "~n Ref: ~p"
+ "~n Options: ~p", [Prio, Parent, Ref, Options]),
+ %% gen_server:start_link(?MODULE, [Prio, Parent, Ref, Options], []).
+ ?GS_START_LINK3(Prio, Parent, Ref, Options).
+
+start_link(Prio, Name, Parent, Ref, Options) ->
+ ?d("start_link -> entry with"
+ "~n Prio: ~p"
+ "~n Name: ~p"
+ "~n Parent: ~p"
+ "~n Ref: ~p"
+ "~n Options: ~p", [Prio, Name, Parent, Ref, Options]),
+% gen_server:start_link({local, Name}, ?MODULE,
+% [Prio, Parent, Ref, Options], []).
+ ?GS_START_LINK4(Prio, Name, Parent, Ref, Options).
+
+stop(Agent) -> call(Agent, stop).
+
+restart_worker(Agent) ->
+ call(Agent, restart_worker).
+
+restart_set_worker(Agent) ->
+ call(Agent, restart_set_worker).
+
+get_log_type(Agent) ->
+ call(Agent, get_log_type).
+
+set_log_type(Agent, NewType) ->
+ call(Agent, {set_log_type, NewType}).
+
+get_request_limit(Agent) ->
+ call(Agent, get_request_limit).
+
+set_request_limit(Agent, NewLimit) ->
+ call(Agent, {set_request_limit, NewLimit}).
+
+mib_of(Oid) when is_list(Oid) ->
+ mib_of(snmp_master_agent, Oid).
+
+mib_of(Agent, Oid) when is_list(Oid) ->
+ call(Agent, {mib_of, Oid}).
+
+me_of(Oid) when is_list(Oid) ->
+ me_of(snmp_master_agent, Oid).
+
+me_of(Agent, Oid) when is_list(Oid) ->
+ call(Agent, {me_of, Oid}).
+
+
+invalidate_mibs_cache(Agent) ->
+ call(Agent, {mibs_cache_request, invalidate_cache}).
+
+
+gc_mibs_cache(Agent) ->
+ call(Agent, {mibs_cache_request, gc_cache}).
+
+gc_mibs_cache(Agent, Age) ->
+ call(Agent, {mibs_cache_request, {gc_cache, Age}}).
+
+gc_mibs_cache(Agent, Age, GcLimit) ->
+ call(Agent, {mibs_cache_request, {gc_cache, Age, GcLimit}}).
+
+
+enable_mibs_cache(Agent) ->
+ call(Agent, {mibs_cache_request, enable_cache}).
+
+disable_mibs_cache(Agent) ->
+ call(Agent, {mibs_cache_request, disable_cache}).
+
+
+enable_mibs_cache_autogc(Agent) ->
+ call(Agent, {mibs_cache_request, enable_autogc}).
+
+disable_mibs_cache_autogc(Agent) ->
+ call(Agent, {mibs_cache_request, disable_autogc}).
+
+
+update_mibs_cache_gclimit(Agent, GcLimit) ->
+ call(Agent, {mibs_cache_request, {update_gclimit, GcLimit}}).
+
+
+update_mibs_cache_age(Agent, Age) ->
+ call(Agent, {mibs_cache_request, {update_age, Age}}).
+
+
+init([Prio, Parent, Ref, Options]) ->
+ ?d("init -> entry with"
+ "~n Prio: ~p"
+ "~n Parent: ~p"
+ "~n Ref: ~p"
+ "~n Options: ~p", [Prio, Parent, Ref, Options]),
+ case (catch do_init(Prio, Parent, Ref, Options)) of
+ {ok, State} ->
+ ?vdebug("started",[]),
+ {ok, State};
+ {error, Reason} ->
+ config_err("failed starting agent: ~n~p", [Reason]),
+ {stop, Reason}
+ end.
+
+do_init(Prio, Parent, Ref, Options) ->
+ process_flag(priority, Prio),
+ put(sname,short_name(Parent)),
+ put(verbosity,get_verbosity(Options)),
+ ?vlog("starting with: "
+ "~n Prio: ~p"
+ "~n Parent: ~p"
+ "~n Ref: ~p"
+ "~n Options: ~p",[Prio, Parent, Ref, Options]),
+
+ Mibs = get_mibs(Options),
+ SetModule = get_set_mechanism(Options),
+ put(set_module, SetModule),
+
+ %% OTP-3324. For AXD301.
+ AuthModule = get_authentication_service(Options),
+ put(auth_module, AuthModule),
+
+ MultiT = get_multi_threaded(Options),
+ Vsns = get_versions(Options),
+
+ NS = start_note_store(Prio, Ref, Options),
+ {Type, NetIfPid, NetIfMod} =
+ start_net_if(Parent, Prio, Ref, Vsns, NS, Options),
+
+ MibPid = start_mib_server(Prio, Ref, Mibs, Options),
+
+ put(net_if, NetIfPid),
+ put(mibserver, MibPid),
+ process_flag(trap_exit, true),
+ {Worker, SetWorker} = workers_start(MultiT),
+ {ok, #state{type = Type,
+ parent = Parent,
+ worker = Worker,
+ set_worker = SetWorker,
+ multi_threaded = MultiT,
+ ref = Ref,
+ vsns = Vsns,
+ note_store = NS,
+ net_if_mod = NetIfMod}}.
+
+
+start_note_store(Prio, Ref, Options) ->
+ ?vdebug("start_note_store -> with Prio: ~p", [Prio]),
+ NsOpts = get_note_store_opt(Options),
+
+ ?vtrace("start_note_store -> NsOpts: ~p", [NsOpts]),
+
+ case (catch snmpa_misc_sup:start_note_store(Prio, Ref, NsOpts)) of
+ {ok, Pid} ->
+ ?vdebug("start_note_store -> Pid: ~p", [Pid]),
+ Pid;
+ {error, Reason} ->
+ ?vinfo("error starting note store: ~n~p",[Reason]),
+ throw({error, {note_store_error, Reason}});
+ {'EXIT', Reason} ->
+ ?vinfo("exit starting note store: ~n~p",[Reason]),
+ throw({error, {note_store_exit, Reason}});
+ Error ->
+ ?vinfo("failed starting note store: ~n~p",[Error]),
+ throw({error, {note_store_failed, Error}})
+ end.
+
+
+start_net_if(none, Prio, Ref, Vsns, NoteStore, Options) ->
+ ?vdebug("start_net_if(none) -> with Prio: ~p", [Prio]),
+ NetIfOpts = get_net_if_opt(Options),
+ Verbosity = get_net_if_verbosity(NetIfOpts),
+ Mod = get_net_if_module(NetIfOpts),
+ NiOptions = get_net_if_options(NetIfOpts),
+ NiOpts = [{versions, Vsns},
+ {verbosity, Verbosity} | NiOptions],
+
+ ?vtrace("start_net_if -> "
+ "~n Mod: ~p"
+ "~n NiOpts: ~p",[Mod, NiOpts]),
+
+ case (catch snmpa_misc_sup:start_net_if(Prio, NoteStore, Ref, self(),
+ Mod, NiOpts)) of
+ {ok, Pid} ->
+ ?vdebug("start_net_if -> Pid: ~p", [Pid]),
+ {master_agent, Pid, Mod};
+ {error, Reason} ->
+ ?vinfo("error starting net if: ~n~p",[Reason]),
+ throw({error, {net_if_error, Reason}});
+ {'EXIT', Reason} ->
+ ?vinfo("exit starting net if: ~n~p",[Reason]),
+ throw({error, {net_if_exit, Reason}});
+ Error ->
+ ?vinfo("failed starting net if: ~n~p",[Error]),
+ throw({error, {net_if_failed, Error}})
+ end;
+start_net_if(Parent, _Prio, _Ref, _Vsns, _NoteStore, _Options)
+ when is_pid(Parent) ->
+ ?vdebug("start_net_if(~p) -> subagent => ignore", [Parent]),
+ {subagent, undefined, undefined}.
+
+
+start_mib_server(Prio, Ref, Mibs, Options) ->
+ ?vdebug("start_mib_server -> with Prio: ~p", [Prio]),
+ MibStorage = get_mib_storage(Options),
+ MibsOpts = [{mib_storage, MibStorage}|get_option(mib_server, Options, [])],
+
+ ?vtrace("start_mib_server -> "
+ "~n Mibs: ~p"
+ "~n MibsOpts: ~p", [Mibs, MibsOpts]),
+
+ case (catch snmpa_misc_sup:start_mib_server(Prio, Ref, Mibs, MibsOpts)) of
+ {ok, Pid} ->
+ ?vdebug("start_mib_server -> Pid: ~p", [Pid]),
+ Pid;
+ {error, Reason} ->
+ ?vinfo("error starting mib server: ~n~p",[Reason]),
+ throw({error, {mib_server_error, Reason}});
+ {'EXIT', Reason} ->
+ ?vinfo("exit starting mib server: ~n~p",[Reason]),
+ throw({error, {mib_server_exit, Reason}});
+ Error ->
+ ?vinfo("failed starting mib server: ~n~p",[Error]),
+ throw({error, {mib_server_failed, Error}})
+ end.
+
+
+%%-----------------------------------------------------------------
+%% Purpose: We must calculate the length of an empty Pdu. This
+%% length is used to calculate the max pdu size allowed
+%% for each get-bulk-request. This size is
+%% dependent on the varbinds. It is calculated
+%% as EmptySize + 8. 8 comes from the fact that the
+%% maximum pdu size needs 31 bits which needs 5 * 7 bits to be
+%% expressed. One 7bit octet is already present in the
+%% empty pdu, leaving 4 more 7bit octets. The length is
+%% repeated twice, once for the varbinds, and once for the
+%% entire pdu; 2 * 4 = 8.
+%% Actually, this function is not used, we use a constant instead.
+%%-----------------------------------------------------------------
+%% Ret: 21
+%% empty_pdu() ->
+%% Pdu = #pdu{type = 'get-response',
+%% request_id = 1,
+%% error_status = noError,
+%% error_index = 0,
+%% varbinds = []},
+%% length(snmp_pdus:enc_pdu(Pdu)) + 8.
+
+
+%%%--------------------------------------------------
+%%% 1. Interface
+%%%--------------------------------------------------
+%% Called by administrator (not subagent; deadlock could occur)
+register_subagent(Agent, SubTreeOid, SubagentPid) ->
+ call(Agent, {register_subagent, SubTreeOid, SubagentPid}).
+
+%% Called by administrator (not subagent; deadlock could occur)
+unregister_subagent(Agent, SubagentOidOrPid) ->
+ call(Agent, {unregister_subagent, SubagentOidOrPid}).
+
+
+%%-----------------------------------------------------------------
+%% These subagent_ functions either return a value, or exits
+%% with {nodedown, Node} | Reason.
+%%-----------------------------------------------------------------
+subagent_get(SubAgent, Varbinds, IsNotification) ->
+ PduData = get_pdu_data(),
+ call(SubAgent, {subagent_get, Varbinds, PduData, IsNotification}).
+
+subagent_get_next(SubAgent, MibView, Varbinds) ->
+ PduData = get_pdu_data(),
+ call(SubAgent, {subagent_get_next, MibView, Varbinds, PduData}).
+
+subagent_set(SubAgent, Arguments) ->
+ PduData = get_pdu_data(),
+ call(SubAgent, {subagent_set, Arguments, PduData}).
+
+
+%% Called by administrator (not agent; deadlock would occur)
+load_mibs(Agent, Mibs) ->
+ call(Agent, {load_mibs, Mibs}).
+
+%% Called by administrator (not agent; deadlock would occur)
+unload_mibs(Agent, Mibs) ->
+ call(Agent, {unload_mibs, Mibs}).
+
+which_mibs(Agent) ->
+ call(Agent, which_mibs).
+
+whereis_mib(Agent, Mib) ->
+ call(Agent, {whereis_mib, Mib}).
+
+info(Agent) ->
+ call(Agent, info).
+
+
+get_net_if(Agent) ->
+ call(Agent, get_net_if).
+
+
+register_notification_filter(Agent, Id, Mod, Args, Where)
+ when (Where =:= first) orelse (Where =:= last) ->
+ case (catch verify_notification_filter_behaviour(Mod)) of
+ ok ->
+ call(Agent, {register_notification_filter, Id, Mod, Args, Where});
+ Error ->
+ Error
+ end;
+register_notification_filter(Agent, Id, Mod, Args, {Loc, _Id} = Where)
+ when (Loc =:= insert_before) orelse (Loc =:= insert_after) ->
+ case (catch verify_notification_filter_behaviour(Mod)) of
+ ok ->
+ call(Agent, {register_notification_filter, Id, Mod, Args, Where});
+ Error ->
+ Error
+ end.
+
+verify_notification_filter_behaviour(Mod) ->
+ snmp_misc:verify_behaviour(snmpa_notification_filter, Mod).
+
+unregister_notification_filter(Agent, Id) ->
+ call(Agent, {unregister_notification_filter, Id}).
+
+which_notification_filter(Agent) ->
+ call(Agent, which_notification_filter).
+
+
+send_trap(Agent, Trap, NotifyName, CtxName, Recv, Varbinds) ->
+ ?d("send_trap -> entry with"
+ "~n self(): ~p"
+ "~n Agent: ~p [~p]"
+ "~n Trap: ~p"
+ "~n NotifyName: ~p"
+ "~n CtxName: ~p"
+ "~n Recv: ~p"
+ "~n Varbinds: ~p",
+ [self(), Agent, wis(Agent), Trap, NotifyName, CtxName, Recv, Varbinds]),
+ Msg = {send_trap, Trap, NotifyName, CtxName, Recv, Varbinds},
+ case (wis(Agent) =:= self()) of
+ false ->
+ call(Agent, Msg);
+ true ->
+ Agent ! Msg
+ end.
+
+
+%% -- Discovery functions --
+
+disco_opts() ->
+ case ets:lookup(snmp_agent_table, discovery) of
+ [] ->
+ [];
+ [{discovery, DiscoOptions}] ->
+ DiscoOptions
+ end.
+
+originating_disco_opts() ->
+ DiscoOpts = disco_opts(),
+ case lists:keysearch(originating, 1, DiscoOpts) of
+ {value, {originating, OrigDisco}} ->
+ OrigDisco;
+ _ ->
+ []
+ end.
+
+is_originating_discovery_enabled() ->
+ OrigDisco = originating_disco_opts(),
+ case lists:keysearch(enable, 1, OrigDisco) of
+ {value, {enable, false}} ->
+ false;
+ _ ->
+ true
+ end.
+
+terminating_disco_opts() ->
+ DiscoOpts = disco_opts(),
+ case lists:keysearch(terminating, 1, DiscoOpts) of
+ {value, {terminating, TermDisco}} ->
+ TermDisco;
+ _ ->
+ []
+ end.
+
+is_terminating_discovery_enabled() ->
+ TermDisco = terminating_disco_opts(),
+ case lists:keysearch(enable, 1, TermDisco) of
+ {value, {enable, false}} ->
+ false;
+ _ ->
+ true
+ end.
+
+terminating_discovery_stage2() ->
+ Default = discovery,
+ TermDisco = terminating_disco_opts(),
+ case lists:keysearch(stage2, 1, TermDisco) of
+ {value, {stage2, Stage2}} when ((Stage2 =:= discovery) orelse (Stage2 =:= plain)) ->
+ Stage2;
+ _ ->
+ Default
+ end.
+
+terminating_trigger_username() ->
+ Default = ?DISCO_TERMINATING_TRIGGER_USERNAME,
+ TermDisco = terminating_disco_opts(),
+ case lists:keysearch(trigger_username, 1, TermDisco) of
+ {value, {trigger_username, Trigger}} when is_list(Trigger) ->
+ Trigger;
+ _ ->
+ Default
+ end.
+
+
+discovery(TargetName, Notification, ContextName, Varbinds,
+ DiscoHandler, ExtraInfo) ->
+ case is_originating_discovery_enabled() of
+ true ->
+ Agent = snmp_master_agent,
+ call(Agent,
+ {discovery,
+ TargetName, Notification, ContextName, Varbinds,
+ DiscoHandler, ExtraInfo});
+ false ->
+ {error, not_enabled}
+ end.
+
+wis(Pid) when is_pid(Pid) ->
+ Pid;
+wis(Atom) when is_atom(Atom) ->
+ whereis(Atom).
+
+forward_trap(Agent, TrapRecord, NotifyName, CtxName, Recv, Varbinds) ->
+ Agent ! {forward_trap, TrapRecord, NotifyName, CtxName, Recv, Varbinds}.
+
+
+%%-----------------------------------------------------------------
+%% Args: Vars = [Oid]
+%% Returns: [Value]
+%% Called from a program to get variables. Don't call this from
+%% an instrumentation function; deadlock can occur!
+%%-----------------------------------------------------------------
+get(Agent, Vars) ->
+ call(Agent, {get, Vars, ""}).
+
+get(Agent, Vars, Context) ->
+ call(Agent, {get, Vars, Context}).
+
+get_next(Agent, Vars) ->
+ call(Agent, {get_next, Vars, ""}).
+
+get_next(Agent, Vars, Context) ->
+ call(Agent, {get_next, Vars, Context}).
+
+
+%%-----------------------------------------------------------------
+
+backup(Agent, BackupDir) when is_list(BackupDir) ->
+ call(Agent, {backup, BackupDir}).
+
+
+%%-----------------------------------------------------------------
+%% Runtime debug support.
+%%-----------------------------------------------------------------
+dump_mibs(Agent) ->
+ call(Agent, dump_mibs).
+dump_mibs(Agent, File) when is_list(File) ->
+ call(Agent, {dump_mibs, File}).
+
+
+%%-----------------------------------------------------------------
+%% Runtime debug (verbosity) support.
+%%-----------------------------------------------------------------
+verbosity(net_if,Verbosity) ->
+ cast(snmp_master_agent,{net_if_verbosity,Verbosity});
+verbosity(mib_server,Verbosity) ->
+ cast(snmp_master_agent,{mib_server_verbosity,Verbosity});
+verbosity(note_store,Verbosity) ->
+ cast(snmp_master_agent,{note_store_verbosity,Verbosity});
+verbosity(sub_agents,Verbosity) ->
+ cast(snmp_master_agent,{sub_agents_verbosity,Verbosity});
+verbosity(master_agent,Verbosity) ->
+ cast(snmp_master_agent,{verbosity,Verbosity});
+verbosity(Agent,{sub_agents,Verbosity}) ->
+ cast(Agent,{sub_agents_verbosity,Verbosity});
+verbosity(Agent,Verbosity) ->
+ cast(Agent,{verbosity,Verbosity}).
+
+
+%%%--------------------------------------------------
+
+get_agent_mib_storage() ->
+ ets:lookup_element(snmp_agent_table, agent_mib_storage, 2).
+
+db(Tab) ->
+ {Tab, get_agent_mib_storage()}.
+
+
+%%%--------------------------------------------------
+%%% 2. Main loop
+%%%--------------------------------------------------
+%% gen_server:reply(From, Reply)
+handle_info({discovery_response, Response}, S) ->
+ ?vdebug("handle_info(discovery_response) -> entry with"
+ "~n Response: ~p", [Response]),
+ NewS = handle_discovery_response(S, Response),
+ {noreply, NewS};
+
+handle_info({snmp_pdu, Vsn, Pdu, PduMS, ACMData, Address, Extra}, S) ->
+ ?vdebug("handle_info(snmp_pdu) -> entry with"
+ "~n Vsn: ~p"
+ "~n Pdu: ~p"
+ "~n Address: ~p", [Vsn, Pdu, Address]),
+
+ NewS = handle_snmp_pdu(is_valid_pdu_type(Pdu#pdu.type),
+ Vsn, Pdu, PduMS, ACMData, Address, Extra, S),
+
+ {noreply, NewS};
+
+handle_info(worker_available, S) ->
+ ?vdebug("worker available",[]),
+ {noreply, S#state{worker_state = ready}};
+
+handle_info({send_trap, Trap, NotifyName, ContextName, Recv, Varbinds}, S) ->
+ ?vlog("[handle_info] send trap request:"
+ "~n Trap: ~p"
+ "~n NotifyName: ~p"
+ "~n ContextName: ~p"
+ "~n Recv: ~p"
+ "~n Varbinds: ~p",
+ [Trap,NotifyName,ContextName,Recv,Varbinds]),
+ case catch handle_send_trap(S, Trap, NotifyName, ContextName,
+ Recv, Varbinds) of
+ {ok, NewS} ->
+ {noreply, NewS};
+ {'EXIT', R} ->
+ ?vinfo("Trap not sent:~n ~p", [R]),
+ {noreply, S};
+ _ ->
+ {noreply, S}
+ end;
+
+handle_info({forward_trap, TrapRecord, NotifyName, ContextName,
+ Recv, Varbinds},S) ->
+ ?vlog("[handle_info] forward trap request:"
+ "~n TrapRecord: ~p"
+ "~n NotifyName: ~p"
+ "~n ContextName: ~p"
+ "~n Recv: ~p"
+ "~n Varbinds: ~p",
+ [TrapRecord,NotifyName,ContextName,Recv,Varbinds]),
+ case (catch maybe_send_trap(S, TrapRecord, NotifyName, ContextName,
+ Recv, Varbinds)) of
+ {ok, NewS} ->
+ {noreply, NewS};
+ {'EXIT', R} ->
+ ?vinfo("Trap not sent:~n ~p", [R]),
+ {noreply, S};
+ _ ->
+ {noreply, S}
+ end;
+
+handle_info({backup_done, Reply}, #state{backup = {_, From}} = S) ->
+ ?vlog("[handle_info] backup done:"
+ "~n Reply: ~p", [Reply]),
+ gen_server:reply(From, Reply),
+ {noreply, S#state{backup = undefined}};
+
+
+handle_info(invalidate_ca_cache, S) ->
+ invalidate_ca_cache(),
+ {noreply, S};
+
+
+%%-----------------------------------------------------------------
+%% If a process crashes, we first check to see if it was the mib,
+%% net-if or note-store.
+%% Otherwise, we check to see if it was a subagent. In this case
+%% we unregister the sa, and unlink us from the sa.
+%%-----------------------------------------------------------------
+handle_info({'EXIT', Pid, Reason}, #state{note_store = Pid} = S) ->
+ ?vlog("note store (~p) exited for reason ~n~p", [Pid, Reason]),
+ error_msg("note-store exited: ~n~p", [Reason]),
+ {stop, {note_store_exit, Reason}, S#state{note_store = undefined}};
+handle_info({'EXIT', Pid, Reason}, #state{worker = Pid} = S) ->
+ ?vlog("worker (~p) exited -> create new ~n ~p", [Pid, Reason]),
+ NewWorker = worker_start(),
+ {noreply, S#state{worker = NewWorker}};
+handle_info({'EXIT', Pid, Reason}, #state{set_worker = Pid} = S) ->
+ ?vlog("set-worker (~p) exited -> create new ~n ~p", [Pid,Reason]),
+ NewWorker = set_worker_start(),
+ {noreply, S#state{set_worker = NewWorker}};
+handle_info({'EXIT', Pid, Reason}, #state{parent = Pid} = S) ->
+ ?vlog("parent (~p) exited for reason ~n~p", [Pid,Reason]),
+ {stop, {parent_died, Reason}, S};
+handle_info({'EXIT', Pid, Reason}, #state{backup = {Pid, From}} = S) ->
+ ?vlog("backup server (~p) exited for reason ~n~p", [Pid, Reason]),
+ case Reason of
+ normal ->
+ {noreply, S};
+ _ ->
+ gen_server:reply(From, {error, Reason}),
+ {noreply, S#state{backup = undefined}}
+ end;
+handle_info({'EXIT', Pid, Reason}, S) ->
+ ?vlog("~p exited for reason ~p", [Pid, Reason]),
+ Mib = get(mibserver),
+ NetIf = get(net_if),
+ case Pid of
+ Mib ->
+ error_msg("mib-server exited: ~n~p", [Reason]),
+ {stop, {mib_server_exit, Reason}, S};
+ NetIf ->
+ error_msg("net-if exited: ~n~p", [Reason]),
+ {stop, {net_if_exit, Reason}, S};
+ _ ->
+ %% Could be a sub-agent
+ SAs = snmpa_mib:info(Mib, subagents),
+ case lists:keysearch(Pid, 1, SAs) of
+ {value, _} ->
+ ?vlog("subagent exit", []),
+ snmpa_mib:unregister_subagent(Mib, Pid),
+ unlink(Pid);
+ _ ->
+ %% Otherwise it was probably a worker thread - ignore
+ ok
+ end,
+ {noreply, S}
+ end;
+handle_info({'DOWN', Ref, process, Pid, {mibs_cache_reply, Reply}},
+ #state{mibs_cache_request = {Pid, Ref, From}} = S) ->
+ ?vlog("reply from the mibs cache request handler (~p): ~n~p",
+ [Pid, Reply]),
+ gen_server:reply(From, Reply),
+ {noreply, S#state{mibs_cache_request = undefined}};
+
+handle_info(Info, S) ->
+ warning_msg("received unexpected info: ~n~p", [Info]),
+ {noreply, S}.
+
+handle_call(restart_worker, _From, #state{worker = Pid} = S) ->
+ if
+ is_pid(Pid) ->
+ ?vlog("[handle_call] restart worker ~p", [Pid]),
+ exit(Pid, kill);
+ true ->
+ ?vlog("[handle_call] not multi-threaded => "
+ "ignoring restart request", []),
+ ok
+ end,
+ {reply, ok, S};
+handle_call(restart_set_worker, _From, #state{set_worker = Pid} = S) ->
+ if
+ is_pid(Pid) ->
+ ?vlog("[handle_call] restart set worker: ~p", [Pid]),
+ exit(Pid, kill);
+ true ->
+ ?vlog("[handle_call] not multi-threaded => "
+ "ignoring restart request", []),
+ ok
+ end,
+ {reply, ok, S};
+handle_call({send_trap, Trap, NotifyName, ContextName, Recv, Varbinds},
+ _From, S) ->
+ ?vlog("[handle_call] send trap request:"
+ "~n Trap: ~p"
+ "~n NotifyName: ~p"
+ "~n ContextName: ~p"
+ "~n Recv: ~p"
+ "~n Varbinds: ~p",
+ [Trap,NotifyName,ContextName,Recv,Varbinds]),
+ case (catch handle_send_trap(S, Trap, NotifyName, ContextName,
+ Recv, Varbinds)) of
+ {ok, NewS} ->
+ {reply, ok, NewS};
+ {'EXIT', Reason} ->
+ ?vinfo("Trap not sent:~n ~p", [Reason]),
+ {reply, {error, {send_failed, Reason}}, S};
+ _ ->
+ ?vinfo("Trap not sent", []),
+ {reply, {error, send_failed}, S}
+ end;
+handle_call({discovery,
+ TargetName, Notification, ContextName, Vbs, DiscoHandler, ExtraInfo},
+ From,
+ #state{disco = undefined} = S) ->
+ ?vlog("[handle_call] initiate discovery process:"
+ "~n TargetName: ~p"
+ "~n Notification: ~p"
+ "~n ContextName: ~p"
+ "~n Vbs: ~p"
+ "~n DiscoHandler: ~p"
+ "~n ExtraInfo: ~p",
+ [TargetName, Notification, ContextName, Vbs,
+ DiscoHandler, ExtraInfo]),
+ case handle_discovery(S, From, TargetName,
+ Notification, ContextName, Vbs, DiscoHandler,
+ ExtraInfo) of
+ {ok, NewS} ->
+ ?vtrace("[handle_call] first stage of discovery process initiated",
+ []),
+ {noreply, NewS};
+ {error, _} = Error ->
+ {reply, Error, S}
+ end;
+handle_call({discovery, _TargetName, _Notification, _ContextName, _Vbs, _DiscoHandler, _ExtraInfo}, _From,
+ #state{disco = DiscoData} = S) ->
+ Reply = {error, {discovery_in_progress, DiscoData}},
+ {reply, Reply, S};
+handle_call({subagent_get, Varbinds, PduData, IsNotification}, _From, S) ->
+ ?vlog("[handle_call] subagent get:"
+ "~n Varbinds: ~p"
+ "~n PduData: ~p",
+ [Varbinds,PduData]),
+ put_pdu_data(PduData),
+ {reply, do_get(Varbinds, IsNotification), S};
+handle_call({subagent_get_next, MibView, Varbinds, PduData}, _From, S) ->
+ ?vlog("[handle_call] subagent get-next:"
+ "~n MibView: ~p"
+ "~n Varbinds: ~p"
+ "~n PduData: ~p",
+ [MibView,Varbinds,PduData]),
+ put_pdu_data(PduData),
+ {reply, do_get_next(MibView, Varbinds), S};
+handle_call({subagent_set, Arguments, PduData}, _From, S) ->
+ ?vlog("[handle_call] subagent set:"
+ "~n Arguments: ~p"
+ "~n PduData: ~p",
+ [Arguments,PduData]),
+ put_pdu_data(PduData),
+ {reply, do_subagent_set(Arguments), S};
+
+handle_call({get, Vars, Context}, _From, S) ->
+ ?vlog("[handle_call] get:"
+ "~n Vars: ~p"
+ "~n Context: ~p", [Vars, Context]),
+ put_pdu_data({undefined, undefined, undefined, undefined, Context}),
+ case catch mapfoldl({?MODULE, tr_var}, [], 1, Vars) of
+ {error, Reason} -> {reply, {error, Reason}, S};
+ {_, Varbinds} ->
+ ?vdebug("Varbinds: ~p",[Varbinds]),
+ Reply =
+ case do_get(Varbinds, false) of
+ {noError, 0, NewVarbinds} ->
+ Vbs = lists:keysort(#varbind.org_index, NewVarbinds),
+ [Value || #varbind{value = Value} <- Vbs];
+ {ErrorStatus, ErrIndex, _} ->
+ N = lists:nth(ErrIndex, Vars),
+ {error, {ErrorStatus, N}}
+ end,
+ {reply, Reply, S}
+ end;
+
+handle_call({get_next, Vars, Context}, _From, S) ->
+ ?vlog("[handle_call] get_next:"
+ "~n Vars: ~p"
+ "~n Context: ~p",[Vars, Context]),
+ put_pdu_data({undefined, undefined, undefined, undefined, Context}),
+ case catch mapfoldl({?MODULE, tr_var}, [], 1, Vars) of
+ {error, Reason} -> {reply, {error, Reason}, S};
+ {_, Varbinds} ->
+ ?vdebug("Varbinds: ~p",[Varbinds]),
+ MibView = snmpa_acm:get_root_mib_view(),
+ Reply =
+ case do_get_next(MibView, Varbinds) of
+ {noError, 0, NewVarbinds} ->
+ Vbs = lists:keysort(#varbind.org_index, NewVarbinds),
+ [{Oid,Val} || #varbind{oid = Oid, value = Val} <- Vbs];
+ {ErrorStatus, ErrIndex, _} ->
+ N = lists:nth(ErrIndex, Vars),
+ {error, {ErrorStatus, N}}
+ end,
+ {reply, Reply, S}
+ end;
+
+handle_call({do_get, MibView, UnsortedVarbinds, IsNotification, PduData},
+ _From, S) ->
+ ?vlog("[handle_call] do_get:"
+ "~n MibView: ~p"
+ "~n UnsortedVarbinds: ~p"
+ "~n IsNotification: ~p"
+ "~n PduData: ~p",
+ [MibView, UnsortedVarbinds, IsNotification, PduData]),
+ put_pdu_data(PduData),
+ Reply = do_get(MibView, UnsortedVarbinds, IsNotification),
+ {reply, Reply, S};
+
+handle_call({register_subagent, SubTreeOid, SubagentPid}, _From, S) ->
+ Reply =
+ case snmpa_mib:register_subagent(get(mibserver),
+ SubTreeOid, SubagentPid) of
+ ok -> link(SubagentPid), ok;
+ Error -> Error
+ end,
+ {reply, Reply, S};
+
+handle_call({unregister_subagent, SubagentPid}, _From, S)
+ when is_pid(SubagentPid) ->
+ ?vlog("[handle_call] unregister subagent ~p", [SubagentPid]),
+ Reply = snmpa_mib:unregister_subagent(get(mibserver), SubagentPid),
+ unlink(SubagentPid),
+ {reply, Reply, S};
+
+handle_call({unregister_subagent, SubTreeOid}, _From, S) ->
+ ?vlog("[handle_call] unregister subagent ~p", [SubTreeOid]),
+ Reply =
+ case snmpa_mib:unregister_subagent(get(mibserver), SubTreeOid) of
+ {ok, DeletedSubagentPid} ->
+ SAs = snmpa_mib:info(get(mibserver), subagents),
+ case lists:keysearch(DeletedSubagentPid, 1, SAs) of
+ {value, _} -> ok;
+ _ -> unlink(DeletedSubagentPid)
+ end,
+ ok;
+ Error ->
+ Error
+ end,
+ {reply, Reply, S};
+
+handle_call({load_mibs, Mibs}, _From, S) ->
+ ?vlog("load mibs ~p", [Mibs]),
+ {reply, snmpa_mib:load_mibs(get(mibserver), Mibs), S};
+
+handle_call({unload_mibs, Mibs}, _From, S) ->
+ ?vlog("unload mibs ~p", [Mibs]),
+ {reply, snmpa_mib:unload_mibs(get(mibserver), Mibs), S};
+
+handle_call(which_mibs, _From, S) ->
+ ?vlog("which mibs", []),
+ {reply, snmpa_mib:which_mibs(get(mibserver)), S};
+
+handle_call({whereis_mib, Mib}, _From, S) ->
+ ?vlog("whereis mib ~p", [Mib]),
+ {reply, snmpa_mib:whereis_mib(get(mibserver), Mib), S};
+
+handle_call({mibs_cache_request, MibsCacheReq}, From, S) ->
+ ?vlog("mibs_cache_request: ~p", [MibsCacheReq]),
+ {MibsCacheWorker, Ref} =
+ handle_mibs_cache_request(get(mibserver), MibsCacheReq),
+ NewS = S#state{mibs_cache_request = {MibsCacheWorker, Ref, From}},
+ {noreply, NewS};
+
+handle_call(info, _From, S) ->
+ ?vlog("info", []),
+ Vsns = S#state.vsns,
+ Stats = get_stats_counters(),
+ AI = agent_info(S),
+ NI = net_if_info(S),
+ NS = note_store_info(S),
+ SS = symbolic_store_info(),
+ LD = local_db_info(),
+ MS = mib_server_info(),
+ Info = [{vsns, Vsns},
+ {stats_counters, Stats},
+ {agent, AI},
+ {net_if, NI},
+ {note_store, NS},
+ {symbolic_store, SS},
+ {local_db, LD},
+ {mib_server, MS}],
+ {reply, Info, S};
+
+handle_call(get_net_if, _From, S) ->
+ {reply, get(net_if), S};
+
+handle_call({backup, BackupDir}, From, S) ->
+ ?vlog("backup: ~p", [BackupDir]),
+ Pid = self(),
+ V = get(verbosity),
+ MS = get(mibserver),
+ BackupServer =
+ erlang:spawn_link(
+ fun() ->
+ put(sname, abs),
+ put(verbosity, V),
+ Dir = filename:join([BackupDir]),
+ Reply = handle_backup(Dir, MS),
+ Pid ! {backup_done, Reply},
+ unlink(Pid)
+ end),
+ ?vtrace("backup server: ~p", [BackupServer]),
+ {noreply, S#state{backup = {BackupServer, From}}};
+
+handle_call(dump_mibs, _From, S) ->
+ Reply = snmpa_mib:dump(get(mibserver)),
+ {reply, Reply, S};
+
+handle_call({dump_mibs,File}, _From, S) ->
+ Reply = snmpa_mib:dump(get(mibserver),File),
+ {reply, Reply, S};
+
+handle_call({register_notification_filter, Id, Mod, Data, Where}, _From,
+ #state{nfilters = NFs} = S) ->
+ ?vlog("register_notification_filter -> "
+ "~n Id: ~p"
+ "~n Mod: ~p"
+ "~n Where: ~p", [Id, Mod, Where]),
+ case lists:keymember(Id, 2, NFs) of
+ true ->
+ {reply, {error, {already_registered, Id}}, S};
+ false ->
+ NF = #notification_filter{id = Id, mod = Mod, data = Data},
+ {Reply, NewNFs} = add_notification_filter(Where, NF, NFs),
+ {reply, Reply, S#state{nfilters = NewNFs}}
+ end;
+
+handle_call({unregister_notification_filter, Id}, _From,
+ #state{nfilters = NFs} = S) ->
+ ?vlog("unregister_notification_filter -> "
+ "~n Id: ~p", [Id]),
+ case lists:keydelete(Id, 2, NFs) of
+ NFs ->
+ {reply, {error, {not_found, Id}}, S};
+ NFs2 ->
+ {reply, ok, S#state{nfilters = NFs2}}
+ end;
+
+handle_call(which_notification_filter, _From,
+ #state{nfilters = NFs} = S) ->
+ ?vlog("which_notification_filter", []),
+ {reply, [Id || #notification_filter{id = Id} <- NFs], S};
+
+handle_call({mib_of, Oid}, _From, S) ->
+ Reply = handle_mib_of(get(mibserver), Oid),
+ {reply, Reply, S};
+
+handle_call({me_of, Oid}, _From, S) ->
+ Reply = handle_me_of(get(mibserver), Oid),
+ {reply, Reply, S};
+
+handle_call(get_log_type, _From, S) ->
+ ?vlog("get_log_type", []),
+ Reply = handle_get_log_type(S),
+ {reply, Reply, S};
+
+handle_call({set_log_type, NewType}, _From, S) ->
+ ?vlog("set_log_type -> "
+ "~n NewType: ~p", [NewType]),
+ Reply = handle_set_log_type(S, NewType),
+ {reply, Reply, S};
+
+handle_call(get_request_limit, _From, S) ->
+ ?vlog("get_request_limit", []),
+ Reply = handle_get_request_limit(S),
+ {reply, Reply, S};
+
+handle_call({set_request_limit, NewLimit}, _From, S) ->
+ ?vlog("set_request_limit -> "
+ "~n NewLimit: ~p", [NewLimit]),
+ Reply = handle_set_request_limit(S, NewLimit),
+ {reply, Reply, S};
+
+handle_call(stop, _From, S) ->
+ {stop, normal, ok, S};
+
+handle_call(Req, _From, S) ->
+ warning_msg("received unknown request: ~n~p", [Req]),
+ Reply = {error, {unknown, Req}},
+ {reply, Reply, S}.
+
+handle_cast({verbosity,Verbosity}, S) ->
+ ?vlog("verbosity: ~p -> ~p",[get(verbosity),Verbosity]),
+ put(verbosity,snmp_verbosity:validate(Verbosity)),
+ case S#state.worker of
+ Pid when is_pid(Pid) -> Pid ! {verbosity,Verbosity};
+ _ -> ok
+ end,
+ case S#state.set_worker of
+ Pid2 when is_pid(Pid2) -> Pid2 ! {verbosity,Verbosity};
+ _ -> ok
+ end,
+ {noreply, S};
+
+handle_cast({sub_agents_verbosity,Verbosity}, S) ->
+ ?vlog("sub_agents verbosity: ~p",[Verbosity]),
+ subagents_verbosity(Verbosity),
+ {noreply, S};
+
+%% This should only happen if we are a master_agent
+handle_cast({net_if_verbosity, Verbosity}, S) ->
+ net_if_verbosity(get(net_if), Verbosity),
+ {noreply, S};
+
+handle_cast({mib_server_verbosity, Verbosity}, S) ->
+ mib_server_verbosity(get(mibserver),Verbosity),
+ {noreply, S};
+
+handle_cast({note_store_verbosity, Verbosity}, #state{note_store = Pid} = S) ->
+ note_store_verbosity(Pid,Verbosity),
+ {noreply, S};
+
+handle_cast(Msg, S) ->
+ warning_msg("received unknown message: ~n~p", [Msg]),
+ {noreply, S}.
+
+
+terminate(shutdown, #state{worker = Worker,
+ set_worker = SetWorker,
+ backup = Backup,
+ ref = Ref}) ->
+ %% Ordered shutdown - stop misc-workers, net_if, mib-server and note-store.
+ backup_server_stop(Backup),
+ worker_stop(Worker, 100),
+ worker_stop(SetWorker, 100),
+ snmpa_misc_sup:stop_net_if(Ref),
+ snmpa_misc_sup:stop_mib_server(Ref);
+terminate(_Reason, _S) ->
+ %% We crashed! We will reuse net_if and mib if we get restarted.
+ ok.
+
+
+handle_mibs_cache_request(MibServer, Req) ->
+ {MibsCacheWorker, MibsCacheRef} =
+ spawn_monitor(
+ fun() ->
+ Reply =
+ case Req of
+ invalidate_cache ->
+ snmpa_mib:invalidate_cache(MibServer);
+ gc_cache ->
+ snmpa_mib:gc_cache(MibServer);
+ {gc_cache, Age} ->
+ snmpa_mib:gc_cache(MibServer, Age);
+ {gc_cache, Age, GcLimit} ->
+ snmpa_mib:gc_cache(MibServer, Age, GcLimit);
+ enable_cache ->
+ snmpa_mib:enable_cache(MibServer);
+ disable_cache ->
+ snmpa_mib:disable_cache(MibServer);
+ enable_autogc ->
+ snmpa_mib:enable_cache_autogc(MibServer);
+ disable_autogc ->
+ snmpa_mib:disable_cache_autogc(MibServer);
+ {update_gclimit, GcLimit} ->
+ snmpa_mib:update_cache_gclimit(MibServer,
+ GcLimit);
+ {update_age, Age} ->
+ snmpa_mib:update_cache_age(MibServer, Age);
+ _ ->
+ {error, {unknown_mibs_cache_request, Req}}
+ end,
+ exit({mibs_cache_reply, Reply})
+ end),
+ {MibsCacheWorker, MibsCacheRef}.
+
+
+%%-----------------------------------------------------------------
+%% Code replacement
+%%
+%%-----------------------------------------------------------------
+
+%% Downgrade
+%%
+code_change({down, _Vsn}, S, downgrade_to_pre_4_13) ->
+ S1 = workers_restart(S),
+ case S1#state.disco of
+ undefined ->
+ ok;
+ #disco{from = From,
+ sender = Sender,
+ stage = Stage} ->
+ gen_server:reply(From, {error, {upgrade, Stage, Sender}}),
+ exit(Sender, kill)
+ end,
+ S2 = {state,
+ S1#state.type,
+ S1#state.parent,
+ S1#state.worker,
+ S1#state.worker_state,
+ S1#state.set_worker,
+ S1#state.multi_threaded,
+ S1#state.ref,
+ S1#state.vsns,
+ S1#state.nfilters,
+ S1#state.note_store,
+ S1#state.mib_server,
+ S1#state.net_if,
+ S1#state.net_if_mod,
+ S1#state.backup,
+ S1#state.disco},
+ {ok, S2};
+
+%% Upgrade
+%%
+code_change(_Vsn, S, upgrade_from_pre_4_13) ->
+ {state,
+ Type,
+ Parent,
+ Worker,
+ WorkerState,
+ SetWorker,
+ MultiThreaded,
+ Ref,
+ Vsns,
+ NFilters = [],
+ NoteStore,
+ MibServer, %% Currently unused
+ NetIf, %% Currently unused
+ NetIfMod,
+ Backup} = S,
+ S1 = #state{type = Type,
+ parent = Parent,
+ worker = Worker,
+ worker_state = WorkerState,
+ set_worker = SetWorker,
+ multi_threaded = MultiThreaded,
+ ref = Ref,
+ vsns = Vsns,
+ nfilters = NFilters,
+ note_store = NoteStore,
+ mib_server = MibServer,
+ net_if = NetIf,
+ net_if_mod = NetIfMod,
+ backup = Backup},
+ S2 = workers_restart(S1),
+ {ok, S2};
+
+code_change(_Vsn, S, _Extra) ->
+ {ok, S}.
+
+
+workers_restart(#state{worker = W, set_worker = SW} = S) ->
+ Worker = worker_restart(W),
+ SetWorker = set_worker_restart(SW),
+ S#state{worker = Worker,
+ set_worker = SetWorker}.
+
+
+%%-----------------------------------------------------------------
+
+backup_server_stop({Pid, _}) when is_pid(Pid) ->
+ exit(Pid, kill);
+backup_server_stop(_) ->
+ ok.
+
+
+workers_start(true) ->
+ ?vdebug("start worker and set-worker",[]),
+ {worker_start(), set_worker_start()};
+workers_start(_) ->
+ {undefined, undefined}.
+
+worker_start() ->
+ worker_start(get()).
+
+set_worker_start() ->
+ worker_start([{master, self()} | get()]).
+
+worker_start(Dict) ->
+ proc_lib:spawn_link(?MODULE, worker, [self(), Dict]).
+
+worker_stop(Pid) ->
+ worker_stop(Pid, infinity).
+
+worker_stop(Pid, Timeout) when is_pid(Pid) ->
+ Pid ! terminate,
+ receive
+ {'EXIT', Pid, normal} ->
+ ok
+ after Timeout ->
+ (catch exit(Pid, kill)),
+ ok
+ end;
+worker_stop(_, _) ->
+ ok.
+
+set_worker_restart(Pid) ->
+ worker_restart(Pid, [{master, self()} | get()]).
+
+worker_restart(Pid) ->
+ worker_restart(Pid, get()).
+
+worker_restart(Pid, Dict) when is_pid(Pid) ->
+ worker_stop(Pid),
+ worker_start(Dict);
+worker_restart(Any, _Dict) ->
+ Any.
+
+
+%%-----------------------------------------------------------------
+
+handle_backup(BackupDir, MibServer) ->
+ ?vlog("handle_backup -> entry with"
+ "~n BackupDir: ~p", [BackupDir]),
+ case ets:lookup(snmp_agent_table, db_dir) of
+ [{db_dir, BackupDir}] ->
+ ?vinfo("handle_backup -> backup dir and db dir the same", []),
+ {error, db_dir};
+ _ ->
+ case file:read_file_info(BackupDir) of
+ {ok, #file_info{type = directory}} ->
+ ?vdebug("handle_backup -> backup dir ok", []),
+
+ VacmRes = (catch snmpa_vacm:backup(BackupDir)),
+ ?vtrace("handle_backup -> "
+ "~n VacmRes: ~p", [VacmRes]),
+
+ LdbRes = (catch snmpa_local_db:backup(BackupDir)),
+ ?vtrace("handle_backup -> "
+ "~n LdbRes: ~p", [LdbRes]),
+
+ MsRes = (catch snmpa_mib:backup(MibServer, BackupDir)),
+ ?vtrace("handle_backup -> "
+ "~n MsRes: ~p", [MsRes]),
+
+ SsRes = (catch snmpa_symbolic_store:backup(BackupDir)),
+ ?vtrace("handle_backup -> "
+ "~n SsRes: ~p", [SsRes]),
+ handle_backup_res([{vacm, VacmRes},
+ {local_db, LdbRes},
+ {mib_server, MsRes},
+ {symbolic_store, SsRes}]);
+ {ok, _} ->
+ ?vinfo("handle_backup -> backup dir not a dir", []),
+ {error, not_a_directory};
+ Error ->
+ ?vinfo("handle_backup -> Error: ~p", [Error]),
+ Error
+ end
+ end.
+
+
+handle_backup_res(Results) ->
+ handle_backup_res(Results, []).
+
+handle_backup_res([], []) ->
+ ok;
+handle_backup_res([], Acc) ->
+ {error, lists:reverse(Acc)};
+handle_backup_res([{_, ok}|Results], Acc) ->
+ handle_backup_res(Results, Acc);
+handle_backup_res([{Who, {error, Reason}}|Results], Acc) ->
+ handle_backup_res(Results, [{Who, Reason}|Acc]);
+handle_backup_res([{Who, Crap}|Results], Acc) ->
+ handle_backup_res(Results, [{Who, Crap}|Acc]).
+
+
+%%-----------------------------------------------------------------
+%% We must cheat to get the community string out of the ACM data,
+%% because we (for some reason) support the function
+%% snmpa:current_community().
+%%-----------------------------------------------------------------
+cheat({community, _SecModel, Community, _IpUdp}, Address, ContextName) ->
+ {Community, Address, ContextName};
+cheat(_, Address, ContextName) ->
+ {"", Address, ContextName}.
+
+
+%% This function will either be in the context of the:
+%% 1) master-agent
+%% 2) set-worker
+%% 3) user code
+%% ( calling e.g. snmp_community_mib:snmpCommunityTable(set, ...) )
+invalidate_ca_cache() ->
+ case get(master) of
+ undefined -> % 1 or 3
+ case get(auth_module) of
+ undefined -> % 3
+ %% Ouch, we are not running in the context of the
+ %% master agent either. Check if we are on the
+ %% master-agent node. If so, sent it there,
+ case whereis(snmp_master_agent) of
+ MasterAgent when is_pid(MasterAgent) ->
+ case node(MasterAgent) =:= node() of
+ true ->
+ %% Ok, we are on the node running the
+ %% master_agent process, so sent it there
+ MasterAgent ! invalidate_ca_cache;
+ false ->
+ %% This is running on a sub-agent node,
+ %% so sent skip it
+ ok
+ end;
+ _ -> % Not on this node
+ ok
+ end;
+ AuthMod -> % 1
+ AuthMod:invalidate_ca_cache()
+ end;
+ Pid -> % 2
+ Pid ! invalidate_ca_cache
+ end.
+
+
+%%-----------------------------------------------------------------
+%% Threads and workers
+%%
+%%-----------------------------------------------------------------
+
+spawn_thread(Vsn, Pdu, PduMS, ACMData, Address, Extra) ->
+ Dict = get(),
+ Args = [Vsn, Pdu, PduMS, ACMData, Address, Extra, Dict],
+ proc_lib:spawn_link(?MODULE, handle_pdu, Args).
+
+spawn_trap_thread(TrapRec, NotifyName, ContextName, Recv, V) ->
+ Dict = get(),
+ proc_lib:spawn_link(?MODULE, do_send_trap,
+ [TrapRec, NotifyName, ContextName, Recv, V, Dict]).
+
+do_send_trap(TrapRec, NotifyName, ContextName, Recv, V, Dict) ->
+ lists:foreach(fun({Key, Val}) -> put(Key, Val) end, Dict),
+ put(sname,trap_sender_short_name(get(sname))),
+ ?vlog("starting",[]),
+ snmpa_trap:send_trap(TrapRec, NotifyName, ContextName, Recv, V,
+ get(net_if)).
+
+worker(Master, Dict) ->
+ lists:foreach(fun({Key, Val}) -> put(Key, Val) end, Dict),
+ put(sname, worker_short_name(get(sname))),
+ ?vlog("starting",[]),
+ worker_loop(Master).
+
+worker_loop(Master) ->
+ receive
+ {Vsn, Pdu, PduMS, ACMData, Address, Extra} ->
+ ?vtrace("worker_loop -> received request", []),
+ handle_pdu(Vsn, Pdu, PduMS, ACMData, Address, Extra),
+ Master ! worker_available;
+
+ %% Old style message
+ {MibView, Vsn, Pdu, PduMS, ACMData, AgentData, Extra} ->
+ ?vtrace("worker_loop -> received (old) request", []),
+ do_handle_pdu(MibView, Vsn, Pdu, PduMS, ACMData, AgentData, Extra),
+ Master ! worker_available;
+
+ {TrapRec, NotifyName, ContextName, Recv, V} -> % We don't trap exits!
+ ?vtrace("worker_loop -> send trap:"
+ "~n ~p", [TrapRec]),
+ snmpa_trap:send_trap(TrapRec, NotifyName,
+ ContextName, Recv, V, get(net_if)),
+ Master ! worker_available;
+
+ {verbosity, Verbosity} ->
+ put(verbosity,snmp_verbosity:validate(Verbosity));
+
+ terminate ->
+ exit(normal);
+
+ _X ->
+ %% ignore
+ ok
+
+ after 30000 ->
+ %% This is to assure that the worker process leaves a
+ %% possibly old version of this module.
+ ok
+ end,
+ ?MODULE:worker_loop(Master).
+
+
+%%-----------------------------------------------------------------
+%%-----------------------------------------------------------------
+
+handle_snmp_pdu(true, Vsn, Pdu, PduMS, ACMData, Address, Extra,
+ #state{multi_threaded = false} = S) ->
+ ?vtrace("handle_snmp_pdu -> single-thread agent",[]),
+ handle_pdu(Vsn, Pdu, PduMS, ACMData, Address, Extra),
+ S;
+handle_snmp_pdu(true, Vsn, #pdu{type = 'set-request'} = Pdu, PduMS,
+ ACMData, Address, Extra,
+ #state{set_worker = Worker} = S) ->
+ ?vtrace("handle_snmp_pdu -> multi-thread agent: "
+ "send set-request to main worker",[]),
+ Worker ! {Vsn, Pdu, PduMS, ACMData, Address, Extra},
+ S#state{worker_state = busy};
+handle_snmp_pdu(true, Vsn, Pdu, PduMS,
+ ACMData, Address, Extra,
+ #state{worker_state = busy} = S) ->
+ ?vtrace("handle_snmp_pdu -> multi-thread agent: "
+ "main worker busy - create new worker",[]),
+ spawn_thread(Vsn, Pdu, PduMS, ACMData, Address, Extra),
+ S;
+handle_snmp_pdu(true, Vsn, Pdu, PduMS, ACMData, Address, Extra,
+ #state{worker = Worker} = S) ->
+ ?vtrace("handle_snmp_pdu -> multi-thread agent: "
+ "send to main worker",[]),
+ Worker ! {Vsn, Pdu, PduMS, ACMData, Address, Extra},
+ S#state{worker_state = busy};
+handle_snmp_pdu(_, _Vsn, _Pdu, _PduMS, _ACMData, _Address, _Extra, S) ->
+ S.
+
+
+%% Called via the spawn_thread function
+handle_pdu(Vsn, Pdu, PduMS, ACMData, Address, Extra, Dict) ->
+ lists:foreach(fun({Key, Val}) -> put(Key, Val) end, Dict),
+ put(sname, pdu_handler_short_name(get(sname))),
+ ?vlog("new worker starting",[]),
+ handle_pdu(Vsn, Pdu, PduMS, ACMData, Address, Extra).
+
+handle_pdu(Vsn, Pdu, PduMS, ACMData, Address, Extra) ->
+ %% OTP-3324
+ AuthMod = get(auth_module),
+ case AuthMod:init_check_access(Pdu, ACMData) of
+ {ok, MibView, ContextName} ->
+ ?vlog("handle_pdu -> ok:"
+ "~n MibView: ~p"
+ "~n ContextName: ~p", [MibView, ContextName]),
+ AgentData = cheat(ACMData, Address, ContextName),
+ do_handle_pdu(MibView, Vsn, Pdu, PduMS, ACMData, AgentData, Extra);
+ {error, Reason} ->
+ ?vlog("handle_pdu -> error:"
+ "~n Reason: ~p", [Reason]),
+ handle_acm_error(Vsn, Reason, Pdu, ACMData, Address, Extra);
+ {discarded, Variable, Reason} ->
+ ?vlog("handle_pdu -> discarded:"
+ "~n Variable: ~p"
+ "~n Reason: ~p", [Variable, Reason]),
+ get(net_if) ! {discarded_pdu, Vsn, Pdu#pdu.request_id,
+ ACMData, Variable, Extra}
+ end.
+
+do_handle_pdu(MibView, Vsn, Pdu, PduMS,
+ ACMData, {Community, Address, ContextName}, Extra) ->
+
+ put(net_if_data, Extra),
+ RePdu = process_msg(MibView, Vsn, Pdu, PduMS, Community,
+ Address, ContextName),
+
+ ?vtrace("do_handle_pdu -> processed:"
+ "~n RePdu: ~p", [RePdu]),
+ get(net_if) ! {snmp_response, Vsn, RePdu,
+ RePdu#pdu.type, ACMData, Address, Extra}.
+
+
+handle_acm_error(Vsn, Reason, Pdu, ACMData, Address, Extra) ->
+ #pdu{type = Type, request_id = ReqId, varbinds = Vbs} = Pdu,
+ RawErrStatus = snmpa_acm:error2status(Reason),
+ case is_valid_pdu_type(Type) of
+ true ->
+ %% RawErrStatus can be authorizationError or genErr. If it is
+ %% authorizationError, we'll have to do different things,
+ %% depending on which SNMP version is used.
+ %% v1 - noSuchName error
+ %% v2 - GET: all variables 'noSuchObject'
+ %% NEXT/BULK: all variables 'endOfMibView'
+ %% SET: noAccess error
+ %% v3 - authorizationError error
+ %%
+ %% NOTE: this procedure is not yet defined in the coex document!
+ ?vdebug("~n Raw error status: ~w",[RawErrStatus]),
+ Idx = case Vbs of
+ [] -> 0;
+ _ -> 1
+ end,
+ RePdu =
+ if
+ Vsn =:= 'version-1' ->
+ ErrStatus = v2err_to_v1err(RawErrStatus),
+ make_response_pdu(ReqId, ErrStatus, Idx, Vbs, Vbs);
+ Vsn =:= 'version-3' ->
+ make_response_pdu(ReqId, RawErrStatus, Idx, Vbs, Vbs);
+ Type =:= 'get-request' -> % this is v2
+ ReVbs = lists:map(
+ fun(Vb) ->
+ Vb#varbind{value=noSuchObject}
+ end,
+ Vbs),
+ make_response_pdu(ReqId, noError, 0, Vbs, ReVbs);
+ Type =:= 'set-request' ->
+ make_response_pdu(ReqId, noAccess, Idx, Vbs, Vbs);
+ true -> % next or bulk
+ ReVbs = lists:map(
+ fun(Vb) ->
+ Vb#varbind{value=endOfMibView}
+ end,
+ Vbs),
+ make_response_pdu(ReqId, noError, 0, Vbs, ReVbs)
+ end,
+ get(net_if) ! {snmp_response, Vsn, RePdu,
+ 'get-response', ACMData, Address, Extra};
+ false ->
+ ?vdebug("~n Raw error status: ~w"
+ "~n invalid pdu type: ~w",
+ [RawErrStatus,Type]),
+ ok
+ end.
+
+
+handle_send_trap(S, TrapName, NotifyName, ContextName, Recv, Varbinds) ->
+ ?vtrace("handle_send_trap -> entry with"
+ "~n S#state.type: ~p"
+ "~n TrapName: ~p"
+ "~n NotifyName: ~p"
+ "~n ContextName: ~p",
+ [S#state.type, TrapName, NotifyName, ContextName]),
+ case snmpa_trap:construct_trap(TrapName, Varbinds) of
+ {ok, TrapRecord, VarList} ->
+ ?vtrace("handle_send_trap -> construction complete: "
+ "~n TrapRecord: ~p"
+ "~n VarList: ~p",
+ [TrapRecord, VarList]),
+ case S#state.type of
+ subagent ->
+ ?vtrace("handle_send_trap -> [sub] forward trap",[]),
+ maybe_forward_trap(S, TrapRecord, NotifyName,
+ ContextName, Recv, VarList),
+ {ok, S};
+ master_agent ->
+ ?vtrace("handle_send_trap -> "
+ "[master] handle send trap",[]),
+ maybe_send_trap(S, TrapRecord, NotifyName,
+ ContextName, Recv, VarList)
+ end;
+ error ->
+ error
+ end.
+
+
+maybe_forward_trap(#state{parent = Parent, nfilters = NFs} = S,
+ TrapRec, NotifyName, ContextName, Recv, V) ->
+ ?vtrace("maybe_forward_trap -> entry with"
+ "~n NFs: ~p", [NFs]),
+ case filter_notification(NFs, [], TrapRec) of
+ {dont_send, [], Id} ->
+ ?vdebug("trap not forwarded [filter ~p]", [Id]),
+ {ok, S};
+
+ {dont_send, Removed, Id} ->
+ ?vdebug("trap not forwarded [filter ~p]", [Id]),
+ NFs2 = del_notification_filter(Removed, NFs),
+ {ok, S#state{nfilters = NFs2}};
+
+ {send, [], TrapRec2} ->
+ ?vtrace("maybe_forward_trap -> forward trap:"
+ "~n ~p", [TrapRec2]),
+ forward_trap(Parent, TrapRec2, NotifyName, ContextName, Recv, V),
+ {ok, S};
+
+ {send, Removed, TrapRec2} ->
+ ?vtrace("maybe_forward_trap -> forward trap:"
+ "~n ~p", [TrapRec2]),
+ forward_trap(Parent, TrapRec2, NotifyName, ContextName, Recv, V),
+ NFs2 = del_notification_filter(Removed, NFs),
+ {ok, S#state{nfilters = NFs2}}
+ end.
+
+
+maybe_send_trap(#state{nfilters = NFs} = S,
+ TrapRec, NotifyName, ContextName, Recv, Varbinds) ->
+ ?vtrace("maybe_send_trap -> entry with"
+ "~n NFs: ~p", [NFs]),
+ case filter_notification(NFs, [], TrapRec) of
+ {dont_send, [], Id} ->
+ ?vdebug("trap not sent [filter ~p]",[Id]),
+ {ok, S};
+
+ {dont_send, Removed, Id} ->
+ ?vdebug("trap not sent [filter ~p]",[Id]),
+ NFs2 = del_notification_filter(Removed, NFs),
+ {ok, S#state{nfilters = NFs2}};
+
+ {send, [], TrapRec2} ->
+ ?vtrace("maybe_send_trap -> send trap:"
+ "~n ~p", [TrapRec2]),
+ do_handle_send_trap(S, TrapRec2,
+ NotifyName, ContextName, Recv, Varbinds);
+
+ {send, Removed, TrapRec2} ->
+ ?vtrace("maybe_send_trap -> send trap:"
+ "~n ~p", [TrapRec2]),
+ NFs2 = del_notification_filter(Removed, NFs),
+ do_handle_send_trap(S#state{nfilters = NFs2}, TrapRec2,
+ NotifyName, ContextName, Recv, Varbinds)
+ end.
+
+do_handle_send_trap(S, TrapRec, NotifyName, ContextName, Recv, Varbinds) ->
+ V = snmpa_trap:try_initialise_vars(get(mibserver), Varbinds),
+ case S#state.type of
+ subagent ->
+ forward_trap(S#state.parent, TrapRec, NotifyName, ContextName,
+ Recv, V),
+ {ok, S};
+ master_agent when S#state.multi_threaded =:= false ->
+ ?vtrace("do_handle_send_trap -> send trap:"
+ "~n ~p", [TrapRec]),
+ snmpa_trap:send_trap(TrapRec, NotifyName, ContextName,
+ Recv, V, get(net_if)),
+ {ok, S};
+ master_agent when S#state.worker_state =:= busy ->
+ %% Main worker busy => create new worker
+ ?vtrace("do_handle_send_trap -> main worker busy: "
+ "spawn a trap sender", []),
+ spawn_trap_thread(TrapRec, NotifyName, ContextName, Recv, V),
+ {ok, S};
+ master_agent ->
+ %% Send to main worker
+ ?vtrace("do_handle_send_trap -> send to main worker",[]),
+ S#state.worker ! {TrapRec, NotifyName, ContextName, Recv, V},
+ {ok, S#state{worker_state = busy}}
+ end.
+
+
+filter_notification([], RemoveNFs, Notif) ->
+ ?vtrace("filter_notification -> done when"
+ "~n RemoveNFs: ~p"
+ "~n Notif: ~p", [RemoveNFs, Notif]),
+ {send, RemoveNFs, Notif};
+filter_notification([NF|NFs], RemoveNFs, Notif0) ->
+ ?vtrace("filter_notification -> entry with"
+ "~n NF: ~p"
+ "~n RemoveNFs: ~p"
+ "~n Notif0: ~p", [NF, RemoveNFs, Notif0]),
+ case do_filter_notification(NF, Notif0) of
+ {dont_send, Id} ->
+ {dont_send, RemoveNFs, Id};
+ {send, Notif} ->
+ filter_notification(NFs, RemoveNFs, Notif);
+ {error, Id} ->
+ filter_notification(NFs, [Id|RemoveNFs], Notif0)
+ end.
+
+do_filter_notification(#notification_filter{id = Id, mod = Mod, data = Data},
+ Notif) ->
+ case (catch Mod:handle_notification(Notif, Data)) of
+ dont_send ->
+ {dont_send, Id};
+ send ->
+ {send, Notif};
+ {send, NewNotif} ->
+ {send, NewNotif};
+ Else ->
+ user_err("notification filter ~p removed: ~n~p", [Id, Else]),
+ {error, Id}
+ end.
+
+
+add_notification_filter(first, NewNF, NFs) ->
+ {ok, [NewNF | NFs]};
+add_notification_filter(last, NewNF, NFs) ->
+ {ok, lists:append(NFs, [NewNF])};
+add_notification_filter(Where, NewNF, NFs) ->
+ case add_nf(Where, NewNF, NFs, []) of
+ {ok, NFs2} ->
+ {ok, NFs2};
+ Error ->
+ {Error, NFs}
+ end.
+
+add_nf({_Loc, Id}, _NewNF, [], _Acc) ->
+ {error, {not_found, Id}};
+add_nf({insert_before, Id}, NewNF, [NF|NFs], Acc)
+ when Id =:= NF#notification_filter.id ->
+ {ok, lists:reverse(Acc) ++ [NewNF,NF|NFs]};
+add_nf({insert_after, Id}, NewNF, [NF|NFs], Acc)
+ when Id =:= NF#notification_filter.id ->
+ {ok, lists:reverse(Acc) ++ [NF,NewNF|NFs]};
+add_nf(Where, NewNF, [NF|NFs], Acc) ->
+ add_nf(Where, NewNF, NFs, [NF|Acc]).
+
+
+del_notification_filter(IDs, NFs) ->
+ Fun = fun(Id, NFilters) -> lists:keydelete(Id, 2, NFilters) end,
+ lists:foldl(Fun, NFs, IDs).
+
+
+handle_discovery(#state{type = master_agent} = S, From,
+ TargetName, Notification, ContextName, Varbinds,
+ DiscoHandler, ExtraInfo) ->
+ ?vtrace("handle_discovery -> entry with"
+ "~n TargetName: ~p"
+ "~n Notification: ~p"
+ "~n ContextName: ~p"
+ "~n Varbinds: ~p",
+ [TargetName, Notification, ContextName, Varbinds]),
+ case snmpa_trap:construct_trap(Notification, Varbinds) of
+ {ok, Record, InitVars} ->
+ ?vtrace("handle_discovery -> trap construction complete: "
+ "~n Record: ~p"
+ "~n InitVars: ~p", [Record, InitVars]),
+ send_discovery(S, From, TargetName,
+ Record, ContextName, InitVars,
+ DiscoHandler, ExtraInfo);
+ error ->
+ {error, failed_constructing_notification}
+ end;
+handle_discovery(_S, _From,
+ _TargetName, _Notification, _ContextName, _Varbinds,
+ _DiscoHandler, _ExtraInfo) ->
+ {error, only_master_discovery}.
+
+%% We ignore if the master agent is multi-threaded or not.
+%%
+send_discovery(S, From,
+ TargetName, Record, ContextName, InitVars,
+ DiscoHandler, ExtraInfo) ->
+ case snmpa_trap:send_discovery(TargetName, Record, ContextName,
+ InitVars, get(net_if)) of
+ {ok, Sender, SecLevel} ->
+ Disco = #disco{from = From,
+ rec = Record,
+ sender = Sender,
+ target = TargetName,
+ sec_level = SecLevel,
+ ctx = ContextName,
+ ivbs = InitVars,
+ stage = 1,
+ handler = DiscoHandler,
+ extra = ExtraInfo},
+ {ok, S#state{disco = Disco}};
+ Error ->
+ ?vlog("send_discovery -> failed sending discovery: "
+ "~n Error: ~p", [Error]),
+ Error
+ end.
+
+
+handle_discovery_response(#state{disco = #disco{from = From}} = S,
+ {error, _} = Error) ->
+ ?vlog("handle_discovery_response -> entry with"
+ "~n From: ~p"
+ "~n Error: ~p", [From, Error]),
+ gen_server:reply(From, Error),
+ S#state{disco = undefined};
+
+handle_discovery_response(#state{disco = #disco{target = TargetName,
+ stage = 1,
+ extra = ExtraInfo} = Disco} = S,
+ {ok, _Pdu, ManagerEngineId})
+ when is_record(Disco, disco) ->
+ ?vlog("handle_discovery_response(1) -> entry with"
+ "~n TargetName: ~p"
+ "~n ManagerEngineId: ~p", [TargetName, ManagerEngineId]),
+ %% This is end of stage 1.
+ %% So, first we need to update the database with the EngineId of the
+ %% manager and then deside if we should continue with stage 2. E.g.
+ %% establish authenticated communication.
+ case snmp_target_mib:set_target_engine_id(TargetName, ManagerEngineId) of
+ true when Disco#disco.sec_level =:= ?'SnmpSecurityLevel_noAuthNoPriv' ->
+ %% Ok, we are done
+ From = Disco#disco.from,
+ Handler = Disco#disco.handler,
+ Reply =
+ case handle_discovery_stage1_finish(Handler,
+ TargetName,
+ ManagerEngineId,
+ ExtraInfo) of
+ {ok, _} ->
+ {ok, ManagerEngineId};
+ Error ->
+ Error
+ end,
+ gen_server:reply(From, Reply),
+ S#state{disco = undefined};
+
+ true when Disco#disco.sec_level =/= ?'SnmpSecurityLevel_noAuthNoPriv' ->
+ %% Ok, time for stage 2
+ %% Send the same inform again,
+ %% this time we have the proper EngineId
+
+ From = Disco#disco.from,
+ Handler = Disco#disco.handler,
+
+ case handle_discovery_stage1_finish(Handler,
+ TargetName,
+ ManagerEngineId,
+ ExtraInfo) of
+ {ok, NewExtraInfo} ->
+ ?vdebug("handle_discovery_response(1) -> "
+ "we are done with stage 1 - "
+ "continue with stage 2", []),
+ #disco{rec = Record,
+ ctx = ContextName,
+ ivbs = InitVars} = Disco,
+ case snmpa_trap:send_discovery(TargetName, Record,
+ ContextName,
+ InitVars, get(net_if)) of
+ {ok, Sender, _SecLevel} ->
+ ?vdebug("handle_discovery_response(1) -> "
+ "stage 2 trap sent", []),
+ Disco2 = Disco#disco{sender = Sender,
+ engine_id = ManagerEngineId,
+ stage = 2,
+ extra = NewExtraInfo},
+ S#state{disco = Disco2};
+ Error ->
+ ?vlog("handle_discovery_response(1) -> "
+ "failed sending stage 2 trap: "
+ "~n ~p", [Error]),
+ error_msg("failed sending second "
+ "discovery message: "
+ "~n ~p", [Error]),
+ Reply = {error, {second_send_failed, Error}},
+ gen_server:reply(From, Reply),
+ S#state{disco = undefined}
+ end;
+ {error, Reason} = Error ->
+ ?vlog("handle_discovery_response(1) -> "
+ "stage 1 finish failed: "
+ "~n ~p", [Reason]),
+ gen_server:reply(From, Error),
+ S#state{disco = undefined}
+ end;
+ false ->
+ ?vinfo("handle_discovery_response(1) -> "
+ "failed setting doscovered engine-id - "
+ "inform the user", []),
+ From = Disco#disco.from,
+ Reason = {failed_setting_engine_id, TargetName, ManagerEngineId},
+ gen_server:reply(From, {error, Reason}),
+ S#state{disco = undefined}
+
+ end;
+
+handle_discovery_response(#state{disco = #disco{from = From,
+ engine_id = EngineID,
+ stage = 2}} = S,
+ {ok, _Pdu}) ->
+ ?vlog("handle_discovery_response(2) -> entry with"
+ "~n From: ~p", [From]),
+ gen_server:reply(From, {ok, EngineID}),
+ S#state{disco = undefined};
+
+handle_discovery_response(#state{disco = #disco{from = From}} = S, Crap) ->
+ Reason = {invalid_response, Crap},
+ gen_server:reply(From, {error, Reason}),
+ S#state{disco = undefined};
+
+handle_discovery_response(S, Crap) ->
+ warning_msg("Received unexpected discovery response: ~p", [Crap]),
+ S.
+
+handle_discovery_stage1_finish(Handler, TargetName, ManagerEngineID,
+ ExtraInfo) ->
+ case (catch Handler:stage1_finish(TargetName, ManagerEngineID,
+ ExtraInfo)) of
+ ignore ->
+ ?vtrace("handle_discovery_stage1_finish -> "
+ "we are done - [ignore] inform the user", []),
+ {ok, ExtraInfo};
+
+ {ok, UsmEntry} when is_tuple(UsmEntry) ->
+ ?vtrace("handle_discovery_stage1_finish -> "
+ "received usm entry - attempt to add it", []),
+ case add_usm_users([UsmEntry]) of
+ ok ->
+ {ok, ExtraInfo};
+ Error ->
+ Error
+ end;
+
+ {ok, UsmEntry, NewExtraInfo} when is_tuple(UsmEntry) ->
+ ?vtrace("handle_discovery_stage1_finish -> "
+ "received usm entry - attempt to add it", []),
+ case add_usm_users([UsmEntry]) of
+ ok ->
+ {ok, NewExtraInfo};
+ Error ->
+ Error
+ end;
+
+ {ok, UsmEntries} when is_list(UsmEntries) ->
+ ?vtrace("handle_discovery_stage1_finish -> "
+ "received usm entries - attempt to add them", []),
+ case add_usm_users(UsmEntries) of
+ ok ->
+ {ok, ExtraInfo};
+ Error ->
+ Error
+ end;
+
+ {ok, UsmEntries, NewExtraInfo} when is_list(UsmEntries) ->
+ ?vtrace("handle_discovery_stage1_finish -> "
+ "received usm entries - attempt to add them", []),
+ case add_usm_users(UsmEntries) of
+ ok ->
+ {ok, NewExtraInfo};
+ Error ->
+ Error
+ end;
+
+ {'EXIT', Reason} ->
+ ?vlog("handle_discovery_stage1_finish -> stage 1 function exited: "
+ "~n ~p", [Reason]),
+ {error, {finish_exit, Reason, ManagerEngineID}};
+
+ {error, Reason} ->
+ ?vlog("handle_discovery_stage1_finish -> stage 1 function error: "
+ "~n ~p", [Reason]),
+ {error, {finish_error, Reason, ManagerEngineID}};
+
+ Unknown ->
+ ?vlog("handle_discovery_stage1_finish -> stage 1 function unknown: "
+ "~n ~p", [Unknown]),
+ {error, {finish_failed, Unknown, ManagerEngineID}}
+ end.
+
+add_usm_users([]) ->
+ ok;
+add_usm_users([UsmEntry|UsmEntries]) when is_tuple(UsmEntry) ->
+ ?vtrace("add_usm_users -> attempt to add entry (~w)",
+ [element(1, UsmEntry)]),
+ case snmp_user_based_sm_mib:add_user(UsmEntry) of
+ {ok, _} ->
+ add_usm_users(UsmEntries);
+ {error, Reason} ->
+ ?vlog("add_usm_users -> failed adding usm entry: "
+ "~n ~p", [Reason]),
+ {error, {failed_adding_entry, Reason, UsmEntry}}
+ end.
+
+
+handle_me_of(MibServer, Oid) ->
+ case snmpa_mib:lookup(MibServer, Oid) of
+ {variable, ME} ->
+ {ok, ME};
+ {table_column, ME, _TableEntryOid} ->
+ {ok, ME};
+ {subagent, SubAgentPid, _SANextOid} ->
+ {error, {subagent, SubAgentPid}};
+ {false, Reason} ->
+ {error, Reason};
+ Else ->
+ {error, Else}
+ end.
+
+
+handle_mib_of(MibServer, Oid) ->
+ snmpa_mib:which_mib(MibServer, Oid).
+
+
+%%-----------------------------------------------------------------
+%% Func: process_msg/7
+%% Returns: RePdu
+%%-----------------------------------------------------------------
+process_msg(MibView, Vsn, Pdu, PduMS, Community, {Ip, Udp}, ContextName) ->
+ #pdu{request_id = ReqId} = Pdu,
+ put(snmp_address, {tuple_to_list(Ip), Udp}),
+ put(snmp_request_id, ReqId),
+ put(snmp_community, Community),
+ put(snmp_context, ContextName),
+ ?vtrace("process ~p",[Pdu#pdu.type]),
+ process_pdu(Pdu, PduMS, Vsn, MibView).
+
+process_pdu(#pdu{type='get-request', request_id = ReqId, varbinds=Vbs},
+ _PduMS, Vsn, MibView) ->
+ ?vtrace("get ~p",[ReqId]),
+ Res = get_err(do_get(MibView, Vbs, false)),
+ ?vtrace("get result: "
+ "~n ~p",[Res]),
+ {ErrStatus, ErrIndex, ResVarbinds} =
+ if
+ Vsn =:= 'version-1' -> validate_get_v1(Res);
+ true -> Res
+ end,
+ ?vtrace("get final result: "
+ "~n Error status: ~p"
+ "~n Error index: ~p"
+ "~n Varbinds: ~p",
+ [ErrStatus,ErrIndex,ResVarbinds]),
+ ResponseVarbinds = lists:keysort(#varbind.org_index, ResVarbinds),
+ ?vtrace("response varbinds: "
+ "~n ~p",[ResponseVarbinds]),
+ make_response_pdu(ReqId, ErrStatus, ErrIndex, Vbs, ResponseVarbinds);
+
+process_pdu(#pdu{type = 'get-next-request', request_id = ReqId, varbinds = Vbs},
+ _PduMS, Vsn, MibView) ->
+ ?vtrace("process get-next-request -> entry with"
+ "~n ReqId: ~p"
+ "~n Vbs: ~p"
+ "~n MibView: ~p",[ReqId, Vbs, MibView]),
+ Res = get_err(do_get_next(MibView, Vbs)),
+ ?vtrace("get-next result: "
+ "~n ~p",[Res]),
+ {ErrStatus, ErrIndex, ResVarbinds} =
+ if
+ Vsn =:= 'version-1' -> validate_next_v1(Res, MibView);
+ true -> Res
+ end,
+ ?vtrace("get-next final result -> validation result:"
+ "~n Error status: ~p"
+ "~n Error index: ~p"
+ "~n Varbinds: ~p",[ErrStatus,ErrIndex,ResVarbinds]),
+ ResponseVarbinds = lists:keysort(#varbind.org_index, ResVarbinds),
+ ?vtrace("get-next final result -> response varbinds: "
+ "~n ~p",[ResponseVarbinds]),
+ make_response_pdu(ReqId, ErrStatus, ErrIndex, Vbs, ResponseVarbinds);
+
+process_pdu(#pdu{type = 'get-bulk-request',request_id = ReqId,varbinds = Vbs,
+ error_status = NonRepeaters, error_index = MaxRepetitions},
+ PduMS, _Vsn, MibView)->
+ {ErrStatus, ErrIndex, ResponseVarbinds} =
+ get_err(do_get_bulk(MibView,NonRepeaters,MaxRepetitions,PduMS,Vbs)),
+ ?vtrace("get-bulk final result: "
+ "~n Error status: ~p"
+ "~n Error index: ~p"
+ "~n Respons varbinds: ~p",
+ [ErrStatus,ErrIndex,ResponseVarbinds]),
+ make_response_pdu(ReqId, ErrStatus, ErrIndex, Vbs, ResponseVarbinds);
+
+process_pdu(#pdu{type = 'set-request', request_id = ReqId, varbinds = Vbs},
+ _PduMS, Vsn, MibView)->
+ Res = do_set(MibView, Vbs),
+ ?vtrace("set result: "
+ "~n ~p",[Res]),
+ {ErrStatus, ErrIndex} =
+ if
+ Vsn =:= 'version-1' -> validate_err(v2_to_v1, Res);
+ true -> Res
+ end,
+ ?vtrace("set final result: "
+ "~n Error status: ~p"
+ "~n Error index: ~p",[ErrStatus,ErrIndex]),
+ make_response_pdu(ReqId, ErrStatus, ErrIndex, Vbs, Vbs).
+
+%%-----------------------------------------------------------------
+%% Transform a value == noSuchInstance | noSuchObject or a
+%% Counter64 type to a noSuchName error for the whole pdu.
+%% Args: {Error, Index, Vbs}
+%% Returns: {NewError, NewIndex, NewVbs}
+%%-----------------------------------------------------------------
+validate_get_v1({noError, _, ResponseVarbinds}) ->
+ case validate_get_v1_2(ResponseVarbinds) of
+ true -> {noError, 0, ResponseVarbinds};
+ {Error, Index} -> {Error, Index, []} % dummy vbs
+ end;
+validate_get_v1({ErrStatus, ErrIndex, ResponseVarbinds}) ->
+ {v2err_to_v1err(ErrStatus), ErrIndex, ResponseVarbinds}.
+
+validate_get_v1_2([Vb | Vbs])
+ when ((Vb#varbind.value =/= noSuchInstance) andalso
+ (Vb#varbind.value =/= noSuchObject) andalso
+ (Vb#varbind.variabletype =/= 'Counter64')) ->
+ validate_get_v1_2(Vbs);
+validate_get_v1_2([Vb | _Vbs]) ->
+ {noSuchName, Vb#varbind.org_index};
+validate_get_v1_2([]) ->
+ true.
+
+%%-----------------------------------------------------------------
+%% Transform a value == endOfMibView to a noSuchName for the
+%% whole pdu, and do another get-next for any Counter64 value.
+%% Args: {Error, Index, Vbs}
+%% Returns: {NewError, NewIndex, NewVbs}
+%%-----------------------------------------------------------------
+validate_next_v1({noError, _, ResponseVarbinds}, MibView) ->
+ case validate_next_v1_2(ResponseVarbinds, MibView, []) of
+ {true, NVbs} -> {noError, 0, NVbs};
+ {Error, Index} -> {Error, Index, []} % dummy vbs
+ end;
+validate_next_v1({ErrStatus, ErrIndex, ResponseVarbinds}, _MibView) ->
+ {v2err_to_v1err(ErrStatus), ErrIndex, ResponseVarbinds}.
+
+validate_next_v1_2([Vb | _Vbs], _MibView, _Res)
+ when Vb#varbind.value =:= endOfMibView ->
+ {noSuchName, Vb#varbind.org_index};
+validate_next_v1_2([Vb | Vbs], MibView, Res)
+ when Vb#varbind.variabletype =:= 'Counter64' ->
+ case validate_next_v1(do_get_next(MibView, [mk_next_oid(Vb)]), MibView) of
+ {noError, 0, [NVb]} ->
+ validate_next_v1_2(Vbs, MibView, [NVb | Res]);
+ {Error, Index, _OrgVb} ->
+ {Error, Index}
+ end;
+validate_next_v1_2([Vb | Vbs], MibView, Res) ->
+ validate_next_v1_2(Vbs, MibView, [Vb | Res]);
+validate_next_v1_2([], _MibView, Res) ->
+ {true, Res}.
+
+%%-----------------------------------------------------------------
+%% Optimization. When we get to a Counter64 object that is a table
+%% column, we'll try to find the next instance. This will be the
+%% next row in the table, which is a Counter64 value as well. This
+%% means that we will loop through the entire table, until we find
+%% a column that isn't a Counter64 column. We can optimze this by
+%% adding 1 to the column-no in the oid of this instance.
+%% If the table is implemented by a subagent this does not help,
+%% we'll call that subagent many times. But it shouldn't be any
+%% problems.
+%%-----------------------------------------------------------------
+mk_next_oid(Vb) ->
+ case snmpa_mib:lookup(get(mibserver), Oid = Vb#varbind.oid) of
+ {table_column, _MibEntry, TableEntryOid} ->
+ [Col | _] = Oid -- TableEntryOid,
+ Vb#varbind{oid = TableEntryOid ++ [Col+1]};
+ _ ->
+ Vb
+ end.
+
+%%%-----------------------------------------------------------------
+%%% 3. GET REQUEST
+%%% --------------
+%%% According to RFC1157, section 4.1.2 and RFC1905, section 4.2.1.
+%%% In rfc1157:4.1.2 it isn't specified if noSuchName should be
+%%% returned even if some other varbind generates a genErr.
+%%% In rfc1905:4.2.1 this is not a problem since exceptions are
+%%% used, and thus a genErr will be returned anyway.
+%%%-----------------------------------------------------------------
+
+%%-----------------------------------------------------------------
+%% Func: do_get/3
+%% Purpose: do_get handles "getRequests".
+%% Pre: incoming varbinds have type == 'NULL', value == unSpecified
+%% Returns: {noError, 0, ListOfNewVarbinds} |
+%% {ErrorStatus, ErrorIndex, []}
+%%-----------------------------------------------------------------
+
+%% If this function is called from a worker-process, we *may*
+%% need to tunnel into the master-agent and let it do the
+%% work
+
+do_get(MibView, UnsortedVarbinds, IsNotification) ->
+ do_get(MibView, UnsortedVarbinds, IsNotification, false).
+
+do_get(MibView, UnsortedVarbinds, IsNotification, ForceMaster) ->
+ ?vtrace("do_get -> entry with"
+ "~n MibView: ~p"
+ "~n UnsortedVarbinds: ~p"
+ "~n IsNotification: ~p",
+ [MibView, UnsortedVarbinds, IsNotification]),
+ case (whereis(snmp_master_agent) =:= self()) of
+ false when (ForceMaster =:= true) ->
+ %% I am a lowly worker process, handoff to the master agent
+ PduData = get_pdu_data(),
+ call(snmp_master_agent,
+ {do_get, MibView, UnsortedVarbinds, IsNotification, PduData});
+
+ _ ->
+ %% This is me, the master, so go ahead
+ {OutSideView, InSideView} =
+ split_vbs_view(UnsortedVarbinds, MibView),
+ {Error, Index, NewVbs} =
+ do_get(InSideView, IsNotification),
+ {Error, Index, NewVbs ++ OutSideView}
+
+ end.
+
+
+split_vbs_view(Vbs, MibView) ->
+ ?vtrace("split the varbinds view", []),
+ split_vbs_view(Vbs, MibView, [], []).
+
+split_vbs_view([Vb | Vbs], MibView, Out, In) ->
+ case snmpa_acm:validate_mib_view(Vb#varbind.oid, MibView) of
+ true -> split_vbs_view(Vbs, MibView, Out, [Vb | In]);
+ false -> split_vbs_view(Vbs, MibView,
+ [Vb#varbind{value = noSuchObject} | Out], In)
+ end;
+split_vbs_view([], _MibView, Out, In) ->
+ {Out, In}.
+
+do_get(UnsortedVarbinds, IsNotification) ->
+ {MyVarbinds, SubagentVarbinds} = sort_varbindlist(UnsortedVarbinds),
+ case do_get_local(MyVarbinds, [], IsNotification) of
+ {noError, 0, NewMyVarbinds} ->
+ case do_get_subagents(SubagentVarbinds, IsNotification) of
+ {noError, 0, NewSubagentVarbinds} ->
+ {noError, 0, NewMyVarbinds ++ NewSubagentVarbinds};
+ {ErrorStatus, ErrorIndex, _} ->
+ {ErrorStatus, ErrorIndex, []}
+ end;
+ {ErrorStatus, ErrorIndex, _} ->
+ {ErrorStatus, ErrorIndex, []}
+ end.
+
+%%-----------------------------------------------------------------
+%% Func: do_get_local/3
+%% Purpose: Loop the variablebindings list. We know that each varbind
+%% in that list belongs to us.
+%% Returns: {noError, 0, ListOfNewVarbinds} |
+%% {ErrorStatus, ErrorIndex, []}
+%%-----------------------------------------------------------------
+do_get_local([Vb | Vbs], Res, IsNotification) ->
+ case try_get(Vb, IsNotification) of
+ NewVb when is_record(NewVb, varbind) ->
+ do_get_local(Vbs, [NewVb | Res], IsNotification);
+ ListOfNewVb when is_list(ListOfNewVb) ->
+ do_get_local(Vbs, lists:append(ListOfNewVb, Res), IsNotification);
+ {error, Error, OrgIndex} ->
+ {Error, OrgIndex, []}
+ end;
+do_get_local([], Res, _IsNotification) ->
+ {noError, 0, Res}.
+
+%%-----------------------------------------------------------------
+%% Func: do_get_subagents/2
+%% Purpose: Loop the list of varbinds for different subagents.
+%% For each of them, call sub_agent_get to retreive
+%% the values for them.
+%% Returns: {noError, 0, ListOfNewVarbinds} |
+%% {ErrorStatus, ErrorIndex, []}
+%%-----------------------------------------------------------------
+do_get_subagents(SubagentVarbinds, IsNotification) ->
+ do_get_subagents(SubagentVarbinds, [], IsNotification).
+do_get_subagents([{SubAgentPid, SAVbs} | Tail], Res, IsNotification) ->
+ {_SAOids, Vbs} = sa_split(SAVbs),
+ case catch subagent_get(SubAgentPid, Vbs, IsNotification) of
+ {noError, 0, NewVbs} ->
+ do_get_subagents(Tail, lists:append(NewVbs, Res), IsNotification);
+ {ErrorStatus, ErrorIndex, _} ->
+ {ErrorStatus, ErrorIndex, []};
+ {'EXIT', Reason} ->
+ user_err("Lost contact with subagent (get) ~w. Using genErr",
+ [Reason]),
+ {genErr, 0, []}
+ end;
+do_get_subagents([], Res, _IsNotification) ->
+ {noError, 0, Res}.
+
+
+%%-----------------------------------------------------------------
+%% Func: try_get/2
+%% Returns: {error, ErrorStatus, OrgIndex} |
+%% #varbind |
+%% List of #varbind
+%%-----------------------------------------------------------------
+try_get(IVb, IsNotification) when is_record(IVb, ivarbind) ->
+ ?vtrace("try_get(ivarbind) -> entry with"
+ "~n IVb: ~p", [IVb]),
+ get_var_value_from_ivb(IVb, IsNotification);
+try_get({TableOid, TableVbs}, IsNotification) ->
+ ?vtrace("try_get(table) -> entry with"
+ "~n TableOid: ~p"
+ "~n TableVbs: ~p", [TableOid, TableVbs]),
+ [#ivarbind{mibentry = MibEntry}|_] = TableVbs,
+ {NoAccessVbs, AccessVbs} =
+ check_all_table_vbs(TableVbs, IsNotification, [], []),
+ case get_tab_value_from_mib(MibEntry, TableOid, AccessVbs) of
+ {error, ErrorStatus, OrgIndex} ->
+ {error, ErrorStatus, OrgIndex};
+ NVbs ->
+ NVbs ++ NoAccessVbs
+ end.
+
+%%-----------------------------------------------------------------
+%% Make sure all requested columns are accessible.
+%%-----------------------------------------------------------------
+check_all_table_vbs([IVb| IVbs], IsNotification, NoA, A) ->
+ #ivarbind{mibentry = Me, varbind = Vb} = IVb,
+ case Me#me.access of
+ 'not-accessible' ->
+ NNoA = [Vb#varbind{value = noSuchInstance} | NoA],
+ check_all_table_vbs(IVbs, IsNotification, NNoA, A);
+ 'accessible-for-notify' when IsNotification =:= false ->
+ NNoA = [Vb#varbind{value = noSuchInstance} | NoA],
+ check_all_table_vbs(IVbs, IsNotification, NNoA, A);
+ 'write-only' ->
+ NNoA = [Vb#varbind{value = noSuchInstance} | NoA],
+ check_all_table_vbs(IVbs, IsNotification, NNoA, A);
+ _ ->
+ check_all_table_vbs(IVbs, IsNotification, NoA, [IVb | A])
+ end;
+check_all_table_vbs([], _IsNotification, NoA, A) -> {NoA, A}.
+
+%%-----------------------------------------------------------------
+%% Returns: {error, ErrorStatus, OrgIndex} |
+%% #varbind
+%%-----------------------------------------------------------------
+get_var_value_from_ivb(IVb, IsNotification)
+ when IVb#ivarbind.status =:= noError ->
+ ?vtrace("get_var_value_from_ivb(noError) -> entry", []),
+ #ivarbind{mibentry = Me, varbind = Vb} = IVb,
+ #varbind{org_index = OrgIndex, oid = Oid} = Vb,
+ case Me#me.access of
+ 'not-accessible' ->
+ Vb#varbind{value = noSuchInstance};
+ 'accessible-for-notify' when IsNotification =:= false ->
+ Vb#varbind{value = noSuchInstance};
+ 'write-only' ->
+ Vb#varbind{value = noSuchInstance};
+ _ ->
+ case get_var_value_from_mib(Me, Oid) of
+ {value, Type, Value} ->
+ Vb#varbind{variabletype = Type, value = Value};
+ {error, ErrorStatus} ->
+ {error, ErrorStatus, OrgIndex}
+ end
+ end;
+get_var_value_from_ivb(#ivarbind{status = Status, varbind = Vb}, _) ->
+ ?vtrace("get_var_value_from_ivb(~p) -> entry", [Status]),
+ Vb#varbind{value = Status}.
+
+%%-----------------------------------------------------------------
+%% Func: get_var_value_from_mib/1
+%% Purpose:
+%% Returns: {error, ErrorStatus} |
+%% {value, Type, Value}
+%%-----------------------------------------------------------------
+%% Pre: Oid is a correct instance Oid (lookup checked that).
+%% Returns: A correct return value (see make_value_a_correct_value)
+get_var_value_from_mib(#me{entrytype = variable,
+ asn1_type = ASN1Type,
+ mfa = {Mod, Func, Args}},
+ _Oid) ->
+ ?vtrace("get_var_value_from_mib(variable) -> entry when"
+ "~n Mod: ~p"
+ "~n Func: ~p"
+ "~n Args: ~p", [Mod, Func, Args]),
+ Result = (catch dbg_apply(Mod, Func, [get | Args])),
+ % mib shall return {value, <a-nice-value-within-range>} |
+ % {noValue, noSuchName} (v1) |
+ % {noValue, noSuchObject | noSuchInstance} (v2, v1)
+ % everything else (including 'genErr') will generate 'genErr'.
+ make_value_a_correct_value(Result, ASN1Type, {Mod, Func, Args});
+
+get_var_value_from_mib(#me{entrytype = table_column,
+ oid = MeOid,
+ asn1_type = ASN1Type,
+ mfa = {Mod, Func, Args}},
+ Oid) ->
+ ?vtrace("get_var_value_from_mib(table_column) -> entry when"
+ "~n MeOid: ~p"
+ "~n Mod: ~p"
+ "~n Func: ~p"
+ "~n Args: ~p"
+ "~n Oid: ~p", [MeOid, Mod, Func, Args, Oid]),
+ Col = lists:last(MeOid),
+ Indexes = snmp_misc:diff(Oid, MeOid),
+ [Result] = (catch dbg_apply(Mod, Func, [get, Indexes, [Col] | Args])),
+ make_value_a_correct_value(Result, ASN1Type,
+ {Mod, Func, Args, Indexes, Col}).
+
+
+%% For table operations we need to pass RestOid down to the table-function.
+%% Its up to the table-function to check for noSuchInstance (ex: a
+%% non-existing row).
+%% Returns: {error, ErrorStatus, OrgIndex} |
+%% {value, Type, Value}
+get_tab_value_from_mib(#me{mfa = {Mod, Func, Args}}, TableOid, TableVbs) ->
+ ?vtrace("get_tab_value_from_mib -> entry when"
+ "~n Mod: ~p"
+ "~n Func: ~p"
+ "~n Args: ~p", [Mod, Func, Args]),
+ TableOpsWithShortOids = deletePrefixes(TableOid, TableVbs),
+ SortedVBsRows = snmpa_svbl:sort_varbinds_rows(TableOpsWithShortOids),
+ case get_value_all_rows(SortedVBsRows, Mod, Func, Args, []) of
+ {Error, Index} ->
+ #ivarbind{varbind = Vb} = lists:nth(Index, TableVbs),
+ {error, Error, Vb#varbind.org_index};
+ ListOfValues ->
+ merge_varbinds_and_value(TableVbs, ListOfValues)
+ end.
+
+%%-----------------------------------------------------------------
+%% Values is a scrambled list of {CorrectValue, Index}, where Index
+%% is index into the #ivarbind list. So for each Value, we must
+%% find the corresponding #ivarbind, and merge them into a new
+%% #varbind.
+%% The Values list comes from validate_tab_res.
+%%-----------------------------------------------------------------
+merge_varbinds_and_value(IVbs, [{{value, Type, Value}, Index} | Values]) ->
+ #ivarbind{varbind = Vb} = lists:nth(Index, IVbs),
+ [Vb#varbind{variabletype = Type, value = Value} |
+ merge_varbinds_and_value(IVbs, Values)];
+merge_varbinds_and_value(_, []) -> [].
+
+get_value_all_rows([{[], OrgCols} | Rows], Mod, Func, Args, Res) ->
+ ?vtrace("get_value_all_rows -> entry when"
+ "~n OrgCols: ~p", [OrgCols]),
+ Cols = [{{value, noValue, noSuchInstance}, Index} ||
+ {_Col, _ASN1Type, Index} <- OrgCols],
+ NewRes = lists:append(Cols, Res),
+ get_value_all_rows(Rows, Mod, Func, Args, NewRes);
+get_value_all_rows([{RowIndex, OrgCols} | Rows], Mod, Func, Args, Res) ->
+ ?vtrace("get_value_all_rows -> entry when"
+ "~n RowIndex: ~p"
+ "~n OrgCols: ~p", [RowIndex, OrgCols]),
+ {DOrgCols, Dup} = remove_duplicates(OrgCols),
+ Cols = delete_index(DOrgCols),
+ Result = (catch dbg_apply(Mod, Func, [get, RowIndex, Cols | Args])),
+ case validate_tab_res(Result, DOrgCols, {Mod, Func, Args}) of
+ Values when is_list(Values) ->
+ NVals = restore_duplicates(Dup, Values),
+ NewRes = lists:append(NVals, Res),
+ get_value_all_rows(Rows, Mod, Func, Args, NewRes);
+ {error, ErrorStatus, Index} ->
+ validate_err(row_set, {ErrorStatus, Index}, {Mod, Func, Args})
+ end;
+get_value_all_rows([], _Mod, _Func, _Args, Res) ->
+ ?vtrace("get_value_all_rows -> entry when done"
+ "~n Res: ~p", [Res]),
+ Res.
+
+%%-----------------------------------------------------------------
+%% Returns: list of {ShortOid, ASN1TYpe}
+%%-----------------------------------------------------------------
+deletePrefixes(Prefix, [#ivarbind{varbind = Varbind, mibentry = ME} | Vbs]) ->
+ #varbind{oid = Oid} = Varbind,
+ [{snmp_misc:diff(Oid, Prefix), ME#me.asn1_type} |
+ deletePrefixes(Prefix, Vbs)];
+deletePrefixes(_Prefix, []) -> [].
+
+%%-----------------------------------------------------------------
+%% Args: {RowIndex, list of {ShortOid, ASN1Type}}
+%% Returns: list of Col
+%%-----------------------------------------------------------------
+delete_index([{Col, _Val, _OrgIndex} | T]) ->
+ [Col | delete_index(T)];
+delete_index([]) -> [].
+
+%%-----------------------------------------------------------------
+%% This function is called before 'get' on a table, and removes
+%% any duplicate columns. It returns {Cols, DupInfo}. The Cols
+%% are the unique columns. The instrumentation function is
+%% called to get the values. These values, together with the
+%% DupInfo, is later passed to restore_duplicates, which uses
+%% the retrieved values to reconstruct the original column list,
+%% but with the retrieved value for each column.
+%%-----------------------------------------------------------------
+remove_duplicates(Cols) ->
+ remove_duplicates(Cols, [], []).
+
+
+remove_duplicates([{Col, V1, OrgIdx1}, {Col, V2, OrgIdx2} | T], NCols, Dup) ->
+ remove_duplicates([{Col, V1, OrgIdx1} | T], NCols,
+ [{Col, V2, OrgIdx2} | Dup]);
+remove_duplicates([Col | T], NCols, Dup) ->
+ remove_duplicates(T, [Col | NCols], Dup);
+remove_duplicates([], NCols, Dup) ->
+ {lists:reverse(NCols), lists:reverse(Dup)}.
+
+restore_duplicates([], Cols) ->
+ [{Val, OrgIndex} || {_Col, Val, OrgIndex} <- Cols];
+restore_duplicates([{Col, _Val2, OrgIndex2} | Dup],
+ [{Col, NVal, OrgIndex1} | Cols]) ->
+ [{NVal, OrgIndex2} |
+ restore_duplicates(Dup, [{Col, NVal, OrgIndex1} | Cols])];
+restore_duplicates(Dup, [{_Col, Val, OrgIndex} | T]) ->
+ [{Val, OrgIndex} | restore_duplicates(Dup, T)].
+
+%% Maps the column number to Index.
+% col_to_index(0, _) -> 0;
+% col_to_index(Col, [{Col, _, Index}|_]) ->
+% Index;
+% col_to_index(Col, [_|Cols]) ->
+% col_to_index(Col, Cols).
+
+%%-----------------------------------------------------------------
+%% Three cases:
+%% 1) All values ok
+%% 2) table_func returned {Error, ...}
+%% 3) Some value in Values list is erroneous.
+%% Args: Value is a list of values from table_func(get..)
+%% OrgCols is a list with {Col, ASN1Type, OrgIndex}
+%% each element in Values and OrgCols correspond to each
+%% other.
+%%-----------------------------------------------------------------
+validate_tab_res(Values, OrgCols, Mfa) when is_list(Values) ->
+ {_Col, _ASN1Type, OneIdx} = hd(OrgCols),
+ validate_tab_res(Values, OrgCols, Mfa, [], OneIdx);
+validate_tab_res({noValue, Error}, OrgCols, Mfa) ->
+ Values = lists:duplicate(length(OrgCols), {noValue, Error}),
+ validate_tab_res(Values, OrgCols, Mfa);
+validate_tab_res({genErr, Col}, OrgCols, Mfa) ->
+ case lists:keysearch(Col, 1, OrgCols) of
+ {value, {_Col, _ASN1Type, Index}} ->
+ {error, genErr, Index};
+ _ ->
+ user_err("Invalid column in {genErr, ~w} from ~w (get)",
+ [Col, Mfa]),
+ [{_Col, _ASN1Type, Index} | _] = OrgCols,
+ {error, genErr, Index}
+ end;
+validate_tab_res(genErr, [{_Col, __ASN1Type, Index} | _OrgCols], _Mfa) ->
+ {error, genErr, Index};
+validate_tab_res(Error, [{_Col, _ASN1Type, Index} | _OrgCols], Mfa) ->
+ user_err("Invalid return value ~w from ~w (get)",[Error, Mfa]),
+ {error, genErr, Index}.
+
+validate_tab_res([Value | Values],
+ [{Col, ASN1Type, Index} | OrgCols],
+ Mfa, Res, I) ->
+ %% This one makes it possible to return a list of genErr, which
+ %% is not allowed according to the manual. But that's ok, as
+ %% everything else will generate a genErr! (the only problem is
+ %% that it won't generate a user_error).
+ case make_value_a_correct_value(Value, ASN1Type, Mfa) of
+ {error, ErrorStatus} ->
+ {error, ErrorStatus, Index};
+ CorrectValue ->
+ NewRes = [{Col, CorrectValue, Index} | Res],
+ validate_tab_res(Values, OrgCols, Mfa, NewRes, I)
+ end;
+validate_tab_res([], [], _Mfa, Res, _I) ->
+ lists:reverse(Res);
+validate_tab_res([], [{_Col, _ASN1Type, Index}|_], Mfa, _Res, _I) ->
+ user_err("Too few values returned from ~w (get)", [Mfa]),
+ {error, genErr, Index};
+validate_tab_res(_TooMany, [], Mfa, _Res, I) ->
+ user_err("Too many values returned from ~w (get)", [Mfa]),
+ {error, genErr, I}.
+
+
+%%%-----------------------------------------------------------------
+%%% 4. GET-NEXT REQUEST
+%%% --------------
+%%% According to RFC1157, section 4.1.3 and RFC1905, section 4.2.2.
+%%%-----------------------------------------------------------------
+%%-----------------------------------------------------------------
+%% Func: do_get_next/2
+%% Purpose: do_get_next handles "getNextRequests".
+%% Note: Even if it is SNMPv1, a varbind's value can be
+%% endOfMibView. This is converted to noSuchName in process_pdu.
+%% Returns: {noError, 0, ListOfNewVarbinds} |
+%% {ErrorStatus, ErrorIndex, []}
+%% Note2: ListOfNewVarbinds is not sorted in any order!!!
+%% Alg: First, the variables are sorted in OID order.
+%%
+%% Second, next in the MIB is performed for each OID, and
+%% the result is collected as: if next oid is a variable,
+%% perform a get to retrieve its value; if next oid is in a
+%% table, save this value and continue until we get an oid
+%% outside this table. Then perform get_next on the table,
+%% and continue with all endOfTables and the oid outside the
+%% table; if next oid is an subagent, save this value and
+%% continue as in the table case.
+%%
+%% Third, each response is checked for endOfMibView, or (for
+%% subagents) that the Oid returned has the correct prefix.
+%% (This is necessary since an SA can be registered under many
+%% separated subtrees, and if the last variable in the first
+%% subtree is requested in a next, the SA will return the first
+%% variable in the second subtree. This might be working, since
+%% there may be a variable in between these subtrees.) For each
+%% of these, a new get-next is performed, one at a time.
+%% This alg. might be optimised in several ways. The most
+%% striking one is that the same SA might be called several
+%% times, when one time should be enough. But it isn't clear
+%% that this really matters, since many nexts across the same
+%% subagent must be considered to be very rare.
+%%-----------------------------------------------------------------
+do_get_next(MibView, UnsortedVarbinds) ->
+ SortedVarbinds = oid_sort_varbindlist(UnsortedVarbinds),
+ next_loop_varbinds([], SortedVarbinds, MibView, [], []).
+
+oid_sort_varbindlist(Vbs) ->
+ lists:keysort(#varbind.oid, Vbs).
+
+%% LAVb is Last Accessible Vb
+next_loop_varbinds([], [Vb | Vbs], MibView, Res, LAVb) ->
+ ?vt("next_loop_varbinds -> entry when"
+ "~n Vb: ~p"
+ "~n MibView: ~p", [Vb, MibView]),
+ case varbind_next(Vb, MibView) of
+ endOfMibView ->
+ RVb = if LAVb =:= [] -> Vb;
+ true -> LAVb
+ end,
+ NewVb = RVb#varbind{variabletype = 'NULL', value = endOfMibView},
+ next_loop_varbinds([], Vbs, MibView, [NewVb | Res], []);
+ {variable, ME, VarOid} when ((ME#me.access =/= 'not-accessible') andalso
+ (ME#me.access =/= 'write-only') andalso
+ (ME#me.access =/= 'accessible-for-notify')) ->
+ case try_get_instance(Vb, ME) of
+ {value, noValue, _NoSuchSomething} ->
+ %% Try next one
+ NewVb = Vb#varbind{oid = VarOid, value = 'NULL'},
+ next_loop_varbinds([], [NewVb | Vbs], MibView, Res, []);
+ {value, Type, Value} ->
+ NewVb = Vb#varbind{oid = VarOid, variabletype = Type,
+ value = Value},
+ next_loop_varbinds([], Vbs, MibView, [NewVb | Res], []);
+ {error, ErrorStatus} ->
+ ?vdebug("next loop varbinds:"
+ "~n ErrorStatus: ~p",[ErrorStatus]),
+ {ErrorStatus, Vb#varbind.org_index, []}
+ end;
+ {variable, _ME, VarOid} ->
+ RVb = if LAVb =:= [] -> Vb;
+ true -> LAVb
+ end,
+ NewVb = Vb#varbind{oid = VarOid, value = 'NULL'},
+ next_loop_varbinds([], [NewVb | Vbs], MibView, Res, RVb);
+ {table, TableOid, TableRestOid, ME} ->
+ next_loop_varbinds({table, TableOid, ME,
+ [{tab_oid(TableRestOid), Vb}]},
+ Vbs, MibView, Res, []);
+ {subagent, SubAgentPid, SAOid} ->
+ NewVb = Vb#varbind{variabletype = 'NULL', value = 'NULL'},
+ next_loop_varbinds({subagent, SubAgentPid, SAOid, [NewVb]},
+ Vbs, MibView, Res, [])
+ end;
+next_loop_varbinds({table, TableOid, ME, TabOids},
+ [Vb | Vbs], MibView, Res, _LAVb) ->
+ ?vt("next_loop_varbinds(table) -> entry with"
+ "~n TableOid: ~p"
+ "~n Vb: ~p", [TableOid, Vb]),
+ case varbind_next(Vb, MibView) of
+ {table, TableOid, TableRestOid, _ME} ->
+ next_loop_varbinds({table, TableOid, ME,
+ [{tab_oid(TableRestOid), Vb} | TabOids]},
+ Vbs, MibView, Res, []);
+ _ ->
+ case get_next_table(ME, TableOid, TabOids, MibView) of
+ {ok, TabRes, TabEndOfTabVbs} ->
+ NewVbs = lists:append(TabEndOfTabVbs, [Vb | Vbs]),
+ NewRes = lists:append(TabRes, Res),
+ next_loop_varbinds([], NewVbs, MibView, NewRes, []);
+ {ErrorStatus, OrgIndex} ->
+ ?vdebug("next loop varbinds: next varbind"
+ "~n ErrorStatus: ~p"
+ "~n OrgIndex: ~p",
+ [ErrorStatus,OrgIndex]),
+ {ErrorStatus, OrgIndex, []}
+ end
+ end;
+next_loop_varbinds({table, TableOid, ME, TabOids},
+ [], MibView, Res, _LAVb) ->
+ ?vt("next_loop_varbinds(table) -> entry with"
+ "~n TableOid: ~p", [TableOid]),
+ case get_next_table(ME, TableOid, TabOids, MibView) of
+ {ok, TabRes, TabEndOfTabVbs} ->
+ ?vt("next_loop_varbinds(table) -> get_next_table result:"
+ "~n TabRes: ~p"
+ "~n TabEndOfTabVbs: ~p", [TabRes, TabEndOfTabVbs]),
+ NewRes = lists:append(TabRes, Res),
+ next_loop_varbinds([], TabEndOfTabVbs, MibView, NewRes, []);
+ {ErrorStatus, OrgIndex} ->
+ ?vdebug("next loop varbinds: next table"
+ "~n ErrorStatus: ~p"
+ "~n OrgIndex: ~p",
+ [ErrorStatus,OrgIndex]),
+ {ErrorStatus, OrgIndex, []}
+ end;
+next_loop_varbinds({subagent, SAPid, SAOid, SAVbs},
+ [Vb | Vbs], MibView, Res, _LAVb) ->
+ ?vt("next_loop_varbinds(subagent) -> entry with"
+ "~n SAPid: ~p"
+ "~n SAOid: ~p"
+ "~n Vb: ~p", [SAPid, SAOid, Vb]),
+ case varbind_next(Vb, MibView) of
+ {subagent, _SubAgentPid, SAOid} ->
+ next_loop_varbinds({subagent, SAPid, SAOid,
+ [Vb | SAVbs]},
+ Vbs, MibView, Res, []);
+ _ ->
+ case get_next_sa(SAPid, SAOid, SAVbs, MibView) of
+ {ok, SARes, SAEndOfMibViewVbs} ->
+ NewVbs = lists:append(SAEndOfMibViewVbs, [Vb | Vbs]),
+ NewRes = lists:append(SARes, Res),
+ next_loop_varbinds([], NewVbs, MibView, NewRes, []);
+ {noSuchName, OrgIndex} ->
+ %% v1 reply, treat this Vb as endOfMibView, and try again
+ %% for the others.
+ case lists:keysearch(OrgIndex, #varbind.org_index, SAVbs) of
+ {value, EVb} ->
+ NextOid = next_oid(SAOid),
+ EndOfVb =
+ EVb#varbind{oid = NextOid,
+ value = {endOfMibView, NextOid}},
+ case lists:delete(EVb, SAVbs) of
+ [] ->
+ next_loop_varbinds([], [EndOfVb, Vb | Vbs],
+ MibView, Res, []);
+ TryAgainVbs ->
+ next_loop_varbinds({subagent, SAPid, SAOid,
+ TryAgainVbs},
+ [EndOfVb, Vb | Vbs],
+ MibView, Res, [])
+ end;
+ false ->
+ %% bad index from subagent
+ {genErr, (hd(SAVbs))#varbind.org_index, []}
+ end;
+ {ErrorStatus, OrgIndex} ->
+ ?vdebug("next loop varbinds: next subagent"
+ "~n Vb: ~p"
+ "~n ErrorStatus: ~p"
+ "~n OrgIndex: ~p",
+ [Vb,ErrorStatus,OrgIndex]),
+ {ErrorStatus, OrgIndex, []}
+ end
+ end;
+next_loop_varbinds({subagent, SAPid, SAOid, SAVbs},
+ [], MibView, Res, _LAVb) ->
+ ?vt("next_loop_varbinds(subagent) -> entry with"
+ "~n SAPid: ~p"
+ "~n SAOid: ~p", [SAPid, SAOid]),
+ case get_next_sa(SAPid, SAOid, SAVbs, MibView) of
+ {ok, SARes, SAEndOfMibViewVbs} ->
+ NewRes = lists:append(SARes, Res),
+ next_loop_varbinds([], SAEndOfMibViewVbs, MibView, NewRes, []);
+ {noSuchName, OrgIndex} ->
+ %% v1 reply, treat this Vb as endOfMibView, and try again for
+ %% the others.
+ case lists:keysearch(OrgIndex, #varbind.org_index, SAVbs) of
+ {value, EVb} ->
+ NextOid = next_oid(SAOid),
+ EndOfVb = EVb#varbind{oid = NextOid,
+ value = {endOfMibView, NextOid}},
+ case lists:delete(EVb, SAVbs) of
+ [] ->
+ next_loop_varbinds([], [EndOfVb], MibView, Res, []);
+ TryAgainVbs ->
+ next_loop_varbinds({subagent, SAPid, SAOid,
+ TryAgainVbs},
+ [EndOfVb], MibView, Res, [])
+ end;
+ false ->
+ %% bad index from subagent
+ {genErr, (hd(SAVbs))#varbind.org_index, []}
+ end;
+ {ErrorStatus, OrgIndex} ->
+ ?vdebug("next loop varbinds: next subagent"
+ "~n ErrorStatus: ~p"
+ "~n OrgIndex: ~p",
+ [ErrorStatus,OrgIndex]),
+ {ErrorStatus, OrgIndex, []}
+ end;
+next_loop_varbinds([], [], _MibView, Res, _LAVb) ->
+ ?vt("next_loop_varbinds -> entry when done", []),
+ {noError, 0, Res}.
+
+try_get_instance(_Vb, #me{mfa = {M, F, A}, asn1_type = ASN1Type}) ->
+ ?vtrace("try get instance from <~p,~p,~p>",[M,F,A]),
+ Result = (catch dbg_apply(M, F, [get | A])),
+ % mib shall return {value, <a-nice-value-within-range>} |
+ % {noValue, noSuchName} (v1) |
+ % {noValue, noSuchObject | noSuchInstance} (v2, v1)
+ % everything else (including 'genErr') will generate 'genErr'.
+ make_value_a_correct_value(Result, ASN1Type, {M, F, A}).
+
+tab_oid([]) -> [0];
+tab_oid(X) -> X.
+
+%%-----------------------------------------------------------------
+%% Perform a next, using the varbinds Oid if value is simple
+%% value. If value is {endOf<something>, NextOid}, use NextOid.
+%% This case happens when a table has returned endOfTable, or
+%% a subagent has returned endOfMibView.
+%%-----------------------------------------------------------------
+varbind_next(#varbind{value = Value, oid = Oid}, MibView) ->
+ ?vt("varbind_next -> entry with"
+ "~n Value: ~p"
+ "~n Oid: ~p"
+ "~n MibView: ~p", [Value, Oid, MibView]),
+ case Value of
+ {endOfTable, NextOid} ->
+ snmpa_mib:next(get(mibserver), NextOid, MibView);
+ {endOfMibView, NextOid} ->
+ snmpa_mib:next(get(mibserver), NextOid, MibView);
+ _ ->
+ snmpa_mib:next(get(mibserver), Oid, MibView)
+ end.
+
+get_next_table(#me{mfa = {M, F, A}}, TableOid, TableOids, MibView) ->
+ % We know that all TableOids have at least a column number as oid
+ ?vt("get_next_table -> entry with"
+ "~n M: ~p"
+ "~n F: ~p"
+ "~n A: ~p"
+ "~n TableOid: ~p"
+ "~n TableOids: ~p"
+ "~n MibView: ~p", [M, F, A, TableOid, TableOids, MibView]),
+ Sorted = snmpa_svbl:sort_varbinds_rows(TableOids),
+ case get_next_values_all_rows(Sorted, M,F,A, [], TableOid) of
+ NewVbs when is_list(NewVbs) ->
+ ?vt("get_next_table -> "
+ "~n NewVbs: ~p", [NewVbs]),
+ % We must now check each Vb for endOfTable and that it is
+ % in the MibView. If not, it becomes a endOfTable. We
+ % collect all of these together.
+ transform_tab_next_result(NewVbs, {[], []}, MibView);
+ {ErrorStatus, OrgIndex} ->
+ {ErrorStatus, OrgIndex}
+ end.
+
+get_next_values_all_rows([Row | Rows], M, F, A, Res, TabOid) ->
+ {RowIndex, TableOids} = Row,
+ Cols = delete_index(TableOids),
+ ?vt("get_next_values_all_rows -> "
+ "~n Cols: ~p", [Cols]),
+ Result = (catch dbg_apply(M, F, [get_next, RowIndex, Cols | A])),
+ ?vt("get_next_values_all_rows -> "
+ "~n Result: ~p", [Result]),
+ case validate_tab_next_res(Result, TableOids, {M, F, A}, TabOid) of
+ Values when is_list(Values) ->
+ ?vt("get_next_values_all_rows -> "
+ "~n Values: ~p", [Values]),
+ NewRes = lists:append(Values, Res),
+ get_next_values_all_rows(Rows, M, F, A, NewRes, TabOid);
+ {ErrorStatus, OrgIndex} ->
+ {ErrorStatus, OrgIndex}
+ end;
+get_next_values_all_rows([], _M, _F, _A, Res, _TabOid) ->
+ Res.
+
+transform_tab_next_result([Vb | Vbs], {Res, EndOfs}, MibView) ->
+ case Vb#varbind.value of
+ {endOfTable, _} ->
+%% ?vtrace("transform_tab_next_result -> endOfTable: "
+%% "split varbinds",[]),
+%% R = split_varbinds(Vbs, Res, [Vb | EndOfs]),
+%% ?vtrace("transform_tab_next_result -> "
+%% "~n R: ~p", [R]),
+%% R;
+ split_varbinds(Vbs, Res, [Vb | EndOfs]);
+ _ ->
+ case snmpa_acm:validate_mib_view(Vb#varbind.oid, MibView) of
+ true ->
+ transform_tab_next_result(Vbs, {[Vb|Res], EndOfs},MibView);
+ _ ->
+ Oid = Vb#varbind.oid,
+ NewEndOf = Vb#varbind{value = {endOfTable, Oid}},
+ transform_tab_next_result(Vbs, {Res, [NewEndOf | EndOfs]},
+ MibView)
+ end
+ end;
+transform_tab_next_result([], {Res, EndOfs}, _MibView) ->
+ ?vt("transform_tab_next_result -> entry with: "
+ "~n Res: ~p"
+ "~n EndIfs: ~p",[Res, EndOfs]),
+ {ok, Res, EndOfs}.
+
+%%-----------------------------------------------------------------
+%% Three cases:
+%% 1) All values ok
+%% 2) table_func returned {Error, ...}
+%% 3) Some value in Values list is erroneous.
+%% Args: Value is a list of values from table_func(get_next, ...)
+%% TableOids is a list of {TabRestOid, OrgVb}
+%% each element in Values and TableOids correspond to each
+%% other.
+%% Returns: List of NewVarbinds |
+%% {ErrorStatus, OrgIndex}
+%% (In the NewVarbinds list, the value may be endOfTable)
+%%-----------------------------------------------------------------
+validate_tab_next_res(Values, TableOids, Mfa, TabOid) ->
+ ?vt("validate_tab_next_res -> entry with: "
+ "~n Values: ~p"
+ "~n TableOids: ~p"
+ "~n Mfa: ~p"
+ "~n TabOid: ~p", [Values, TableOids, Mfa, TabOid]),
+ {_Col, _ASN1Type, OneIdx} = hd(TableOids),
+ validate_tab_next_res(Values, TableOids, Mfa, [], TabOid,
+ next_oid(TabOid), OneIdx).
+validate_tab_next_res([{NextOid, Value} | Values],
+ [{_ColNo, OrgVb, _Index} | TableOids],
+ Mfa, Res, TabOid, TabNextOid, I) ->
+ ?vt("validate_tab_next_res -> entry with: "
+ "~n NextOid: ~p"
+ "~n Value: ~p"
+ "~n Values: ~p"
+ "~n TableOids: ~p"
+ "~n Mfa: ~p"
+ "~n TabOid: ~p",
+ [NextOid, Value, Values, TableOids, Mfa, TabOid]),
+ #varbind{org_index = OrgIndex} = OrgVb,
+ ?vt("validate_tab_next_res -> OrgIndex: ~p", [OrgIndex]),
+ NextCompleteOid = lists:append(TabOid, NextOid),
+ case snmpa_mib:lookup(get(mibserver), NextCompleteOid) of
+ {table_column, #me{asn1_type = ASN1Type}, _TableEntryOid} ->
+ ?vt("validate_tab_next_res -> ASN1Type: ~p", [ASN1Type]),
+ case make_value_a_correct_value({value, Value}, ASN1Type, Mfa) of
+ {error, ErrorStatus} ->
+ ?vt("validate_tab_next_res -> "
+ "~n ErrorStatus: ~p", [ErrorStatus]),
+ {ErrorStatus, OrgIndex};
+ {value, Type, NValue} ->
+ ?vt("validate_tab_next_res -> "
+ "~n Type: ~p"
+ "~n NValue: ~p", [Type, NValue]),
+ NewVb = OrgVb#varbind{oid = NextCompleteOid,
+ variabletype = Type, value = NValue},
+ validate_tab_next_res(Values, TableOids, Mfa,
+ [NewVb | Res], TabOid, TabNextOid, I)
+ end;
+ Error ->
+ user_err("Invalid oid ~w from ~w (get_next). Using genErr => ~p",
+ [NextOid, Mfa, Error]),
+ {genErr, OrgIndex}
+ end;
+validate_tab_next_res([endOfTable | Values],
+ [{_ColNo, OrgVb, _Index} | TableOids],
+ Mfa, Res, TabOid, TabNextOid, I) ->
+ ?vt("validate_tab_next_res(endOfTable) -> entry with: "
+ "~n Values: ~p"
+ "~n OrgVb: ~p"
+ "~n TableOids: ~p"
+ "~n Mfa: ~p"
+ "~n Res: ~p"
+ "~n TabOid: ~p"
+ "~n TabNextOid: ~p"
+ "~n I: ~p",
+ [Values, OrgVb, TableOids, Mfa, Res, TabOid, TabNextOid, I]),
+ NewVb = OrgVb#varbind{value = {endOfTable, TabNextOid}},
+ validate_tab_next_res(Values, TableOids, Mfa, [NewVb | Res],
+ TabOid, TabNextOid, I);
+validate_tab_next_res([], [], _Mfa, Res, _TabOid, _TabNextOid, _I) ->
+ Res;
+validate_tab_next_res([], [{_Col, _OrgVb, Index}|_], Mfa, _Res, _, _, _I) ->
+ user_err("Too few values returned from ~w (get_next)", [Mfa]),
+ {genErr, Index};
+validate_tab_next_res({genErr, ColNumber}, OrgCols,
+ Mfa, _Res, _TabOid, _TabNextOid, _I) ->
+ OrgIndex = snmpa_svbl:col_to_orgindex(ColNumber, OrgCols),
+ validate_err(table_next, {genErr, OrgIndex}, Mfa);
+validate_tab_next_res({error, Reason}, [{_ColNo, OrgVb, _Index} | _TableOids],
+ Mfa, _Res, _TabOid, _TabNextOid, _I) ->
+ #varbind{org_index = OrgIndex} = OrgVb,
+ user_err("Erroneous return value ~w from ~w (get_next)",
+ [Reason, Mfa]),
+ {genErr, OrgIndex};
+validate_tab_next_res(Error, [{_ColNo, OrgVb, _Index} | _TableOids],
+ Mfa, _Res, _TabOid, _TabNextOid, _I) ->
+ #varbind{org_index = OrgIndex} = OrgVb,
+ user_err("Invalid return value ~w from ~w (get_next)",
+ [Error, Mfa]),
+ {genErr, OrgIndex};
+validate_tab_next_res(TooMany, [], Mfa, _Res, _, _, I) ->
+ user_err("Too many values ~w returned from ~w (get_next)",
+ [TooMany, Mfa]),
+ {genErr, I}.
+
+%%-----------------------------------------------------------------
+%% Func: get_next_sa/4
+%% Purpose: Loop the list of varbinds for the subagent.
+%% Call subagent_get_next to retreive
+%% the next varbinds.
+%% Returns: {ok, ListOfNewVbs, ListOfEndOfMibViewsVbs} |
+%% {ErrorStatus, ErrorIndex}
+%%-----------------------------------------------------------------
+get_next_sa(SAPid, SAOid, SAVbs, MibView) ->
+ case catch subagent_get_next(SAPid, MibView, SAVbs) of
+ {noError, 0, NewVbs} ->
+ NewerVbs = transform_sa_next_result(NewVbs,SAOid,next_oid(SAOid)),
+ split_varbinds(NewerVbs, [], []);
+ {ErrorStatus, ErrorIndex, _} ->
+ {ErrorStatus, ErrorIndex};
+ {'EXIT', Reason} ->
+ user_err("Lost contact with subagent (next) ~w. Using genErr",
+ [Reason]),
+ {genErr, 0}
+ end.
+
+%%-----------------------------------------------------------------
+%% Check for wrong prefix returned or endOfMibView, and convert
+%% into {endOfMibView, SANextOid}.
+%%-----------------------------------------------------------------
+transform_sa_next_result([Vb | Vbs], SAOid, SANextOid)
+ when Vb#varbind.value =:= endOfMibView ->
+ [Vb#varbind{value = {endOfMibView, SANextOid}} |
+ transform_sa_next_result(Vbs, SAOid, SANextOid)];
+transform_sa_next_result([Vb | Vbs], SAOid, SANextOid) ->
+ case lists:prefix(SAOid, Vb#varbind.oid) of
+ true ->
+ [Vb | transform_sa_next_result(Vbs, SAOid, SANextOid)];
+ _ ->
+ [Vb#varbind{oid = SANextOid, value = {endOfMibView, SANextOid}} |
+ transform_sa_next_result(Vbs, SAOid, SANextOid)]
+ end;
+transform_sa_next_result([], _SAOid, _SANextOid) ->
+ [].
+
+split_varbinds([Vb | Vbs], Res, EndOfs) ->
+ case Vb#varbind.value of
+ {endOfMibView, _} -> split_varbinds(Vbs, Res, [Vb | EndOfs]);
+ {endOfTable, _} -> split_varbinds(Vbs, Res, [Vb | EndOfs]);
+ _ -> split_varbinds(Vbs, [Vb | Res], EndOfs)
+ end;
+split_varbinds([], Res, EndOfs) -> {ok, Res, EndOfs}.
+
+next_oid(Oid) ->
+ case lists:reverse(Oid) of
+ [H | T] -> lists:reverse([H+1 | T]);
+ [] -> []
+ end.
+
+
+%%%-----------------------------------------------------------------
+%%% 5. GET-BULK REQUEST
+%%%-----------------------------------------------------------------
+do_get_bulk(MibView, NonRepeaters, MaxRepetitions, PduMS, Varbinds) ->
+ ?vtrace("do get bulk: start with"
+ "~n MibView: ~p"
+ "~n NonRepeaters: ~p"
+ "~n MaxRepetitions: ~p"
+ "~n PduMS: ~p"
+ "~n Varbinds: ~p",
+ [MibView, NonRepeaters, MaxRepetitions, PduMS, Varbinds]),
+ {NonRepVbs, RestVbs} = split_vbs(NonRepeaters, Varbinds, []),
+ ?vt("do get bulk -> split: "
+ "~n NonRepVbs: ~p"
+ "~n RestVbs: ~p", [NonRepVbs, RestVbs]),
+ case do_get_next(MibView, NonRepVbs) of
+ {noError, 0, UResNonRepVbs} ->
+ ?vt("do get bulk -> next: "
+ "~n UResNonRepVbs: ~p", [UResNonRepVbs]),
+ ResNonRepVbs = lists:keysort(#varbind.org_index, UResNonRepVbs),
+ %% Decode the first varbinds, produce a reversed list of
+ %% listOfBytes.
+ case (catch enc_vbs(PduMS - ?empty_pdu_size, ResNonRepVbs)) of
+ {error, Idx, Reason} ->
+ user_err("failed encoding varbind ~w:~n~p", [Idx, Reason]),
+ {genErr, Idx, []};
+ {SizeLeft, Res} when is_integer(SizeLeft) and is_list(Res) ->
+ ?vtrace("do get bulk -> encoded: "
+ "~n SizeLeft: ~p"
+ "~n Res: ~w", [SizeLeft, Res]),
+ case (catch do_get_rep(SizeLeft, MibView, MaxRepetitions,
+ RestVbs, Res)) of
+ {error, Idx, Reason} ->
+ user_err("failed encoding varbind ~w:~n~p",
+ [Idx, Reason]),
+ {genErr, Idx, []};
+ Res when is_list(Res) ->
+ ?vtrace("do get bulk -> Res: "
+ "~n ~w", [Res]),
+ {noError, 0, conv_res(Res)};
+ Else ->
+ ?vtrace("do get bulk -> Else: "
+ "~n ~w", [Else]),
+ Else
+ end;
+ Res when is_list(Res) ->
+ {noError, 0, conv_res(Res)}
+ end;
+ {ErrorStatus, Index, _} ->
+ ?vdebug("do get bulk: "
+ "~n ErrorStatus: ~p"
+ "~n Index: ~p",[ErrorStatus, Index]),
+ {ErrorStatus, Index, []}
+ end.
+
+% sz(L) when list(L) -> length(L);
+% sz(B) when binary(B) -> size(B);
+% sz(_) -> unknown.
+
+split_vbs(N, Varbinds, Res) when N =< 0 -> {Res, Varbinds};
+split_vbs(N, [H | T], Res) -> split_vbs(N-1, T, [H | Res]);
+split_vbs(_N, [], Res) -> {Res, []}.
+
+enc_vbs(SizeLeft, Vbs) ->
+ ?vt("enc_vbs -> entry with"
+ "~n SizeLeft: ~w", [SizeLeft]),
+ Fun = fun(Vb, {Sz, Res}) when Sz > 0 ->
+ ?vt("enc_vbs -> (fun) entry with"
+ "~n Vb: ~p"
+ "~n Sz: ~p"
+ "~n Res: ~w", [Vb, Sz, Res]),
+ case (catch snmp_pdus:enc_varbind(Vb)) of
+ {'EXIT', Reason} ->
+ ?vtrace("enc_vbs -> encode failed: "
+ "~n Reason: ~p", [Reason]),
+ throw({error, Vb#varbind.org_index, Reason});
+ X ->
+ ?vt("enc_vbs -> X: ~w", [X]),
+ Lx = length(X),
+ ?vt("enc_vbs -> Lx: ~w", [Lx]),
+ if
+ Lx < Sz ->
+ {Sz - length(X), [X | Res]};
+ true ->
+ throw(Res)
+ end
+ end;
+ (_Vb, {_Sz, [_H | T]}) ->
+ ?vt("enc_vbs -> (fun) entry with"
+ "~n T: ~p", [T]),
+ throw(T);
+ (_Vb, {_Sz, []}) ->
+ ?vt("enc_vbs -> (fun) entry", []),
+ throw([])
+ end,
+ lists:foldl(Fun, {SizeLeft, []}, Vbs).
+
+do_get_rep(Sz, MibView, MaxRepetitions, Varbinds, Res)
+ when MaxRepetitions >= 0 ->
+ do_get_rep(Sz, MibView, 0, MaxRepetitions, Varbinds, Res);
+do_get_rep(Sz, MibView, _MaxRepetitions, Varbinds, Res) ->
+ do_get_rep(Sz, MibView, 0, 0, Varbinds, Res).
+
+conv_res(ResVarbinds) ->
+ conv_res(ResVarbinds, []).
+conv_res([VbListOfBytes | T], Bytes) ->
+ conv_res(T, VbListOfBytes ++ Bytes);
+conv_res([], Bytes) ->
+ Bytes.
+
+do_get_rep(_Sz, _MibView, Max, Max, _, Res) ->
+ ?vt("do_get_rep -> done when: "
+ "~n Res: ~p", [Res]),
+ {noError, 0, conv_res(Res)};
+do_get_rep(Sz, MibView, Count, Max, Varbinds, Res) ->
+ ?vt("do_get_rep -> entry when: "
+ "~n Sz: ~p"
+ "~n Count: ~p"
+ "~n Res: ~w", [Sz, Count, Res]),
+ case try_get_bulk(Sz, MibView, Varbinds) of
+ {noError, NextVarbinds, SizeLeft, Res2} ->
+ ?vt("do_get_rep -> noError: "
+ "~n SizeLeft: ~p"
+ "~n Res2: ~p", [SizeLeft, Res2]),
+ do_get_rep(SizeLeft, MibView, Count+1, Max, NextVarbinds,
+ Res2 ++ Res);
+ {endOfMibView, _NextVarbinds, _SizeLeft, Res2} ->
+ ?vt("do_get_rep -> endOfMibView: "
+ "~n Res2: ~p", [Res2]),
+ {noError, 0, conv_res(Res2 ++ Res)};
+ {ErrorStatus, Index} ->
+ ?vtrace("do_get_rep -> done when error: "
+ "~n ErrorStatus: ~p"
+ "~n Index: ~p", [ErrorStatus, Index]),
+ {ErrorStatus, Index, []}
+ end.
+
+try_get_bulk(Sz, MibView, Varbinds) ->
+ ?vt("try_get_bulk -> entry with"
+ "~n Sz: ~w", [Sz]),
+ case do_get_next(MibView, Varbinds) of
+ {noError, 0, UNextVarbinds} ->
+ ?vt("try_get_bulk -> noError", []),
+ NextVarbinds = lists:keysort(#varbind.org_index, UNextVarbinds),
+ case (catch enc_vbs(Sz, NextVarbinds)) of
+ {error, Idx, Reason} ->
+ user_err("failed encoding varbind ~w:~n~p", [Idx, Reason]),
+ ?vtrace("try_get_bulk -> error: "
+ "~n Idx: ~p"
+ "~n Reason: ~p", [Idx, Reason]),
+ {genErr, Idx};
+ {SizeLeft, Res} when is_integer(SizeLeft) andalso is_list(Res) ->
+ ?vt("try get bulk -> "
+ "~n SizeLeft: ~w"
+ "~n Res: ~w", [SizeLeft, Res]),
+ {check_end_of_mibview(NextVarbinds),
+ NextVarbinds, SizeLeft, Res};
+ Res when is_list(Res) ->
+ ?vt("try get bulk -> Res: "
+ "~n ~w", [Res]),
+ {endOfMibView, [], 0, Res}
+ end;
+ {ErrorStatus, Index, _} ->
+ ?vt("try get bulk: "
+ "~n ErrorStatus: ~p"
+ "~n Index: ~p",[ErrorStatus, Index]),
+ {ErrorStatus, Index}
+ end.
+
+%% If all variables in this pass are endOfMibView,
+%% there is no reason to continue.
+check_end_of_mibview([#varbind{value = endOfMibView} | T]) ->
+ check_end_of_mibview(T);
+check_end_of_mibview([]) -> endOfMibView;
+check_end_of_mibview(_) -> noError.
+
+
+%%%--------------------------------------------------
+%%% 6. SET REQUEST
+%%%--------------------------------------------------
+%% return: {ErrStatus, ErrIndex}
+%% where ErrIndex is an index in Varbinds list (not org_index (user-functions
+%% doesn't see org_index)).
+do_set(MibView, UnsortedVarbinds) ->
+ SetModule = get(set_module),
+ ?vtrace("set module: ~p",[SetModule]),
+ apply(SetModule, do_set, [MibView, UnsortedVarbinds]).
+
+do_subagent_set(Arguments) ->
+ SetModule = get(set_module),
+ apply(SetModule, do_subagent_set, [Arguments]).
+
+%%%-----------------------------------------------------------------
+%%% 7. Misc functions
+%%%-----------------------------------------------------------------
+sort_varbindlist(Varbinds) ->
+ snmpa_svbl:sort_varbindlist(get(mibserver), Varbinds).
+
+sa_split(SubagentVarbinds) ->
+ snmpa_svbl:sa_split(SubagentVarbinds).
+
+make_response_pdu(ReqId, ErrStatus, ErrIndex, OrgVarbinds, _ResponseVarbinds)
+ when ErrIndex =/= 0 ->
+ #pdu{type = 'get-response', request_id = ReqId, error_status = ErrStatus,
+ error_index = ErrIndex, varbinds = OrgVarbinds};
+make_response_pdu(ReqId, ErrStatus, ErrIndex, _OrgVarbinds, ResponseVarbinds) ->
+ #pdu{type = 'get-response', request_id = ReqId, error_status = ErrStatus,
+ error_index = ErrIndex, varbinds = ResponseVarbinds}.
+
+%% Valid errormsgs for different operations.
+validate_err(consistency_check, {'EXIT', _Reason}, _) ->
+ {genErr, 0};
+validate_err(consistency_check, X, _) ->
+ X;
+
+validate_err(is_set_ok, noError, _) -> noError;
+validate_err(is_set_ok, noCreation, _) -> noCreation;
+validate_err(is_set_ok, inconsistentValue, _) -> inconsistentValue;
+validate_err(is_set_ok, resourceUnavailable, _) -> resourceUnavailable;
+validate_err(is_set_ok, inconsistentName, _) -> inconsistentName;
+validate_err(is_set_ok, badValue, _) -> badValue;
+validate_err(is_set_ok, wrongValue, _) -> wrongValue;
+validate_err(is_set_ok, noSuchName, _) -> noSuchName;
+validate_err(is_set_ok, noAccess, _) -> noAccess;
+validate_err(is_set_ok, notWritable, _) -> notWritable;
+validate_err(is_set_ok, genErr, _) -> genErr;
+validate_err(is_set_ok, X, Mfa) ->
+ user_err("~w with is_set_ok, returned: ~w. Using genErr.",
+ [Mfa, X]),
+ genErr;
+
+validate_err(set, commitFailed, _) -> commitFailed;
+validate_err(set, undoFailed, _) -> undoFailed;
+validate_err(set, noError, _) -> noError;
+validate_err(set, genErr, _) -> genErr;
+validate_err(set, X, Mfa) ->
+ user_err("~w with set, returned: ~w. Using genErr.",
+ [Mfa, X]),
+ genErr;
+
+validate_err(undo, undoFailed, _) -> undoFailed;
+validate_err(undo, noError, _) -> noError;
+validate_err(undo, genErr, _) -> genErr;
+validate_err(undo, X, Mfa) ->
+ user_err("~w with undo, returned: ~w. Using genErr.",
+ [Mfa, X]),
+ genErr;
+
+validate_err(table_is_set_ok, {Err, Idx}, Mfa) when is_integer(Idx) ->
+ {validate_err(is_set_ok, Err, Mfa), Idx};
+validate_err(table_is_set_ok, X, Mfa) ->
+ user_err("~w with is_set_ok (table), returned: ~w. Using genErr.",
+ [Mfa, X]),
+ {genErr, 0};
+
+validate_err(row_is_set_ok, {Err, Idx}, _) when is_integer(Idx) ->
+ {Err, Idx};
+validate_err(row_is_set_ok, {_Err, {false, BadCol}}, Mfa) ->
+ user_err("~w with is_set_ok (table), returned bad column: "
+ "~w. Using genErr.", [Mfa, BadCol]),
+ {genErr, 0};
+
+validate_err(table_undo, {Err, Idx}, Mfa) when is_integer(Idx) ->
+ {validate_err(undo, Err, Mfa), Idx};
+validate_err(table_undo, X, Mfa) ->
+ user_err("~w with undo (table), returned: ~w. Using genErr.",
+ [Mfa, X]),
+ {genErr, 0};
+
+validate_err(row_undo, {Err, Idx}, _) when is_integer(Idx) ->
+ {Err, Idx};
+validate_err(row_undo, {_Err, {false, BadCol}}, Mfa) ->
+ user_err("~w with undo (table), returned bad column: "
+ "~w. Using genErr.", [Mfa, BadCol]),
+ {genErr, 0};
+
+validate_err(table_set, {Err, Idx}, Mfa) when is_integer(Idx) ->
+ {validate_err(set, Err, Mfa), Idx};
+validate_err(table_set, X, Mfa) ->
+ user_err("~w with set (table), returned: ~w. Using genErr.",
+ [Mfa, X]),
+ {genErr, 0};
+
+validate_err(row_set, {Err, Idx}, _) when is_integer(Idx) ->
+ {Err, Idx};
+validate_err(row_set, {_Err, {false, BadCol}}, Mfa) ->
+ user_err("~w with set (table), returned bad column: "
+ "~w. Using genErr.", [Mfa, BadCol]),
+ {genErr, 0};
+
+validate_err(table_next, {Err, Idx}, _Mfa) when is_integer(Idx) ->
+ {Err, Idx};
+validate_err(table_next, {_Err, {false, BadCol}}, Mfa) ->
+ user_err("~w with get_next, returned bad column: "
+ "~w. Using genErr.", [Mfa, BadCol]),
+ {genErr, 0}.
+
+validate_err(v2_to_v1, {V2Err, Index}) ->
+ {v2err_to_v1err(V2Err), Index};
+validate_err(v2_to_v1, _) ->
+ {genErr, 0}.
+
+get_err({ErrC, ErrI, Vbs}) ->
+ {get_err_i(ErrC), ErrI, Vbs}.
+
+get_err_i(noError) -> noError;
+get_err_i(S) ->
+ ?vtrace("convert '~p' to 'genErr'",[S]),
+ genErr.
+
+v2err_to_v1err(noError) -> noError;
+v2err_to_v1err(noAccess) -> noSuchName;
+v2err_to_v1err(noCreation) -> noSuchName;
+v2err_to_v1err(notWritable) -> noSuchName;
+v2err_to_v1err(wrongLength) -> badValue;
+v2err_to_v1err(wrongEncoding) -> badValue;
+v2err_to_v1err(wrongType) -> badValue;
+v2err_to_v1err(wrongValue) -> badValue;
+v2err_to_v1err(inconsistentValue) -> badValue;
+v2err_to_v1err(inconsistentName) -> noSuchName;
+v2err_to_v1err(noSuchName) -> noSuchName;
+v2err_to_v1err(badValue) -> badValue;
+v2err_to_v1err(authorizationError) -> noSuchName;
+%% genErr | resourceUnavailable | undoFailed | commitFailed -> genErr
+v2err_to_v1err(_Error) -> genErr.
+
+%%-----------------------------------------------------------------
+%% transforms a (hopefully correct) return value ((perhaps) from a
+%% mib-function) to a typed and guaranteed correct return value.
+%% An incorrect return value is transformed to {error, genErr}.
+%% A correct return value is on the form:
+%% {error, <error-msg>} | {value, <variable-type>, <value>}
+%%-----------------------------------------------------------------
+make_value_a_correct_value({value, Val}, Asn1, Mfa)
+ when Asn1#asn1_type.bertype =:= 'INTEGER' ->
+ check_integer(Val, Asn1, Mfa);
+
+make_value_a_correct_value({value, Val}, Asn1, Mfa)
+ when Asn1#asn1_type.bertype =:= 'Counter32' ->
+ check_integer(Val, Asn1, Mfa);
+
+make_value_a_correct_value({value, Val}, Asn1, Mfa)
+ when Asn1#asn1_type.bertype =:= 'Unsigned32' ->
+ check_integer(Val, Asn1, Mfa);
+
+make_value_a_correct_value({value, Val}, Asn1, Mfa)
+ when Asn1#asn1_type.bertype =:= 'TimeTicks' ->
+ check_integer(Val, Asn1, Mfa);
+
+make_value_a_correct_value({value, Val}, Asn1, Mfa)
+ when Asn1#asn1_type.bertype =:= 'Counter64' ->
+ check_integer(Val, Asn1, Mfa);
+
+make_value_a_correct_value({value, Val}, Asn1, Mfa)
+ when (Asn1#asn1_type.bertype =:= 'BITS') andalso is_list(Val) ->
+ {value,Kibbles} = snmp_misc:assq(kibbles,Asn1#asn1_type.assocList),
+ case snmp_misc:bits_to_int(Val,Kibbles) of
+ error ->
+ wrongValue(Val, Mfa);
+ Int ->
+ make_value_a_correct_value({value,Int},Asn1,Mfa)
+ end;
+
+make_value_a_correct_value({value, Val}, Asn1, Mfa)
+ when (Asn1#asn1_type.bertype =:= 'BITS') andalso is_integer(Val) ->
+ {value,Kibbles} = snmp_misc:assq(kibbles,Asn1#asn1_type.assocList),
+ {_Kibble,BitNo} = lists:last(Kibbles),
+ case (1 bsl (BitNo+1)) of
+ X when Val < X ->
+ {value,'BITS',Val};
+ _Big ->
+ wrongValue(Val, Mfa)
+ end;
+
+make_value_a_correct_value({value, String},
+ #asn1_type{bertype = 'OCTET STRING',
+ hi = Hi, lo = Lo}, Mfa) ->
+ check_octet_string(String, Hi, Lo, Mfa, 'OCTET STRING');
+
+make_value_a_correct_value({value, String},
+ #asn1_type{bertype = 'IpAddress',
+ hi = Hi, lo = Lo}, Mfa) ->
+ check_octet_string(String, Hi, Lo, Mfa, 'IpAddress');
+
+make_value_a_correct_value({value, Oid},
+ #asn1_type{bertype = 'OBJECT IDENTIFIER'},
+ _Mfa) ->
+ case snmp_misc:is_oid(Oid) of
+ true -> {value, 'OBJECT IDENTIFIER', Oid};
+ _Else -> {error, wrongType}
+ end;
+
+make_value_a_correct_value({value, Val}, Asn1, _Mfa)
+ when Asn1#asn1_type.bertype =:= 'Opaque' ->
+ if is_list(Val) -> {value, 'Opaque', Val};
+ true -> {error, wrongType}
+ end;
+
+make_value_a_correct_value({noValue, noSuchObject}, _ASN1Type, _Mfa) ->
+ {value, noValue, noSuchObject};
+make_value_a_correct_value({noValue, noSuchInstance}, _ASN1Type, _Mfa) ->
+ {value, noValue, noSuchInstance};
+make_value_a_correct_value({noValue, noSuchName}, _ASN1Type, _Mfa) ->
+ %% Transform this into a v2 value. It is converted to noSuchName
+ %% later if it was v1. If it was v2, we use noSuchInstance.
+ {value, noValue, noSuchInstance};
+%% For backwards compatibility only - we really shouldn't allow this;
+%% it makes no sense to return unSpecified for a variable! But we did
+%% allow it previously. -- We transform unSpecified to noSuchInstance
+%% (OTP-3303).
+make_value_a_correct_value({noValue, unSpecified}, _ASN1Type, _Mfa) ->
+ {value, noValue, noSuchInstance};
+make_value_a_correct_value(genErr, _ASN1Type, _MFA) ->
+ {error, genErr};
+
+make_value_a_correct_value(_WrongVal, _ASN1Type, undef) ->
+ {error, genErr};
+
+make_value_a_correct_value(WrongVal, ASN1Type, Mfa) ->
+ user_err("Got ~w from ~w. (~w) Using genErr",
+ [WrongVal, Mfa, ASN1Type]),
+ {error, genErr}.
+
+check_integer(Val, Asn1, Mfa) ->
+ case Asn1#asn1_type.assocList of
+ undefined -> check_size(Val, Asn1, Mfa);
+ Alist ->
+ case snmp_misc:assq(enums, Alist) of
+ {value, Enums} -> check_enums(Val, Asn1, Enums, Mfa);
+ false -> check_size(Val, Asn1, Mfa)
+ end
+ end.
+
+check_octet_string(String, Hi, Lo, Mfa, Type) ->
+ Len = (catch length(String)), % it might not be a list
+ case snmp_misc:is_string(String) of
+ true when Lo =:= undefined -> {value, Type, String};
+ true when Len =< Hi, Len >= Lo ->
+ {value, Type, String};
+ true ->
+ wrongLength(String, Mfa);
+ _Else ->
+ wrongType(String, Mfa)
+ end.
+
+check_size(Val, #asn1_type{lo = Lo, hi = Hi, bertype = Type}, Mfa)
+ when is_integer(Val) ->
+ ?vtrace("check size of integer: "
+ "~n Value: ~p"
+ "~n Upper limit: ~p"
+ "~n Lower limit: ~p"
+ "~n BER-type: ~p",
+ [Val,Hi,Lo,Type]),
+ if
+ (Lo =:= undefined) andalso (Hi =:= undefined) -> {value, Type, Val};
+ (Lo =:= undefined) andalso is_integer(Hi) andalso (Val =< Hi) ->
+ {value, Type, Val};
+ is_integer(Lo) andalso (Val >= Lo) andalso (Hi =:= undefined) ->
+ {value, Type, Val};
+ is_integer(Lo) andalso is_integer(Hi) andalso (Val >= Lo) andalso (Val =< Hi) ->
+ {value, Type, Val};
+ true ->
+ wrongValue(Val, Mfa)
+ end;
+check_size(Val, _, Mfa) ->
+ wrongType(Val, Mfa).
+
+check_enums(Val, Asn1, Enums, Mfa) ->
+ Association =
+ if
+ is_integer(Val) -> lists:keysearch(Val, 2, Enums);
+ is_atom(Val) -> lists:keysearch(Val, 1, Enums);
+ true -> {error, wrongType}
+ end,
+ case Association of
+ {value, {_AliasIntName, Val2}} ->
+ {value, Asn1#asn1_type.bertype, Val2};
+ false ->
+ wrongValue(Val, Mfa);
+ {error, wrongType} ->
+ wrongType(Val, Mfa)
+ end.
+
+wrongLength(Val, Mfa) ->
+ report_err(Val, Mfa, wrongLength).
+
+wrongValue(Val, Mfa) ->
+ report_err(Val, Mfa, wrongValue).
+
+wrongType(Val, Mfa) ->
+ report_err(Val, Mfa, wrongType).
+
+report_err(_Val, undef, Err) ->
+ {error, Err};
+report_err(Val, Mfa, Err) ->
+ user_err("Got ~p from ~w. Using ~w", [Val, Mfa, Err]),
+ {error, Err}.
+
+is_valid_pdu_type('get-request') -> true;
+is_valid_pdu_type('get-next-request') -> true;
+is_valid_pdu_type('get-bulk-request') -> true;
+is_valid_pdu_type('set-request') -> true;
+is_valid_pdu_type(_) -> false.
+
+get_pdu_data() ->
+ {get(net_if_data),
+ get(snmp_request_id),
+ get(snmp_address),
+ get(snmp_community),
+ get(snmp_context)}.
+
+put_pdu_data({Extra, ReqId, Address, Community, ContextName}) ->
+ {put(net_if_data, Extra),
+ put(snmp_address, Address),
+ put(snmp_request_id, ReqId),
+ put(snmp_community, Community),
+ put(snmp_context, ContextName)}.
+
+tr_var(Oid, Idx) ->
+ case snmp_misc:is_oid(Oid) of
+ true ->
+ {#varbind{oid = Oid, value = unSpecified, org_index = Idx},
+ Idx+1};
+ false -> throw({error, {bad_oid, Oid}})
+ end.
+
+tr_varbind(#varbind{value = Value}) -> Value.
+
+mapfoldl(F, Eas, Accu0, [Hd|Tail]) ->
+ {R,Accu1} = apply(F, [Hd,Accu0|Eas]),
+ {Accu2,Rs} = mapfoldl(F, Eas, Accu1, Tail),
+ {Accu2,[R|Rs]};
+mapfoldl(_F, _Eas, Accu, []) -> {Accu,[]}.
+
+%%-----------------------------------------------------------------
+%% Runtime debugging of the agent.
+%%-----------------------------------------------------------------
+
+dbg_apply(M,F,A) ->
+ case get(verbosity) of
+ silence ->
+ apply(M,F,A);
+ _ ->
+ ?vlog("~n apply: ~w,~w,~p~n", [M,F,A]),
+ Res = (catch apply(M,F,A)),
+ case Res of
+ {'EXIT', Reason} ->
+ ?vinfo("Call to: "
+ "~n Module: ~p"
+ "~n Function: ~p"
+ "~n Args: ~p"
+ "~n"
+ "~nresulted in an exit"
+ "~n"
+ "~n ~p", [M, F, A, Reason]);
+ _ ->
+ ?vlog("~n returned: ~p", [Res])
+ end,
+ Res
+ end.
+
+
+short_name(none) -> ma;
+short_name(_Pid) -> sa.
+
+worker_short_name(ma) -> maw;
+worker_short_name(_) -> saw.
+
+trap_sender_short_name(ma) -> mats;
+trap_sender_short_name(_) -> sats.
+
+pdu_handler_short_name(ma) -> maph;
+pdu_handler_short_name(_) -> saph.
+
+
+mib_server_verbosity(Pid,Verbosity) when is_pid(Pid) ->
+ snmpa_mib:verbosity(Pid,Verbosity);
+mib_server_verbosity(_Pid,_Verbosity) ->
+ ok.
+
+note_store_verbosity(Pid,Verbosity) when is_pid(Pid) ->
+ snmp_note_store:verbosity(Pid,Verbosity);
+note_store_verbosity(_Pid,_Verbosity) ->
+ ok.
+
+subagents_verbosity(V) ->
+ subagents_verbosity(catch snmpa_mib:info(get(mibserver),subagents),V).
+
+subagents_verbosity([],_V) ->
+ ok;
+subagents_verbosity([{Pid,_Oid}|T],V) ->
+ catch verbosity(Pid,V), %% On the agent
+ catch verbosity(Pid,{subagents,V}), %% and it's subagents
+ subagents_verbosity(T,V);
+subagents_verbosity(_,_V) ->
+ ok.
+
+
+%% ---------------------------------------------------------------------
+
+handle_get_log_type(#state{net_if_mod = Mod})
+ when Mod =/= undefined ->
+ case (catch Mod:get_log_type(get(net_if))) of
+ {'EXIT', _} ->
+ {error, not_supported};
+ Else ->
+ Else
+ end;
+handle_get_log_type(_) ->
+ {error, not_supported}.
+
+handle_set_log_type(#state{net_if_mod = Mod}, NewType)
+ when Mod =/= undefined ->
+ case (catch Mod:set_log_type(get(net_if), NewType)) of
+ {'EXIT', _} ->
+ {error, not_supported};
+ Else ->
+ Else
+ end;
+handle_set_log_type(_, _) ->
+ {error, not_supported}.
+
+
+handle_get_request_limit(#state{net_if_mod = Mod})
+ when Mod =/= undefined ->
+ case (catch Mod:get_request_limit(get(net_if))) of
+ {'EXIT', _} ->
+ {error, not_supported};
+ Else ->
+ Else
+ end;
+handle_get_request_limit(_) ->
+ {error, not_supported}.
+
+handle_set_request_limit(#state{net_if_mod = Mod}, NewLimit)
+ when Mod =/= undefined ->
+ case (catch Mod:set_request_limit(get(net_if), NewLimit)) of
+ {'EXIT', _} ->
+ {error, not_supported};
+ Else ->
+ Else
+ end;
+handle_set_request_limit(_, _) ->
+ {error, not_supported}.
+
+
+agent_info(#state{worker = W, set_worker = SW}) ->
+ case (catch get_agent_info(W, SW)) of
+ Info when is_list(Info) ->
+ Info;
+ E ->
+ [{error, E}]
+ end.
+
+get_agent_info(W, SW) ->
+ MASz = proc_mem(self()),
+ WSz = proc_mem(W),
+ SWSz = proc_mem(SW),
+ ATSz = tab_mem(snmp_agent_table),
+ CCSz = tab_mem(snmp_community_cache),
+ VacmSz = tab_mem(snmpa_vacm),
+ [{process_memory, [{master_agent, MASz},
+ {worker, WSz},
+ {set_worker, SWSz}]},
+ {db_memory, [{agent, ATSz},
+ {community_cache, CCSz},
+ {vacm, VacmSz}]}].
+
+proc_mem(P) when is_pid(P) ->
+ case (catch erlang:process_info(P, memory)) of
+ {memory, Sz} when is_integer(Sz) ->
+ Sz;
+ _ ->
+ undefined
+ end;
+proc_mem(_) ->
+ undefined.
+
+tab_mem(T) ->
+ case (catch ets:info(T, memory)) of
+ Sz when is_integer(Sz) ->
+ Sz;
+ _ ->
+ undefined
+ end.
+
+net_if_info(#state{net_if_mod = Mod}) when Mod =/= undefined ->
+ case (catch Mod:info(get(net_if))) of
+ Info when is_list(Info) ->
+ Info;
+ E ->
+ [{error, E}]
+ end;
+net_if_info(_) ->
+ %% This could be a result of a code upgrade
+ %% Make best effert
+ [{process_memory, proc_mem(get(net_if))}].
+
+note_store_info(#state{note_store = NS}) ->
+ case (catch snmp_note_store:info(NS)) of
+ Info when is_list(Info) ->
+ Info;
+ E ->
+ [{error, E}]
+ end.
+
+symbolic_store_info() ->
+ case (catch snmpa_symbolic_store:info()) of
+ Info when is_list(Info) ->
+ Info;
+ E ->
+ [{error, E}]
+ end.
+
+local_db_info() ->
+ case (catch snmpa_local_db:info()) of
+ Info when is_list(Info) ->
+ Info;
+ E ->
+ [{error, E}]
+ end.
+
+mib_server_info() ->
+ case (catch snmpa_mib:info(get(mibserver))) of
+ Info when is_list(Info) ->
+ Info;
+ E ->
+ [{error, E}]
+ end.
+
+get_stats_counters() ->
+ Counters = snmpa_mpd:counters(),
+ get_stats_counters(Counters, []).
+
+get_stats_counters([], Acc) ->
+ lists:reverse(Acc);
+get_stats_counters([Counter|Counters], Acc) ->
+ case ets:lookup(snmp_agent_table, Counter) of
+ [CounterVal] ->
+ get_stats_counters(Counters, [CounterVal|Acc]);
+ _ ->
+ get_stats_counters(Counters, Acc)
+ end.
+
+
+%% ---------------------------------------------------------------------
+
+%% info_msg(F, A) ->
+%% ?snmpa_info(F, A).
+
+warning_msg(F, A) ->
+ ?snmpa_warning(F, A).
+
+error_msg(F, A) ->
+ ?snmpa_error(F, A).
+
+%% ---
+
+config_err(F, A) ->
+ snmpa_error:config_err(F, A).
+
+user_err(F, A) ->
+ snmpa_error:user_err(F, A).
+
+
+%% ---------------------------------------------------------------------
+
+call(Server, Req) ->
+ gen_server:call(Server, Req, infinity).
+
+cast(Server, Msg) ->
+ gen_server:cast(Server, Msg).
+
+
+%% ---------------------------------------------------------------------
+
+get_verbosity(Opts) ->
+ get_option(verbosity, Opts, ?default_verbosity).
+
+get_mibs(Opts) ->
+ get_option(mibs, Opts, []).
+
+get_mib_storage(Opts) ->
+ get_option(mib_storage, Opts, ets).
+
+get_set_mechanism(Opts) ->
+ get_option(set_mechanism, Opts, snmpa_set).
+
+get_authentication_service(Opts) ->
+ get_option(authentication_service, Opts, snmpa_acm).
+
+get_multi_threaded(Opts) ->
+ get_option(multi_threaded, Opts, false).
+
+get_versions(Opts) ->
+ get_option(versions, Opts, [v1,v2,v3]).
+
+get_note_store_opt(Opts) ->
+ get_option(note_store, Opts, []).
+
+get_net_if_opt(Opts) ->
+ get_option(net_if, Opts, []).
+
+get_net_if_verbosity(Opts) ->
+ get_option(verbosity, Opts, silence).
+
+get_net_if_module(Opts) ->
+ get_option(module, Opts, snmpa_net_if).
+
+get_net_if_options(Opts) ->
+ get_option(options, Opts, []).
+
+
+net_if_verbosity(Pid,Verbosity) when is_pid(Pid) ->
+ Pid ! {verbosity,Verbosity};
+net_if_verbosity(_Pid,_Verbosity) ->
+ ok.
+
+
+get_option(Key, Opts, Default) ->
+ snmp_misc:get_option(Key, Opts, Default).
+
+
+%% ---------------------------------------------------------------------
+
+
+%% i(F) ->
+%% i(F, []).
+
+%% i(F, A) ->
+%% io:format("~p: " ++ F ++ "~n", [?MODULE|A]).
+
+
+
diff --git a/lib/snmp/src/agent/snmpa_agent_sup.erl b/lib/snmp/src/agent/snmpa_agent_sup.erl
new file mode 100644
index 0000000000..9b8c4d12a6
--- /dev/null
+++ b/lib/snmp/src/agent/snmpa_agent_sup.erl
@@ -0,0 +1,116 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1997-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%
+%%
+-module(snmpa_agent_sup).
+
+-include("snmp_debug.hrl").
+
+-behaviour(supervisor).
+
+%% External exports
+-export([start_link/0, start_link/1, start_subagent/3, stop_subagent/1]).
+
+%% Internal exports
+-export([init/1]).
+
+-define(SERVER, ?MODULE).
+-ifdef(snmp_debug).
+-define(DEFAULT_OPTS, [{verbosity, trace}]).
+-else.
+-define(DEFAULT_OPTS, []).
+-endif.
+
+
+%%%-----------------------------------------------------------------
+%%% This is a supervisor for the mib processes. Each agent has one
+%%% mib process.
+%%%-----------------------------------------------------------------
+start_link() ->
+ ?d("start_link -> entry", []),
+ supervisor:start_link({local, ?SERVER}, ?MODULE, [[]]).
+
+start_link(AgentSpec) ->
+ ?d("start_link -> entry with"
+ "~n AgentSpec: ~p", [AgentSpec]),
+ supervisor:start_link({local, ?SERVER}, ?MODULE, [[AgentSpec]]).
+
+start_subagent(ParentAgent, Subtree, Mibs) ->
+ ?d("start_subagent -> entry with"
+ "~n ParentAgent: ~p"
+ "~n Subtree: ~p"
+ "~n Mibs: ~p", [ParentAgent, Subtree, Mibs]),
+ Children = supervisor:which_children(?SERVER),
+ ?d("start_subagent -> Children: ~n~p", [Children]),
+ Max = find_max(Children, 1),
+ ?d("start_subagent -> Max: ~p", [Max]),
+ [{_, Prio}] = ets:lookup(snmp_agent_table, priority),
+ ?d("start_subagent -> Prio: ~p", [Prio]),
+ Ref = make_ref(),
+ ?d("start_subagent -> Ref: ~p", [Ref]),
+ Options = [{priority, Prio},
+ {mibs, Mibs},
+ {misc_sup, snmpa_misc_sup} | ?DEFAULT_OPTS],
+ Agent = {{sub_agent, Max},
+ {snmpa_agent, start_link,
+ [Prio, ParentAgent, Ref, Options]},
+ permanent, 2000, worker, [snmpa_agent]},
+ case supervisor:start_child(?SERVER, Agent) of
+ {ok, SA} ->
+ ?d("start_subagent -> SA: ~p", [SA]),
+ snmpa_agent:register_subagent(ParentAgent, Subtree, SA),
+ {ok, SA};
+ Error ->
+ ?d("start_subagent -> Error: ~p", [Error]),
+ Error
+ end.
+
+stop_subagent(SubAgentPid) ->
+ case find_name(supervisor:which_children(?SERVER), SubAgentPid) of
+ undefined ->
+ no_such_child;
+ Name ->
+ supervisor:terminate_child(?SERVER, Name),
+ supervisor:delete_child(?SERVER, Name),
+ ok
+ end.
+
+init([Children]) ->
+ ?d("init -> entry with"
+ "~n Children: ~p", [Children]),
+ %% 20 restarts in ten minutes. If the agent crashes and restarts,
+ %% it may very well crash again, because the management application
+ %% tries to resend the very same request. This depends on the resend
+ %% strategy used by the management application.
+ SupFlags = {one_for_one, 20, 600},
+ {ok, {SupFlags, Children}}.
+
+
+find_max([{{sub_agent, N}, _, _, _} | T], M) when N >= M -> find_max(T, N+1);
+find_max([_|T], M) -> find_max(T, M);
+find_max([], M) -> M.
+
+find_name([{Name, Pid, _, _} | _T], Pid)-> Name;
+find_name([_|T], Pid) -> find_name(T, Pid);
+find_name([], _Pid) -> undefined.
+
+
+% i(F) ->
+% i(F, []).
+
+% i(F, A) ->
+% io:format("~p:~p: " ++ F ++ "~n", [node(),?MODULE|A]).
diff --git a/lib/snmp/src/agent/snmpa_app.erl b/lib/snmp/src/agent/snmpa_app.erl
new file mode 100644
index 0000000000..4e65e8e283
--- /dev/null
+++ b/lib/snmp/src/agent/snmpa_app.erl
@@ -0,0 +1,372 @@
+%%
+%% %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%
+%%
+%%-----------------------------------------------------------------
+%% This module implements the config conversion for the old SNMP
+%% application start method
+%% The purpose is to extract all agent app-env and convert to the
+%% new format
+%%
+%% ---
+%%
+%% What about the restart times for the children
+%% note_store (snmpa_supervisor) and
+%% net_if and mib_server (snmpa_misc_sup)?
+%%
+%%-----------------------------------------------------------------
+
+-module(snmpa_app).
+
+-include("snmp_debug.hrl").
+
+-export([convert_config/0, convert_config/1]).
+
+%% Internal (test)
+-export([start/1]).
+
+
+convert_config() ->
+ ?d("convert_config -> entry", []),
+ convert_config( application:get_all_env(snmp) ).
+
+convert_config(Opts) ->
+ ?d("convert_config -> Opts: ~p", [Opts]),
+ Prio = get_priority(Opts),
+ DbDir = get_db_dir(Opts),
+ DbInitError = terminate,
+ LdbOpts = get_local_db_opts(Opts),
+ MibStorage = get_mib_storage(Opts),
+ MibsOpts = get_mib_server_opts(Opts),
+ SymOpts = get_symbolic_store_opts(Opts),
+ SetModule = get_set_mechanism(Opts),
+ AuthModule = get_authentication_service(Opts),
+ MultiT = get_multi_threaded(Opts),
+ Vsns = get_versions(Opts),
+ SupOpts = get_supervisor_opts(Opts),
+ ErrorReportMod = get_error_report_mod(Opts),
+ AgentType = get_agent_type(Opts),
+ case AgentType of
+ sub ->
+ ?d("convert_config -> agent type: sub",[]),
+ SaVerb = get_sub_agent_verbosity(Opts),
+ [{agent_type, AgentType},
+ {agent_verbosity, SaVerb},
+ {set_mechanism, SetModule},
+ {authentication_service, AuthModule},
+ {priority, Prio},
+ {versions, Vsns},
+ {db_dir, DbDir},
+ {db_init_error, DbInitError},
+ {multi_threaded, MultiT},
+ {error_report_mod, ErrorReportMod},
+ {mib_storage, MibStorage},
+ {mib_server, MibsOpts},
+ {local_db, LdbOpts},
+ {supervisor, SupOpts},
+ {symbolic_store, SymOpts}];
+
+ master ->
+ ?d("convert_config -> agent type: master",[]),
+ MaVerb = get_master_agent_verbosity(Opts),
+ NoteOpts = get_note_store_opts(Opts),
+ NiOptions = get_net_if_options(Opts),
+ NiOpts = [{options, NiOptions}|get_net_if_opts(Opts)],
+ AtlOpts = get_audit_trail_log_opts(Opts),
+ Mibs = get_master_agent_mibs(Opts),
+ ForceLoad = get_force_config_load(Opts),
+ ConfVerb = get_opt(verbosity, SupOpts, silence),
+ ConfDir = get_config_dir(Opts),
+ ConfOpts = [{dir, ConfDir},
+ {force_load, ForceLoad},
+ {verbosity, ConfVerb}],
+ [{agent_type, AgentType},
+ {agent_verbosity, MaVerb},
+ {set_mechanism, SetModule},
+ {authentication_service, AuthModule},
+ {db_dir, DbDir},
+ {db_init_error, DbInitError},
+ {config, ConfOpts},
+ {priority, Prio},
+ {versions, Vsns},
+ {multi_threaded, MultiT},
+ {error_report_mod, ErrorReportMod},
+ {supervisor, SupOpts},
+ {mibs, Mibs},
+ {mib_storage, MibStorage},
+ {symbolic_store, SymOpts},
+ {note_store, NoteOpts},
+ {net_if, NiOpts},
+ {mib_server, MibsOpts},
+ {local_db, LdbOpts}] ++ AtlOpts
+ end.
+
+
+start(Type) ->
+ snmp_app_sup:start_agent(Type, convert_config()).
+
+
+%% ------------------------------------------------------------------
+
+get_db_dir(Opts) ->
+ case get_opt(snmp_db_dir, Opts) of
+ {value, Dir} when is_list(Dir) ->
+ Dir;
+ {value, Bad} ->
+ exit({bad_config, {db_dir, Bad}});
+ false ->
+ exit({undefined_config, db_dir})
+ end.
+
+
+%% --
+
+get_priority(Opts) ->
+ case get_opt(snmp_priority, Opts) of
+ {value, Prio} when is_atom(Prio) ->
+ Prio;
+ _ ->
+ normal
+ end.
+
+
+%% --
+
+get_mib_storage(Opts) ->
+ get_opt(snmp_mib_storage, Opts, ets).
+
+get_mib_server_opts(Opts) ->
+ Options = [{snmp_mibserver_verbosity, verbosity, silence},
+ {mibentry_override, mibentry_override, false},
+ {trapentry_override, trapentry_override, false}],
+ get_opts(Options, Opts, []).
+
+
+%% --
+
+get_audit_trail_log_opts(Opts) ->
+ case get_audit_trail_log(Opts) of
+ false ->
+ [];
+ Type ->
+ Dir = get_audit_trail_log_dir(Opts),
+ Size = get_audit_trail_log_size(Opts),
+ AtlOpts0 = [{type, Type},
+ {dir, Dir},
+ {size, Size},
+ {repair, true}],
+ [{audit_trail_log, AtlOpts0}]
+ end.
+
+
+get_audit_trail_log(Opts) ->
+ case get_opt(audit_trail_log, Opts) of
+ {value, write_log} -> write;
+ {value, read_log} -> read;
+ {value, read_write_log} -> read_write;
+ _ -> false
+ end.
+
+get_audit_trail_log_dir(Opts) ->
+ case get_opt(audit_trail_log_dir, Opts) of
+ {value, Dir} when is_list(Dir) ->
+ Dir;
+ {value, Bad} ->
+ exit({bad_config, {audit_trail_log_dir, Bad}});
+ _ ->
+ exit({undefined_config, audit_trail_log_dir})
+ end.
+
+get_audit_trail_log_size(Opts) ->
+ case get_opt(audit_trail_log_size, Opts) of
+ {value, {MB, MF} = Sz} when is_integer(MB) andalso is_integer(MF) ->
+ Sz;
+ {value, Bad} ->
+ exit({bad_config, {audit_trail_log_size, Bad}});
+ _ ->
+ exit({undefined_config, audit_trail_log_size})
+ end.
+
+
+%% --
+
+get_master_agent_verbosity(Opts) ->
+ get_opt(snmp_master_agent_verbosity, Opts, silence).
+
+
+%% --
+
+get_sub_agent_verbosity(Opts) ->
+ get_opt(snmp_subagent_verbosity, Opts, silence).
+
+
+%% --
+
+get_supervisor_opts(Opts) ->
+ Options = [{snmp_supervisor_verbosity, verbosity, silence}],
+ get_opts(Options, Opts, []).
+
+
+%% --
+
+get_symbolic_store_opts(Opts) ->
+ Options = [{snmp_symbolic_store_verbosity, verbosity, silence}],
+ get_opts(Options, Opts, []).
+
+
+%% --
+
+get_note_store_opts(Opts) ->
+ Options = [{snmp_note_store_verbosity, verbosity, silence}],
+ get_opts(Options, Opts, []).
+
+
+%% --
+
+get_local_db_opts(Opts) ->
+ Options = [{snmp_local_db_auto_repair, repair, true},
+ {snmp_local_db_verbosity, verbosity, silence}],
+ get_opts(Options, Opts, []).
+
+
+%% --
+
+get_multi_threaded(Opts) ->
+ case get_opt(snmp_multi_threaded, Opts) of
+ {value, true} ->
+ true;
+ {value, false} ->
+ false;
+ _ ->
+ false
+ end.
+
+get_versions(Opts) ->
+ F = fun(Ver) ->
+ case get_opt(Ver, Opts) of
+ {value, true} ->
+ [Ver];
+ {value, false} ->
+ [];
+ _ ->
+ [Ver] % Default is true
+ end
+ end,
+ V1 = F(v1),
+ V2 = F(v2),
+ V3 = F(v3),
+ V1 ++ V2 ++ V3.
+
+get_set_mechanism(Opts) ->
+ get_opt(set_mechanism, Opts, snmpa_set).
+
+get_authentication_service(Opts) ->
+ get_opt(authentication_service, Opts, snmpa_acm).
+
+get_error_report_mod(Opts) ->
+ get_opt(snmp_error_report_mod, Opts, snmpa_error_logger).
+
+
+%% --
+
+get_net_if_opts(Opts) ->
+ Options = [{snmp_net_if_module, module, snmpa_net_if},
+ {snmp_net_if_verbosity, verbosity, silence}],
+ get_opts(Options, Opts, []).
+
+get_net_if_options(Opts) ->
+ Options = [recbuf,
+ {req_limit, req_limit, infinity},
+ {bind_to_ip_address, bind_to, false},
+ {no_reuse_address, no_reuse, false}],
+ get_opts(Options, Opts, []).
+
+
+%% --
+
+get_agent_type(Opts) ->
+ get_opt(snmp_agent_type, Opts, master).
+
+
+%% --
+
+get_config_dir(Opts) ->
+ case get_opt(snmp_config_dir, Opts) of
+ {value, Dir} when is_list(Dir) -> Dir;
+ {value, Bad} ->
+ exit({bad_config, {config_dir, Bad}});
+ _ ->
+ exit({undefined_config, config_dir})
+ end.
+
+get_master_agent_mibs(Opts) ->
+ get_opt(snmp_master_agent_mibs, Opts, []).
+
+get_force_config_load(Opts) ->
+ case get_opt(force_config_load, Opts) of
+ {value, true} -> true;
+ {value, false} -> false;
+ _ -> false
+ end.
+
+
+%% --
+
+get_opts([], _Options, Opts) ->
+ Opts;
+get_opts([{Key1, Key2, Def}|KeyVals], Options, Opts) ->
+ %% If not found among Options, then use default value
+ case lists:keysearch(Key1, 1, Options) of
+ {value, {Key1, Val}} ->
+ get_opts(KeyVals, Options, [{Key2, Val}|Opts]);
+ false ->
+ get_opts(KeyVals, Options, [{Key2, Def}|Opts])
+ end;
+get_opts([Key|KeyVals], Options, Opts) ->
+ %% If not found among Options, then ignore
+ case lists:keysearch(Key, 1, Options) of
+ {value, KeyVal} ->
+ get_opts(KeyVals, Options, [KeyVal|Opts]);
+ false ->
+ get_opts(KeyVals, Options, Opts)
+ end.
+
+
+%% --
+
+
+get_opt(Key, Opts, Def) ->
+ case get_opt(Key, Opts) of
+ {value, Val} ->
+ Val;
+ false ->
+ Def
+ end.
+
+get_opt(Key, Opts) ->
+ case lists:keysearch(Key, 1, Opts) of
+ {value, {_, Val}} ->
+ {value, Val};
+ false ->
+ false
+ end.
+
+% i(F) ->
+% i(F, []).
+
+% i(F, A) ->
+% io:format("~p: " ++ F ++ "~n", [?MODULE|A]).
diff --git a/lib/snmp/src/agent/snmpa_atl.hrl b/lib/snmp/src/agent/snmpa_atl.hrl
new file mode 100644
index 0000000000..ec6beb3542
--- /dev/null
+++ b/lib/snmp/src/agent/snmpa_atl.hrl
@@ -0,0 +1,21 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2004-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%
+%%
+
+-define(audit_trail_log_name, "snmpa_log").
+-define(audit_trail_log_file, "snmpa.log").
diff --git a/lib/snmp/src/agent/snmpa_authentication_service.erl b/lib/snmp/src/agent/snmpa_authentication_service.erl
new file mode 100644
index 0000000000..572fab7fbf
--- /dev/null
+++ b/lib/snmp/src/agent/snmpa_authentication_service.erl
@@ -0,0 +1,57 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2004-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%
+%%
+-module(snmpa_authentication_service).
+
+-export([behaviour_info/1]).
+
+behaviour_info(callbacks) ->
+ [{init_check_access, 2}];
+behaviour_info(_) ->
+ undefined.
+
+
+%%-----------------------------------------------------------------
+%% init_check_access(Pdu, ACMData)
+%% Pdu = #pdu
+%% ACMData = acm_data() = {community, Community, Address} |
+%% {v3, MsgID, SecModel, SecName, SecLevel,
+%% ContextEngineID, ContextName, SecData}
+%% Community = string()
+%% Address = ip() ++ udp() (list)
+%% MsgID = integer() <not used>
+%% SecModel = ?SEC_* (see snmp_types.hrl)
+%% SecName = string()
+%% SecLevel = ?'SnmpSecurityLevel_*' (see SNMP-FRAMEWORK-MIB.hrl)
+%% ContextEngineID = string() <not used>
+%% ContextName = string()
+%% SecData = <not used>
+%% Variable = snmpInBadCommunityNames |
+%% snmpInBadCommunityUses |
+%% snmpInASNParseErrs
+%% Reason = snmp_message_decoding |
+%% {bad_community_name, Address, Community}} |
+%% {invalid_access, Access, Op}
+%%
+%% Purpose: Called once for each Pdu. Returns a MibView
+%% which is later used for each variable in the pdu.
+%% The authenticationFailure trap is sent (maybe) when the auth.
+%% procedure evaluates to unauthentic,
+%%
+%% NOTE: This function is executed in the Master agents's context
+%%-----------------------------------------------------------------
diff --git a/lib/snmp/src/agent/snmpa_conf.erl b/lib/snmp/src/agent/snmpa_conf.erl
new file mode 100644
index 0000000000..b14a0c806c
--- /dev/null
+++ b/lib/snmp/src/agent/snmpa_conf.erl
@@ -0,0 +1,937 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2006-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%
+%%
+
+-module(snmpa_conf).
+
+-export([
+ %% agent.conf
+ agent_entry/2,
+ write_agent_config/2, write_agent_config/3,
+ append_agent_config/2,
+ read_agent_config/1,
+
+ %% context.conf
+ context_entry/1,
+ write_context_config/2, write_context_config/3,
+ append_context_config/2,
+ read_context_config/1,
+
+ %% community.conf
+ community_entry/1, community_entry/5,
+ write_community_config/2, write_community_config/3,
+ append_community_config/2,
+ read_community_config/1,
+
+ %% standard.conf
+ standard_entry/2,
+ write_standard_config/2, write_standard_config/3,
+ append_standard_config/2,
+ read_standard_config/1,
+
+ %% target_addr.conf
+ target_addr_entry/5, target_addr_entry/6,
+ target_addr_entry/8, target_addr_entry/10,
+ write_target_addr_config/2, write_target_addr_config/3,
+ append_target_addr_config/2,
+ read_target_addr_config/1,
+
+ %% target_params.conf
+ target_params_entry/2, target_params_entry/4, target_params_entry/5,
+ write_target_params_config/2, write_target_params_config/3,
+ append_target_params_config/2,
+ read_target_params_config/1,
+
+ %% xyz.conf
+ notify_entry/3,
+ write_notify_config/2, write_notify_config/3,
+ append_notify_config/2,
+ read_notify_config/1,
+
+ %% xyz.conf
+ usm_entry/1, usm_entry/13,
+ write_usm_config/2, write_usm_config/3,
+ append_usm_config/2,
+ read_usm_config/1,
+
+ %% xyz.conf
+ vacm_s2g_entry/3,
+ vacm_acc_entry/8,
+ vacm_vtf_entry/2, vacm_vtf_entry/4,
+ write_vacm_config/2, write_vacm_config/3,
+ append_vacm_config/2,
+ read_vacm_config/1
+ ]).
+
+
+
+%%
+%% ------ agent.conf ------
+%%
+
+agent_entry(Tag, Val) ->
+ {Tag, Val}.
+
+
+write_agent_config(Dir, Conf) ->
+ Comment =
+"%% This file defines the Agent local configuration info\n"
+"%% The data is inserted into the snmpEngine* variables defined\n"
+"%% in SNMP-FRAMEWORK-MIB, and the intAgent* variables defined\n"
+"%% in OTP-SNMPEA-MIB.\n"
+"%% Each row is a 2-tuple:\n"
+"%% {AgentVariable, Value}.\n"
+"%% For example\n"
+"%% {intAgentUDPPort, 4000}.\n"
+"%% The ip address for the agent is sent as id in traps.\n"
+"%% {intAgentIpAddress, [127,42,17,5]}.\n"
+"%% {snmpEngineID, \"agentEngine\"}.\n"
+"%% {snmpEngineMaxMessageSize, 484}.\n"
+"%%\n\n",
+ Hdr = header() ++ Comment,
+ write_agent_config(Dir, Hdr, Conf).
+
+write_agent_config(Dir, Hdr, Conf)
+ when is_list(Dir) and is_list(Hdr) and is_list(Conf) ->
+ Verify = fun() -> verify_agent_conf(Conf) end,
+ Write = fun(Fd) -> write_agent_conf(Fd, Hdr, Conf) end,
+ write_config_file(Dir, "agent.conf", Verify, Write).
+
+
+append_agent_config(Dir, Conf)
+ when is_list(Dir) and is_list(Conf) ->
+ Verify = fun() -> verify_agent_conf(Conf) end,
+ Write = fun(Fd) -> write_agent_conf(Fd, Conf) end,
+ append_config_file(Dir, "agent.conf", Verify, Write).
+
+
+read_agent_config(Dir) ->
+ Verify = fun(Entry) -> verify_agent_conf_entry(Entry) end,
+ read_config_file(Dir, "agent.conf", Verify).
+
+
+verify_agent_conf([]) ->
+ ok;
+verify_agent_conf([H|T]) ->
+ verify_agent_conf_entry(H),
+ verify_agent_conf(T);
+verify_agent_conf(X) ->
+ error({bad_agent_config, X}).
+
+verify_agent_conf_entry(Entry) ->
+ ok = snmp_framework_mib:check_agent(Entry),
+ ok.
+
+write_agent_conf(Fd, "", Conf) ->
+ write_agent_conf(Fd, Conf);
+write_agent_conf(Fd, Hdr, Conf) ->
+ io:format(Fd, "~s~n", [Hdr]),
+ write_agent_conf(Fd, Conf).
+
+write_agent_conf(_Fd, []) ->
+ ok;
+write_agent_conf(Fd, [H|T]) ->
+ do_write_agent_conf(Fd, H),
+ write_agent_conf(Fd, T).
+
+do_write_agent_conf(Fd, {intAgentIpAddress = Tag, Val}) ->
+ io:format(Fd, "{~w, ~w}.~n", [Tag, Val]);
+do_write_agent_conf(Fd, {intAgentUDPPort = Tag, Val} ) ->
+ io:format(Fd, "{~w, ~w}.~n", [Tag, Val]);
+do_write_agent_conf(Fd, {intAgentMaxPacketSize = Tag, Val} ) ->
+ io:format(Fd, "{~w, ~w}.~n", [Tag, Val]);
+do_write_agent_conf(Fd, {snmpEngineMaxMessageSize = Tag, Val} ) ->
+ io:format(Fd, "{~w, ~w}.~n", [Tag, Val]);
+do_write_agent_conf(Fd, {snmpEngineID = Tag, Val} ) ->
+ io:format(Fd, "{~w, \"~s\"}.~n", [Tag, Val]);
+do_write_agent_conf(_Fd, Crap) ->
+ error({bad_agent_config, Crap}).
+
+
+%%
+%% ------ context.conf ------
+%%
+
+context_entry(Ctx) ->
+ Ctx.
+
+
+write_context_config(Dir, Conf) ->
+ Comment =
+"%% This file defines the contexts known to the agent.\n"
+"%% The data is inserted into the vacmContextTable defined\n"
+"%% in SNMP-VIEW-BASED-ACM-MIB.\n"
+"%% Each row is a string:\n"
+"%% ContextName.\n"
+"%%\n"
+"%% The empty string is the default context.\n"
+"%% For example\n"
+"%% \"bridge1\".\n"
+"%% \"bridge2\".\n"
+"%%\n\n",
+ Hdr = header() ++ Comment,
+ write_context_config(Dir, Hdr, Conf).
+
+write_context_config(Dir, Hdr, Conf)
+ when is_list(Dir) and is_list(Hdr) and is_list(Conf) ->
+ Verify = fun() -> verify_context_conf(Conf) end,
+ Write = fun(Fd) -> write_context_conf(Fd, Hdr, Conf) end,
+ write_config_file(Dir, "context.conf", Verify, Write).
+
+
+append_context_config(Dir, Conf)
+ when is_list(Dir) and is_list(Conf) ->
+ Verify = fun() -> verify_context_conf(Conf) end,
+ Write = fun(Fd) -> write_context_conf(Fd, Conf) end,
+ append_config_file(Dir, "context.conf", Verify, Write).
+
+
+read_context_config(Dir) ->
+ Verify = fun(Entry) -> verify_context_conf_entry(Entry) end,
+ read_config_file(Dir, "context.conf", Verify).
+
+
+verify_context_conf([]) ->
+ ok;
+verify_context_conf([H|T]) ->
+ verify_context_conf_entry(H),
+ verify_context_conf(T);
+verify_context_conf(X) ->
+ error({error_context_config, X}).
+
+verify_context_conf_entry(Context) ->
+ {ok, _} = snmp_framework_mib:check_context(Context),
+ ok.
+
+write_context_conf(Fd, "", Conf) ->
+ write_context_conf(Fd, Conf);
+write_context_conf(Fd, Hdr, Conf) ->
+ io:format(Fd, "~s~n", [Hdr]),
+ write_context_conf(Fd, Conf).
+
+write_context_conf(_Fd, []) ->
+ ok;
+write_context_conf(Fd, [H|T]) when is_list(H) ->
+ io:format(Fd, "\"~s\".~n", [H]),
+ write_context_conf(Fd, T);
+write_context_conf(_Fd, X) ->
+ error({invalid_context_config, X}).
+
+
+%%
+%% ------ community.conf ------
+%%
+
+community_entry(CommIndex) when CommIndex == "public" ->
+ CommName = CommIndex,
+ SecName = "initial",
+ CtxName = "",
+ TransportTag = "",
+ community_entry(CommIndex, CommName, SecName, CtxName, TransportTag);
+community_entry(CommIndex) when CommIndex == "all-rights" ->
+ CommName = CommIndex,
+ SecName = CommIndex,
+ CtxName = "",
+ TransportTag = "",
+ community_entry(CommIndex, CommName, SecName, CtxName, TransportTag).
+
+community_entry(CommIndex, CommName, SecName, CtxName, TransportTag) ->
+ {CommIndex, CommName, SecName, CtxName, TransportTag}.
+
+
+write_community_config(Dir, Conf) ->
+ Comment =
+"%% This file defines the community info which maps to VACM parameters.\n"
+"%% The data is inserted into the snmpCommunityTable defined\n"
+"%% in SNMP-COMMUNITY-MIB.\n"
+"%% Each row is a 5-tuple:\n"
+"%% {CommunityIndex, CommunityName, SecurityName, ContextName, TransportTag}.\n"
+"%% For example\n"
+"%% {\"1\", \"public\", \"initial\", \"\", \"\"}.\n"
+"%% {\"2\", \"secret\", \"secret_name\", \"\", \"tag\"}.\n"
+"%% {\"3\", \"bridge1\", \"initial\", \"bridge1\", \"\"}.\n"
+"%%\n\n",
+ Hdr = header() ++ Comment,
+ write_community_config(Dir, Hdr, Conf).
+
+write_community_config(Dir, Hdr, Conf)
+ when is_list(Dir) and is_list(Hdr) and is_list(Conf) ->
+ Verify = fun() -> verify_community_conf(Conf) end,
+ Write = fun(Fd) -> write_community_conf(Fd, Hdr, Conf) end,
+ write_config_file(Dir, "community.conf", Verify, Write).
+
+
+append_community_config(Dir, Conf)
+ when is_list(Dir) and is_list(Conf) ->
+ Verify = fun() -> verify_community_conf(Conf) end,
+ Write = fun(Fd) -> write_community_conf(Fd, Conf) end,
+ append_config_file(Dir, "community.conf", Verify, Write).
+
+
+read_community_config(Dir) ->
+ Verify = fun(Entry) -> verify_community_conf_entry(Entry) end,
+ read_config_file(Dir, "community.conf", Verify).
+
+
+verify_community_conf([]) ->
+ ok;
+verify_community_conf([H|T]) ->
+ verify_community_conf_entry(H),
+ verify_community_conf(T);
+verify_community_conf(X) ->
+ error({invalid_community_config, X}).
+
+verify_community_conf_entry(Context) ->
+ {ok, _} = snmp_community_mib:check_community(Context),
+ ok.
+
+write_community_conf(Fd, "", Conf) ->
+ write_community_conf(Fd, Conf);
+write_community_conf(Fd, Hdr, Conf) ->
+ io:format(Fd, "~s~n", [Hdr]),
+ write_community_conf(Fd, Conf).
+
+write_community_conf(Fd, Conf) ->
+ Fun = fun({Idx, Name, SecName, CtxName, TranspTag}) ->
+ io:format(Fd, "{\"~s\", \"~s\", \"~s\", \"~s\", \"~s\"}.~n",
+ [Idx, Name, SecName, CtxName, TranspTag]);
+ (Crap) ->
+ error({bad_community_config, Crap})
+ end,
+ lists:foreach(Fun, Conf).
+
+
+%%
+%% ------ standard.conf ------
+%%
+
+standard_entry(Tag, Val) ->
+ {Tag, Val}.
+
+
+write_standard_config(Dir, Conf) ->
+ Comment =
+"%% This file defines the STANDARD-MIB info.\n"
+"%% Each row is a 2-tuple:\n"
+"%% {StandardVariable, Value}.\n"
+"%% For example\n"
+"%% {sysDescr, \"Erlang SNMP agent\"}.\n"
+"%% {sysObjectID, [1,2,3]}.\n"
+"%% {sysContact, \"{mbj,eklas}@erlang.ericsson.se\"}.\n"
+"%% {sysName, \"test\"}.\n"
+"%% {sysLocation, \"erlang\"}.\n"
+"%% {sysServices, 72}.\n"
+"%% {snmpEnableAuthenTraps, enabled}.\n"
+"%%\n\n",
+ Hdr = header() ++ Comment,
+ write_standard_config(Dir, Hdr, Conf).
+
+write_standard_config(Dir, Hdr, Conf)
+ when is_list(Dir) and is_list(Hdr) and is_list(Conf) ->
+ Verify = fun() -> verify_standard_conf(Conf) end,
+ Write = fun(Fd) -> write_standard_conf(Fd, Hdr, Conf) end,
+ write_config_file(Dir, "standard.conf", Verify, Write).
+
+
+append_standard_config(Dir, Conf)
+ when is_list(Dir) and is_list(Conf) ->
+ Verify = fun() -> verify_standard_conf(Conf) end,
+ Write = fun(Fd) -> write_standard_conf(Fd, Conf) end,
+ append_config_file(Dir, "standard.conf", Verify, Write).
+
+
+read_standard_config(Dir) ->
+ Verify = fun(Entry) -> verify_standard_conf_entry(Entry) end,
+ read_config_file(Dir, "standard.conf", Verify).
+
+
+verify_standard_conf([]) ->
+ ok;
+verify_standard_conf([H|T]) ->
+ verify_standard_conf_entry(H),
+ verify_standard_conf(T);
+verify_standard_conf(X) ->
+ error({bad_standard_config, X}).
+
+verify_standard_conf_entry(Std) ->
+ case snmp_standard_mib:check_standard(Std) of
+ ok ->
+ ok;
+ {ok, _} ->
+ ok
+ end.
+
+write_standard_conf(Fd, "", Conf) ->
+ write_standard_conf(Fd, Conf);
+write_standard_conf(Fd, Hdr, Conf) ->
+ io:format(Fd, "~s~n", [Hdr]),
+ write_standard_conf(Fd, Conf).
+
+write_standard_conf(Fd, Conf) ->
+ Fun = fun({Tag, Val}) -> do_write_standard_conf(Fd, Tag, Val) end,
+ lists:foreach(Fun, Conf).
+
+do_write_standard_conf(Fd, sysDescr = Tag, Val) ->
+ io:format(Fd, "{~w, \"~s\"}.~n", [Tag, Val]);
+do_write_standard_conf(Fd, sysObjectID = Tag, Val) ->
+ io:format(Fd, "{~w, ~w}.~n", [Tag, Val]);
+do_write_standard_conf(Fd, sysContact = Tag, Val) ->
+ io:format(Fd, "{~w, \"~s\"}.~n", [Tag, Val]);
+do_write_standard_conf(Fd, sysName = Tag, Val) ->
+ io:format(Fd, "{~w, \"~s\"}.~n", [Tag, Val]);
+do_write_standard_conf(Fd, sysLocation = Tag, Val) ->
+ io:format(Fd, "{~w, \"~s\"}.~n", [Tag, Val]);
+do_write_standard_conf(Fd, sysServices = Tag, Val) ->
+ io:format(Fd, "{~w, ~w}.~n", [Tag, Val]);
+do_write_standard_conf(Fd, snmpEnableAuthenTraps = Tag, Val) ->
+ io:format(Fd, "{~w, ~w}.~n", [Tag, Val]);
+do_write_standard_conf(_Fd, Tag, Val) ->
+ error({bad_standard_config, {Tag, Val}}).
+
+
+%%
+%% ------ target_addr.conf ------
+%%
+
+target_addr_entry(Name,
+ Ip,
+ TagList,
+ ParamsName,
+ EngineId) ->
+ target_addr_entry(Name, Ip, TagList, ParamsName, EngineId, []).
+
+target_addr_entry(Name,
+ Ip,
+ TagList,
+ ParamsName,
+ EngineId,
+ TMask) ->
+ target_addr_entry(Name, Ip, 162, TagList,
+ ParamsName, EngineId, TMask, 2048).
+
+target_addr_entry(Name,
+ Ip,
+ Udp,
+ TagList,
+ ParamsName,
+ EngineId,
+ TMask,
+ MaxMessageSize) ->
+ target_addr_entry(Name, Ip, Udp, 1500, 3, TagList,
+ ParamsName, EngineId, TMask, MaxMessageSize).
+
+target_addr_entry(Name,
+ Ip,
+ Udp,
+ Timeout,
+ RetryCount,
+ TagList,
+ ParamsName,
+ EngineId,
+ TMask,
+ MaxMessageSize) ->
+ {Name,
+ Ip,
+ Udp,
+ Timeout,
+ RetryCount,
+ TagList,
+ ParamsName,
+ EngineId,
+ TMask,
+ MaxMessageSize}.
+
+
+write_target_addr_config(Dir, Conf) ->
+ Comment =
+"%% This file defines the target address parameters.\n"
+"%% The data is inserted into the snmpTargetAddrTable defined\n"
+"%% in SNMP-TARGET-MIB, and in the snmpTargetAddrExtTable defined\n"
+"%% in SNMP-COMMUNITY-MIB.\n"
+"%% Each row is a 10-tuple:\n"
+"%% {Name, Ip, Udp, Timeout, RetryCount, TagList, ParamsName, EngineId,\n"
+"%% TMask, MaxMessageSize}.\n"
+"%% The EngineId value is only used if Inform-Requests are sent to this\n"
+"%% target. If Informs are not sent, this value is ignored, and can be\n"
+"%% e.g. an empty string. However, if Informs are sent, it is essential\n"
+"%% that the value of EngineId matches the value of the target's\n"
+"%% actual snmpEngineID.\n"
+"%% For example\n"
+"%% {\"1.2.3.4 v1\", [1,2,3,4], 162, \n"
+"%% 1500, 3, \"std_inform\", \"otp_v2\", \"\",\n"
+"%% [127,0,0,0], 2048}.\n"
+"%%\n\n",
+ Hdr = header() ++ Comment,
+ write_target_addr_config(Dir, Hdr, Conf).
+
+write_target_addr_config(Dir, Hdr, Conf)
+ when is_list(Dir) and is_list(Hdr) and is_list(Conf) ->
+ Verify = fun() -> verify_target_addr_conf(Conf) end,
+ Write = fun(Fd) -> write_target_addr_conf(Fd, Hdr, Conf) end,
+ write_config_file(Dir, "target_addr.conf", Verify, Write).
+
+
+
+append_target_addr_config(Dir, Conf)
+ when is_list(Dir) and is_list(Conf) ->
+ Verify = fun() -> verify_target_addr_conf(Conf) end,
+ Write = fun(Fd) -> write_target_addr_conf(Fd, Conf) end,
+ append_config_file(Dir, "target_addr.conf", Verify, Write).
+
+
+read_target_addr_config(Dir) ->
+ Verify = fun(Entry) -> verify_target_addr_conf_entry(Entry) end,
+ read_config_file(Dir, "target_addr.conf", Verify).
+
+
+verify_target_addr_conf([]) ->
+ ok;
+verify_target_addr_conf([H|T]) ->
+ verify_target_addr_conf_entry(H),
+ verify_target_addr_conf(T);
+verify_target_addr_conf(X) ->
+ error({bad_target_addr_config, X}).
+
+verify_target_addr_conf_entry(Entry) ->
+ {ok, _} = snmp_target_mib:check_target_addr(Entry),
+ ok.
+
+write_target_addr_conf(Fd, "", Conf) ->
+ write_target_addr_conf(Fd, Conf);
+write_target_addr_conf(Fd, Hdr, Conf) ->
+ io:format(Fd, "~s~n", [Hdr]),
+ write_target_addr_conf(Fd, Conf).
+
+write_target_addr_conf(Fd, Conf) ->
+ Fun = fun(Entry) -> do_write_target_addr_conf(Fd, Entry) end,
+ lists:foreach(Fun, Conf).
+
+do_write_target_addr_conf(Fd,
+ {Name, Ip, Udp,
+ Timeout, RetryCount, TagList,
+ ParamsName, EngineId,
+ TMask, MaxMessageSize}) ->
+ io:format(Fd,
+ "{\"~s\", ~w, ~w, ~w, ~w, \"~s\", \"~s\", \"~s\", ~w, ~w}.~n",
+ [Name, Ip, Udp, Timeout, RetryCount, TagList,
+ ParamsName, EngineId, TMask, MaxMessageSize]);
+do_write_target_addr_conf(_Fd, Crap) ->
+ error({bad_target_addr_config, Crap}).
+
+
+%%
+%% ------ target_params.conf ------
+%%
+
+target_params_entry(Name, Vsn) ->
+ SecName = "initial",
+ SecLevel = noAuthNoPriv,
+ target_params_entry(Name, Vsn, SecName, SecLevel).
+
+target_params_entry(Name, Vsn, SecName, SecLevel) ->
+ MPModel = if Vsn == v1 -> v1;
+ Vsn == v2 -> v2c;
+ Vsn == v3 -> v3
+ end,
+ SecModel = if Vsn == v1 -> v1;
+ Vsn == v2 -> v2c;
+ Vsn == v3 -> usm
+ end,
+ target_params_entry(Name, MPModel, SecModel, SecName, SecLevel).
+
+target_params_entry(Name, MPModel, SecModel, SecName, SecLevel) ->
+ {Name, MPModel, SecModel, SecName, SecLevel}.
+
+
+write_target_params_config(Dir, Conf) ->
+ Comment =
+"%% This file defines the target parameters.\n"
+"%% The data is inserted into the snmpTargetParamsTable defined\n"
+"%% in SNMP-TARGET-MIB.\n"
+"%% Each row is a 5-tuple:\n"
+"%% {Name, MPModel, SecurityModel, SecurityName, SecurityLevel}.\n"
+"%% For example\n"
+"%% {\"target_v3\", v3, usm, \"\", noAuthNoPriv}.\n"
+"%%\n\n",
+ Hdr = header() ++ Comment,
+ write_target_params_config(Dir, Hdr, Conf).
+
+write_target_params_config(Dir, Hdr, Conf)
+ when is_list(Dir) and is_list(Hdr) and is_list(Conf) ->
+ Verify = fun() -> verify_target_params_conf(Conf) end,
+ Write = fun(Fd) -> write_target_params_conf(Fd, Hdr, Conf) end,
+ write_config_file(Dir, "target_params.conf", Verify, Write).
+
+
+append_target_params_config(Dir, Conf)
+ when is_list(Dir) and is_list(Conf) ->
+ Verify = fun() -> verify_target_params_conf(Conf) end,
+ Write = fun(Fd) -> write_target_params_conf(Fd, Conf) end,
+ append_config_file(Dir, "target_params.conf", Verify, Write).
+
+
+read_target_params_config(Dir) ->
+ Verify = fun(Entry) -> verify_target_params_conf_entry(Entry) end,
+ read_config_file(Dir, "target_params.conf", Verify).
+
+
+verify_target_params_conf([]) ->
+ ok;
+verify_target_params_conf([H|T]) ->
+ verify_target_params_conf_entry(H),
+ verify_target_params_conf(T);
+verify_target_params_conf(X) ->
+ error({bad_target_params_config, X}).
+
+verify_target_params_conf_entry(Entry) ->
+ {ok, _} = snmp_target_mib:check_target_params(Entry),
+ ok.
+
+write_target_params_conf(Fd, "", Conf) ->
+ write_target_params_conf(Fd, Conf);
+write_target_params_conf(Fd, Hdr, Conf) ->
+ io:format(Fd, "~s~n", [Hdr]),
+ write_target_params_conf(Fd, Conf).
+
+write_target_params_conf(Fd, Conf) ->
+ Fun = fun(Entry) -> do_write_target_params_conf(Fd, Entry) end,
+ lists:foreach(Fun, Conf).
+
+do_write_target_params_conf(Fd,
+ {Name, MpModel, SecModel, SecName, SecLevel}) ->
+ io:format(Fd, "{\"~s\", ~w, ~w, \"~s\", ~w}.~n",
+ [Name, MpModel, SecModel, SecName, SecLevel]);
+do_write_target_params_conf(_Fd, Crap) ->
+ error({bad_target_params_config, Crap}).
+
+
+%%
+%% ------ notify.conf ------
+%%
+
+notify_entry(Name, Tag, Type) ->
+ {Name, Tag, Type}.
+
+
+write_notify_config(Dir, Conf) ->
+ Comment =
+"%% This file defines the notification parameters.\n"
+"%% The data is inserted into the snmpNotifyTable defined\n"
+"%% in SNMP-NOTIFICATION-MIB.\n"
+"%% The Name is used as CommunityString for v1 and v2c.\n"
+"%% Each row is a 3-tuple:\n"
+"%% {Name, Tag, Type}.\n"
+"%% For example\n"
+"%% {\"standard trap\", \"std_trap\", trap}.\n"
+"%% {\"standard inform\", \"std_inform\", inform}.\n"
+"%%\n\n",
+ Hdr = header() ++ Comment,
+ write_notify_config(Dir, Hdr, Conf).
+
+write_notify_config(Dir, Hdr, Conf)
+ when is_list(Dir) and is_list(Hdr) and is_list(Conf) ->
+ Verify = fun() -> verify_notify_conf(Conf) end,
+ Write = fun(Fd) -> write_notify_conf(Fd, Hdr, Conf) end,
+ write_config_file(Dir, "notify.conf", Verify, Write).
+
+
+append_notify_config(Dir, Conf)
+ when is_list(Dir) and is_list(Conf) ->
+ Verify = fun() -> verify_notify_conf(Conf) end,
+ Write = fun(Fd) -> write_notify_conf(Fd, Conf) end,
+ append_config_file(Dir, "notify.conf", Verify, Write).
+
+
+read_notify_config(Dir) ->
+ Verify = fun(Entry) -> verify_notify_conf_entry(Entry) end,
+ read_config_file(Dir, "notify.conf", Verify).
+
+
+verify_notify_conf([]) ->
+ ok;
+verify_notify_conf([H|T]) ->
+ verify_notify_conf_entry(H),
+ verify_notify_conf(T);
+verify_notify_conf(X) ->
+ error({bad_notify_config, X}).
+
+verify_notify_conf_entry(Entry) ->
+ {ok, _} = snmp_notification_mib:check_notify(Entry),
+ ok.
+
+write_notify_conf(Fd, "", Conf) ->
+ write_notify_conf(Fd, Conf);
+write_notify_conf(Fd, Hdr, Conf) ->
+ io:format(Fd, "~s~n", [Hdr]),
+ write_notify_conf(Fd, Conf).
+
+write_notify_conf(Fd, Conf) ->
+ Fun = fun(Entry) -> do_write_notify_conf(Fd, Entry) end,
+ lists:foreach(Fun, Conf).
+
+do_write_notify_conf(Fd, {Name, Tag, Type}) ->
+ io:format(Fd, "{\"~s\", \"~s\", ~w}.~n", [Name, Tag, Type]);
+do_write_notify_conf(_Fd, Crap) ->
+ error({bad_notify_config, Crap}).
+
+
+%%
+%% ------ usm.conf ------
+%%
+
+usm_entry(EngineID) ->
+ UserName = "initial",
+ SecName = "initial",
+ Clone = zeroDotZero,
+ AuthP = usmNoAuthProtocol,
+ AuthKeyC = "",
+ OwnAuthKeyC = "",
+ PrivP = usmNoPrivProtocol,
+ PrivKeyC = "",
+ OwnPrivKeyC = "",
+ Public = "",
+ AuthKey = "",
+ PrivKey = "",
+ usm_entry(EngineID, UserName, SecName, Clone,
+ AuthP, AuthKeyC, OwnAuthKeyC,
+ PrivP, PrivKeyC, OwnPrivKeyC,
+ Public, AuthKey, PrivKey).
+
+usm_entry(EngineID, UserName, SecName, Clone,
+ AuthP, AuthKeyC, OwnAuthKeyC,
+ PrivP, PrivKeyC, OwnPrivKeyC,
+ Public, AuthKey, PrivKey) ->
+ {EngineID, UserName, SecName, Clone,
+ AuthP, AuthKeyC, OwnAuthKeyC,
+ PrivP, PrivKeyC, OwnPrivKeyC,
+ Public, AuthKey, PrivKey}.
+
+
+write_usm_config(Dir, Conf) ->
+ Comment =
+"%% This file defines the security parameters for the user-based\n"
+"%% security model.\n"
+"%% The data is inserted into the usmUserTable defined\n"
+"%% in SNMP-USER-BASED-SM-MIB.\n"
+"%% Each row is a 13-tuple:\n"
+"%% {EngineID, UserName, SecName, Clone, AuthP, AuthKeyC, OwnAuthKeyC,\n"
+"%% PrivP, PrivKeyC, OwnPrivKeyC, Public, AuthKey, PrivKey}.\n"
+"%% For example\n"
+"%% {\"agentEngine\", \"initial\", \"initial\", zeroDotZero,\n"
+"%% usmNoAuthProtocol, \"\", \"\", usmNoPrivProtocol, \"\", \"\", \"\",\n"
+"%% \"\", \"\"}.\n"
+"%%\n\n",
+ Hdr = header() ++ Comment,
+ write_usm_config(Dir, Hdr, Conf).
+
+write_usm_config(Dir, Hdr, Conf)
+ when is_list(Dir) and is_list(Hdr) and is_list(Conf) ->
+ Verify = fun() -> verify_usm_conf(Conf) end,
+ Write = fun(Fd) -> write_usm_conf(Fd, Hdr, Conf) end,
+ write_config_file(Dir, "usm.conf", Verify, Write).
+
+
+append_usm_config(Dir, Conf)
+ when is_list(Dir) and is_list(Conf) ->
+ Verify = fun() -> verify_usm_conf(Conf) end,
+ Write = fun(Fd) -> write_usm_conf(Fd, Conf) end,
+ append_config_file(Dir, "usm.conf", Verify, Write).
+
+
+read_usm_config(Dir) ->
+ Verify = fun(Entry) -> verify_usm_conf_entry(Entry) end,
+ read_config_file(Dir, "usm.conf", Verify).
+
+
+verify_usm_conf([]) ->
+ ok;
+verify_usm_conf([H|T]) ->
+ verify_usm_conf_entry(H),
+ verify_usm_conf(T);
+verify_usm_conf(X) ->
+ error({bad_usm_conf, X}).
+
+verify_usm_conf_entry(Entry) ->
+ {ok, _} = snmp_user_based_sm_mib:check_usm(Entry),
+ ok.
+
+write_usm_conf(Fd, "", Conf) ->
+ write_usm_conf(Fd, Conf);
+write_usm_conf(Fd, Hdr, Conf) ->
+ io:format(Fd, "~s~n", [Hdr]),
+ write_usm_conf(Fd, Conf).
+
+write_usm_conf(Fd, Conf) ->
+ Fun = fun(Entry) -> do_write_usm_conf(Fd, Entry) end,
+ lists:foreach(Fun, Conf).
+
+do_write_usm_conf(Fd,
+ {EngineID, UserName, SecName, Clone,
+ AuthP, AuthKeyC, OwnAuthKeyC,
+ PrivP, PrivKeyC, OwnPrivKeyC,
+ Public, AuthKey, PrivKey}) ->
+ io:format(Fd, "{", []),
+ io:format(Fd, "\"~s\", ", [EngineID]),
+ io:format(Fd, "\"~s\", ", [UserName]),
+ io:format(Fd, "\"~s\", ", [SecName]),
+ io:format(Fd, "~w, ", [Clone]),
+ io:format(Fd, "~w, ", [AuthP]),
+ do_write_usm2(Fd, AuthKeyC, ", "),
+ do_write_usm2(Fd, OwnAuthKeyC, ", "),
+ io:format(Fd, "~w, ", [PrivP]),
+ do_write_usm2(Fd, PrivKeyC, ", "),
+ do_write_usm2(Fd, OwnPrivKeyC, ", "),
+ do_write_usm2(Fd, Public, ", "),
+ do_write_usm2(Fd, AuthKey, ", "),
+ do_write_usm2(Fd, PrivKey, ""),
+ io:format(Fd, "}.~n", []);
+do_write_usm_conf(_Fd, Crap) ->
+ error({bad_usm_config, Crap}).
+
+do_write_usm2(Fd, "", P) ->
+ io:format(Fd, "\"\"~s", [P]);
+do_write_usm2(Fd, X, P) ->
+ io:format(Fd, "~w~s", [X, P]).
+
+
+%%
+%% ------ vacm.conf ------
+%%
+
+vacm_s2g_entry(SecModel, SecName, GroupName) ->
+ {vacmSecurityToGroup, SecModel, SecName, GroupName}.
+
+vacm_acc_entry(GroupName, Prefix, SecModel, SecLevel, Match, RV, WV, NV) ->
+ {vacmAccess, GroupName, Prefix, SecModel, SecLevel, Match, RV, WV, NV}.
+
+vacm_vtf_entry(ViewIndex, ViewSubtree) ->
+ vacm_vtf_entry(ViewIndex, ViewSubtree, included, null).
+vacm_vtf_entry(ViewIndex, ViewSubtree, ViewStatus, ViewMask) ->
+ {vacmViewTreeFamily, ViewIndex, ViewSubtree, ViewStatus, ViewMask}.
+
+
+write_vacm_config(Dir, Conf) ->
+ Comment =
+"%% This file defines the Mib Views.\n"
+"%% The data is inserted into the vacm* tables defined\n"
+"%% in SNMP-VIEW-BASED-ACM-MIB.\n"
+"%% Each row is one of 3 tuples; one for each table in the MIB:\n"
+"%% {vacmSecurityToGroup, SecModel, SecName, GroupName}.\n"
+"%% {vacmAccess, GroupName, Prefix, SecModel, SecLevel, Match, RV, WV, NV}.\n"
+"%% {vacmViewTreeFamily, ViewIndex, ViewSubtree, ViewStatus, ViewMask}.\n"
+"%% For example\n"
+"%% {vacmSecurityToGroup, v2c, \"initial\", \"initial\"}.\n"
+"%% {vacmSecurityToGroup, usm, \"initial\", \"initial\"}.\n"
+"%% read/notify access to system\n"
+"%% {vacmAccess, \"initial\", \"\", any, noAuthNoPriv, exact,\n"
+"%% \"system\", \"\", \"system\"}.\n"
+"%% {vacmViewTreeFamily, \"system\", [1,3,6,1,2,1,1], included, null}.\n"
+"%% {vacmViewTreeFamily, \"exmib\", [1,3,6,1,3], included, null}."
+" % for EX1-MIB\n"
+"%% {vacmViewTreeFamily, \"internet\", [1,3,6,1], included, null}.\n"
+"%%\n\n",
+ Hdr = header() ++ Comment,
+ write_vacm_config(Dir, Hdr, Conf).
+
+write_vacm_config(Dir, Hdr, Conf)
+ when is_list(Dir) and is_list(Hdr) and is_list(Conf) ->
+ Verify = fun() -> verify_vacm_conf(Conf) end,
+ Write = fun(Fd) -> write_vacm_conf(Fd, Hdr, Conf) end,
+ write_config_file(Dir, "vacm.conf", Verify, Write).
+
+
+append_vacm_config(Dir, Conf)
+ when is_list(Dir) and is_list(Conf) ->
+ Verify = fun() -> verify_vacm_conf(Conf) end,
+ Write = fun(Fd) -> write_vacm_conf(Fd, Conf) end,
+ append_config_file(Dir, "vacm.conf", Verify, Write).
+
+
+read_vacm_config(Dir) ->
+ Verify = fun(Entry) -> verify_vacm_conf_entry(Entry) end,
+ read_config_file(Dir, "vacm.conf", Verify).
+
+
+verify_vacm_conf([]) ->
+ ok;
+verify_vacm_conf([H|T]) ->
+ verify_vacm_conf_entry(H),
+ verify_vacm_conf(T);
+verify_vacm_conf(X) ->
+ error({bad_vacm_conf, X}).
+
+verify_vacm_conf_entry(Entry) ->
+ {ok, _} = snmp_view_based_acm_mib:check_vacm(Entry),
+ ok.
+
+write_vacm_conf(Fd, "", Conf) ->
+ write_vacm_conf(Fd, Conf);
+write_vacm_conf(Fd, Hdr, Conf) ->
+ io:format(Fd, "~s~n", [Hdr]),
+ write_vacm_conf(Fd, Conf).
+
+write_vacm_conf(Fd, Conf) ->
+ Fun = fun(Entry) -> do_write_vacm_conf(Fd, Entry) end,
+ lists:foreach(Fun, Conf).
+
+do_write_vacm_conf(Fd,
+ {vacmSecurityToGroup,
+ SecModel, SecName, GroupName}) ->
+ io:format(Fd, "{vacmSecurityToGroup, ~w, \"~s\", \"~s\"}.~n",
+ [SecModel, SecName, GroupName]);
+do_write_vacm_conf(Fd,
+ {vacmAccess,
+ GroupName, Prefix, SecModel, SecLevel, Match, RV, WV, NV}) ->
+ io:format(Fd, "{vacmAccess, \"~s\", \"~s\", ~w, ~w, ~w, "
+ "\"~s\", \"~s\", \"~s\"}.~n",
+ [GroupName, Prefix, SecModel, SecLevel,
+ Match, RV, WV, NV]);
+do_write_vacm_conf(Fd,
+ {vacmViewTreeFamily,
+ ViewIndex, ViewSubtree, ViewStatus, ViewMask}) ->
+ io:format(Fd, "{vacmViewTreeFamily, \"~s\", ~w, ~w, ~w}.~n",
+ [ViewIndex, ViewSubtree, ViewStatus, ViewMask]);
+do_write_vacm_conf(_Fd, Crap) ->
+ error({bad_vacm_config, Crap}).
+
+
+%% ---- config file wrapper functions ----
+
+write_config_file(Dir, File, Verify, Write) ->
+ snmp_config:write_config_file(Dir, File, Verify, Write).
+
+append_config_file(Dir, File, Verify, Write) ->
+ snmp_config:append_config_file(Dir, File, Verify, Write).
+
+read_config_file(Dir, File, Verify) ->
+ snmp_config:read_config_file(Dir, File, Verify).
+
+
+%% ---- config file utility functions ----
+
+header() ->
+ {Y,Mo,D} = date(),
+ {H,Mi,S} = time(),
+ io_lib:format("%% This file was generated by "
+ "~w (version-~s) ~w-~2.2.0w-~2.2.0w "
+ "~2.2.0w:~2.2.0w:~2.2.0w\n",
+ [?MODULE, ?version, Y, Mo, D, H, Mi, S]).
+
+
+error(R) ->
+ throw({error, R}).
diff --git a/lib/snmp/src/agent/snmpa_discovery_handler.erl b/lib/snmp/src/agent/snmpa_discovery_handler.erl
new file mode 100644
index 0000000000..cf38583054
--- /dev/null
+++ b/lib/snmp/src/agent/snmpa_discovery_handler.erl
@@ -0,0 +1,29 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 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%
+%%
+-module(snmpa_discovery_handler).
+
+-export([behaviour_info/1, verify/1]).
+
+behaviour_info(callbacks) ->
+ [{stage1_finish, 3}];
+behaviour_info(_) ->
+ undefined.
+
+verify(Mod) ->
+ snmp_misc:verify_behaviour(?MODULE, Mod).
diff --git a/lib/snmp/src/agent/snmpa_discovery_handler_default.erl b/lib/snmp/src/agent/snmpa_discovery_handler_default.erl
new file mode 100644
index 0000000000..12a27993ab
--- /dev/null
+++ b/lib/snmp/src/agent/snmpa_discovery_handler_default.erl
@@ -0,0 +1,38 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 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%
+%%
+-module(snmpa_discovery_handler_default).
+
+-behaviour(snmpa_discovery_handler).
+
+
+%%%-----------------------------------------------------------------
+%%% Implements different error mechanisms.
+%%%-----------------------------------------------------------------
+-export([stage1_finish/3]).
+
+
+%%-----------------------------------------------------------------
+%% This function is called at the end of stage 1 of the discovery
+%% process. If security-level is noAuthNoPriv, then
+%%
+%%
+%%-----------------------------------------------------------------
+stage1_finish(_TargetName, _ManagerEngineID, _ExtraInfo) ->
+ ignore.
+
diff --git a/lib/snmp/src/agent/snmpa_error.erl b/lib/snmp/src/agent/snmpa_error.erl
new file mode 100644
index 0000000000..db2b8d0178
--- /dev/null
+++ b/lib/snmp/src/agent/snmpa_error.erl
@@ -0,0 +1,66 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2002-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%
+%%
+-module(snmpa_error).
+
+-behaviour(snmpa_error_report).
+
+
+%%%-----------------------------------------------------------------
+%%% Implements different error mechanisms.
+%%%-----------------------------------------------------------------
+-export([user_err/2, config_err/2]).
+
+
+%%-----------------------------------------------------------------
+%% This function is called when there is an error in a user
+%% supplied item, e.g. instrumentation function.
+%%-----------------------------------------------------------------
+user_err(F, A) ->
+ report_err(user_err, F, A).
+
+
+%%-----------------------------------------------------------------
+%% This function is called when there is a configuration error,
+%% either at startup (in a conf-file) or at run-time (e.g. when
+%% information in the configuration tables are inconsistent.)
+%%-----------------------------------------------------------------
+config_err(F, A) ->
+ report_err(config_err, F, A).
+
+
+%% -----------------------------------------------------------------
+
+
+report_err(Func, Format, Args) ->
+ case report_module() of
+ {ok, Mod} ->
+ (catch Mod:Func(Format, Args));
+ _ ->
+ ok
+ end.
+
+
+
+report_module() ->
+ case (catch ets:lookup(snmp_agent_table, error_report_mod)) of
+ [{error_report_mod, Mod}] ->
+ {ok, Mod};
+ _ ->
+ error
+ end.
diff --git a/lib/snmp/src/agent/snmpa_error_io.erl b/lib/snmp/src/agent/snmpa_error_io.erl
new file mode 100644
index 0000000000..54cdb6baac
--- /dev/null
+++ b/lib/snmp/src/agent/snmpa_error_io.erl
@@ -0,0 +1,49 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2002-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%
+%%
+-module(snmpa_error_io).
+
+-behaviour(snmpa_error_report).
+
+
+%%%-----------------------------------------------------------------
+%%% Implements different error mechanisms.
+%%%-----------------------------------------------------------------
+-export([user_err/2, config_err/2]).
+
+
+%%-----------------------------------------------------------------
+%% This function is called when there is an error in a user
+%% supplied item, e.g. instrumentation function.
+%%-----------------------------------------------------------------
+user_err(F, A) ->
+ error_msg("User error", F, A).
+
+
+%%-----------------------------------------------------------------
+%% This function is called when there is a configuration error,
+%% either at startup (in a conf-file) or at run-time (e.g. when
+%% information in the configuration tables are inconsistent.)
+%%-----------------------------------------------------------------
+config_err(F, A) ->
+ error_msg("Configuration error", F, A).
+
+
+error_msg(P, F, A) ->
+ io:format("*** SNMP ~s *** ~n" ++ F ++ "~n", [P|A]).
+
diff --git a/lib/snmp/src/agent/snmpa_error_logger.erl b/lib/snmp/src/agent/snmpa_error_logger.erl
new file mode 100644
index 0000000000..b1124fd728
--- /dev/null
+++ b/lib/snmp/src/agent/snmpa_error_logger.erl
@@ -0,0 +1,50 @@
+%%
+%% %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%
+%%
+-module(snmpa_error_logger).
+
+-behaviour(snmpa_error_report).
+
+
+%%%-----------------------------------------------------------------
+%%% Implements different error mechanisms.
+%%%-----------------------------------------------------------------
+-export([user_err/2, config_err/2]).
+
+
+%%-----------------------------------------------------------------
+%% This function is called when there is an error in a user
+%% supplied item, e.g. instrumentation function.
+%%-----------------------------------------------------------------
+user_err(F, A) ->
+ error_msg("** User error: ", F, A).
+
+
+%%-----------------------------------------------------------------
+%% This function is called when there is a configuration error,
+%% either at startup (in a conf-file) or at run-time (e.g. when
+%% information in the configuration tables are inconsistent.)
+%%-----------------------------------------------------------------
+config_err(F, A) ->
+ error_msg("** Configuration error: ", F, A).
+
+
+error_msg(P, F, A) ->
+ S = snmp_misc:format(1024, lists:concat([P, F, "\n"]), A),
+ catch error_logger:error_msg("~s", [S]).
+
diff --git a/lib/snmp/src/agent/snmpa_error_report.erl b/lib/snmp/src/agent/snmpa_error_report.erl
new file mode 100644
index 0000000000..35c02edcab
--- /dev/null
+++ b/lib/snmp/src/agent/snmpa_error_report.erl
@@ -0,0 +1,27 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2004-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%
+%%
+-module(snmpa_error_report).
+
+-export([behaviour_info/1]).
+
+behaviour_info(callbacks) ->
+ [{user_err, 2},
+ {config_err, 2}];
+behaviour_info(_) ->
+ undefined.
diff --git a/lib/snmp/src/agent/snmpa_general_db.erl b/lib/snmp/src/agent/snmpa_general_db.erl
new file mode 100644
index 0000000000..795c353a9e
--- /dev/null
+++ b/lib/snmp/src/agent/snmpa_general_db.erl
@@ -0,0 +1,578 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2000-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%
+%%
+-module(snmpa_general_db).
+
+
+%%%-----------------------------------------------------------------
+%%% This module implements a very simple "generic" MIB database
+%%% interface. It contains the most common functions performed.
+%%% It is generic in the sense that it implements both an interface
+%%% to mnesia and ets.
+%%%
+%%% Note that this module has nothing to do with the snmp_generic
+%%% and snmp_generic_mnesia modules.
+%%%-----------------------------------------------------------------
+
+-export([open/5, close/1, read/2, write/2, delete/1, delete/2]).
+-export([sync/1, backup/2]).
+-export([match_object/2, match_delete/2]).
+-export([tab2list/1, info/1, info/2]).
+
+
+-define(VMODULE,"GDB").
+-include("snmp_verbosity.hrl").
+
+
+%% ---------------------------------------------------------------
+%% open(Info,Name,RecName,Attr,Type) -> term()
+%% Info -> ets | {ets, Dir} |
+%% {dets, Dir} | {dets, Dir, Action} |
+%% {mnesia, Nodes} | {mnesia, Nodes, Action}
+%% Name -> atom()
+%% RecName -> Name of the record to store
+%% Attr -> Attributes of the record stored in the table
+%% Type -> set | bag
+%% Dir -> string()
+%% Nodes -> [node()]
+%% Action -> keep | clear
+%%
+%% Open or create a database table. In the mnesia/dets case,
+%% where the table is stored on disc, it could be of interest
+%% to clear the table. This is controlled by the Action parameter.
+%% An empty node list ([]), is traslated into a list containing
+%% only the own node.
+%% ---------------------------------------------------------------
+open({mnesia,Nodes,clear}, Name, RecName, Attr, Type) when is_list(Nodes) ->
+ ?vtrace("[mnesia] open ~p database ~p for ~p on ~p; clear",
+ [Type, Name, RecName, Nodes]),
+ mnesia_open(mnesia_table_check(Name), Nodes, RecName, Attr, Type, clear);
+open({mnesia,Nodes,_}, Name, RecName, Attr, Type) ->
+ ?vtrace("[mnesia] open ~p database ~p for ~p on ~p; keep",
+ [Type, Name, RecName, Nodes]),
+ open({mnesia,Nodes}, Name, RecName, Attr, Type);
+open({mnesia,Nodes}, Name, RecName, Attr, Type) when is_list(Nodes) ->
+ ?vtrace("[mnesia] open ~p database ~p for ~p on ~p",
+ [Type, Name, RecName, Nodes]),
+ mnesia_open(mnesia_table_check(Name), Nodes, RecName, Attr, Type, keep);
+
+open({dets, Dir, Action}, Name, _RecName, _Attr, Type) ->
+ dets_open(Name, dets_filename(Name, Dir), Type, Action);
+open({dets, Dir}, Name, _RecName, _Attr, Type) ->
+ dets_open(Name, dets_filename(Name, Dir), Type, keep);
+
+%% This function creates the ets table
+open(ets, Name, _RecName, _Attr, Type) ->
+ ?vtrace("[ets] open ~p database ~p", [Type, Name]),
+ Ets = ets:new(Name, [Type, protected, {keypos, 2}]),
+ {ets, Ets, undefined};
+open({ets, Dir}, Name, _RecName, _Attr, Type) ->
+ ets_open(Name, Dir, keep, Type);
+open({ets, Dir, Action}, Name, _RecName, _Attr, Type) ->
+ ets_open(Name, Dir, Action, Type).
+
+ets_open(Name, Dir, keep, Type) ->
+ ?vtrace("[ets] open ~p database ~p", [Type, Name]),
+ File = filename:join(Dir, atom_to_list(Name) ++ ".db"),
+ case file:read_file_info(File) of
+ {ok, _} ->
+ case ets:file2tab(File) of
+ {ok, Tab} ->
+ {ets, Tab, File};
+ {error, Reason} ->
+ user_err("failed converting file to (ets-) tab: "
+ "File: ~p"
+ "~n~p", [File, Reason]),
+ Ets = ets:new(Name, [Type, protected, {keypos, 2}]),
+ {ets, Ets, File}
+ end;
+ {error, _} ->
+ Ets = ets:new(Name, [Type, protected, {keypos, 2}]),
+ {ets, Ets, File}
+ end;
+ets_open(Name, Dir, clear, Type) ->
+ File = filename:join(Dir, atom_to_list(Name) ++ ".db"),
+ Ets = ets:new(Name, [Type, protected, {keypos, 2}]),
+ {ets, Ets, File}.
+
+
+
+mnesia_open({table_exist,Name},_Nodes,_RecName,_Attr,_Type,clear) ->
+ ?vtrace("[mnesia] database ~p already exists; clear content",[Name]),
+ Pattern = '_',
+ F = fun() ->
+ Recs = mnesia:match_object(Name,Pattern,read),
+ lists:foreach(fun(Rec) ->
+ mnesia:delete_object(Name,Rec,write)
+ end, Recs),
+ Recs
+ end,
+ case mnesia:transaction(F) of
+ {aborted,Reason} ->
+ exit({aborted,Reason});
+ {atomic,_} ->
+ {mnesia,Name}
+ end;
+mnesia_open({table_exist,Name},_Nodes,_RecName,_Attr,_Type,keep) ->
+ ?vtrace("[mnesia] database ~p already exists; keep content",[Name]),
+ {mnesia,Name};
+mnesia_open({no_table,Name},[],Type,RecName,Attr,Action) ->
+ mnesia_open({no_table,Name},[node()],Type,RecName,Attr,Action);
+mnesia_open({no_table,Name},Nodes,RecName,Attr,Type,_) ->
+ ?vtrace("[mnesia] no database ~p: create for ~p of type ~p",
+ [Name,RecName,Type]),
+ %% Ok, we assume that this means that the table does not exist
+ Args = [{record_name,RecName}, {attributes,Attr},
+ {type,Type}, {disc_copies,Nodes}],
+ case mnesia:create_table(Name,Args) of
+ {atomic,ok} ->
+ {mnesia,Name};
+ {aborted,Reason} ->
+ %% ?vinfo("[mnesia] aborted: ~p", [Reason]),
+ exit({failed_create_mnesia_table,Reason})
+ end.
+
+
+mnesia_table_check(Name) ->
+ ?vtrace("[mnesia] check existens of database ~p",[Name]),
+ case (catch mnesia:table_info(Name,type)) of
+ {'EXIT', _Reason} ->
+ {no_table, Name};
+ _ ->
+ {table_exist, Name}
+ end.
+
+
+dets_open(Name, File, Type, Action) ->
+ ?vtrace("[dets] open database ~p (~p)", [Name, Action]),
+ N = dets_open1(Name, File, Type),
+ dets_open2(N, Action).
+
+dets_open1(Name, File, Type) ->
+ ?vtrace("[dets] open database ~p of type ~p",[Name, Type]),
+ {ok, N} = dets:open_file(Name, [{file, File}, {type, Type}, {keypos, 2}]),
+ N.
+
+dets_open2(N, clear) ->
+ dets:match_delete(N,'_'),
+ {dets, N};
+dets_open2(N, _) ->
+ {dets, N}.
+
+%% dets_table_check(Name, Dir) ->
+%% Filename = dets_filename(Name, Dir),
+%% ?vtrace("[dets] check existens of database: "
+%% "~n ~p -> ~s"
+%% "~n ~p"
+%% "~n ~p"
+%% ,
+%% [Name, Filename, file:list_dir(Dir), file:read_file_info(Filename)]),
+%% case (catch dets:info(Filename, size)) of
+%% {'EXIT', Reason} ->
+%% {no_table, Name, Filename};
+%% undefined -> %% Introduced in R8
+%% {no_table, Name, Filename};
+%% _ ->
+%% {table_exist, Name, Filename}
+%% end.
+
+
+dets_filename(Name, Dir) ->
+ Dir1 = dets_filename1(Dir),
+ Dir2 = string:strip(Dir1, right, $/),
+ io_lib:format("~s/~p.dat", [Dir2, Name]).
+
+dets_filename1([]) -> ".";
+dets_filename1(Dir) -> Dir.
+
+
+%% ---------------------------------------------------------------
+%% close(DbRef) ->
+%% DbRef -> term()
+%%
+%% Close the database. This does nothing in the mnesia case, but
+%% deletes the table in the ets case.
+%% ---------------------------------------------------------------
+close({mnesia,_}) ->
+ ?vtrace("[mnesia] close database: NO ACTION",[]),
+ ok;
+close({dets, Name}) ->
+ ?vtrace("[dets] close database ~p",[Name]),
+ dets:close(Name);
+close({ets, Name, undefined}) ->
+ ?vtrace("[ets] close (delete) table ~p",[Name]),
+ ets:delete(Name);
+close({ets, Name, File}) ->
+ ?vtrace("[ets] close (delete) table ~p",[Name]),
+ write_ets_file(Name, File),
+ ets:delete(Name).
+
+
+%% ---------------------------------------------------------------
+%% read(DbRef,Key) -> false | {value,Rec}
+%% DbRef -> term()
+%% Rec -> tuple()
+%%
+%% Retrieve a record from the database.
+%% ---------------------------------------------------------------
+read({mnesia, Name}, Key) ->
+ ?vtrace("[mnesia] read (dirty) from database ~p: ~p",[Name,Key]),
+ case (catch mnesia:dirty_read(Name,Key)) of
+ [Rec|_] -> {value,Rec};
+ _ -> false
+ end;
+read({dets, Name}, Key) ->
+ ?vtrace("[dets] read from table ~p: ~p",[Name,Key]),
+ case dets:lookup(Name, Key) of
+ [Rec|_] -> {value, Rec};
+ _ -> false
+ end;
+read({ets, Name, _}, Key) ->
+ ?vtrace("[ets] read from table ~p: ~p",[Name,Key]),
+ case ets:lookup(Name, Key) of
+ [Rec|_] -> {value, Rec};
+ _ -> false
+ end.
+
+
+%% ---------------------------------------------------------------
+%% write(DbRef,Rec) -> ok
+%% DbRef -> term()
+%% Rec -> tuple()
+%%
+%% Write a record to the database.
+%% ---------------------------------------------------------------
+write({mnesia, Name}, Rec) ->
+ ?vtrace("[mnesia] write to database ~p",[Name]),
+ F = fun() -> mnesia:write(Name, Rec, write) end,
+ case mnesia:transaction(F) of
+ {aborted, Reason} ->
+ exit({aborted, Reason});
+ {atomic,_} ->
+ ok
+ end;
+write({dets, Name}, Rec) ->
+ ?vtrace("[dets] write to table ~p",[Name]),
+ dets:insert(Name, Rec);
+write({ets, Name, _}, Rec) ->
+ ?vtrace("[ets] write to table ~p",[Name]),
+ ets:insert(Name, Rec).
+
+
+%% ---------------------------------------------------------------
+%% delete(DbRef) ->
+%% DbRef -> term()
+%%
+%% Delete the database.
+%% ---------------------------------------------------------------
+delete({mnesia, Name}) ->
+ ?vtrace("[mnesia] delete database: ~p",[Name]),
+ mnesia:delete_table(Name);
+delete({dets, Name}) ->
+ ?vtrace("[dets] delete database ~p",[Name]),
+ File = dets:info(Name, filename),
+ case dets:close(Name) of
+ ok ->
+ file:delete(File);
+ Error ->
+ Error
+ end;
+delete({ets, Name, undefined}) ->
+ ?vtrace("[dets] delete table ~p",[Name]),
+ ets:delete(Name);
+delete({ets, Name, File}) ->
+ ?vtrace("[dets] delete table ~p",[Name]),
+ file:delete(File),
+ ets:delete(Name).
+
+
+%% ---------------------------------------------------------------
+%% delete(DbRef, Key) -> ok
+%% DbRef -> term()
+%% Key -> term()
+%%
+%% Delete a record from the database.
+%% ---------------------------------------------------------------
+delete({mnesia, Name}, Key) ->
+ ?vtrace("[mnesia] delete from database ~p: ~p", [Name, Key]),
+ F = fun() -> mnesia:delete(Name, Key, write) end,
+ case mnesia:transaction(F) of
+ {aborted,Reason} ->
+ exit({aborted,Reason});
+ {atomic,_} ->
+ ok
+ end;
+delete({dets, Name}, Key) ->
+ ?vtrace("[dets] delete from table ~p: ~p", [Name, Key]),
+ dets:delete(Name, Key);
+delete({ets, Name, _}, Key) ->
+ ?vtrace("[ets] delete from table ~p: ~p", [Name, Key]),
+ ets:delete(Name, Key).
+
+
+%% ---------------------------------------------------------------
+%% match_object(DbRef,Pattern) -> [tuple()]
+%% DbRef -> term()
+%% Pattern -> tuple()
+%%
+%% Search the database for records witch matches the pattern.
+%% ---------------------------------------------------------------
+match_object({mnesia, Name}, Pattern) ->
+ ?vtrace("[mnesia] match_object in ~p of ~p",[Name, Pattern]),
+ F = fun() -> mnesia:match_object(Name, Pattern, read) end,
+ case mnesia:transaction(F) of
+ {aborted, Reason} ->
+ exit({aborted, Reason});
+ {atomic, Recs} ->
+ Recs
+ end;
+match_object({dets, Name}, Pattern) ->
+ ?vtrace("[dets] match_object in ~p of ~p",[Name, Pattern]),
+ dets:match_object(Name, Pattern);
+match_object({ets, Name, _}, Pattern) ->
+ ?vtrace("[ets] match_object in ~p of ~p",[Name, Pattern]),
+ ets:match_object(Name, Pattern).
+
+
+%% ---------------------------------------------------------------
+%% match_delete(DbRef,Pattern) ->
+%% DbRef -> term()
+%% Pattern -> tuple()
+%%
+%% Search the database for records witch matches the pattern and
+%% deletes them from the database.
+%% ---------------------------------------------------------------
+match_delete({mnesia, Name}, Pattern) ->
+ ?vtrace("[mnesia] match_delete in ~p with pattern ~p",[Name,Pattern]),
+ F = fun() ->
+ Recs = mnesia:match_object(Name, Pattern, read),
+ lists:foreach(fun(Rec) ->
+ mnesia:delete_object(Name, Rec, write)
+ end, Recs),
+ Recs
+ end,
+ case mnesia:transaction(F) of
+ {aborted, Reason} ->
+ exit({aborted, Reason});
+ {atomic,R} ->
+ R
+ end;
+match_delete({dets, Name}, Pattern) ->
+ ?vtrace("[dets] match_delete in ~p with pattern ~p",[Name,Pattern]),
+ Recs = dets:match_object(Name, Pattern),
+ dets:match_delete(Name, Pattern),
+ Recs;
+match_delete({ets, Name, _}, Pattern) ->
+ ?vtrace("[ets] match_delete in ~p with pattern ~p",[Name,Pattern]),
+ Recs = ets:match_object(Name, Pattern),
+ ets:match_delete(Name, Pattern),
+ Recs.
+
+
+%% ---------------------------------------------------------------
+%% tab2list(DbRef) -> [tuple()]
+%% DbRef -> term()
+%%
+%% Return all records in the table in the form of a list.
+%% ---------------------------------------------------------------
+tab2list({mnesia, Name}) ->
+ ?vtrace("[mnesia] tab2list -> list of ~p", [Name]),
+ match_object({mnesia, Name}, mnesia:table_info(Name, wild_pattern));
+tab2list({dets, Name}) ->
+ ?vtrace("[dets] tab2list -> list of ~p", [Name]),
+ match_object({dets, Name}, '_');
+tab2list({ets, Name, _}) ->
+ ?vtrace("[ets] tab2list -> list of ~p", [Name]),
+ ets:tab2list(Name).
+
+
+
+%% ---------------------------------------------------------------
+%% info(Db) -> taglist()
+%% info(Db, Item) -> Info
+%% Db -> term()
+%% Item -> atom()
+%% tablist() -> [{key(),value()}]
+%% key() -> atom()
+%% value() -> term()
+%%
+%% Retrieve table information.
+%% ---------------------------------------------------------------
+info({mnesia, Name}) ->
+ case (catch mnesia:table_info(Name, all)) of
+ Info when is_list(Info) ->
+ Info;
+ {'EXIT', {aborted, Reason}} ->
+ {error, Reason};
+ Else ->
+ {error, Else}
+ end;
+info({dets, Name}) ->
+ dets:info(Name);
+info({ets, Name, _}) ->
+ case ets:info(Name) of
+ undefined ->
+ [];
+ L ->
+ L
+ end.
+
+
+info({mnesia, Name}, Item) ->
+ case (catch mnesia:table_info(Name, Item)) of
+ {'EXIT', {aborted, Reason}} ->
+ {error, Reason};
+ Info ->
+ Info
+ end;
+info({dets, Name}, memory) ->
+ dets:info(Name, file_size);
+info({dets, Name}, Item) ->
+ dets:info(Name, Item);
+info({ets, Name, _}, Item) ->
+ ets:info(Name, Item).
+
+
+%% ---------------------------------------------------------------
+%% sync(Db) -> ok | {error, Reason}
+%% Db -> term()
+%% Reason -> term()
+%%
+%% Dump table to disc (if possible)
+%% ---------------------------------------------------------------
+
+sync({mnesia, _}) ->
+ ok;
+sync({dets, Name}) ->
+ dets:sync(Name);
+sync({ets, _Name, undefined}) ->
+ ok;
+sync({ets, Name, File}) ->
+ write_ets_file(Name, File).
+
+
+%% ---------------------------------------------------------------
+%% backup(Db, BackupDir) -> ok | {error, Reason}
+%% Db -> term()
+%% Reason -> term()
+%%
+%% Make a backup copy of the DB (only valid for det and ets)
+%% ---------------------------------------------------------------
+
+backup({mnesia, _}, _) ->
+ ok;
+backup({dets, Name}, BackupDir) ->
+ case dets:info(Name, filename) of
+ undefined ->
+ {error, no_file};
+ Filename ->
+ case filename:dirname(Filename) of
+ BackupDir ->
+ {error, db_dir};
+ _ ->
+ Type = dets:info(Name, type),
+ KP = dets:info(Name, keypos),
+ dets_backup(Name,
+ filename:basename(Filename),
+ BackupDir, Type, KP)
+ end
+ end;
+backup({ets, _Name, undefined}, _BackupDir) ->
+ ok;
+backup({ets, Name, File}, BackupDir) ->
+ Filename = filename:basename(File),
+ case filename:join(BackupDir, Filename) of
+ File ->
+ %% Oups: backup-dir and db-dir the same
+ {error, db_dir};
+ BackupFile ->
+ write_ets_file(Name, BackupFile)
+ end.
+
+
+dets_backup(Name, Filename, BackupDir, Type, KP) ->
+ ?vtrace("dets_backup -> entry with"
+ "~n Name: ~p"
+ "~n Filename: ~p"
+ "~n BackupDir: ~p"
+ "~n Type: ~p"
+ "~n KP: ~p", [Name, Filename, BackupDir, Type, KP]),
+ BackupFile = filename:join(BackupDir, Filename),
+ ?vtrace("dets_backup -> "
+ "~n BackupFile: ~p", [BackupFile]),
+ Backup = list_to_atom(atom_to_list(Name) ++ "_backup"),
+ Opts = [{file, BackupFile}, {type, Type}, {keypos, KP}],
+ case dets:open_file(Backup, Opts) of
+ {ok, B} ->
+ ?vtrace("dets_backup -> create fun", []),
+ F = fun(Arg) ->
+ dets_backup(Arg, start, Name, B)
+ end,
+ dets:safe_fixtable(Name, true),
+ Res = dets:init_table(Backup, F, [{format, bchunk}]),
+ dets:safe_fixtable(Name, false),
+ ?vtrace("dets_backup -> Res: ~p", [Res]),
+ Res;
+ Error ->
+ ?vinfo("dets_backup -> open_file failed: "
+ "~n ~p", [Error]),
+ Error
+ end.
+
+
+dets_backup(close, _Cont, _Name, B) ->
+ dets:close(B),
+ ok;
+dets_backup(read, Cont1, Name, B) ->
+ case dets:bchunk(Name, Cont1) of
+ {Cont2, Data} ->
+ F = fun(Arg) ->
+ dets_backup(Arg, Cont2, Name, B)
+ end,
+ {Data, F};
+ '$end_of_table' ->
+ dets:close(B),
+ end_of_input;
+ Error ->
+ Error
+ end.
+
+
+%%----------------------------------------------------------------------
+
+write_ets_file(Name, File) ->
+ TmpFile = File ++ ".tmp",
+ case ets:tab2file(Name, TmpFile) of
+ ok ->
+ case file:rename(TmpFile, File) of
+ ok ->
+ ok;
+ Else ->
+ user_err("Warning: could not move file ~p"
+ " (~p)", [File, Else])
+ end;
+ {error, Reason} ->
+ user_err("Warning: could not save file ~p (~p)",
+ [File, Reason])
+ end.
+
+
+%%----------------------------------------------------------------------
+
+user_err(F, A) ->
+ snmpa_error:user_err(F, A).
diff --git a/lib/snmp/src/agent/snmpa_internal.hrl b/lib/snmp/src/agent/snmpa_internal.hrl
new file mode 100644
index 0000000000..a33a6809dc
--- /dev/null
+++ b/lib/snmp/src/agent/snmpa_internal.hrl
@@ -0,0 +1,32 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2006-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%
+%%
+
+-ifndef(snmpa_internal).
+-define(snmpa_internal, true).
+
+-include_lib("snmp/src/app/snmp_internal.hrl").
+
+-define(snmpa_info(F, A), ?snmp_info("agent", F, A)).
+-define(snmpa_warning(F, A), ?snmp_warning("agent", F, A)).
+-define(snmpa_error(F, A), ?snmp_error("agent", F, A)).
+
+-endif. % -ifdef(snmpa_internal).
+
+
+
diff --git a/lib/snmp/src/agent/snmpa_local_db.erl b/lib/snmp/src/agent/snmpa_local_db.erl
new file mode 100644
index 0000000000..d9d6e633de
--- /dev/null
+++ b/lib/snmp/src/agent/snmpa_local_db.erl
@@ -0,0 +1,1226 @@
+%%
+%% %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%
+%%
+-module(snmpa_local_db).
+
+-include_lib("kernel/include/file.hrl").
+-include("snmpa_internal.hrl").
+-include("snmp_types.hrl").
+-include("STANDARD-MIB.hrl").
+
+%% -define(VMODULE, "LDB").
+-include("snmp_verbosity.hrl").
+
+
+%% External exports
+-export([start_link/3, start_link/4, stop/0, info/0, verbosity/1]).
+-export([dump/0, backup/1,
+ register_notify_client/2, unregister_notify_client/1]).
+-export([table_func/2, table_func/4,
+ variable_get/1, variable_set/2, variable_delete/1, variable_inc/2,
+ table_create/1, table_exists/1, table_delete/1,
+ table_create_row/3, table_create_row/4, table_construct_row/4,
+ table_delete_row/2,
+ table_get_row/2,
+ table_get_element/3, table_get_elements/4,
+ table_set_elements/3, table_set_status/7,
+ table_next/2,
+ table_max_col/2,
+ table_get/1]).
+
+-export([get_elements/2]).
+
+-export([match/2]).
+
+%% Debug exports
+-export([print/0, print/1, print/2]).
+
+%% Internal exports
+-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2,
+ code_change/3]).
+
+
+-define(BACKUP_TAB, snmpa_local_backup).
+-define(DETS_TAB, snmpa_local_db1).
+-define(ETS_TAB, snmpa_local_db2).
+-define(SERVER, ?MODULE).
+
+-record(state, {dets, ets, notify_clients = [], backup}).
+-record(dets, {tab, shadow}).
+
+%% -define(snmp_debug,true).
+-include("snmp_debug.hrl").
+
+
+-ifdef(snmp_debug).
+-define(GS_START_LINK(Prio, Dir, DbInitError, Opts),
+ gen_server:start_link({local, ?SERVER}, ?MODULE,
+ [Prio, Dir, DbInitError, Opts],
+ [{debug,[trace]}])).
+-else.
+-define(GS_START_LINK(Prio, Dir, DbInitError, Opts),
+ gen_server:start_link({local, ?SERVER}, ?MODULE,
+ [Prio, Dir, DbInitError, Opts],
+ [])).
+-endif.
+
+
+%%%-----------------------------------------------------------------
+%%% Implements a general database in which its possible
+%%% to store variables and tables. Provide functions for
+%%% tableaccess by row or by element, and for next.
+%%%
+%%% Opts = [Opt]
+%%% Opt = {auto_repair, false | true | true_verbose} |
+%%% {verbosity,silence | log | debug}
+%%%-----------------------------------------------------------------
+start_link(Prio, DbDir, Opts) when is_list(Opts) ->
+ start_link(Prio, DbDir, terminate, Opts).
+
+start_link(Prio, DbDir, DbInitError, Opts) when is_list(Opts) ->
+ ?d("start_link -> entry with"
+ "~n Prio: ~p"
+ "~n DbDir: ~p"
+ "~n DbInitError: ~p"
+ "~n Opts: ~p", [Prio, DbDir, DbInitError, Opts]),
+ ?GS_START_LINK(Prio, DbDir, DbInitError, Opts).
+
+stop() ->
+ call(stop).
+
+register_notify_client(Client,Module) ->
+ call({register_notify_client,Client,Module}).
+
+
+unregister_notify_client(Client) ->
+ call({unregister_notify_client,Client}).
+
+backup(BackupDir) ->
+ call({backup, BackupDir}).
+
+dump() ->
+ call(dump).
+
+info() ->
+ call(info).
+
+verbosity(Verbosity) ->
+ cast({verbosity,Verbosity}).
+
+
+%%%-----------------------------------------------------------------
+
+init([Prio, DbDir, DbInitError, Opts]) ->
+ ?d("init -> entry with"
+ "~n Prio: ~p"
+ "~n DbDir: ~p"
+ "~n DbInitError: ~p"
+ "~n Opts: ~p", [Prio, DbDir, DbInitError, Opts]),
+ case (catch do_init(Prio, DbDir, DbInitError, Opts)) of
+ {ok, State} ->
+ ?vdebug("started",[]),
+ {ok, State};
+ {error, Reason} ->
+ config_err("failed starting local-db: ~n~p", [Reason]),
+ {stop, {error, Reason}};
+ Error ->
+ config_err("failed starting local-db: ~n~p", [Error]),
+ {stop, {error, Error}}
+ end.
+
+do_init(Prio, DbDir, DbInitError, Opts) ->
+ process_flag(priority, Prio),
+ process_flag(trap_exit, true),
+ put(sname,ldb),
+ put(verbosity,get_opt(verbosity, Opts, ?default_verbosity)),
+ ?vlog("starting",[]),
+ Dets = dets_open(DbDir, DbInitError, Opts),
+ Ets = ets:new(?ETS_TAB, [set, protected]),
+ ?vdebug("started",[]),
+ {ok, #state{dets = Dets, ets = Ets}}.
+
+dets_open(DbDir, DbInitError, Opts) ->
+ Name = ?DETS_TAB,
+ Filename = dets_filename(Name, DbDir),
+ case file:read_file_info(Filename) of
+ {ok, _} ->
+ %% File exists
+ case do_dets_open(Name, Filename, Opts) of
+ {ok, Dets} ->
+ ?vdebug("dets open done",[]),
+ Shadow = ets:new(snmp_local_db1_shadow, [set, protected]),
+ dets:to_ets(Dets, Shadow),
+ ?vtrace("shadow table created and populated",[]),
+ #dets{tab = Dets, shadow = Shadow};
+ {error, Reason1} ->
+ user_err("Corrupt local database: ~p", [Filename]),
+ case DbInitError of
+ terminate ->
+ throw({error, {failed_open_dets, Reason1}});
+ _ ->
+ Saved = Filename ++ ".saved",
+ file:rename(Filename, Saved),
+ case do_dets_open(Name, Filename, Opts) of
+ {ok, Dets} ->
+ Shadow = ets:new(snmp_local_db1_shadow,
+ [set, protected]),
+ #dets{tab = Dets, shadow = Shadow};
+ {error, Reason2} ->
+ user_err("Could not create local "
+ "database: ~p"
+ "~n ~p"
+ "~n ~p",
+ [Filename, Reason1, Reason2]),
+ throw({error, {failed_open_dets, Reason2}})
+ end
+ end
+ end;
+ _ ->
+ case do_dets_open(Name, Filename, Opts) of
+ {ok, Dets} ->
+ ?vdebug("dets open done",[]),
+ Shadow = ets:new(snmp_local_db1_shadow, [set, protected]),
+ ?vtrace("shadow table created",[]),
+ #dets{tab = Dets, shadow = Shadow};
+ {error, Reason} ->
+ user_err("Could not create local database ~p"
+ "~n ~p", [Filename, Reason]),
+ throw({error, {failed_open_dets, Reason}})
+ end
+ end.
+
+do_dets_open(Name, Filename, Opts) ->
+ Repair = get_opt(repair, Opts, true),
+ AutoSave = get_opt(auto_save, Opts, 5000),
+ Args = [{auto_save, AutoSave},
+ {file, Filename},
+ {repair, Repair}],
+ dets:open_file(Name, Args).
+
+
+dets_filename(Name, Dir) when is_atom(Name) ->
+ dets_filename(atom_to_list(Name), Dir);
+dets_filename(Name, Dir) ->
+ filename:join(dets_filename1(Dir), Name).
+
+dets_filename1([]) -> ".";
+dets_filename1(Dir) -> Dir.
+
+
+%%-----------------------------------------------------------------
+%% Interface functions.
+%%-----------------------------------------------------------------
+
+%%-----------------------------------------------------------------
+%% Functions for debugging.
+%%-----------------------------------------------------------------
+print() -> call(print).
+print(Table) -> call({print,Table,volatile}).
+print(Table, Db) -> call({print,Table,Db}).
+
+variable_get({Name, Db}) ->
+ call({variable_get, Name, Db});
+variable_get(Name) ->
+ call({variable_get, Name, volatile}).
+
+variable_set({Name, Db}, Val) ->
+ call({variable_set, Name, Db, Val});
+variable_set(Name, Val) ->
+ call({variable_set, Name, volatile, Val}).
+
+variable_inc({Name, Db}, N) ->
+ cast({variable_inc, Name, Db, N});
+variable_inc(Name, N) ->
+ cast({variable_inc, Name, volatile, N}).
+
+variable_delete({Name, Db}) ->
+ call({variable_delete, Name, Db});
+variable_delete(Name) ->
+ call({variable_delete, Name, volatile}).
+
+
+table_create({Name, Db}) ->
+ call({table_create, Name, Db});
+table_create(Name) ->
+ call({table_create, Name, volatile}).
+
+table_exists({Name, Db}) ->
+ call({table_exists, Name, Db});
+table_exists(Name) ->
+ call({table_exists, Name, volatile}).
+
+table_delete({Name, Db}) ->
+ call({table_delete, Name, Db});
+table_delete(Name) ->
+ call({table_delete, Name, volatile}).
+
+table_delete_row({Name, Db}, RowIndex) ->
+ call({table_delete_row, Name, Db, RowIndex});
+table_delete_row(Name, RowIndex) ->
+ call({table_delete_row, Name, volatile, RowIndex}).
+
+table_get_row({Name, Db}, RowIndex) ->
+ call({table_get_row, Name, Db, RowIndex});
+table_get_row(Name, RowIndex) ->
+ call({table_get_row, Name, volatile, RowIndex}).
+
+table_get_element({Name, Db}, RowIndex, Col) ->
+ call({table_get_element, Name, Db, RowIndex, Col});
+table_get_element(Name, RowIndex, Col) ->
+ call({table_get_element, Name, volatile, RowIndex, Col}).
+
+table_set_elements({Name, Db}, RowIndex, Cols) ->
+ call({table_set_elements, Name, Db, RowIndex, Cols});
+table_set_elements(Name, RowIndex, Cols) ->
+ call({table_set_elements, Name, volatile, RowIndex, Cols}).
+
+table_next({Name, Db}, RestOid) ->
+ call({table_next, Name, Db, RestOid});
+table_next(Name, RestOid) ->
+ call({table_next, Name, volatile, RestOid}).
+
+table_max_col({Name, Db}, Col) ->
+ call({table_max_col, Name, Db, Col});
+table_max_col(Name, Col) ->
+ call({table_max_col, Name, volatile, Col}).
+
+table_create_row({Name, Db}, RowIndex, Row) ->
+ call({table_create_row, Name, Db,RowIndex, Row});
+table_create_row(Name, RowIndex, Row) ->
+ call({table_create_row, Name, volatile, RowIndex, Row}).
+table_create_row(NameDb, RowIndex, Status, Cols) ->
+ Row = table_construct_row(NameDb, RowIndex, Status, Cols),
+ table_create_row(NameDb, RowIndex, Row).
+
+match({Name, Db}, Pattern) ->
+ call({match, Name, Db, Pattern});
+match(Name, Pattern) ->
+ call({match, Name, volatile, Pattern}).
+
+
+table_get(Table) ->
+ table_get(Table, [], []).
+
+table_get(Table, Idx, Acc) ->
+ case table_next(Table, Idx) of
+ endOfTable ->
+ lists:reverse(Acc);
+ NextIdx ->
+ case table_get_row(Table, NextIdx) of
+ undefined ->
+ {error, {failed_get_row, NextIdx, lists:reverse(Acc)}};
+ Row ->
+ NewAcc = [{NextIdx, Row}|Acc],
+ table_get(Table, NextIdx, NewAcc)
+ end
+ end.
+
+
+%%-----------------------------------------------------------------
+%% Implements the variable functions.
+%%-----------------------------------------------------------------
+handle_call({variable_get, Name, Db}, _From, State) ->
+ ?vlog("variable get: ~p [~p]",[Name, Db]),
+ {reply, lookup(Db, Name, State), State};
+
+handle_call({variable_set, Name, Db, Val}, _From, State) ->
+ ?vlog("variable ~p set [~p]: "
+ "~n Val: ~p",[Name, Db, Val]),
+ {reply, insert(Db, Name, Val, State), State};
+
+handle_call({variable_delete, Name, Db}, _From, State) ->
+ ?vlog("variable delete: ~p [~p]",[Name, Db]),
+ {reply, delete(Db, Name, State), State};
+
+
+%%-----------------------------------------------------------------
+%% Implements the table functions.
+%%-----------------------------------------------------------------
+%% Entry in ets for a tablerow:
+%% Key = {<tableName>, <(flat) list of indexes>}
+%% Val = {{Row}, <Prev>, <Next>}
+%% Where Prev and Next = <list of indexes>; "pointer to prev/next"
+%% Each table is a double linked list, with a head-element, with
+%% direct access to each individual element.
+%% Head-el: Key = {<tableName>, first}
+%% Operations:
+%% table_create_row(<tableName>, <list of indexes>, <row>) O(n)
+%% table_delete_row(<tableName>, <list of indexes>) O(1)
+%% get(<tableName>, <list of indexes>, Col) O(1)
+%% set(<tableName>, <list of indexes>, Col, Val) O(1)
+%% next(<tableName>, <list of indexes>) if Row exist O(1), else O(n)
+%%-----------------------------------------------------------------
+handle_call({table_create, Name, Db}, _From, State) ->
+ ?vlog("table create: ~p [~p]",[Name, Db]),
+ catch handle_delete(Db, Name, State),
+ {reply, insert(Db, {Name, first}, {undef, first, first}, State), State};
+
+handle_call({table_exists, Name, Db}, _From, State) ->
+ ?vlog("table exist: ~p [~p]",[Name, Db]),
+ Res =
+ case lookup(Db, {Name, first}, State) of
+ {value, _} -> true;
+ undefined -> false
+ end,
+ ?vdebug("table exist result: "
+ "~n ~p",[Res]),
+ {reply, Res, State};
+
+handle_call({table_delete, Name, Db}, _From, State) ->
+ ?vlog("table delete: ~p [~p]",[Name, Db]),
+ catch handle_delete(Db, Name, State),
+ {reply, true, State};
+
+handle_call({table_create_row, Name, Db, Indexes, Row}, _From, State) ->
+ ?vlog("table create row [~p]: "
+ "~n Name: ~p"
+ "~n Indexes: ~p"
+ "~n Row: ~p",[Db, Name, Indexes, Row]),
+ Res =
+ case catch handle_create_row(Db, Name, Indexes, Row, State) of
+ {'EXIT', _} -> false;
+ _ -> true
+ end,
+ ?vdebug("table create row result: "
+ "~n ~p",[Res]),
+ {reply, Res, State};
+
+handle_call({table_delete_row, Name, Db, Indexes}, _From, State) ->
+ ?vlog("table delete row [~p]: "
+ "~n Name: ~p"
+ "~n Indexes: ~p", [Db, Name, Indexes]),
+ Res =
+ case catch handle_delete_row(Db, Name, Indexes, State) of
+ {'EXIT', _} -> false;
+ _ -> true
+ end,
+ ?vdebug("table delete row result: "
+ "~n ~p",[Res]),
+ {reply, Res, State};
+
+handle_call({table_get_row, Name, Db, Indexes}, _From, State) ->
+ ?vlog("table get row [~p]: "
+ "~n Name: ~p"
+ "~n Indexes: ~p",[Db, Name, Indexes]),
+ Res = case lookup(Db, {Name, Indexes}, State) of
+ undefined ->
+ undefined;
+ {value, {Row, _Prev, _Next}} ->
+ Row
+ end,
+ ?vdebug("table get row result: "
+ "~n ~p",[Res]),
+ {reply, Res, State};
+
+handle_call({table_get_element, Name, Db, Indexes, Col}, _From, State) ->
+ ?vlog("table ~p get element [~p]: "
+ "~n Indexes: ~p"
+ "~n Col: ~p", [Name, Db, Indexes, Col]),
+ Res = case lookup(Db, {Name, Indexes}, State) of
+ undefined -> undefined;
+ {value, {Row, _Prev, _Next}} -> {value, element(Col, Row)}
+ end,
+ ?vdebug("table get element result: "
+ "~n ~p",[Res]),
+ {reply, Res, State};
+
+handle_call({table_set_elements, Name, Db, Indexes, Cols}, _From, State) ->
+ ?vlog("table ~p set element [~p]: "
+ "~n Indexes: ~p"
+ "~n Cols: ~p", [Name, Db, Indexes, Cols]),
+ Res =
+ case catch handle_set_elements(Db, Name, Indexes, Cols, State) of
+ {'EXIT', _} -> false;
+ _ -> true
+ end,
+ ?vdebug("table set element result: "
+ "~n ~p",[Res]),
+ {reply, Res, State};
+
+handle_call({table_next, Name, Db, []}, From, State) ->
+ ?vlog("table next: ~p [~p]",[Name, Db]),
+ handle_call({table_next, Name, Db, first}, From, State);
+
+handle_call({table_next, Name, Db, Indexes}, _From, State) ->
+ ?vlog("table ~p next [~p]: "
+ "~n Indexes: ~p",[Name, Db, Indexes]),
+ Res = case lookup(Db, {Name, Indexes}, State) of
+ {value, {_Row, _Prev, Next}} ->
+ if
+ Next =:= first -> endOfTable;
+ true -> Next
+ end;
+ undefined ->
+ table_search_next(Db, Name, Indexes, State)
+ end,
+ ?vdebug("table next result: "
+ "~n ~p",[Res]),
+ {reply, Res, State};
+
+handle_call({table_max_col, Name, Db, Col}, _From, State) ->
+ ?vlog("table ~p max col [~p]: "
+ "~n Col: ~p",[Name, Db, Col]),
+ Res = table_max_col(Db, Name, Col, 0, first, State),
+ ?vdebug("table max col result: "
+ "~n ~p",[Res]),
+ {reply, Res, State};
+
+handle_call({match, Name, Db, Pattern}, _From, State) ->
+ ?vlog("match ~p [~p]:"
+ "~n Pat: ~p", [Name, Db, Pattern]),
+ L1 = match(Db, Name, Pattern, State),
+ {reply, lists:delete([undef], L1), State};
+
+handle_call({backup, BackupDir}, From, #state{dets = Dets} = State) ->
+ ?vlog("backup: ~p",[BackupDir]),
+ Pid = self(),
+ V = get(verbosity),
+ case file:read_file_info(BackupDir) of
+ {ok, #file_info{type = directory}} ->
+ BackupServer =
+ erlang:spawn_link(
+ fun() ->
+ put(sname, albs),
+ put(verbosity, V),
+ Dir = filename:join([BackupDir]),
+ #dets{tab = Tab} = Dets,
+ Reply = handle_backup(Tab, Dir),
+ Pid ! {backup_done, Reply},
+ unlink(Pid)
+ end),
+ ?vtrace("backup server: ~p", [BackupServer]),
+ {noreply, State#state{backup = {BackupServer, From}}};
+ {ok, _} ->
+ {reply, {error, not_a_directory}, State};
+ Error ->
+ {reply, Error, State}
+ end;
+
+handle_call(dump, _From, #state{dets = Dets} = State) ->
+ ?vlog("dump",[]),
+ dets_sync(Dets),
+ {reply, ok, State};
+
+handle_call(info, _From, #state{dets = Dets, ets = Ets} = State) ->
+ ?vlog("info",[]),
+ Info = get_info(Dets, Ets),
+ {reply, Info, State};
+
+handle_call(print, _From, #state{dets = Dets, ets = Ets} = State) ->
+ ?vlog("print",[]),
+ L1 = ets:tab2list(Ets),
+ L2 = dets_match_object(Dets, '_'),
+ {reply, {{ets, L1}, {dets, L2}}, State};
+
+handle_call({print, Table, Db}, _From, State) ->
+ ?vlog("print: ~p [~p]", [Table, Db]),
+ L = match(Db, Table, '$1', State),
+ {reply, lists:delete([undef], L), State};
+
+handle_call({register_notify_client, Client, Module}, _From, State) ->
+ ?vlog("register_notify_client: "
+ "~n Client: ~p"
+ "~n Module: ~p", [Client, Module]),
+ Nc = State#state.notify_clients,
+ case lists:keysearch(Client,1,Nc) of
+ {value,{Client,Mod}} ->
+ ?vlog("register_notify_client: already registered to: ~p",
+ [Module]),
+ {reply, {error,{already_registered,Mod}}, State};
+ false ->
+ {reply, ok, State#state{notify_clients = [{Client,Module}|Nc]}}
+ end;
+
+handle_call({unregister_notify_client, Client}, _From, State) ->
+ ?vlog("unregister_notify_client: ~p",[Client]),
+ Nc = State#state.notify_clients,
+ case lists:keysearch(Client,1,Nc) of
+ {value,{Client,_Module}} ->
+ Nc1 = lists:keydelete(Client,1,Nc),
+ {reply, ok, State#state{notify_clients = Nc1}};
+ false ->
+ ?vlog("unregister_notify_client: not registered",[]),
+ {reply, {error,not_registered}, State}
+ end;
+
+handle_call(stop, _From, State) ->
+ ?vlog("stop",[]),
+ {stop, normal, stopped, State};
+
+handle_call(Req, _From, State) ->
+ warning_msg("received unknown request: ~n~p", [Req]),
+ Reply = {error, {unknown, Req}},
+ {reply, Reply, State}.
+
+
+handle_cast({variable_inc, Name, Db, N}, State) ->
+ ?vlog("variable ~p inc"
+ "~n N: ~p", [Name, N]),
+ M = case lookup(Db, Name, State) of
+ {value, Val} -> Val;
+ _ -> 0
+ end,
+ insert(Db, Name, M+N rem 4294967296, State),
+ {noreply, State};
+
+handle_cast({verbosity,Verbosity}, State) ->
+ ?vlog("verbosity: ~p -> ~p",[get(verbosity),Verbosity]),
+ put(verbosity,?vvalidate(Verbosity)),
+ {noreply, State};
+
+handle_cast(Msg, State) ->
+ warning_msg("received unknown message: ~n~p", [Msg]),
+ {noreply, State}.
+
+
+handle_info({'EXIT', Pid, Reason}, #state{backup = {Pid, From}} = S) ->
+ ?vlog("backup server (~p) exited for reason ~n~p", [Pid, Reason]),
+ gen_server:reply(From, {error, Reason}),
+ {noreply, S#state{backup = undefined}};
+
+handle_info({'EXIT', Pid, Reason}, S) ->
+ %% The only other processes we should be linked to are
+ %% either the master agent or our supervisor, so die...
+ {stop, {received_exit, Pid, Reason}, S};
+
+handle_info({backup_done, Reply}, #state{backup = {_, From}} = S) ->
+ ?vlog("backup done:"
+ "~n Reply: ~p", [Reply]),
+ gen_server:reply(From, Reply),
+ {noreply, S#state{backup = undefined}};
+
+handle_info(Info, State) ->
+ warning_msg("received unknown info: ~n~p", [Info]),
+ {noreply, State}.
+
+
+terminate(Reason, State) ->
+ ?vlog("terminate: ~p",[Reason]),
+ close(State).
+
+
+%%----------------------------------------------------------
+%% Code change
+%%----------------------------------------------------------
+
+%% downgrade
+%%
+code_change({down, _Vsn}, S1, downgrade_to_pre_4_11) ->
+ #state{dets = D} = S1,
+ #dets{tab = Dets, shadow = Shadow} = D,
+ ets:delete(Shadow),
+ S2 = S1#state{dets = Dets},
+ {ok, S2};
+
+%% upgrade
+%%
+code_change(_Vsn, S1, upgrade_from_pre_4_11) ->
+ #state{dets = D} = S1,
+ Shadow = ets:new(snmp_local_db1_shadow, [set, protected]),
+ dets:to_ets(D, Shadow),
+ Dets = #dets{tab = D, shadow = Shadow},
+ S2 = S1#state{dets = Dets},
+ {ok, S2};
+
+code_change(_Vsn, State, _Extra) ->
+ {ok, State}.
+
+
+
+%%----------------------------------------------------------
+%% Backup
+%%----------------------------------------------------------
+
+handle_backup(D, BackupDir) ->
+ %% First check that we do not wrote to the corrent db-dir...
+ ?vtrace("handle_backup -> entry with"
+ "~n D: ~p"
+ "~n BackupDir: ~p", [D, BackupDir]),
+ case dets:info(D, filename) of
+ undefined ->
+ ?vinfo("handle_backup -> no file to backup", []),
+ {error, no_file};
+ Filename ->
+ ?vinfo("handle_backup -> file to backup: ~n ~p", [Filename]),
+ case filename:dirname(Filename) of
+ BackupDir ->
+ ?vinfo("handle_backup -> backup dir and db dir the same",
+ []),
+ {error, db_dir};
+ _ ->
+ case file:read_file_info(BackupDir) of
+ {ok, #file_info{type = directory}} ->
+ ?vdebug("handle_backup -> backup dir ok", []),
+ %% All well so far...
+ Type = dets:info(D, type),
+ KP = dets:info(D, keypos),
+ dets_backup(D,
+ filename:basename(Filename),
+ BackupDir, Type, KP);
+ {ok, _} ->
+ ?vinfo("handle_backup -> backup dir not a dir",
+ []),
+ {error, not_a_directory};
+ Error ->
+ ?vinfo("handle_backup -> Error: ~p", [Error]),
+ Error
+ end
+ end
+ end.
+
+dets_backup(D, Filename, BackupDir, Type, KP) ->
+ ?vtrace("dets_backup -> entry with"
+ "~n D: ~p"
+ "~n Filename: ~p"
+ "~n BackupDir: ~p", [D, Filename, BackupDir]),
+ BackupFile = filename:join(BackupDir, Filename),
+ ?vtrace("dets_backup -> "
+ "~n BackupFile: ~p", [BackupFile]),
+ Opts = [{file, BackupFile}, {type, Type}, {keypos, KP}],
+ case dets:open_file(?BACKUP_TAB, Opts) of
+ {ok, B} ->
+ F = fun(Arg) ->
+ dets_backup(Arg, start, D, B)
+ end,
+ ?vtrace("dets_backup -> fix table", []),
+ dets:safe_fixtable(D, true),
+ ?vtrace("dets_backup -> copy table", []),
+ Res = dets:init_table(?BACKUP_TAB, F, [{format, bchunk}]),
+ ?vtrace("dets_backup -> unfix table", []),
+ dets:safe_fixtable(D, false),
+ ?vtrace("dets_backup -> Res: ~p", [Res]),
+ Res;
+ Error ->
+ ?vinfo("dets_backup -> open_file failed: "
+ "~n ~p", [Error]),
+ Error
+ end.
+
+
+dets_backup(close, _Cont, _D, B) ->
+ dets:close(B),
+ ok;
+dets_backup(read, Cont1, D, B) ->
+ case dets:bchunk(D, Cont1) of
+ {Cont2, Data} ->
+ F = fun(Arg) ->
+ dets_backup(Arg, Cont2, D, B)
+ end,
+ {Data, F};
+ '$end_of_table' ->
+ dets:close(B),
+ end_of_input;
+ Error ->
+ Error
+ end.
+
+
+%%-----------------------------------------------------------------
+%% All handle_ functions exists so we can catch the call to
+%% them, because we don't want to crash the server if a user
+%% forgets to call e.g. table_create.
+%%-----------------------------------------------------------------
+%% Find larger element and insert before.
+handle_create_row(Db, Name, Indexes, Row, State) ->
+ case table_find_first_after_maybe_same(Db, Name, Indexes, State) of
+ {{Name, Next}, {NRow, NPrev, NNext}} ->
+ {value, {PRow, PPrev, _PNext}} = lookup(Db, {Name, NPrev}, State),
+ if
+ Next =:= NPrev ->
+ % Insert before first
+ insert(Db, {Name, NPrev}, {PRow, Indexes, Indexes}, State);
+ true ->
+ insert(Db, {Name, NPrev}, {PRow, PPrev, Indexes}, State),
+ insert(Db, {Name, Next}, {NRow, Indexes, NNext}, State)
+ end,
+ insert(Db, {Name, Indexes}, {Row, NPrev, Next}, State);
+ {same_row, {Prev, Next}} ->
+ insert(Db, {Name, Indexes}, {Row, Prev, Next}, State)
+ end.
+
+handle_delete_row(Db, Name, Indexes, State) ->
+ {value, {_, Prev, Next}} = lookup(Db, {Name, Indexes}, State),
+ {value, {PRow, PPrev, Indexes}} = lookup(Db, {Name, Prev}, State),
+ insert(Db, {Name, Prev}, {PRow, PPrev, Next}, State),
+ {value, {NRow, Indexes, NNext}} = lookup(Db, {Name, Next}, State),
+ insert(Db, {Name, Next}, {NRow, Prev, NNext}, State),
+ delete(Db, {Name, Indexes}, State).
+
+handle_set_elements(Db, Name, Indexes, Cols, State) ->
+ {value, {Row, Prev, Next}} = lookup(Db, {Name, Indexes}, State),
+ NewRow = set_new_row(Cols, Row),
+ insert(Db, {Name, Indexes}, {NewRow, Prev, Next}, State).
+
+set_new_row([{Col, Val} | Cols], Row) ->
+ set_new_row(Cols, setelement(Col, Row, Val));
+set_new_row([], Row) ->
+ Row.
+
+handle_delete(Db, Name, State) ->
+ {value, {_, _, Next}} = lookup(Db, {Name, first}, State),
+ delete(Db, {Name, first}, State),
+ handle_delete(Db, Name, Next, State).
+handle_delete(_Db, _Name, first, _State) -> true;
+handle_delete(Db, Name, Indexes, State) ->
+ {value, {_, _, Next}} = lookup(Db, {Name, Indexes}, State),
+ delete(Db, {Name, Indexes}, State),
+ handle_delete(Db, Name, Next, State).
+
+%%-----------------------------------------------------------------
+%% Implementation of next.
+%%-----------------------------------------------------------------
+table_search_next(Db, Name, Indexes, State) ->
+ case catch table_find_first_after(Db, Name, Indexes, State) of
+ {{Name, Key}, {_, _, _Next}} ->
+ case Key of
+ first -> endOfTable;
+ _ -> Key
+ end;
+ {'EXIT', _} -> endOfTable
+ end.
+
+table_find_first_after(Db, Name, Indexes, State) ->
+ {value, {_Row, _Prev, Next}} = lookup(Db, {Name, first}, State),
+ table_loop(Db, Name, Indexes, Next, State).
+
+table_loop(Db, Name, _Indexes, first, State) ->
+ {value, FirstVal} = lookup(Db, {Name, first}, State),
+ {{Name, first}, FirstVal};
+
+table_loop(Db, Name, Indexes, Cur, State) ->
+ {value, {Row, Prev, Next}} = lookup(Db, {Name, Cur}, State),
+ if
+ Cur > Indexes ->
+ {{Name, Cur}, {Row, Prev, Next}};
+ true ->
+ table_loop(Db, Name, Indexes, Next, State)
+ end.
+
+table_find_first_after_maybe_same(Db, Name, Indexes, State) ->
+ {value, {_Row, _Prev, Next}} = lookup(Db, {Name, first}, State),
+ table_loop2(Db, Name, Indexes, Next, State).
+
+table_loop2(Db, Name, _Indexes, first, State) ->
+ {value, FirstVal} = lookup(Db, {Name, first}, State),
+ {{Name, first}, FirstVal};
+
+table_loop2(Db, Name, Indexes, Cur, State) ->
+ {value, {Row, Prev, Next}} = lookup(Db, {Name, Cur}, State),
+ if
+ Cur > Indexes ->
+ {{Name, Cur}, {Row, Prev, Next}};
+ Cur =:= Indexes ->
+ {same_row, {Prev, Next}};
+ true ->
+ table_loop2(Db, Name, Indexes, Next, State)
+ end.
+
+%%-----------------------------------------------------------------
+%% Implementation of max.
+%% The value in a column could be noinit or undefined,
+%% so we must check only those with an integer.
+%%-----------------------------------------------------------------
+table_max_col(Db, Name, Col, Max, Indexes, State) ->
+ case lookup(Db, {Name, Indexes}, State) of
+ {value, {Row, _Prev, Next}} ->
+ if
+ Next =:= first ->
+ if
+ is_integer(element(Col, Row)) andalso
+ (element(Col, Row) > Max) ->
+ element(Col, Row);
+ true ->
+ Max
+ end;
+ is_integer(element(Col, Row)) andalso
+ (element(Col, Row) > Max) ->
+ table_max_col(Db,Name, Col,element(Col, Row),Next, State);
+ true ->
+ table_max_col(Db, Name, Col, Max, Next, State)
+ end;
+ undefined -> table_search_next(Db, Name, Indexes, State)
+ end.
+
+%%-----------------------------------------------------------------
+%% Interface to Pets.
+%%-----------------------------------------------------------------
+insert(volatile, Key, Val, #state{ets = Ets}) ->
+ ?vtrace("insert(volatile) -> entry with"
+ "~n Key: ~p"
+ "~n Val: ~p",
+ [Key,Val]),
+ ets:insert(Ets, {Key, Val}),
+ true;
+insert(persistent, Key, Val, #state{dets = Dets, notify_clients = NC}) ->
+ ?vtrace("insert(persistent) -> entry with"
+ "~n Key: ~p"
+ "~n Val: ~p",
+ [Key,Val]),
+ case dets_insert(Dets, {Key, Val}) of
+ ok ->
+ notify_clients(insert,NC),
+ true;
+ {error, Reason} ->
+ error_msg("DETS (persistent) insert failed for {~w,~w}: ~n~w",
+ [Key, Val, Reason]),
+ false
+ end;
+insert(permanent, Key, Val, #state{dets = Dets, notify_clients = NC}) ->
+ ?vtrace("insert(permanent) -> entry with"
+ "~n Key: ~p"
+ "~n Val: ~p",
+ [Key,Val]),
+ case dets_insert(Dets, {Key, Val}) of
+ ok ->
+ notify_clients(insert,NC),
+ true;
+ {error, Reason} ->
+ error_msg("DETS (permanent) insert failed for {~w,~w}: ~n~w",
+ [Key, Val, Reason]),
+ false
+ end;
+insert(UnknownDb, Key, Val, _) ->
+ error_msg("Tried to insert ~w = ~w into unknown db ~w",
+ [Key, Val, UnknownDb]),
+ false.
+
+delete(volatile, Key, State) ->
+ ets:delete(State#state.ets, Key),
+ true;
+delete(persistent, Key, #state{dets = Dets, notify_clients = NC}) ->
+ case dets_delete(Dets, Key) of
+ ok ->
+ notify_clients(delete,NC),
+ true;
+ {error, Reason} ->
+ error_msg("DETS (persistent) delete failed for ~w: ~n~w",
+ [Key, Reason]),
+ false
+ end;
+delete(permanent, Key, #state{dets = Dets, notify_clients = NC}) ->
+ case dets_delete(Dets, Key) of
+ ok ->
+ notify_clients(delete,NC),
+ true;
+ {error, Reason} ->
+ error_msg("DETS (permanent) delete failed for ~w: ~n~w",
+ [Key, Reason]),
+ false
+ end;
+delete(UnknownDb, Key, _) ->
+ error_msg("Tried to delete ~w from unknown db ~w",
+ [Key, UnknownDb]),
+ false.
+
+
+match(volatile, Name, Pattern, #state{ets = Ets}) ->
+ ets:match(Ets, {{Name,'_'},{Pattern,'_','_'}});
+match(persistent, Name, Pattern, #state{dets = Dets}) ->
+ dets_match(Dets, {{Name,'_'},{Pattern,'_','_'}});
+match(permanent, Name, Pattern, #state{dets = Dets}) ->
+ dets_match(Dets, {{Name,'_'},{Pattern,'_','_'}});
+match(UnknownDb, Name, Pattern, _) ->
+ error_msg("Tried to match [~p,~p] from unknown db ~w",
+ [Name, Pattern, UnknownDb]),
+ [].
+
+lookup(volatile, Key, #state{ets = Ets}) ->
+ case ets:lookup(Ets, Key) of
+ [{_, Val}] ->
+ {value, Val};
+ [] ->
+ undefined
+ end;
+lookup(persistent, Key, #state{dets = Dets}) ->
+ case dets_lookup(Dets, Key) of
+ [{_, Val}] ->
+ {value, Val};
+ [] ->
+ undefined
+ end;
+lookup(permanent, Key, #state{dets = Dets}) ->
+ case dets_lookup(Dets, Key) of
+ [{_, Val}] ->
+ {value, Val};
+ [] ->
+ undefined
+ end;
+lookup(UnknownDb, Key, _) ->
+ error_msg("Tried to lookup ~w in unknown db ~w", [Key, UnknownDb]),
+ false.
+
+close(#state{dets = Dets, ets = Ets}) ->
+ ets:delete(Ets),
+ dets_close(Dets).
+
+
+%%-----------------------------------------------------------------
+%% Notify clients interface
+%%-----------------------------------------------------------------
+notify_clients(Event, Clients) ->
+ F = fun(Client) -> notify_client(Client, Event) end,
+ lists:foreach(F, Clients).
+
+notify_client({Client,Module}, Event) ->
+ (catch Module:notify(Client,Event)).
+
+
+%%------------------------------------------------------------------
+%% Constructs a row with first elements the own part of RowIndex,
+%% and last element RowStatus. All values are stored "as is", i.e.
+%% dynamic key values are stored without length first.
+%% RowIndex is a list of the
+%% first elements. RowStatus is needed, because the
+%% provided value may not be stored, e.g. createAndGo
+%% should be active.
+%% Returns a tuple of values for the row. If a value
+%% isn't specified in the Col list, then the
+%% corresponding value will be noinit.
+%%------------------------------------------------------------------
+table_construct_row(Name, RowIndex, Status, Cols) ->
+ #table_info{nbr_of_cols = LastCol, index_types = Indexes,
+ defvals = Defs, status_col = StatusCol,
+ first_own_index = FirstOwnIndex, not_accessible = NoAccs} =
+ snmp_generic:table_info(Name),
+ Keys = snmp_generic:split_index_to_keys(Indexes, RowIndex),
+ OwnKeys = snmp_generic:get_own_indexes(FirstOwnIndex, Keys),
+ Row = OwnKeys ++ snmp_generic:table_create_rest(length(OwnKeys) + 1,
+ LastCol, StatusCol,
+ Status, Cols, NoAccs),
+ L = snmp_generic:init_defaults(Defs, Row),
+ list_to_tuple(L).
+
+
+table_get_elements(NameDb, RowIndex, Cols, _FirstOwnIndex) ->
+ get_elements(Cols, table_get_row(NameDb, RowIndex)).
+
+get_elements(_Cols, undefined) ->
+ undefined;
+get_elements([Col | Cols], Row) when is_tuple(Row) and (size(Row) >= Col) ->
+ [element(Col, Row) | get_elements(Cols, Row)];
+get_elements([], _Row) ->
+ [];
+get_elements(Cols, Row) ->
+ erlang:error({bad_arguments, Cols, Row}).
+
+
+%%----------------------------------------------------------------------
+%% This should/could be a generic function, but since Mnesia implements
+%% its own and this version still is local_db dependent, it's not generic yet.
+%%----------------------------------------------------------------------
+%% createAndGo
+table_set_status(NameDb, RowIndex, ?'RowStatus_createAndGo', StatusCol, Cols,
+ ChangedStatusFunc, _ConsFunc) ->
+ case table_create_row(NameDb, RowIndex, ?'RowStatus_active', Cols) of
+ true -> snmp_generic:try_apply(ChangedStatusFunc,
+ [NameDb, ?'RowStatus_createAndGo',
+ RowIndex, Cols]);
+ _ -> {commitFailed, StatusCol}
+ end;
+
+%%------------------------------------------------------------------
+%% createAndWait - set status to notReady, and try to
+%% make row consistent.
+%%------------------------------------------------------------------
+table_set_status(NameDb, RowIndex, ?'RowStatus_createAndWait', StatusCol, Cols,
+ ChangedStatusFunc, ConsFunc) ->
+ case table_create_row(NameDb, RowIndex, ?'RowStatus_notReady', Cols) of
+ true ->
+ case snmp_generic:try_apply(ConsFunc, [NameDb, RowIndex, Cols]) of
+ {noError, 0} ->
+ snmp_generic:try_apply(ChangedStatusFunc,
+ [NameDb, ?'RowStatus_createAndWait',
+ RowIndex, Cols]);
+ Error -> Error
+ end;
+ _ -> {commitFailed, StatusCol}
+ end;
+
+%% destroy
+table_set_status(NameDb, RowIndex, ?'RowStatus_destroy', _StatusCol, Cols,
+ ChangedStatusFunc, _ConsFunc) ->
+ case snmp_generic:try_apply(ChangedStatusFunc,
+ [NameDb, ?'RowStatus_destroy',
+ RowIndex, Cols]) of
+ {noError, 0} ->
+ table_delete_row(NameDb, RowIndex),
+ {noError, 0};
+ Error -> Error
+ end;
+
+%% Otherwise, active or notInService
+table_set_status(NameDb, RowIndex, Val, _StatusCol, Cols,
+ ChangedStatusFunc, ConsFunc) ->
+ snmp_generic:table_set_cols(NameDb, RowIndex, Cols, ConsFunc),
+ snmp_generic:try_apply(ChangedStatusFunc, [NameDb, Val, RowIndex, Cols]).
+
+table_func(new, NameDb) ->
+ case table_exists(NameDb) of
+ true -> ok;
+ _ -> table_create(NameDb)
+ end;
+
+table_func(delete, _NameDb) ->
+ ok.
+
+table_func(get, RowIndex, Cols, NameDb) ->
+ TableInfo = snmp_generic:table_info(NameDb),
+ snmp_generic:handle_table_get(NameDb, RowIndex, Cols,
+ TableInfo#table_info.first_own_index);
+
+%%------------------------------------------------------------------
+%% Returns: List of endOfTable | {NextOid, Value}.
+%% Implements the next operation, with the function
+%% handle_table_next. Next should return the next accessible
+%% instance, which cannot be a key.
+%%------------------------------------------------------------------
+table_func(get_next, RowIndex, Cols, NameDb) ->
+ #table_info{first_accessible = FirstCol, first_own_index = FOI,
+ nbr_of_cols = LastCol} = snmp_generic:table_info(NameDb),
+ snmp_generic:handle_table_next(NameDb, RowIndex, Cols,
+ FirstCol, FOI, LastCol);
+
+%%-----------------------------------------------------------------
+%% This function must only be used by tables with a RowStatus col!
+%% Other tables must check if row exist themselves.
+%%-----------------------------------------------------------------
+table_func(is_set_ok, RowIndex, Cols, NameDb) ->
+ snmp_generic:table_try_row(NameDb, nofunc, RowIndex, Cols);
+
+%%------------------------------------------------------------------
+%% Cols is here a list of {ColumnNumber, NewValue}
+%% This function must only be used by tables with a RowStatus col!
+%% Other tables should use table_set_cols/3,4.
+%%------------------------------------------------------------------
+table_func(set, RowIndex, Cols, NameDb) ->
+ snmp_generic:table_set_row(NameDb,
+ nofunc,
+ {snmp_generic, table_try_make_consistent},
+ RowIndex,
+ Cols);
+
+table_func(undo, _RowIndex, _Cols, _NameDb) ->
+ {noError, 0}.
+
+
+
+%%------------------------------------------------------------------
+%% This functions retrieves option values from the Options list.
+%%------------------------------------------------------------------
+get_opt(Key, Opts, Def) ->
+ snmp_misc:get_option(Key, Opts, Def).
+
+
+%%------------------------------------------------------------------
+
+get_info(Dets, Ets) ->
+ ProcSize = proc_mem(self()),
+ DetsSz = dets_size(Dets),
+ EtsSz = ets_size(Ets),
+ [{process_memory, ProcSize},
+ {db_memory, [{persistent, DetsSz}, {volatile, EtsSz}]}].
+
+proc_mem(P) when is_pid(P) ->
+ case (catch erlang:process_info(P, memory)) of
+ {memory, Sz} ->
+ Sz;
+ _ ->
+ undefined
+ end.
+%% proc_mem(_) ->
+%% undefined.
+
+dets_size(#dets{tab = Tab, shadow = Shadow}) ->
+ TabSz =
+ case (catch dets:info(Tab, file_size)) of
+ Sz when is_integer(Sz) ->
+ Sz;
+ _ ->
+ undefined
+ end,
+ ShadowSz = ets_size(Shadow),
+ [{tab, TabSz}, {shadow, ShadowSz}].
+
+ets_size(T) ->
+ case (catch ets:info(T, memory)) of
+ Sz when is_integer(Sz) ->
+ Sz;
+ _ ->
+ undefined
+ end.
+
+%%------------------------------------------------------------------
+
+%% info_msg(F, A) ->
+%% ?snmpa_info("Local DB server: " ++ F, A).
+
+warning_msg(F, A) ->
+ ?snmpa_warning("Local DB server: " ++ F, A).
+
+error_msg(F, A) ->
+ ?snmpa_error("Local DB server: " ++ F, A).
+
+%% ---
+
+user_err(F, A) ->
+ snmpa_error:user_err(F, A).
+
+config_err(F, A) ->
+ snmpa_error:config_err(F, A).
+
+
+%% ----------------------------------------------------------------
+
+call(Req) ->
+ gen_server:call(?SERVER, Req, infinity).
+
+cast(Msg) ->
+ gen_server:cast(?SERVER, Msg).
+
+
+%% ----------------------------------------------------------------
+%% DETS wrapper functions
+%% The purpose of these fuctions is basically to hide the shadow
+%% table.
+%% Changes are made both in dets and in the shadow table.
+%% Reads are made from the shadow table.
+%% ----------------------------------------------------------------
+
+dets_sync(#dets{tab = Dets}) ->
+ dets:sync(Dets).
+
+dets_insert(#dets{tab = Tab, shadow = Shadow}, Data) ->
+ ets:insert(Shadow, Data),
+ dets:insert(Tab, Data).
+
+dets_delete(#dets{tab = Tab, shadow = Shadow}, Key) ->
+ ets:delete(Shadow, Key),
+ dets:delete(Tab, Key).
+
+dets_match(#dets{shadow = Shadow}, Pat) ->
+ ets:match(Shadow, Pat).
+
+dets_match_object(#dets{shadow = Shadow}, Pat) ->
+ ets:match_object(Shadow, Pat).
+
+dets_lookup(#dets{shadow = Shadow}, Key) ->
+ ets:lookup(Shadow, Key).
+
+dets_close(#dets{tab = Tab, shadow = Shadow}) ->
+ ets:delete(Shadow),
+ dets:close(Tab).
diff --git a/lib/snmp/src/agent/snmpa_mib.erl b/lib/snmp/src/agent/snmpa_mib.erl
new file mode 100644
index 0000000000..370989d0be
--- /dev/null
+++ b/lib/snmp/src/agent/snmpa_mib.erl
@@ -0,0 +1,892 @@
+%%
+%% %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%
+%%
+-module(snmpa_mib).
+
+%% c(snmpa_mib).
+
+%%%-----------------------------------------------------------------
+%%% This module implements a MIB server.
+%%%-----------------------------------------------------------------
+
+%% External exports
+-export([start_link/3, stop/1,
+ lookup/2, next/3, which_mib/2, which_mibs/1, whereis_mib/2,
+ load_mibs/2, unload_mibs/2,
+ register_subagent/3, unregister_subagent/2, info/1, info/2,
+ verbosity/2, dump/1, dump/2,
+ backup/2,
+ invalidate_cache/1,
+ gc_cache/1, gc_cache/2, gc_cache/3,
+ enable_cache/1, disable_cache/1,
+ enable_cache_autogc/1, disable_cache_autogc/1,
+ update_cache_gclimit/2,
+ update_cache_age/2,
+ which_cache_size/1
+ ]).
+
+%% Internal exports
+-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2,
+ code_change/3]).
+
+-include_lib("kernel/include/file.hrl").
+-include("snmpa_internal.hrl").
+-include("snmp_types.hrl").
+-include("snmp_verbosity.hrl").
+-include("snmp_debug.hrl").
+
+
+-define(SERVER, ?MODULE).
+-define(NO_CACHE, no_mibs_cache).
+-define(DEFAULT_CACHE_USAGE, true).
+-define(CACHE_GC_TICKTIME, timer:minutes(1)).
+-define(DEFAULT_CACHE_AUTOGC, false).
+-define(DEFAULT_CACHE_GCLIMIT, 100).
+-define(DEFAULT_CACHE_AGE, timer:minutes(10)).
+-define(CACHE_GC_TRIGGER, cache_gc_trigger).
+
+
+
+-ifdef(snmp_debug).
+-define(GS_START_LINK(Prio, Mibs, Opts),
+ gen_server:start_link(?MODULE, [Prio, Mibs, Opts], [{debug,[trace]}])).
+-else.
+-define(GS_START_LINK(Prio, Mibs, Opts),
+ gen_server:start_link(?MODULE, [Prio, Mibs, Opts], [])).
+-endif.
+
+
+%%-----------------------------------------------------------------
+%% Internal Data structures
+%%
+%% State
+%% data - is the MIB data (defined in snmpa_mib_data)
+%% meo - mib entry override
+%% teo - trap (notification) entry override
+%%-----------------------------------------------------------------
+-record(state, {data, meo, teo, backup,
+ cache, cache_tmr, cache_autogc, cache_gclimit, cache_age}).
+
+
+
+%%-----------------------------------------------------------------
+%% Func: start_link/1
+%% Args: Mibs is a list of mibnames.
+%% Prio is priority of mib-server
+%% Opts is a list of options
+%% Purpose: starts the mib server synchronized
+%% Returns: {ok, Pid} | {error, Reason}
+%%-----------------------------------------------------------------
+start_link(Prio, Mibs, Opts) ->
+ ?d("start_link -> entry with"
+ "~n Prio: ~p"
+ "~n Mibs: ~p"
+ "~n Opts: ~p", [Prio, Mibs, Opts]),
+ ?GS_START_LINK(Prio, Mibs, Opts).
+
+verbosity(MibServer, Verbosity) ->
+ cast(MibServer, {verbosity,Verbosity}).
+
+stop(MibServer) ->
+ call(MibServer, stop).
+
+invalidate_cache(MibServer) ->
+ call(MibServer, invalidate_cache).
+
+gc_cache(MibServer) ->
+ call(MibServer, gc_cache).
+
+gc_cache(MibServer, Age) ->
+ call(MibServer, {gc_cache, Age}).
+
+gc_cache(MibServer, Age, GcLimit) ->
+ call(MibServer, {gc_cache, Age, GcLimit}).
+
+which_cache_size(MibServer) ->
+ call(MibServer, cache_size).
+
+enable_cache(MibServer) ->
+ update_cache_opts(MibServer, cache, true).
+disable_cache(MibServer) ->
+ update_cache_opts(MibServer, cache, false).
+
+enable_cache_autogc(MibServer) ->
+ update_cache_opts(MibServer, autogc, true).
+disable_cache_autogc(MibServer) ->
+ update_cache_opts(MibServer, autogc, false).
+
+update_cache_gclimit(MibServer, GcLimit)
+ when ((is_integer(GcLimit) andalso (GcLimit > 0)) orelse
+ (GcLimit =:= infinity)) ->
+ update_cache_opts(MibServer, gclimit, GcLimit);
+update_cache_gclimit(_, BadLimit) ->
+ {error, {bad_gclimit, BadLimit}}.
+
+update_cache_age(MibServer, Age)
+ when is_integer(Age) andalso (Age > 0) ->
+ update_cache_opts(MibServer, age, Age);
+update_cache_age(_, BadAge) ->
+ {error, {bad_age, BadAge}}.
+
+update_cache_opts(MibServer, Key, Value) ->
+ call(MibServer, {update_cache_opts, Key, Value}).
+
+
+%%-----------------------------------------------------------------
+%% Func: lookup/2
+%% Purpose: Finds the mib entry corresponding to the Oid. If it is a
+%% variable, the Oid must be <Oid for var>.0 and if it is
+%% a table, Oid must be <table>.<entry>.<col>.<any>
+%% Returns: {variable, MibEntry} |
+%% {table_column, MibEntry, TableEntryOid} |
+%% {subagent, SubAgentPid} |
+%% false
+%%-----------------------------------------------------------------
+lookup(MibServer, Oid) ->
+ call(MibServer, {lookup, Oid}).
+
+which_mib(MibServer, Oid) ->
+ call(MibServer, {which_mib, Oid}).
+
+
+%%-----------------------------------------------------------------
+%% Func: next/3
+%% Purpose: Finds the lexicographically next oid.
+%% Returns: {subagent, SubAgentPid, SANextOid} |
+%% endOfMibView |
+%% genErr |
+%% NextOid
+%% The SANextOid is used by the agent if the SubAgent returns
+%% endOfMib, in a new call to next/2.
+%%-----------------------------------------------------------------
+next(MibServer, Oid, MibView) ->
+ call(MibServer, {next, Oid, MibView}).
+
+
+%%----------------------------------------------------------------------
+%% Purpose: Loads mibs into the mib process.
+%% Args: Mibs is a list of Filenames (compiled mibs).
+%% Returns: ok | {error, Reason}
+%%----------------------------------------------------------------------
+load_mibs(MibServer, Mibs) ->
+ call(MibServer, {load_mibs, Mibs}).
+
+
+%%----------------------------------------------------------------------
+%% Purpose: Loads mibs into the mib process.
+%% Args: Mibs is a list of Filenames (compiled mibs).
+%% Returns: ok | {error, Reason}
+%%----------------------------------------------------------------------
+unload_mibs(MibServer, Mibs) ->
+ call(MibServer, {unload_mibs, Mibs}).
+
+
+%%----------------------------------------------------------------------
+%% Purpose: Simple management functions
+%% Args: Mib is the name of the mib (atom)
+%% Returns: ok | {error, Reason}
+%%----------------------------------------------------------------------
+which_mibs(MibServer) ->
+ call(MibServer, which_mibs).
+
+whereis_mib(MibServer, Mib) ->
+ call(MibServer, {whereis_mib, Mib}).
+
+
+%%----------------------------------------------------------------------
+%% Registers subagent with pid Pid under subtree Oid.
+%%----------------------------------------------------------------------
+register_subagent(MibServer, Oid, Pid) ->
+ call(MibServer, {register_subagent, Oid, Pid}).
+
+unregister_subagent(MibServer, OidOrPid) ->
+ call(MibServer, {unregister_subagent, OidOrPid}).
+
+info(MibServer) ->
+ call(MibServer, info).
+
+info(MibServer, Type) ->
+ call(MibServer, {info, Type}).
+
+dump(MibServer) ->
+ call(MibServer, dump).
+
+dump(MibServer, File) when is_list(File) ->
+ call(MibServer, {dump, File}).
+
+backup(MibServer, BackupDir) when is_list(BackupDir) ->
+ call(MibServer, {backup, BackupDir}).
+
+
+%%--------------------------------------------------
+%% The standard MIB 'stdmib' must be present in the
+%% current directory.
+%%--------------------------------------------------
+init([Prio, Mibs, Opts]) ->
+ ?d("init -> entry with"
+ "~n Prio: ~p"
+ "~n Mibs: ~p"
+ "~n Opts: ~p", [Prio, Mibs, Opts]),
+ case (catch do_init(Prio, Mibs, Opts)) of
+ {ok, State} ->
+ {ok, State};
+ {error, Reason} ->
+ config_err("failed starting mib-server: ~n~p", [Reason]),
+ {stop, {error, Reason}};
+ Error ->
+ config_err("failed starting mib-server: ~n~p", [Error]),
+ {stop, {error, Error}}
+ end.
+
+do_init(Prio, Mibs, Opts) ->
+ process_flag(priority, Prio),
+ process_flag(trap_exit, true),
+ put(sname,ms),
+ put(verbosity, ?vvalidate(get_verbosity(Opts))),
+ ?vlog("starting",[]),
+
+ %% Extract the cache options
+ {Cache, CacheOptions} =
+ case get_opt(cache, Opts, ?DEFAULT_CACHE_USAGE) of
+ true ->
+ {new_cache(), []};
+ false ->
+ {?NO_CACHE, []};
+ CacheOpts when is_list(CacheOpts) ->
+ {new_cache(), CacheOpts};
+ Bad ->
+ throw({error, {bad_option, {cache, Bad}}})
+ end,
+ CacheAutoGC = get_cacheopt_autogc(Cache, CacheOptions),
+ CacheGcLimit = get_cacheopt_gclimit(Cache, CacheOptions),
+ CacheAge = get_cacheopt_age(Cache, CacheOptions),
+
+ %% Maybe start the cache gc timer
+ CacheGcTimer =
+ if
+ ((Cache =/= ?NO_CACHE) andalso
+ (CacheAutoGC =:= true)) ->
+ start_cache_gc_timer();
+ true ->
+ undefined
+ end,
+
+ MeOverride = get_me_override(Opts),
+ TeOverride = get_te_override(Opts),
+ MibStorage = get_mib_storage(Opts),
+ Data = snmpa_mib_data:new(MibStorage),
+ ?vtrace("init -> mib data created",[]),
+ case (catch mib_operations(load_mib, Mibs, Data,
+ MeOverride, TeOverride, true)) of
+ {ok, Data2} ->
+ ?vdebug("started",[]),
+ snmpa_mib_data:sync(Data2),
+ ?vdebug("mib data synced",[]),
+ {ok, #state{data = Data2,
+ teo = TeOverride,
+ meo = MeOverride,
+ cache = Cache,
+ cache_tmr = CacheGcTimer,
+ cache_autogc = CacheAutoGC,
+ cache_gclimit = CacheGcLimit,
+ cache_age = CacheAge}};
+ {'aborted at', Mib, _NewData, Reason} ->
+ ?vinfo("failed loading mib ~p: ~p",[Mib,Reason]),
+ {error, {Mib, Reason}}
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Returns: {ok, NewMibData} | {'aborted at', Mib, NewData, Reason}
+%% Args: Operation is load_mib | unload_mib.
+%%----------------------------------------------------------------------
+mib_operations(Operation, Mibs, Data, MeOverride, TeOverride) ->
+ mib_operations(Operation, Mibs, Data, MeOverride, TeOverride, false).
+
+
+mib_operations(_Operation, [], Data, _MeOverride, _TeOverride, _Force) ->
+ {ok, Data};
+mib_operations(Operation, [Mib|Mibs], Data0, MeOverride, TeOverride, Force) ->
+ ?vtrace("mib operations ~p on"
+ "~n Mibs: ~p"
+ "~n with "
+ "~n MeOverride: ~p"
+ "~n TeOverride: ~p"
+ "~n Force: ~p", [Operation,Mibs,MeOverride,TeOverride,Force]),
+ Data = mib_operation(Operation, Mib, Data0, MeOverride, TeOverride, Force),
+ mib_operations(Operation, Mibs, Data, MeOverride, TeOverride, Force).
+
+mib_operation(Operation, Mib, Data0, MeOverride, TeOverride, Force)
+ when is_list(Mib) ->
+ ?vtrace("mib operation on mib ~p", [Mib]),
+ case apply(snmpa_mib_data, Operation, [Data0,Mib,MeOverride,TeOverride]) of
+ {error, 'already loaded'} when (Operation =:= load_mib) andalso
+ (Force =:= true) ->
+ ?vlog("ignore mib ~p -> already loaded", [Mib]),
+ Data0;
+ {error, 'not loaded'} when (Operation =:= unload_mib) andalso
+ (Force =:= true) ->
+ ?vlog("ignore mib ~p -> not loaded", [Mib]),
+ Data0;
+ {error, Reason} ->
+ ?vlog("mib_operation -> failed ~p of mib ~p for ~p",
+ [Operation, Mib, Reason]),
+ throw({'aborted at', Mib, Data0, Reason});
+ {ok, Data} ->
+ Data
+ end;
+mib_operation(_Op, Mib, Data, _MeOverride, _TeOverride, _Force) ->
+ throw({'aborted at', Mib, Data, bad_mibname}).
+
+
+%%-----------------------------------------------------------------
+%% Handle messages
+%%-----------------------------------------------------------------
+
+handle_call(invalidate_cache, _From, #state{cache = Cache} = State) ->
+ ?vlog("invalidate_cache", []),
+ NewCache = maybe_invalidate_cache(Cache),
+ {reply, ignore, State#state{cache = NewCache}};
+
+handle_call(cache_size, _From, #state{cache = Cache} = State) ->
+ ?vlog("cache_size", []),
+ Reply = maybe_cache_size(Cache),
+ {reply, Reply, State};
+
+handle_call(gc_cache, _From,
+ #state{cache = Cache,
+ cache_age = Age,
+ cache_gclimit = GcLimit} = State) ->
+ ?vlog("gc_cache", []),
+ Result = maybe_gc_cache(Cache, Age, GcLimit),
+ {reply, Result, State};
+
+handle_call({gc_cache, Age}, _From,
+ #state{cache = Cache,
+ cache_gclimit = GcLimit} = State) ->
+ ?vlog("gc_cache with Age = ~p", [Age]),
+ Result = maybe_gc_cache(Cache, Age, GcLimit),
+ {reply, Result, State};
+
+handle_call({gc_cache, Age, GcLimit}, _From,
+ #state{cache = Cache} = State) ->
+ ?vlog("gc_cache with Age = ~p and GcLimut = ~p", [Age, GcLimit]),
+ Result = maybe_gc_cache(Cache, Age, GcLimit),
+ {reply, Result, State};
+
+handle_call({update_cache_opts, Key, Value}, _From, State) ->
+ ?vlog("update_cache_opts: ~p -> ~p", [Key, Value]),
+ {Result, NewState} = handle_update_cache_opts(Key, Value, State),
+ {reply, Result, NewState};
+
+handle_call({lookup, Oid}, _From,
+ #state{data = Data, cache = Cache} = State) ->
+ ?vlog("lookup ~p", [Oid]),
+ Key = {lookup, Oid},
+ {Reply, NewState} =
+ case maybe_cache_lookup(Cache, Key) of
+ ?NO_CACHE ->
+ {snmpa_mib_data:lookup(Data, Oid), State};
+ [] ->
+ Rep = snmpa_mib_data:lookup(Data, Oid),
+ ets:insert(Cache, {Key, Rep, timestamp()}),
+ {Rep, maybe_start_cache_gc_timer(State)};
+ [{Key, Rep, _}] ->
+ ?vdebug("lookup -> found in cache", []),
+ ets:update_element(Cache, Key, {3, timestamp()}),
+ {Rep, State}
+ end,
+ ?vdebug("lookup -> Reply: ~p", [Reply]),
+ {reply, Reply, NewState};
+
+handle_call({which_mib, Oid}, _From, #state{data = Data} = State) ->
+ ?vlog("which_mib ~p",[Oid]),
+ Reply = snmpa_mib_data:which_mib(Data, Oid),
+ ?vdebug("which_mib: ~p",[Reply]),
+ {reply, Reply, State};
+
+handle_call({next, Oid, MibView}, _From,
+ #state{data = Data, cache = Cache} = State) ->
+ ?vlog("next ~p [~p]", [Oid, MibView]),
+ Key = {next, Oid, MibView},
+ {Reply, NewState} =
+ case maybe_cache_lookup(Cache, Key) of
+ ?NO_CACHE ->
+ {snmpa_mib_data:next(Data, Oid, MibView), State};
+ [] ->
+ Rep = snmpa_mib_data:next(Data, Oid, MibView),
+ ets:insert(Cache, {Key, Rep, timestamp()}),
+ {Rep, maybe_start_cache_gc_timer(State)};
+ [{Key, Rep, _}] ->
+ ?vdebug("lookup -> found in cache", []),
+ ets:update_element(Cache, Key, {3, timestamp()}),
+ {Rep, State}
+ end,
+ ?vdebug("next -> Reply: ~p", [Reply]),
+ {reply, Reply, NewState};
+
+handle_call({load_mibs, Mibs}, _From,
+ #state{data = Data,
+ teo = TeOverride,
+ meo = MeOverride,
+ cache = Cache} = State) ->
+ ?vlog("load mibs ~p",[Mibs]),
+ %% Invalidate cache
+ NewCache = maybe_invalidate_cache(Cache),
+ {NData,Reply} =
+ case (catch mib_operations(load_mib, Mibs, Data,
+ MeOverride, TeOverride)) of
+ {'aborted at', Mib, NewData, Reason} ->
+ ?vlog("aborted at ~p for reason ~p",[Mib,Reason]),
+ {NewData,{error, {'load aborted at', Mib, Reason}}};
+ {ok, NewData} ->
+ {NewData,ok}
+ end,
+ snmpa_mib_data:sync(NData),
+ {reply, Reply, State#state{data = NData, cache = NewCache}};
+
+handle_call({unload_mibs, Mibs}, _From,
+ #state{data = Data,
+ teo = TeOverride,
+ meo = MeOverride,
+ cache = Cache} = State) ->
+ ?vlog("unload mibs ~p",[Mibs]),
+ %% Invalidate cache
+ NewCache = maybe_invalidate_cache(Cache),
+ %% Unload mib(s)
+ {NData,Reply} =
+ case (catch mib_operations(unload_mib, Mibs, Data,
+ MeOverride, TeOverride)) of
+ {'aborted at', Mib, NewData, Reason} ->
+ ?vlog("aborted at ~p for reason ~p",[Mib,Reason]),
+ {NewData, {error, {'unload aborted at', Mib, Reason}}};
+ {ok, NewData} ->
+ {NewData,ok}
+ end,
+ snmpa_mib_data:sync(NData),
+ {reply, Reply, State#state{data = NData, cache = NewCache}};
+
+handle_call(which_mibs, _From, #state{data = Data} = State) ->
+ ?vlog("which mibs",[]),
+ Reply = snmpa_mib_data:which_mibs(Data),
+ {reply, Reply, State};
+
+handle_call({whereis_mib, Mib}, _From, #state{data = Data} = State) ->
+ ?vlog("whereis mib: ~p",[Mib]),
+ Reply = snmpa_mib_data:whereis_mib(Data, Mib),
+ {reply, Reply, State};
+
+handle_call({register_subagent, Oid, Pid}, _From,
+ #state{data = Data, cache = Cache} = State) ->
+ ?vlog("register subagent ~p, ~p",[Oid,Pid]),
+ %% Invalidate cache
+ NewCache = maybe_invalidate_cache(Cache),
+ case snmpa_mib_data:register_subagent(Data, Oid, Pid) of
+ {error, Reason} ->
+ ?vlog("registration failed: ~p",[Reason]),
+ {reply, {error, Reason}, State#state{cache = NewCache}};
+ NewData ->
+ {reply, ok, State#state{data = NewData, cache = NewCache}}
+ end;
+
+handle_call({unregister_subagent, OidOrPid}, _From,
+ #state{data = Data, cache = Cache} = State) ->
+ ?vlog("unregister subagent ~p",[OidOrPid]),
+ %% Invalidate cache
+ NewCache = maybe_invalidate_cache(Cache),
+ case snmpa_mib_data:unregister_subagent(Data, OidOrPid) of
+ {ok, NewData, DeletedSubagentPid} ->
+ {reply, {ok, DeletedSubagentPid}, State#state{data = NewData,
+ cache = NewCache}};
+ {error, Reason} ->
+ ?vlog("unregistration failed: ~p",[Reason]),
+ {reply, {error, Reason}, State#state{cache = NewCache}};
+ NewData ->
+ {reply, ok, State#state{data = NewData, cache = NewCache}}
+ end;
+
+handle_call(info, _From, #state{data = Data, cache = Cache} = State) ->
+ ?vlog("info",[]),
+ Reply =
+ case (catch snmpa_mib_data:info(Data)) of
+ Info when is_list(Info) ->
+ [{cache, size_cache(Cache)} | Info];
+ E ->
+ [{error, E}]
+ end,
+ {reply, Reply, State};
+
+handle_call({info, Type}, _From, #state{data = Data} = State) ->
+ ?vlog("info ~p",[Type]),
+ Reply =
+ case (catch snmpa_mib_data:info(Data, Type)) of
+ Info when is_list(Info) ->
+ Info;
+ E ->
+ [{error, E}]
+ end,
+ {reply, Reply, State};
+
+handle_call(dump, _From, State) ->
+ ?vlog("dump",[]),
+ Reply = snmpa_mib_data:dump(State#state.data),
+ {reply, Reply, State};
+
+handle_call({dump, File}, _From, #state{data = Data} = State) ->
+ ?vlog("dump on ~s",[File]),
+ Reply = snmpa_mib_data:dump(Data, File),
+ {reply, Reply, State};
+
+handle_call({backup, BackupDir}, From, #state{data = Data} = State) ->
+ ?vlog("backup to ~s",[BackupDir]),
+ Pid = self(),
+ V = get(verbosity),
+ case file:read_file_info(BackupDir) of
+ {ok, #file_info{type = directory}} ->
+ BackupServer =
+ erlang:spawn_link(
+ fun() ->
+ put(sname, ambs),
+ put(verbosity, V),
+ Dir = filename:join([BackupDir]),
+ Reply = snmpa_mib_data:backup(Data, Dir),
+ Pid ! {backup_done, Reply},
+ unlink(Pid)
+ end),
+ ?vtrace("backup server: ~p", [BackupServer]),
+ {noreply, State#state{backup = {BackupServer, From}}};
+ {ok, _} ->
+ {reply, {error, not_a_directory}, State};
+ Error ->
+ {reply, Error, State}
+ end;
+
+handle_call(stop, _From, State) ->
+ ?vlog("stop",[]),
+ {stop, normal, ok, State};
+
+handle_call(Req, _From, State) ->
+ warning_msg("received unknown request: ~n~p", [Req]),
+ Reply = {error, {unknown, Req}},
+ {reply, Reply, State}.
+
+handle_cast({verbosity, Verbosity}, State) ->
+ ?vlog("verbosity: ~p -> ~p",[get(verbosity),Verbosity]),
+ put(verbosity,snmp_verbosity:validate(Verbosity)),
+ {noreply, State};
+
+handle_cast(Msg, State) ->
+ warning_msg("received unknown message: ~n~p", [Msg]),
+ {noreply, State}.
+
+
+handle_info({'EXIT', Pid, Reason}, #state{backup = {Pid, From}} = S) ->
+ ?vlog("backup server (~p) exited for reason ~n~p", [Pid, Reason]),
+ gen_server:reply(From, {error, Reason}),
+ {noreply, S#state{backup = undefined}};
+
+handle_info({'EXIT', Pid, Reason}, S) ->
+ %% The only other processes we should be linked to are
+ %% either the master agent or our supervisor, so die...
+ {stop, {received_exit, Pid, Reason}, S};
+
+handle_info({backup_done, Reply}, #state{backup = {_, From}} = S) ->
+ ?vlog("backup done:"
+ "~n Reply: ~p", [Reply]),
+ gen_server:reply(From, Reply),
+ {noreply, S#state{backup = undefined}};
+
+handle_info(?CACHE_GC_TRIGGER, #state{cache = Cache,
+ cache_age = Age,
+ cache_gclimit = GcLimit,
+ cache_autogc = true} = S)
+ when (Cache =/= ?NO_CACHE) ->
+ ?vlog("cache gc trigger event", []),
+ maybe_gc_cache(Cache, Age, GcLimit),
+ Tmr = start_cache_gc_timer(),
+ {noreply, S#state{cache_tmr = Tmr}};
+
+handle_info(?CACHE_GC_TRIGGER, S) ->
+ ?vlog("out-of-date cache gc trigger event - ignore", []),
+ {noreply, S#state{cache_tmr = undefined}};
+
+handle_info(Info, State) ->
+ warning_msg("received unknown info: ~n~p", [Info]),
+ {noreply, State}.
+
+terminate(_Reason, #state{data = Data}) ->
+ catch snmpa_mib_data:close(Data),
+ ok.
+
+
+
+%%----------------------------------------------------------
+%% Code change
+%%----------------------------------------------------------
+
+%% downgrade
+%%
+%% code_change({down, _Vsn}, S1, downgrade_to_pre_4_12) ->
+%% #state{data = Data, meo = MEO, teo = TEO, backup = B, cache = Cache} = S1,
+%% del_cache(Cache),
+%% S2 = {state, Data, MEO, TEO, B},
+%% {ok, S2};
+
+%% %% upgrade
+%% %%
+%% code_change(_Vsn, S1, upgrade_from_pre_4_12) ->
+%% {state, Data, MEO, TEO, B} = S1,
+%% Cache = new_cache(),
+%% S2 = #state{data = Data, meo = MEO, teo = TEO, backup = B, cache = Cache},
+%% {ok, S2};
+
+code_change(_Vsn, State, _Extra) ->
+ {ok, State}.
+
+
+%%-----------------------------------------------------------------
+%% Option access functions
+%%-----------------------------------------------------------------
+
+get_verbosity(Options) ->
+ get_opt(verbosity, Options, ?default_verbosity).
+
+get_me_override(Options) ->
+ get_opt(mibentry_override, Options, false).
+
+get_te_override(Options) ->
+ get_opt(trapentry_override, Options, false).
+
+get_mib_storage(Options) ->
+ get_opt(mib_storage, Options, ets).
+
+get_cacheopt_autogc(Cache, CacheOpts) ->
+ IsValid = fun(AutoGC) when ((AutoGC =:= true) orelse
+ (AutoGC =:= false)) ->
+ true;
+ (_) ->
+ false
+ end,
+ get_cacheopt(Cache, autogc, CacheOpts,
+ false, ?DEFAULT_CACHE_AUTOGC,
+ IsValid).
+
+get_cacheopt_gclimit(Cache, CacheOpts) ->
+ IsValid = fun(Limit) when ((is_integer(Limit) andalso (Limit > 0)) orelse
+ (Limit =:= infinity)) ->
+ true;
+ (_) ->
+ false
+ end,
+ get_cacheopt(Cache, gclimit, CacheOpts,
+ infinity, ?DEFAULT_CACHE_GCLIMIT,
+ IsValid).
+
+get_cacheopt_age(Cache, CacheOpts) ->
+ IsValid = fun(Age) when is_integer(Age) andalso (Age > 0) ->
+ true;
+ (_) ->
+ false
+ end,
+ get_cacheopt(Cache, age, CacheOpts,
+ ?DEFAULT_CACHE_AGE, ?DEFAULT_CACHE_AGE,
+ IsValid).
+
+get_cacheopt(?NO_CACHE, _, _, NoCacheVal, _, _) ->
+ NoCacheVal;
+get_cacheopt(_, Key, Opts, _, Default, IsValid) ->
+ Val = get_opt(Key, Opts, Default),
+ case IsValid(Val) of
+ true ->
+ Val;
+ false ->
+ throw({error, {bad_option, {Key, Val}}})
+ end.
+
+
+%% ----------------------------------------------------------------
+
+handle_update_cache_opts(cache, true = _Value,
+ #state{cache = ?NO_CACHE} = State) ->
+ {ok, State#state{cache = new_cache()}};
+handle_update_cache_opts(cache, true = _Value, State) ->
+ {ok, State};
+
+handle_update_cache_opts(cache, false = _Value,
+ #state{cache = ?NO_CACHE} = State) ->
+ {ok, State};
+handle_update_cache_opts(cache, false = _Value,
+ #state{cache = Cache,
+ cache_tmr = Tmr} = State) ->
+ maybe_stop_cache_gc_timer(Tmr),
+ del_cache(Cache),
+ {ok, State#state{cache = ?NO_CACHE, cache_tmr = undefined}};
+
+handle_update_cache_opts(autogc, true = _Value,
+ #state{cache_autogc = true} = State) ->
+ {ok, State};
+handle_update_cache_opts(autogc, true = Value, State) ->
+ {ok, maybe_start_cache_gc_timer(State#state{cache_autogc = Value})};
+handle_update_cache_opts(autogc, false = _Value,
+ #state{cache_autogc = false} = State) ->
+ {ok, State};
+handle_update_cache_opts(autogc, false = Value,
+ #state{cache_tmr = Tmr} = State) ->
+ maybe_stop_cache_gc_timer(Tmr),
+ {ok, State#state{cache_autogc = Value, cache_tmr = undefined}};
+
+handle_update_cache_opts(age, Age, State) ->
+ {ok, State#state{cache_age = Age}};
+
+handle_update_cache_opts(gclimit, GcLimit, State) ->
+ {ok, State#state{cache_gclimit = GcLimit}};
+
+handle_update_cache_opts(BadKey, Value, State) ->
+ {{error, {bad_cache_opt, BadKey, Value}}, State}.
+
+
+maybe_stop_cache_gc_timer(undefined) ->
+ ok;
+maybe_stop_cache_gc_timer(Tmr) ->
+ erlang:cancel_timer(Tmr).
+
+
+maybe_start_cache_gc_timer(#state{cache = Cache,
+ cache_autogc = true,
+ cache_tmr = undefined} = State)
+ when (Cache =/= ?NO_CACHE) ->
+ Tmr = start_cache_gc_timer(),
+ State#state{cache_tmr = Tmr};
+maybe_start_cache_gc_timer(State) ->
+ State.
+
+start_cache_gc_timer() ->
+ erlang:send_after(?CACHE_GC_TICKTIME, self(), ?CACHE_GC_TRIGGER).
+
+
+%% ----------------------------------------------------------------
+
+maybe_gc_cache(?NO_CACHE, _Age) ->
+ ?vtrace("cache not enabled", []),
+ ok;
+maybe_gc_cache(Cache, Age) ->
+ MatchSpec = gc_cache_matchspec(Age),
+ Keys = ets:select(Cache, MatchSpec),
+ do_gc_cache(Cache, Keys),
+ {ok, length(Keys)}.
+
+maybe_gc_cache(?NO_CACHE, _Age, _GcLimit) ->
+ ok;
+maybe_gc_cache(Cache, Age, infinity = _GcLimit) ->
+ maybe_gc_cache(Cache, Age);
+maybe_gc_cache(Cache, Age, GcLimit) ->
+ MatchSpec = gc_cache_matchspec(Age),
+ Keys =
+ case ets:select(Cache, MatchSpec, GcLimit) of
+ {Match, _Cont} ->
+ Match;
+ '$end_of_table' ->
+ []
+ end,
+ do_gc_cache(Cache, Keys),
+ {ok, length(Keys)}.
+
+gc_cache_matchspec(Age) ->
+ Oldest = timestamp() - Age,
+ MatchHead = {'$1', '_', '$2'},
+ Guard = [{'<', '$2', Oldest}],
+ MatchFunc = {MatchHead, Guard, ['$1']},
+ MatchSpec = [MatchFunc],
+ MatchSpec.
+
+do_gc_cache(_, []) ->
+ ok;
+do_gc_cache(Cache, [Key|Keys]) ->
+ ets:delete(Cache, Key),
+ do_gc_cache(Cache, Keys).
+
+maybe_invalidate_cache(?NO_CACHE) ->
+ ?NO_CACHE;
+maybe_invalidate_cache(Cache) ->
+ del_cache(Cache),
+ new_cache().
+
+maybe_cache_size(?NO_CACHE) ->
+ {error, not_enabled};
+maybe_cache_size(Cache) ->
+ {ok, ets:info(Cache, size)}.
+
+new_cache() ->
+ ets:new(snmpa_mib_cache, [set, protected, {keypos, 1}]).
+
+del_cache(?NO_CACHE) ->
+ ok;
+del_cache(Cache) ->
+ ets:delete(Cache).
+
+maybe_cache_lookup(?NO_CACHE, _) ->
+ ?NO_CACHE;
+maybe_cache_lookup(Cache, Key) ->
+ ets:lookup(Cache, Key).
+
+size_cache(?NO_CACHE) ->
+ undefined;
+size_cache(Cache) ->
+ case (catch ets:info(Cache, memory)) of
+ Sz when is_integer(Sz) ->
+ Sz;
+ _ ->
+ undefined
+ end.
+
+timestamp() ->
+ snmp_misc:now(ms).
+
+
+%% ----------------------------------------------------------------
+
+get_opt(Key, Options, Default) ->
+ snmp_misc:get_option(Key, Options, Default).
+
+
+%% ----------------------------------------------------------------
+
+cast(MibServer, Msg) ->
+ gen_server:cast(MibServer, Msg).
+
+call(MibServer, Req) ->
+ call(MibServer, Req, infinity).
+
+call(MibServer, Req, To) ->
+ gen_server:call(MibServer, Req, To).
+
+
+%% ----------------------------------------------------------------
+
+%% info_msg(F, A) ->
+%% ?snmpa_info("Mib server: " ++ F, A).
+
+warning_msg(F, A) ->
+ ?snmpa_warning("Mib server: " ++ F, A).
+
+%% error_msg(F, A) ->
+%% ?snmpa_error("Mib server: " ++ F, A).
+
+config_err(F, A) ->
+ snmpa_error:config_err(F, A).
+
diff --git a/lib/snmp/src/agent/snmpa_mib_data.erl b/lib/snmp/src/agent/snmpa_mib_data.erl
new file mode 100644
index 0000000000..b80d85d2ee
--- /dev/null
+++ b/lib/snmp/src/agent/snmpa_mib_data.erl
@@ -0,0 +1,1355 @@
+%%
+%% %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%
+%%
+-module(snmpa_mib_data).
+
+%%%-----------------------------------------------------------------
+%%% This module implements the MIB internal data structures.
+%%% An MIB Data Structure consists of three items; an ets-table,
+%%% a tree and a list of registered subagents.
+%%% The subagent information is consequently duplicated. It resides
+%%% both in the tree and in the list.
+%%% The ets-table contains all data associated with each variable,
+%%% table, tableentry and tablecolumn in the MIB.
+%%% The tree contains information of the Oids in the MIB.
+%%%
+%%% When a mib is loaded, the tree is built from the plain list
+%%% in the binary file.
+%%%-----------------------------------------------------------------
+-include("snmp_types.hrl").
+-include("snmp_debug.hrl").
+
+-define(VMODULE,"MDATA").
+-include("snmp_verbosity.hrl").
+
+-define(MIB_DATA,snmpa_mib_data).
+-define(MIB_NODE,snmpa_mib_node).
+-define(MIB_TREE,snmpa_mib_tree).
+-define(DUMMY_TREE_GENERATION,1).
+-define(DEFAULT_TREE,{tree,{undefined_node},internal}).
+%%-define(DUMMY_TREE_DB,dummy_tree_db).
+%%-define(DUMMY_TREE_DB_INIT,{?DUMMY_TREE_DB,?DEFAULT_TREE}).
+
+
+%%%-----------------------------------------------------------------
+%%% Table of contents
+%%% =================
+%%% 1. Interface
+%%% 2. Implementation of tree access
+%%% 3. Tree building functions
+%%% 4. Tree merging
+%%% 5. Tree deletion routines
+%%% 6. Functions for subagent handling
+%%% 7. Misc functions
+%%%-----------------------------------------------------------------
+
+
+%%----------------------------------------------------------------------
+%% data_db is an database containing loaded mibs as:
+%% {MibName = atom(), Symbolic = ?, FullFileName = string()}
+%% it is either ets or mnesia
+%% tree_db is a database containing _one_ record with the tree!
+%% (the reason for this is part to get replication and part out of convenience)
+%% ref_tree is the root node, without any subagent.
+%% tree is the root node (same as ref_tree but with the subagents added).
+%% subagents is a list of {SAPid, Oid}
+%%----------------------------------------------------------------------
+-record(mib_data, {mib_db, % table of #mib_info
+ node_db, % table of #node_info
+ tree_db, % table of #tree
+ tree, % The actual tree
+ subagents = []}).
+
+-record(mib_info, {name, symbolic, file_name}).
+-record(node_info, {oid, mib_name, me}).
+
+
+%% API
+-export([new/0, new/1, sync/1, close/1,
+ load_mib/4, unload_mib/4, which_mibs/1, whereis_mib/2,
+ info/1, info/2,
+ dump/1, dump/2,
+ backup/2,
+ lookup/2, next/3, which_mib/2,
+ register_subagent/3, unregister_subagent/2]).
+
+%% Internal exports
+-export([code_change/2]).
+
+
+%%-----------------------------------------------------------------
+%% A tree is represented as a N-tuple, where each element is a
+%% node. A node is:
+%% 1) {tree, Tree, Info} where Info can be {table, Id}, {table_entry, Id}
+%% or perhaps 'internal'
+%% 2) undefined_node (memory optimization (instead of {node, undefined}))
+%% 3) {node, Info} where Info can be {subagent, Pid}, {variable, Id},
+%% {table_column, Id}
+%% Id is {MibName, MibEntry}
+%% The over all root is represented as {tree, Tree, internal}.
+%%
+%% tree() = {tree, nodes(), tree_info()}
+%% nodes() = {tree() | node() | undefined_node, ...}
+%% node() = {node, node_info()}
+%% tree_info() = {table, Id} | {table_entry, Id} | internal
+%% node_info() = {subagent, Pid} | {variable, Id} | {table_colum, Id}
+%%-----------------------------------------------------------------
+
+%% This record is what is stored in the database. The 'tree' part
+%% is described above...
+-record(tree,{generation = ?DUMMY_TREE_GENERATION, root = ?DEFAULT_TREE}).
+
+
+%%%======================================================================
+%%% 1. Interface
+%%%======================================================================
+
+%%-----------------------------------------------------------------
+%% Func: new/0, new/1
+%% Returns: A representation of mib data.
+%%-----------------------------------------------------------------
+new() ->
+ new(ets).
+
+%% Where -> A list of nodes where the tables will be created
+new(Storage) ->
+ %% First we must check if there is already something to read
+ %% If a database already exists, then the tree structure has to be read
+ ?vtrace("open (mib) database",[]),
+ MibDb = snmpa_general_db:open(Storage, ?MIB_DATA,
+ mib_info,
+ record_info(fields,mib_info), set),
+ ?vtrace("open (mib) node database",[]),
+ NodeDb = snmpa_general_db:open(Storage, ?MIB_NODE,
+ node_info,
+ record_info(fields,node_info), set),
+ ?vtrace("open (mib) tree database",[]),
+ TreeDb = snmpa_general_db:open(Storage, ?MIB_TREE,
+ tree,
+ record_info(fields,tree), set),
+ Tree =
+ case snmpa_general_db:read(TreeDb, ?DUMMY_TREE_GENERATION) of
+ false ->
+ T = #tree{},
+ snmpa_general_db:write(TreeDb, T),
+ T;
+ {value, T} ->
+ T
+ end,
+ install_mibs(MibDb, NodeDb),
+ #mib_data{mib_db = MibDb,
+ node_db = NodeDb,
+ tree_db = TreeDb,
+ tree = Tree}.
+
+
+%%----------------------------------------------------------------------
+%% Returns: new mib data | {error, Reason}
+%%----------------------------------------------------------------------
+load_mib(MibData,FileName,MeOverride,TeOverride)
+ when is_record(MibData,mib_data) andalso is_list(FileName) ->
+ ?vlog("load mib file: ~p",[FileName]),
+ ActualFileName = filename:rootname(FileName, ".bin") ++ ".bin",
+ MibName = list_to_atom(filename:basename(FileName, ".bin")),
+ (catch do_load_mib(MibData, ActualFileName, MibName,
+ MeOverride, TeOverride)).
+
+do_load_mib(MibData, ActualFileName, MibName, MeOverride, TeOverride) ->
+ ?vtrace("do_load_mib -> entry with"
+ "~n ActualFileName: ~s"
+ "~n MibName: ~p",[ActualFileName, MibName]),
+ #mib_data{mib_db = MibDb,
+ node_db = NodeDb,
+ %% tree_db = TreeDb,
+ tree = Tree} = MibData,
+ verify_not_loaded(MibDb, MibName),
+ ?vtrace("do_load_mib -> already loaded mibs:"
+ "~n ~p",[loaded(MibDb)]),
+ Mib = do_read_mib(ActualFileName),
+ ?vtrace("do_load_mib -> read mib ~s",[Mib#mib.name]),
+ NonInternalMes =
+ lists:filter(fun(ME) -> maybe_drop_me(ME) end, Mib#mib.mes),
+ OldRoot = Tree#tree.root,
+ T = build_tree(NonInternalMes, MibName),
+ ?d("load_mib -> "
+ "~n OldRoot: ~p"
+ "~n T: ~p", [OldRoot, T]),
+ case (catch merge_nodes(T, OldRoot)) of
+ {error_merge_nodes, Node1, Node2} ->
+ ?vlog("error merging nodes:"
+ "~n~p~nand~n~p", [Node1,Node2]),
+ {error, oid_conflict};
+ NewRoot when is_tuple(NewRoot) andalso (element(1,NewRoot) =:= tree) ->
+ ?d("load_mib -> "
+ "~n NewRoot: ~p", [NewRoot]),
+ Symbolic = not lists:member(no_symbolic_info, Mib#mib.misc),
+ case (catch check_notif_and_mes(TeOverride, MeOverride, Symbolic,
+ Mib#mib.traps, NonInternalMes)) of
+ true ->
+ install_mes(NodeDb, MibName, NonInternalMes),
+ install_mib(MibDb, Symbolic, Mib,
+ MibName, ActualFileName, NonInternalMes),
+ ?vtrace("installed mib ~s", [Mib#mib.name]),
+ Tree2 = Tree#tree{root = NewRoot},
+ %% snmpa_general_db:write(TreeDb, Tree2), %% Store later?
+ {ok, MibData#mib_data{tree = Tree2}};
+ Else ->
+ Else
+ end
+ end.
+
+
+verify_not_loaded(Db, Name) ->
+ case snmpa_general_db:read(Db, Name) of
+ {value, #mib_info{name = Name}} ->
+ throw({error, 'already loaded'});
+ false ->
+ ok
+ end.
+
+do_read_mib(ActualFileName) ->
+ case snmp_misc:read_mib(ActualFileName) of
+ {error, Reason} ->
+ ?vlog("Failed reading mib file ~p with reason: ~p",
+ [ActualFileName,Reason]),
+ throw({error, Reason});
+ {ok, Mib} ->
+ Mib
+ end.
+
+%% The Tree DB is handled in a special way since it can be very large.
+sync(#mib_data{mib_db = M,
+ node_db = N,
+ tree_db = T, tree = Tree, subagents = []}) ->
+ snmpa_general_db:sync(M),
+ snmpa_general_db:sync(N),
+ snmpa_general_db:write(T, Tree),
+ snmpa_general_db:sync(T);
+sync(#mib_data{mib_db = M,
+ node_db = N,
+ tree_db = T, tree = Tree, subagents = SAs}) ->
+
+ snmpa_general_db:sync(M),
+ snmpa_general_db:sync(N),
+
+ %% Ouch. Since the subagent info is dynamic we do not
+ %% want to store the tree containing subagent info. So, we
+ %% have to create a tmp tree without those and store it.
+
+ case delete_subagents(Tree, SAs) of
+ {ok, TreeWithoutSAs} ->
+ snmpa_general_db:write(T, TreeWithoutSAs),
+ snmpa_general_db:sync(T);
+ Error ->
+ Error
+ end.
+
+delete_subagents(Tree, []) ->
+ {ok, Tree};
+delete_subagents(Tree0, [{_, Oid}|SAs]) ->
+ case (catch delete_subagent(Tree0, Oid)) of
+ {tree, _Tree, _Info} = Tree1 ->
+ delete_subagents(Tree1, SAs);
+ _Error ->
+ {error, {'invalid oid', Oid}}
+ end.
+
+%%----------------------------------------------------------------------
+%% (OTP-3601)
+%%----------------------------------------------------------------------
+check_notif_and_mes(TeOverride,MeOverride,Symbolic,Traps,MEs) ->
+ ?vtrace("check notifications and mib entries",[]),
+ check_notifications(TeOverride,Symbolic,Traps),
+ check_mes(MeOverride,MEs).
+
+check_notifications(true, _Symbolic, _Traps) ->
+ ?vtrace("trapentry override = true => skip check",[]),
+ true;
+check_notifications(_, Symbolic, Traps) ->
+ check_notifications(Symbolic, Traps).
+
+check_notifications(true, Traps) ->
+ check_notifications(Traps);
+check_notifications(_, _) -> true.
+
+check_notifications([]) -> true;
+check_notifications([#trap{trapname = Key} = Trap | Traps]) ->
+ ?vtrace("check notification [trap] with Key: ~p",[Key]),
+ case snmpa_symbolic_store:get_notification(Key) of
+ {value, Trap} -> check_notifications(Traps);
+ {value, _} -> throw({error, {'trap already defined', Key}});
+ undefined -> check_notifications(Traps)
+ end;
+check_notifications([#notification{trapname = Key} = Notif | Traps]) ->
+ ?vtrace("check notification [notification] with Key: ~p",[Key]),
+ case snmpa_symbolic_store:get_notification(Key) of
+ {value, Notif} ->
+ check_notifications(Traps);
+ {value, _} ->
+ throw({error, {'notification already defined', Key}});
+ undefined ->
+ check_notifications(Traps)
+ end;
+check_notifications([Crap | Traps]) ->
+ ?vlog("skipped check of: ~n~p",[Crap]),
+ check_notifications(Traps).
+
+check_mes(true,_) ->
+ ?vtrace("mibentry override = true => skip check",[]),
+ true;
+check_mes(_,MEs) ->
+ check_mes(MEs).
+
+check_mes([]) -> true;
+check_mes([#me{aliasname = Name, oid = Oid1} | MEs]) ->
+ ?vtrace("check mib entries with aliasname: ~p",[Name]),
+ case snmpa_symbolic_store:aliasname_to_oid(Name) of
+ {value, Oid1} ->
+ check_mes(MEs);
+ {value, Oid2} ->
+ ?vinfo("~n expecting '~p'~n but found '~p'",[Oid1, Oid2]),
+ throw({error, {'mibentry already defined', Name}});
+ false ->
+ check_mes(MEs)
+ end;
+check_mes([Crap | MEs]) ->
+ ?vlog("skipped check of: ~n~p",[Crap]),
+ check_mes(MEs).
+
+
+
+%%----------------------------------------------------------------------
+%% Returns: new mib data | {error, Reason}
+%%----------------------------------------------------------------------
+unload_mib(MibData, FileName, _, _) when is_list(FileName) ->
+ MibName = list_to_atom(filename:basename(FileName, ".bin")),
+ (catch do_unload_mib(MibData, MibName)).
+
+do_unload_mib(MibData, MibName) ->
+ ?vtrace("do_unload_mib -> entry with"
+ "~n MibName: ~p", [MibName]),
+ #mib_data{mib_db = MibDb,
+ node_db = NodeDb,
+ %% tree_db = TreeDb,
+ tree = Tree} = MibData,
+ #mib_info{symbolic = Symbolic} = verify_loaded(MibDb, MibName),
+ NewRoot = delete_mib_from_tree(MibName, Tree#tree.root),
+ MEs = uninstall_mes(NodeDb, MibName),
+ uninstall_mib(MibDb, Symbolic, MibName, MEs),
+ NewMibData = MibData#mib_data{tree = Tree#tree{root = NewRoot}},
+ {ok, NewMibData}.
+
+verify_loaded(Db, Name) ->
+ case snmpa_general_db:read(Db, Name) of
+ {value, MibInfo} ->
+ MibInfo;
+ false ->
+ throw({error, 'not loaded'})
+ end.
+
+
+close(#mib_data{mib_db = MibDb, node_db = NodeDb, tree_db = TreeDb}) ->
+ snmpa_general_db:close(MibDb),
+ snmpa_general_db:close(NodeDb),
+ snmpa_general_db:close(TreeDb),
+ ok.
+
+register_subagent(#mib_data{tree = T} = MibData, Oid, Pid) ->
+ case insert_subagent(Oid, T#tree.root) of
+ {error, Reason} ->
+ {error, Reason};
+ NewRootTree ->
+ SAs = [{Pid, Oid} | MibData#mib_data.subagents],
+ T2 = T#tree{root = NewRootTree},
+ MibData#mib_data{tree = T2, subagents = SAs}
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Purpose: Get a list of all loaded mibs
+%% Returns: [{Name, File}]
+%%----------------------------------------------------------------------
+
+which_mibs(#mib_data{mib_db = Db}) ->
+ Mibs = snmpa_general_db:tab2list(Db),
+ [{Name, File} || #mib_info{name = Name, file_name = File} <- Mibs].
+
+
+%%----------------------------------------------------------------------
+%% Purpose: Get a list of all loaded mibs
+%% Returns: [{Name, File}]
+%%----------------------------------------------------------------------
+
+whereis_mib(#mib_data{mib_db = Db}, Name) ->
+ case snmpa_general_db:read(Db, Name) of
+ {value, #mib_info{file_name = File}} ->
+ {ok, File};
+ false ->
+ {error, not_found}
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Purpose: Deletes SA with Pid from all subtrees it handles.
+%% Returns: NewMibData.
+%%----------------------------------------------------------------------
+unregister_subagent(MibData, Pid) when is_pid(Pid) ->
+ SAs = MibData#mib_data.subagents,
+ case lists:keysearch(Pid, 1, SAs) of
+ false -> MibData;
+ {value, {Pid, Oid}} ->
+ % we should never get an error since Oid is found in MibData.
+ {ok, NewMibData, _DeletedSA} = unregister_subagent(MibData, Oid),
+ % continue if the same Pid handles other mib subtrees.
+ unregister_subagent(NewMibData, Pid)
+ end;
+
+%%----------------------------------------------------------------------
+%% Purpose: Deletes one unique subagent.
+%% Returns: {error, Reason} | {ok, NewMibData, DeletedSubagentPid}
+%%----------------------------------------------------------------------
+unregister_subagent(#mib_data{tree = T} = MibData, Oid) when is_list(Oid) ->
+ case catch delete_subagent(T#tree.root, Oid) of
+ {tree, Tree, Info} ->
+ OldSAs = MibData#mib_data.subagents,
+ {value, {Pid, _Oid}} = lists:keysearch(Oid, 2, OldSAs),
+ SAs = lists:keydelete(Oid, 2, OldSAs),
+ T2 = T#tree{root = {tree, Tree, Info}},
+ {ok,
+ MibData#mib_data{tree = T2, subagents = SAs},
+ Pid};
+ _ ->
+ {error, {'invalid oid', Oid}}
+ end.
+
+%%----------------------------------------------------------------------
+%% Purpose: To inpect memory usage, loaded mibs, registered subagents
+%%----------------------------------------------------------------------
+info(MibData) ->
+ ?vtrace("retrieve info",[]),
+ #mib_data{mib_db = MibDb, node_db = NodeDb, tree_db = TreeDb,
+ tree = Tree, subagents = SAs} = MibData,
+ LoadedMibs = old_format(snmpa_general_db:tab2list(MibDb)),
+ TreeSize = snmp_misc:mem_size(Tree),
+ {memory, ProcSize} = erlang:process_info(self(),memory),
+ MibDbSize = snmpa_general_db:info(MibDb, memory),
+ NodeDbSize = snmpa_general_db:info(NodeDb, memory),
+ TreeDbSize = snmpa_general_db:info(TreeDb, memory),
+ [{loaded_mibs, LoadedMibs}, {subagents, SAs}, {tree_size_bytes, TreeSize},
+ {process_memory, ProcSize},
+ {db_memory, [{mib,MibDbSize},{node,NodeDbSize},{tree,TreeDbSize}]}].
+
+info(#mib_data{mib_db = MibDb}, loaded_mibs) ->
+ Mibs = snmpa_general_db:tab2list(MibDb),
+ [filename:rootname(FN, ".bin") || #mib_info{file_name = FN} <- Mibs];
+info(#mib_data{tree = Tree}, tree_size_bytes) ->
+ snmp_misc:mem_size(Tree);
+info(_, process_memory) ->
+ {memory, ProcSize} = erlang:process_info(self(),memory),
+ ProcSize;
+info(#mib_data{mib_db = MibDb, node_db = NodeDb, tree_db = TreeDb},
+ db_memory) ->
+ MibDbSize = snmpa_general_db:info(MibDb, memory),
+ NodeDbSize = snmpa_general_db:info(NodeDb, memory),
+ TreeDbSize = snmpa_general_db:info(TreeDb, memory),
+ [{mib,MibDbSize},{node,NodeDbSize},{tree,TreeDbSize}];
+info(#mib_data{subagents = SAs}, subagents) ->
+ SAs.
+
+old_format(LoadedMibs) ->
+ ?vtrace("convert mib info to old format",[]),
+ [{N,S,F} || #mib_info{name=N,symbolic=S,file_name=F} <- LoadedMibs].
+
+
+%%----------------------------------------------------------------------
+%% A total dump for debugging.
+%%----------------------------------------------------------------------
+dump(#mib_data{mib_db = MibDb, node_db = NodeDb, tree = Tree}) ->
+ (catch io:format("MIB-tables:~n~p~n~n",
+ [snmpa_general_db:tab2list(MibDb)])),
+ (catch io:format("MIB-entries:~n~p~n~n",
+ [snmpa_general_db:tab2list(NodeDb)])),
+ (catch io:format("Tree:~n~p~n", [Tree])), % good luck reading it!
+ ok.
+
+dump(#mib_data{mib_db = MibDb, node_db = NodeDb, tree = Tree}, File) ->
+ case file:open(File,[write]) of
+ {ok, Fd} ->
+ io:format(Fd,"~s~n",
+ [snmp:date_and_time_to_string(snmp:date_and_time())]),
+ (catch io:format(Fd,"MIB-tables:~n~p~n~n",
+ [snmpa_general_db:tab2list(MibDb)])),
+ (catch io:format(Fd, "MIB-entries:~n~p~n~n",
+ [snmpa_general_db:tab2list(NodeDb)])),
+ io:format(Fd,"Tree:~n~p~n", [Tree]), % good luck reading it!
+ file:close(Fd),
+ ok;
+ {error,Reason} ->
+ ?vinfo("~n Failed opening file '~s' for reason ~p",
+ [File,Reason]),
+ {error,Reason}
+ end.
+
+
+backup(#mib_data{mib_db = M, node_db = N, tree_db = T}, BackupDir) ->
+ MRes = snmpa_general_db:backup(M, BackupDir),
+ NRes = snmpa_general_db:backup(N, BackupDir),
+ TRes = snmpa_general_db:backup(T, BackupDir),
+ handle_backup_res([{mib_db, MRes}, {node_db, NRes}, {tree_db, TRes}]).
+
+handle_backup_res(Res) ->
+ handle_backup_res(Res, []).
+
+handle_backup_res([], []) ->
+ ok;
+handle_backup_res([], Err) ->
+ {error, lists:reverse(Err)};
+handle_backup_res([{_, ok}|Res], Err) ->
+ handle_backup_res(Res, Err);
+handle_backup_res([{Tag, {error, Reason}}|Res], Err) ->
+ handle_backup_res(Res, [{Tag, Reason}|Err]);
+handle_backup_res([{Tag, Error}|Res], Err) ->
+ handle_backup_res(Res, [{Tag, Error}|Err]).
+
+
+%%%======================================================================
+%%% 2. Implementation of tree access
+%%% lookup and next.
+%%%======================================================================
+
+
+which_mib(#mib_data{tree = T} = D, Oid) ->
+ ?vtrace("which_mib -> entry with"
+ "~n Oid: ~p",[Oid]),
+ case (catch find_node(D, T#tree.root, Oid, [])) of
+ {variable, _ME, Mib} ->
+ ?vtrace("which_mib -> variable:"
+ "~n Mib: ~p", [Mib]),
+ {ok, Mib};
+ {table, _EntryME, _, Mib} ->
+ ?vtrace("which_mib -> table:"
+ "~n Mib: ~p", [Mib]),
+ {ok, Mib};
+ {subagent, SubAgentPid, _SANextOid} ->
+ ?vtrace("which_mib -> subagent:"
+ "~n SubAgentPid: ~p", [SubAgentPid]),
+ {error, {subagent, SubAgentPid}};
+ {false, ErrorCode} ->
+ ?vtrace("which_mib -> false:"
+ "~n ErrorCode: ~p",[ErrorCode]),
+ {error, ErrorCode};
+ false ->
+ ?vtrace("which_mib -> false",[]),
+ {error, noSuchObject};
+ {'EXIT', R} ->
+ ?vtrace("which_mib -> exit:"
+ "~n R: ~p",[R]),
+ {error, noSuchObject}
+ end.
+
+
+%%-----------------------------------------------------------------
+%% Func: lookup/2
+%% Purpose: Finds the mib entry corresponding to the Oid. If it is a
+%% variable, the Oid must be <Oid for var>.0 and if it is
+%% a table, Oid must be <table>.<entry>.<col>.<any>
+%% Returns: {variable, MibEntry} |
+%% {table_column, MibEntry, TableEntryOid} |
+%% {subagent, SubAgentPid, SAOid} |
+%% {false, Reason}
+%%-----------------------------------------------------------------
+lookup(#mib_data{tree = T} = D, Oid) ->
+ ?vtrace("lookup -> entry with"
+ "~n Oid: ~p",[Oid]),
+ case (catch find_node(D, T#tree.root, Oid, [])) of
+ {variable, ME, _Mib} when is_record(ME, me) ->
+ ?vtrace("lookup -> variable:"
+ "~n ME: ~p",[ME]),
+ {variable, ME};
+ {table, EntryME, {ColME, TableEntryOid}, _Mib} ->
+ ?vtrace("lookup -> table:"
+ "~n EntryME: ~p"
+ "~n ColME: ~p"
+ "~n RevTableEntryOid: ~p",
+ [EntryME, ColME, TableEntryOid]),
+ MFA = EntryME#me.mfa,
+ RetME = ColME#me{mfa = MFA},
+ {table_column, RetME, TableEntryOid};
+ {subagent, SubAgentPid, SANextOid} ->
+ ?vtrace("lookup -> subagent:"
+ "~n SubAgentPid: ~p"
+ "~n SANextOid: ~p", [SubAgentPid, SANextOid]),
+ {subagent, SubAgentPid, SANextOid};
+ {false, ErrorCode} ->
+ ?vtrace("lookup -> false:"
+ "~n ErrorCode: ~p",[ErrorCode]),
+ {false, ErrorCode};
+ false ->
+ ?vtrace("lookup -> false",[]),
+ {false, noSuchObject};
+ {'EXIT', R} ->
+ ?vtrace("lookup -> exit:"
+ "~n R: ~p",[R]),
+ {false, noSuchObject}
+ end.
+
+
+find_node(D, {tree, Tree, {table, _}}, RestOfOid, RevOid) ->
+ ?vtrace("find_node(tree,table) -> entry with"
+ "~n RestOfOid: ~p"
+ "~n RevOid: ~p",[RestOfOid, RevOid]),
+ find_node(D, {tree, Tree, internal}, RestOfOid, RevOid);
+find_node(D, {tree, Tree, {table_entry, _}}, RestOfOid, RevOid) ->
+ ?vtrace("find_node(tree,table_entry) -> entry with"
+ "~n RestOfOid: ~p"
+ "~n RevOid: ~p",[RestOfOid, RevOid]),
+ #mib_data{node_db = Db} = D,
+ Oid = lists:reverse(RevOid),
+ case snmpa_general_db:read(Db, Oid) of
+ {value, #node_info{me = ME, mib_name = Mib}} ->
+ case find_node(D, {tree, Tree, internal}, RestOfOid, RevOid) of
+ {false, ErrorCode} -> {false, ErrorCode};
+ Val -> {table, ME, Val, Mib}
+ end;
+ false ->
+ ?vinfo("find_node -> could not find table_entry ME with"
+ "~n RevOid: ~p"
+ "~n when"
+ "~n RestOfOid: ~p",
+ [RevOid, RestOfOid]),
+ false
+ end;
+find_node(D, {tree, Tree, _Internal}, [Int | RestOfOid], RevOid) ->
+ ?vtrace("find_node(tree) -> entry with"
+ "~n Int: ~p"
+ "~n RestOfOid: ~p"
+ "~n RevOid: ~p",[Int, RestOfOid, RevOid]),
+ find_node(D, element(Int+1, Tree), RestOfOid, [Int | RevOid]);
+find_node(D, {node, {table_column, _}}, RestOfOid, [ColInt | RevOid]) ->
+ ?vtrace("find_node(tree,table_column) -> entry with"
+ "~n RestOfOid: ~p"
+ "~n ColInt: ~p"
+ "~n RevOid: ~p",[RestOfOid, ColInt, RevOid]),
+ #mib_data{node_db = Db} = D,
+ Oid = lists:reverse([ColInt | RevOid]),
+ case snmpa_general_db:read(Db, Oid) of
+ {value, #node_info{me = ME}} ->
+ {ME, lists:reverse(RevOid)};
+ false ->
+ X = snmpa_general_db:read(Db, lists:reverse([ColInt | RevOid])),
+ ?vinfo("find_node -> could not find table_column ME with"
+ "~n RevOid: ~p"
+ "~n trying [~p|~p]"
+ "~n X: ~p",
+ [RevOid, [ColInt | RevOid], X]),
+ false
+ end;
+find_node(D, {node, {variable, _MibName}}, [0], RevOid) ->
+ ?vtrace("find_node(tree,variable,[0]) -> entry with"
+ "~n RevOid: ~p",[RevOid]),
+ #mib_data{node_db = Db} = D,
+ Oid = lists:reverse(RevOid),
+ %% {value, #node_info{me = ME}} = snmpa_general_db:read(Db, Oid),
+ case snmpa_general_db:read(Db, Oid) of
+ {value, #node_info{me = ME, mib_name = Mib}} ->
+ {variable, ME, Mib};
+ false ->
+ ?vinfo("find_node -> could not find variable ME with"
+ "~n RevOid: ~p", [RevOid]),
+ false
+ end;
+find_node(_D, {node, {variable, _MibName}}, [], _RevOid) ->
+ ?vtrace("find_node(tree,variable,[]) -> entry",[]),
+ {false, noSuchObject};
+find_node(_D, {node, {variable, _MibName}}, _, _RevOid) ->
+ ?vtrace("find_node(tree,variable) -> entry",[]),
+ {false, noSuchInstance};
+find_node(D, {node, subagent}, _RestOfOid, SARevOid) ->
+ ?vtrace("find_node(tree,subagent) -> entry with"
+ "~n SARevOid: ~p",[SARevOid]),
+ #mib_data{subagents = SAs} = D,
+ SAOid = lists:reverse(SARevOid),
+ case lists:keysearch(SAOid, 2, SAs) of
+ {value, {SubAgentPid, SAOid}} ->
+ {subagent, SubAgentPid, SAOid};
+ false ->
+ ?vinfo("find_node -> could not find subagent with"
+ "~n SAOid: ~p"
+ "~n SAs: ~p", [SAOid, SAs]),
+ false
+ end;
+find_node(_D, Node, _RestOfOid, _RevOid) ->
+ ?vtrace("find_node -> failed:~n~p",[Node]),
+ {false, noSuchObject}.
+
+
+%%-----------------------------------------------------------------
+%% Func: next/3
+%% Purpose: Finds the lexicographically next oid.
+%% Returns: endOfMibView |
+%% {subagent, SubAgentPid, SAOid} |
+%% {variable, MibEntry, VarOid} |
+%% {table, TableOid, TableRestOid, MibEntry}
+%% If a variable is returnes, it is in the MibView.
+%% If a table or subagent is returned, it *may* be in the MibView.
+%%-----------------------------------------------------------------
+next(#mib_data{tree = T} = D, Oid, MibView) ->
+ case catch next_node(D, T#tree.root, Oid, [], MibView) of
+ false -> endOfMibView;
+ Else -> Else
+ end.
+
+%%-----------------------------------------------------------------
+%% This function is used as long as we have any Oid left. Take
+%% one integer at a time from the Oid, and traverse the tree
+%% accordingly. When the Oid is empty, call find_next.
+%% Returns: {subagent, SubAgentPid, SAOid} |
+%% false |
+%% {variable, MibEntry, VarOid} |
+%% {table, TableOid, TableRestOid, MibEntry}
+%%-----------------------------------------------------------------
+next_node(_D, undefined_node, _Oid, _RevOidSoFar, _MibView) ->
+ ?vtrace("next_node(undefined_node) -> entry", []),
+ false;
+
+next_node(_D, {tree, Tree, {table_entry, _Id}}, [Int | _Oid],
+ _RevOidSoFar, _MibView)
+ when Int+1 > size(Tree) ->
+ ?vtrace("next_node(tree,table_entry) -> entry when not found whith"
+ "~n Int: ~p"
+ "~n size(Tree): ~p", [Int, size(Tree)]),
+ false;
+next_node(D, {tree, Tree, {table_entry, _MibName}},
+ Oid, RevOidSoFar, MibView) ->
+ ?vtrace("next_node(tree,table_entry) -> entry when"
+ "~n size(Tree): ~p"
+ "~n Oid: ~p"
+ "~n RevOidSoFar: ~p"
+ "~n MibView: ~p", [size(Tree), Oid, RevOidSoFar, MibView]),
+ OidSoFar = lists:reverse(RevOidSoFar),
+ case snmpa_acm:is_definitely_not_in_mib_view(OidSoFar, MibView) of
+ true ->
+ ?vdebug("next_node(tree,table_entry) -> not in mib view",[]),
+ false;
+ _ ->
+ #mib_data{node_db = Db} = D,
+ case snmpa_general_db:read(Db, OidSoFar) of
+ false ->
+ ?vinfo("next_node -> could not find table_entry with"
+ "~n OidSoFar: ~p", [OidSoFar]),
+ false;
+ {value, #node_info{me = ME}} ->
+ ?vtrace("next_node(tree,table_entry) -> found: ~n ~p",
+ [ME]),
+ {table, OidSoFar, Oid, ME}
+ end
+ end;
+
+next_node(D, {tree, Tree, _Info}, [Int | RestOfOid], RevOidSoFar, MibView)
+ when (Int < size(Tree)) andalso (Int >= 0) ->
+ ?vtrace("next_node(tree) -> entry when"
+ "~n size(Tree): ~p"
+ "~n Int: ~p"
+ "~n RestOfOid: ~p"
+ "~n RevOidSoFar: ~p"
+ "~n MibView: ~p",
+ [size(Tree), Int, RestOfOid, RevOidSoFar, MibView]),
+ case next_node(D, element(Int+1,Tree),
+ RestOfOid, [Int|RevOidSoFar], MibView) of
+ false ->
+ find_next(D, {tree, Tree, _Info}, Int+1, RevOidSoFar, MibView);
+ Else ->
+ Else
+ end;
+%% no solution
+next_node(D, {tree, Tree, _Info}, [], RevOidSoFar, MibView) ->
+ ?vtrace("next_node(tree,[]) -> entry when"
+ "~n size(Tree): ~p"
+ "~n RevOidSoFar: ~p"
+ "~n MibView: ~p",
+ [size(Tree), RevOidSoFar, MibView]),
+ find_next(D, {tree, Tree, _Info}, 0, RevOidSoFar, MibView);
+next_node(_D, {tree, Tree, _Info}, _RestOfOid, _RevOidSoFar, _MibView) ->
+ ?vtrace("next_node(tree) -> entry when"
+ "~n size(Tree): ~p", [size(Tree)]),
+ false;
+
+next_node(D, {node, subagent}, Oid, RevOidSoFar, MibView) ->
+ ?vtrace("next_node(node,subagent) -> entry when"
+ "~n Oid: ~p"
+ "~n RevOidSoFar: ~p"
+ "~n MibView: ~p",
+ [Oid, RevOidSoFar, MibView]),
+ OidSoFar = lists:reverse(RevOidSoFar),
+ case snmpa_acm:is_definitely_not_in_mib_view(OidSoFar, MibView) of
+ true ->
+ false;
+ _ ->
+ #mib_data{subagents = SAs} = D,
+ case lists:keysearch(OidSoFar, 2, SAs) of
+ {value, {SubAgentPid, OidSoFar}} ->
+ {subagent, SubAgentPid, OidSoFar};
+ _ ->
+ ?vinfo("next_node -> could not find subagent with"
+ "~n OidSoFar: ~p"
+ "~n SAs: ~p", [OidSoFar, SAs]),
+ false
+ end
+ end;
+
+next_node(D, {node, {variable, _MibName}}, [], RevOidSoFar, MibView) ->
+ ?vtrace("next_node(node,variable,[]) -> entry when"
+ "~n RevOidSoFar: ~p"
+ "~n MibView: ~p",
+ [RevOidSoFar, MibView]),
+ OidSoFar = lists:reverse([0 | RevOidSoFar]),
+ case snmpa_acm:validate_mib_view(OidSoFar, MibView) of
+ true ->
+ #mib_data{node_db = Db} = D,
+ case snmpa_general_db:read(Db, lists:reverse(RevOidSoFar)) of
+ false ->
+ ?vinfo("next_node -> could not find variable with"
+ "~n RevOidSoFar: ~p", [RevOidSoFar]),
+ false;
+ {value, #node_info{me = ME}} ->
+ {variable, ME, OidSoFar}
+ end;
+ _ ->
+ false
+ end;
+
+next_node(_D, {node, {variable, _MibName}}, _Oid, _RevOidSoFar, _MibView) ->
+ ?vtrace("next_node(node,variable) -> entry", []),
+ false.
+
+%%-----------------------------------------------------------------
+%% This function is used to find the first leaf from where we
+%% are.
+%% Returns: {subagent, SubAgentPid, SAOid} |
+%% false |
+%% {variable, MibEntry, VarOid} |
+%% {table, TableOid, TableRestOid, MibEntry}
+%% PRE: This function must always be called with a {internal, Tree}
+%% node.
+%%-----------------------------------------------------------------
+find_next(D, {tree, Tree, internal}, Idx, RevOidSoFar, MibView)
+ when Idx < size(Tree) ->
+ case find_next(D, element(Idx+1, Tree), 0, [Idx| RevOidSoFar], MibView) of
+ false ->
+ find_next(D, {tree, Tree, internal}, Idx+1, RevOidSoFar, MibView);
+ Other ->
+ Other
+ end;
+find_next(_D, {tree, _Tree, internal}, _Idx, _RevOidSoFar, _MibView) ->
+ false;
+find_next(_D, undefined_node, _Idx, _RevOidSoFar, _MibView) ->
+ false;
+find_next(D, {tree, Tree, {table, _MibName}}, Idx, RevOidSoFar, MibView) ->
+ find_next(D, {tree, Tree, internal}, Idx, RevOidSoFar, MibView);
+find_next(D, {tree, _Tree, {table_entry, _MibName}}, _Index,
+ RevOidSoFar, MibView) ->
+ OidSoFar = lists:reverse(RevOidSoFar),
+ case snmpa_acm:is_definitely_not_in_mib_view(OidSoFar, MibView) of
+ true ->
+ false;
+ _ ->
+ #mib_data{node_db = Db} = D,
+ case snmpa_general_db:read(Db, OidSoFar) of
+ false ->
+ ?vinfo("find_next -> could not find table_entry ME with"
+ "~n OidSoFar: ~p", [OidSoFar]),
+ false;
+ {value, #node_info{me = ME}} ->
+ {table, OidSoFar, [], ME}
+ end
+ end;
+find_next(D, {node, {variable, _MibName}}, _Idx, RevOidSoFar, MibView) ->
+ OidSoFar = lists:reverse([0 | RevOidSoFar]),
+ case snmpa_acm:validate_mib_view(OidSoFar, MibView) of
+ true ->
+ #mib_data{node_db = Db} = D,
+ case snmpa_general_db:read(Db, lists:reverse(RevOidSoFar)) of
+ false ->
+ ?vinfo("find_next -> could not find variable with"
+ "~n RevOidSoFar: ~p", [RevOidSoFar]),
+ false;
+ {value, #node_info{me = ME}} ->
+ {variable, ME, OidSoFar}
+ end;
+ _ ->
+ false
+ end;
+find_next(D, {node, subagent}, _Idx, RevOidSoFar, MibView) ->
+ OidSoFar = lists:reverse(RevOidSoFar),
+ case snmpa_acm:is_definitely_not_in_mib_view(OidSoFar, MibView) of
+ true ->
+ false;
+ _ ->
+ #mib_data{subagents = SAs} = D,
+ case lists:keysearch(OidSoFar, 2, SAs) of
+ {value, {SubAgentPid, OidSoFar}} ->
+ {subagent, SubAgentPid, OidSoFar};
+ false ->
+ ?vinfo("find_node -> could not find subagent with"
+ "~n OidSoFar: ~p"
+ "~n SAs: ~p", [OidSoFar, SAs]),
+ false
+ end
+ end.
+
+%%%======================================================================
+%%% 3. Tree building functions
+%%% Used when loading mibs.
+%%%======================================================================
+
+build_tree(Mes, MibName) ->
+ ?d("build_tree -> "
+ "~n Mes: ~p", [Mes]),
+ {ListTree, []} = build_subtree([], Mes, MibName),
+ {tree, convert_tree(ListTree), internal}.
+
+%%----------------------------------------------------------------------
+%% Purpose: Builds the tree where all oids have prefix equal to LevelPrefix.
+%% Returns: {Tree, RestMes}
+%% RestMes are Mes that should not be in this subtree.
+%% The Tree is a temporary and simplified data structure that is easy to
+%% convert to the final tuple tree used by the MIB process.
+%% A Node is represented as in the final tree.
+%% The tree is not represented as a N-tuple, but as an Index-list.
+%% Example: Temporary: [{1, Node1}, {3, Node3}]
+%% Final: {Node1, undefined_node, Node3}
+%% Pre: Mes are sorted on oid.
+%%----------------------------------------------------------------------
+build_subtree(LevelPrefix, [Me | Mes], MibName) ->
+ ?vtrace("build subtree -> ~n"
+ " oid: ~p~n"
+ " LevelPrefix: ~p~n"
+ " MibName: ~p", [Me#me.oid, LevelPrefix, MibName]),
+ EType = Me#me.entrytype,
+ ?vtrace("build subtree -> EType = ~p",[EType]),
+ case in_subtree(LevelPrefix, Me) of
+ above ->
+ ?vtrace("build subtree -> above",[]),
+ {[], [Me|Mes]};
+ {node, Index} ->
+ ?vtrace("build subtree -> node at ~p",[Index]),
+ {Tree, RestMes} = build_subtree(LevelPrefix, Mes, MibName),
+ {[{Index, {node, {EType, MibName}}} | Tree], RestMes};
+ {subtree, Index, NewLevelPrefix} ->
+ ?vtrace("build subtree -> subtree at"
+ "~n ~w with ~w",
+ [Index, NewLevelPrefix]),
+ {BelowTree, RestMes} =
+ build_subtree(NewLevelPrefix, Mes, MibName),
+ {CurTree, RestMes2} =
+ build_subtree(LevelPrefix, RestMes, MibName),
+ {[{Index, {tree, BelowTree, {EType,MibName}}}| CurTree], RestMes2};
+ {internal_subtree, Index, NewLevelPrefix} ->
+ ?vtrace("build subtree -> internal_subtree at"
+ "~n ~w with ~w",
+ [Index,NewLevelPrefix]),
+ {BelowTree, RestMes} =
+ build_subtree(NewLevelPrefix, [Me | Mes], MibName),
+ {CurTree, RestMes2} =
+ build_subtree(LevelPrefix, RestMes, MibName),
+ {[{Index, {tree, BelowTree, internal}} | CurTree], RestMes2}
+ end;
+
+build_subtree(_LevelPrefix, [], _MibName) ->
+ ?vtrace("build subtree -> done", []),
+ {[], []}.
+
+%%--------------------------------------------------
+%% Purpose: Determine how/if/where Me should be inserted in subtree
+%% with LevelPrefix. This function does not build any tree, only
+%% determinses what should be done (by build subtree).
+%% Returns:
+%% above - Indicating that this ME should _not_ be in this subtree.
+%% {node, Index} - yes, construct a node with index Index on this level
+%% {internal_subtree, Index, NewLevelPrefix} - yes, there should be an
+%% internal subtree at this index.
+%% {subtree, Index, NewLevelPrefix} - yes, construct a subtree with
+%% NewLevelPrefix and insert this on current level in position Index.
+%%--------------------------------------------------
+in_subtree(LevelPrefix, Me) ->
+ case lists:prefix(LevelPrefix, Me#me.oid) of
+ true when length(Me#me.oid) > length(LevelPrefix) ->
+ classify_how_in_subtree(LevelPrefix, Me);
+ _ ->
+ above
+ end.
+
+%%--------------------------------------------------
+%% See comment about in_subtree/2. This function takes care of all cases
+%% where the ME really should be in _this_ subtree (not above).
+%%--------------------------------------------------
+classify_how_in_subtree(LevelPrefix, Me)
+ when (length(Me#me.oid) =:= (length(LevelPrefix) + 1)) ->
+ Oid = Me#me.oid,
+ case node_or_subtree(Me#me.entrytype) of
+ subtree ->
+ {subtree, lists:last(Oid), Oid};
+ node ->
+ {node, lists:last(Oid)}
+ end;
+
+classify_how_in_subtree(LevelPrefix, Me)
+ when (length(Me#me.oid) > (length(LevelPrefix) + 1)) ->
+ L1 = length(LevelPrefix) + 1,
+ Oid = Me#me.oid,
+ {internal_subtree, lists:nth(L1, Oid), lists:sublist(Oid, 1, L1)}.
+
+%%--------------------------------------------------
+%% Determines how to treat different kinds om MEs in the tree building process.
+%% Pre: all internal nodes have been removed.
+%%--------------------------------------------------
+node_or_subtree(table) -> subtree;
+node_or_subtree(table_entry) -> subtree;
+node_or_subtree(variable) -> node;
+node_or_subtree(table_column) -> node.
+
+%%--------------------------------------------------
+%% Purpose: (Recursively) Converts a temporary tree (see above) to a final tree.
+%% If input is a ListTree, output is a TupleTree.
+%% If input is a Node, output is the same Node.
+%% Pre: All Indexes are >= 0.
+%%--------------------------------------------------
+convert_tree({Index, {tree, Tree, Info}}) when Index >= 0 ->
+ L = lists:map(fun convert_tree/1, Tree),
+ {Index, {tree, dict_list_to_tuple(L), Info}};
+convert_tree({Index, {node, Info}}) when Index >= 0 ->
+ {Index, {node, Info}};
+convert_tree(Tree) when is_list(Tree) ->
+ L = lists:map(fun convert_tree/1, Tree),
+ dict_list_to_tuple(L).
+
+%%----------------------------------------------------------------------
+%% Purpose: Converts a single level (that is non-recursively) from
+%% the temporary indexlist to the N-tuple.
+%% Input: A list of {Index, Data}.
+%% Output: A tuple where element Index is Data.
+%%----------------------------------------------------------------------
+dict_list_to_tuple(L) ->
+ L2 = lists:keysort(1, L),
+ list_to_tuple(integrate_indexes(0, L2)).
+
+%%----------------------------------------------------------------------
+%% Purpose: Helper function for dict_list_to_tuple/1.
+%% Converts an indexlist to a N-list.
+%% Input: A list of {Index, Data}.
+%% Output: A (usually longer, never shorter) list where element Index is Data.
+%% Example: [{1,hej}, {3, sven}] will give output
+%% [undefined_node, hej, undefined_node, sven].
+%% Initially CurIndex should be 0.
+%%----------------------------------------------------------------------
+integrate_indexes(CurIndex, [{CurIndex, Data} | T]) ->
+ [Data | integrate_indexes(CurIndex + 1, T)];
+integrate_indexes(_Index, []) ->
+ [];
+integrate_indexes(CurIndex, L) ->
+ [undefined_node | integrate_indexes(CurIndex + 1, L)].
+
+%%%======================================================================
+%%% 4. Tree merging
+%%% Used by: load mib, insert subagent.
+%%%======================================================================
+
+%%----------------------------------------------------------------------
+%% Arg: Two root nodes (that is to be merged).
+%% Returns: A new root node where the nodes have been merger to one.
+%%----------------------------------------------------------------------
+merge_nodes(Same, Same) ->
+ Same;
+merge_nodes(Node, undefined_node) ->
+ Node;
+merge_nodes(undefined_node, Node) ->
+ Node;
+merge_nodes({tree, Tree1, internal}, {tree, Tree2, internal}) ->
+ {tree, merge_levels(tuple_to_list(Tree1),tuple_to_list(Tree2)), internal};
+merge_nodes(Node1, Node2) ->
+ throw({error_merge_nodes, Node1, Node2}).
+
+%%----------------------------------------------------------------------
+%% Arg: Two levels to be merged.
+%% Here, a level is represented as a list of nodes. A list is easier
+%% to extend than a tuple.
+%% Returns: The resulting, merged level tuple.
+%%----------------------------------------------------------------------
+merge_levels(Level1, Level2) when length(Level1) =:= length(Level2) ->
+ MergeNodes = fun(N1, N2) -> merge_nodes(N1, N2) end,
+ list_to_tuple(snmp_misc:multi_map(MergeNodes, [Level1, Level2]));
+merge_levels(Level1, Level2) when length(Level1) > length(Level2) ->
+ merge_levels(Level1, Level2 ++
+ undefined_nodes_list(length(Level1) - length(Level2)));
+merge_levels(Level1, Level2) when length(Level1) < length(Level2) ->
+ merge_levels(Level2, Level1).
+
+undefined_nodes_list(N) -> lists:duplicate(N, undefined_node).
+
+
+%%%======================================================================
+%%% 5. Tree deletion routines
+%%% (for unload mib)
+%%%======================================================================
+
+%%----------------------------------------------------------------------
+%% Purpose: Actually kicks of the tree reconstruction.
+%% Returns: {list of removed MEs, NewTree}
+%%----------------------------------------------------------------------
+delete_mib_from_tree(MibName, {tree, Tree, internal}) ->
+ case delete_tree(Tree, MibName) of
+ [] ->
+ {tree, {undefined_node}, internal}; % reduce
+ LevelList ->
+ {tree, list_to_tuple(LevelList), internal}
+ end.
+
+%%----------------------------------------------------------------------
+%% Purpose: Deletes all nodes associated to MibName from this level and
+%% all levels below.
+%% If the new level does not contain information (that is, no
+%% other mibs use it) anymore the empty list is returned.
+%% Returns: {MEs, The new level represented as a list}
+%%----------------------------------------------------------------------
+delete_tree(Tree, MibName) when is_tuple(Tree) ->
+ NewLevel = delete_nodes(tuple_to_list(Tree), MibName, []),
+ case lists:filter(fun drop_undefined_nodes/1,NewLevel) of
+ [] -> [];
+ _A_perhaps_shorted_list ->
+ NewLevel % some other mib needs this level
+ end.
+
+%%----------------------------------------------------------------------
+%% Purpose: Nodes belonging to MibName are removed from the tree.
+%% Recursively deletes sub trees to this node.
+%% Returns: {MEs, NewNodesList}
+%%----------------------------------------------------------------------
+delete_nodes([], _MibName, AccNodes) ->
+ lists:reverse(AccNodes);
+
+delete_nodes([{node, {variable, MibName}}|T], MibName, AccNodes) ->
+ delete_nodes(T, MibName, [undefined_node | AccNodes]);
+
+delete_nodes([{node, {table_column, MibName}}|T], MibName, AccNodes) ->
+ delete_nodes(T, MibName, [undefined_node | AccNodes]);
+
+delete_nodes([{tree, _Tree, {table, MibName}}|T], MibName, AccNodes) ->
+ delete_nodes(T, MibName, [undefined_node | AccNodes]);
+
+delete_nodes([{tree, _Tree, {table_entry, MibName}}|T], MibName, AccNodes) ->
+ delete_nodes(T, MibName, [undefined_node | AccNodes]);
+
+delete_nodes([{tree, Tree, Info}|T], MibName, AccNodes) ->
+ case delete_tree(Tree, MibName) of
+ [] -> % tree completely deleted
+ delete_nodes(T, MibName, [undefined_node | AccNodes]);
+ LevelList ->
+ delete_nodes(T, MibName,
+ [{tree, list_to_tuple(LevelList), Info} | AccNodes])
+ end;
+
+delete_nodes([NodeToKeep|T], MibName, AccNodes) ->
+ delete_nodes(T, MibName, [NodeToKeep | AccNodes]).
+
+drop_undefined_nodes(undefined_node) -> false;
+drop_undefined_nodes(_) -> true.
+
+
+%%%======================================================================
+%%% 6. Functions for subagent handling
+%%%======================================================================
+
+%%----------------------------------------------------------------------
+%% Returns: A new Root|{error, reason}
+%%----------------------------------------------------------------------
+insert_subagent(Oid, OldRoot) ->
+ ListTree = build_tree_for_subagent(Oid),
+ case catch convert_tree(ListTree) of
+ {'EXIT', _Reason} ->
+ {error, 'cannot construct tree from oid'};
+ Level when is_tuple(Level) ->
+ T = {tree, Level, internal},
+ case catch merge_nodes(T, OldRoot) of
+ {error_merge_nodes, _Node1, _Node2} ->
+ {error, oid_conflict};
+ NewRoot when is_tuple(NewRoot) andalso
+ (element(1, NewRoot) =:= tree) ->
+ NewRoot
+ end
+ end.
+
+build_tree_for_subagent([Index]) ->
+ [{Index, {node, subagent}}];
+
+build_tree_for_subagent([Index | T]) ->
+ [{Index, {tree, build_tree_for_subagent(T), internal}}].
+
+%%----------------------------------------------------------------------
+%% Returns: A new tree where the subagent at Oid (2nd arg) has been deleted.
+%%----------------------------------------------------------------------
+delete_subagent({tree, Tree, Info}, [Index]) ->
+ {node, subagent} = element(Index+1, Tree),
+ {tree, setelement(Index+1, Tree, undefined_node), Info};
+delete_subagent({tree, Tree, Info}, [Index | TI]) ->
+ {tree, setelement(Index+1, Tree,
+ delete_subagent(element(Index+1, Tree), TI)), Info}.
+
+%%%======================================================================
+%%% 7. Misc functions
+%%%======================================================================
+
+%%----------------------------------------------------------------------
+%% Installs the mibs found in the database when starting the agent.
+%% Basically calls the instrumentation functions for all non-internal
+%% mib-entries
+%%----------------------------------------------------------------------
+install_mibs(MibDb, NodeDb) ->
+ MibNames = loaded(MibDb),
+ ?vtrace("install_mibs -> found following mibs in database: ~n"
+ "~p", [MibNames]),
+ install_mibs2(NodeDb, MibNames).
+
+install_mibs2(_, []) ->
+ ok;
+install_mibs2(NodeDb, [MibName|MibNames]) ->
+ Pattern = #node_info{oid = '_', mib_name = MibName, me = '_'},
+ Nodes = snmpa_general_db:match_object(NodeDb, Pattern),
+ MEs = [ME || #node_info{me = ME} <- Nodes],
+ ?vtrace("install_mibs2 -> installing ~p MEs for mib ~p",
+ [length(MEs),MibName]),
+ NewF = fun(ME) -> call_instrumentation(ME, new) end,
+ lists:foreach(NewF, MEs),
+ install_mibs2(NodeDb, MibNames).
+
+
+%%----------------------------------------------------------------------
+%% Does all side effect stuff during load_mib.
+%%----------------------------------------------------------------------
+install_mib(Db, Symbolic, Mib, MibName, FileName, NonInternalMes) ->
+ ?vdebug("install_mib -> entry with"
+ "~n Symbolic: ~p"
+ "~n MibName: ~p"
+ "~n FileName: ~p", [Symbolic, MibName, FileName]),
+ Rec = #mib_info{name = MibName, symbolic = Symbolic, file_name = FileName},
+ snmpa_general_db:write(Db, Rec),
+ install_mib2(Symbolic, MibName, Mib),
+ NewF = fun(ME) -> call_instrumentation(ME, new) end,
+ lists:foreach(NewF, NonInternalMes).
+
+install_mib2(true, MibName, Mib) ->
+ #mib{table_infos = TabInfos,
+ variable_infos = VarInfos,
+ mes = MEs,
+ asn1_types = ASN1Types,
+ traps = Traps} = Mib,
+ snmpa_symbolic_store:add_table_infos(MibName, TabInfos),
+ snmpa_symbolic_store:add_variable_infos(MibName, VarInfos),
+ snmpa_symbolic_store:add_aliasnames(MibName, MEs),
+ snmpa_symbolic_store:add_types(MibName, ASN1Types),
+ SetF = fun(Trap) ->
+ snmpa_symbolic_store:set_notification(Trap, MibName)
+ end,
+ lists:foreach(SetF, Traps);
+install_mib2(_, _, _) ->
+ ok.
+
+install_mes(_Db, _MibName, []) ->
+ ok;
+install_mes(Db, MibName, [ME|MEs]) ->
+ Node = #node_info{oid = ME#me.oid, mib_name = MibName, me = ME},
+ snmpa_general_db:write(Db, Node),
+ install_mes(Db, MibName, MEs).
+
+
+%%----------------------------------------------------------------------
+%% Does all side effect stuff during unload_mib.
+%%----------------------------------------------------------------------
+uninstall_mib(Db, Symbolic, MibName, MEs) ->
+ ?vtrace("uninstall_mib -> entry with"
+ "~n Db: ~p"
+ "~n Symbolic: ~p"
+ "~n MibName: ~p", [Db, Symbolic, MibName]),
+ Res = snmpa_general_db:delete(Db, MibName),
+ ?vtrace("uninstall_mib -> (mib) db delete result: ~p", [Res]),
+ uninstall_mib2(Symbolic, MibName),
+ DelF = fun(ME) -> call_instrumentation(ME, delete) end,
+ lists:foreach(DelF, MEs).
+
+uninstall_mib2(true, MibName) ->
+ snmpa_symbolic_store:delete_table_infos(MibName),
+ snmpa_symbolic_store:delete_variable_infos(MibName),
+ snmpa_symbolic_store:delete_aliasnames(MibName),
+ snmpa_symbolic_store:delete_types(MibName),
+ snmpa_symbolic_store:delete_notifications(MibName);
+uninstall_mib2(_, _) ->
+ ok.
+
+uninstall_mes(Db, MibName) ->
+ Pattern = #node_info{oid = '_', mib_name = MibName, me = '_'},
+ snmpa_general_db:match_delete(Db, Pattern).
+
+
+%%----------------------------------------------------------------------
+%% Create a list of the names of all the loaded mibs
+%%----------------------------------------------------------------------
+loaded(Db) ->
+ [N || #mib_info{name = N} <- snmpa_general_db:tab2list(Db)].
+
+
+%%----------------------------------------------------------------------
+%% Calls MFA-instrumentation with 'new' or 'delete' operation.
+%%----------------------------------------------------------------------
+call_instrumentation(#me{entrytype = variable, mfa={M,F,A}}, Operation) ->
+ ?vtrace("call instrumentation with"
+ "~n entrytype: variable"
+ "~n MFA: {~p,~p,~p}"
+ "~n Operation: ~p",
+ [M,F,A,Operation]),
+ catch apply(M, F, [Operation | A]);
+call_instrumentation(#me{entrytype = table_entry, mfa={M,F,A}}, Operation) ->
+ ?vtrace("call instrumentation with"
+ "~n entrytype: table_entry"
+ "~n MFA: {~p,~p,~p}"
+ "~n Operation: ~p",
+ [M,F,A,Operation]),
+ catch apply(M, F, [Operation | A]);
+call_instrumentation(_ShitME, _Operation) ->
+ done.
+
+
+maybe_drop_me(#me{entrytype = internal}) -> false;
+maybe_drop_me(#me{entrytype = group}) -> false;
+maybe_drop_me(#me{imported = true}) -> false;
+maybe_drop_me(_) -> true.
+
+
+%%----------------------------------------------------------------------
+%% Code change functions
+%%----------------------------------------------------------------------
+
+code_change(down, State) ->
+ ?d("code_change(down) -> entry",[]),
+ State;
+
+code_change(up, State) ->
+ ?d("code_change(up)",[]),
+ State;
+
+code_change(_Vsn, State) ->
+ State.
+
diff --git a/lib/snmp/src/agent/snmpa_mib_lib.erl b/lib/snmp/src/agent/snmpa_mib_lib.erl
new file mode 100644
index 0000000000..441228b9ee
--- /dev/null
+++ b/lib/snmp/src/agent/snmpa_mib_lib.erl
@@ -0,0 +1,207 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2004-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%
+%%
+-module(snmpa_mib_lib).
+
+-export([table_cre_row/3, table_del_row/2]).
+-export([get_table/2, print_table/3, print_table/4, print_tables/1]).
+-export([gc_tab/3, gc_tab/5]).
+
+-include("SNMPv2-TC.hrl").
+-include("snmp_types.hrl").
+
+-define(VMODULE,"MIB-LIB").
+-include("snmp_verbosity.hrl").
+
+-ifndef(default_verbosity).
+-define(default_verbosity,silence).
+-endif.
+
+
+%%%-----------------------------------------------------------------
+%%%-----------------------------------------------------------------
+
+%% returns: bool()
+table_cre_row({Tab, mnesia}, Key, _Row) ->
+ ?vtrace("create mnesia table ~w row with Key: ~w",[Tab, Key]),
+ {error, mnesia_not_supported};
+table_cre_row({Tab, Db} = TabDb, Key, Row) ->
+ ?vtrace("create ~w table ~w row with Key: ~w",[Db, Tab, Key]),
+ snmpa_local_db:table_create_row(TabDb, Key, Row).
+
+%% returns: bool()
+table_del_row({Tab, mnesia}, Key) ->
+ ?vtrace("delete mnesia table ~w row with Key: ~w",[Tab, Key]),
+ {error, mnesia_not_supported};
+table_del_row({Tab, Db} = TabDb, Key) ->
+ ?vtrace("delete ~w table ~w row with Key: ~w", [Db, Tab, Key]),
+ snmpa_local_db:table_delete_row(TabDb, Key).
+
+
+%%%-----------------------------------------------------------------
+%%% Retreives the entire table. Used for debugging
+%%%-----------------------------------------------------------------
+
+get_table(NameDb, FOI) ->
+ (catch get_table(NameDb, FOI, [], [])).
+
+get_table(NameDb, FOI, Oid, Acc) ->
+ case table_next(NameDb, Oid) of
+ endOfTable ->
+ ?vdebug("end of table",[]),
+ {ok, lists:reverse(Acc)};
+ Oid ->
+ %% Crap, circular ref
+ ?vinfo("cyclic reference: ~w -> ~w", [Oid,Oid]),
+ throw({error, {cyclic_db_reference, Oid, Acc}});
+ NextOid ->
+ ?vtrace("get row for oid ~w", [NextOid]),
+ case table_get_row(NameDb, NextOid, FOI) of
+ undefined ->
+ throw({error, {invalid_rowindex, NextOid, Acc}});
+ Row ->
+ ?vtrace("row: ~w", [Row]),
+ get_table(NameDb, FOI, NextOid, [{NextOid, Row}|Acc])
+ end
+ end.
+
+
+print_tables(Tables) when is_list(Tables) ->
+ lists:foreach(fun({Table, DB, FOI, PrintRow}) ->
+ print_table(Table, DB, FOI, PrintRow)
+ end, Tables),
+ ok.
+
+%% print_table(Table, DB, FOI, PrintRow) ->
+%% TableInfo = get_table(DB(Table), FOI(Table)),
+%% print_table(Table, TableInfo, PrintRow),
+%% ok.
+
+print_table(Table, DB, FOI, PrintRow) ->
+ TableInfo = get_table(DB, FOI),
+ print_table(Table, TableInfo, PrintRow).
+
+print_table(Table, TableInfo, PrintRow) when is_function(PrintRow, 2) ->
+ io:format("~w => ~n", [Table]),
+ do_print_table(TableInfo, PrintRow).
+
+do_print_table({ok, TableInfo}, PrintRow) when is_function(PrintRow, 2) ->
+ lists:foreach(fun({RowIdx, Row}) ->
+ io:format(" ~w => ~n~s~n",
+ [RowIdx, PrintRow(" ", Row)])
+ end, TableInfo),
+ io:format("~n", []);
+do_print_table({error, {invalid_rowindex, BadRowIndex, []}}, _PrintRow) ->
+ io:format("Error: Bad rowindex ~w~n", [BadRowIndex]);
+do_print_table({error, {invalid_rowindex, BadRowIndex, TableInfo}}, PrintRow) ->
+ io:format("Error: Bad rowindex ~w", [BadRowIndex]),
+ do_print_table(TableInfo, PrintRow);
+do_print_table(Error, _PrintRow) ->
+ io:format("Error: ~p~n", [Error]).
+
+
+%%%-----------------------------------------------------------------
+%%%
+%%%-----------------------------------------------------------------
+
+table_next({Name, mnesia}, RestOid) ->
+ snmp_generic_mnesia:table_next(Name, RestOid);
+table_next(NameDb, RestOid) ->
+ snmpa_local_db:table_next(NameDb, RestOid).
+
+
+table_get_row({Name, mnesia}, RowIndex) ->
+ snmp_generic_mnesia:table_get_row(Name, RowIndex);
+table_get_row(NameDb, RowIndex) ->
+ snmpa_local_db:table_get_row(NameDb, RowIndex).
+
+table_get_row(NameDb, RowIndex, undefined) ->
+ table_get_row(NameDb, RowIndex);
+table_get_row({Name, mnesia}, RowIndex, FOI) ->
+ snmp_generic_mnesia:table_get_row(Name, RowIndex, FOI);
+table_get_row(NameDb, RowIndex, _FOI) ->
+ snmpa_local_db:table_get_row(NameDb, RowIndex).
+
+
+%%%-----------------------------------------------------------------
+%%% Utility module for the mib-implementation modules (such as
+%%% snmp_target_mib).
+%%%-----------------------------------------------------------------
+
+gc_tab(TabDb, STC, FOI) ->
+ InvalidateRow = fun(_) -> ok end,
+ UpdateRow = fun(_) -> ok end,
+ gc_tab(TabDb, STC, FOI, InvalidateRow, UpdateRow).
+
+gc_tab({Tab,mnesia} = TabDb, STC, FOI, InvalidateRow, UpdateRow) ->
+ F = fun(RowIndex, Row) ->
+ case element(STC, Row) of
+ ?'StorageType_volatile' ->
+ snmp_generic_mnesia:table_delete_row(Tab, RowIndex),
+ InvalidateRow(RowIndex);
+ _ ->
+ UpdateRow(RowIndex)
+ end
+ end,
+ gc_tab1(F, TabDb, FOI);
+
+gc_tab(TabDb, STC, FOI, InvalidateRow, UpdateRow) ->
+ F = fun(RowIndex, Row) ->
+ case element(STC, Row) of
+ ?'StorageType_volatile' ->
+ snmpa_local_db:table_delete_row(TabDb, RowIndex),
+ InvalidateRow(RowIndex);
+ _ ->
+ UpdateRow(RowIndex),
+ ok
+ end
+ end,
+ gc_tab1(F, TabDb, FOI).
+
+
+gc_tab1(F, {Tab,_} = TabDb, FOI) ->
+ case (catch snmp_generic:table_foreach(TabDb, F, FOI)) of
+ {'EXIT',{cyclic_db_reference,Oid}} ->
+ %% Remove the row regardless of storage type since this
+ %% is a major error. This row must be removed.
+ case table_delete_row(TabDb, Oid) of
+ true ->
+ ?vlog("deleted cyclic ref row for: ~w;~w",
+ [Tab, Oid]),
+ config_err("cyclic reference in table ~w: "
+ "~w -> ~w. Row deleted",
+ [Tab, Oid, Oid]),
+ gc_tab1(F, TabDb, FOI);
+ false ->
+ ?vlog("unable to remove faulty row from table ~w",
+ [Tab]),
+ config_err("failed removing faulty row. "
+ "Giving up on table ~w cleanup", [Tab])
+ end;
+ _ ->
+ ok
+ end.
+
+table_delete_row({Tab, mnesia}, Oid) ->
+ snmp_generic_mnesia:table_delete_row(Tab, Oid),
+ true;
+table_delete_row(TabDb, Oid) ->
+ snmpa_local_db:table_delete_row(TabDb, Oid).
+
+config_err(F, A) ->
+ snmpa_error:config_err(F, A).
diff --git a/lib/snmp/src/agent/snmpa_misc_sup.erl b/lib/snmp/src/agent/snmpa_misc_sup.erl
new file mode 100644
index 0000000000..488d3f7921
--- /dev/null
+++ b/lib/snmp/src/agent/snmpa_misc_sup.erl
@@ -0,0 +1,158 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1997-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%
+%%
+-module(snmpa_misc_sup).
+
+-include("snmp_debug.hrl").
+
+-behaviour(supervisor).
+
+%% External exports
+-export([
+ start_link/0,
+ start_mib_server/4, stop_mib_server/1,
+ start_net_if/6, stop_net_if/1,
+ start_note_store/3, stop_note_store/1
+ ]).
+
+%% Internal exports
+-export([init/1]).
+
+-define(SERVER, ?MODULE).
+
+
+%%%-----------------------------------------------------------------
+%%% This is a supervisor for the mib and net_ifprocesses.
+%%% Each agent has one mib process.
+%%%-----------------------------------------------------------------
+
+start_link() ->
+ ?d("start_link -> entry", []),
+ supervisor:start_link({local, ?SERVER}, ?MODULE, []).
+
+
+%%-----------------------------------------------------------------
+%% When the agent starts, it calls this function. If there already
+%% exist a mib process for the agent, this one is used. Otherwise
+%% a new one is started.
+%%-----------------------------------------------------------------
+start_mib_server(Prio, Ref, Mibs, Opts) ->
+ ?d("start_mib_server -> entry with"
+ "~n Prio: ~p"
+ "~n Ref: ~p"
+ "~n Mibs: ~p"
+ "~n Opts: ~p", [Prio, Ref, Mibs, Opts]),
+ SupName = ?SERVER,
+ start_mibserver(SupName, Ref, [Prio, Mibs, Opts]).
+
+start_mibserver(SupName, Ref, Args) ->
+ Children = supervisor:which_children(SupName),
+ case lists:keysearch({mib, Ref}, 1, Children) of
+ {value, {_, Pid, _, _}} -> {ok, Pid};
+ _ ->
+ Mib = {{mib, Ref},
+ {snmpa_mib, start_link, Args},
+ transient, 10000, worker, [snmpa_mib]},
+ supervisor:start_child(SupName, Mib)
+ end.
+
+stop_mib_server(Ref) ->
+ SupName = ?SERVER,
+ case whereis(SupName) of
+ undefined ->
+ ok;
+ _ ->
+ supervisor:terminate_child(SupName, {mib, Ref}),
+ supervisor:delete_child(SupName, {mib, Ref})
+ end.
+
+
+start_net_if(Prio, NoteStore, Ref, Master, Mod, Opts) ->
+ ?d("start_mib -> entry with"
+ "~n Prio: ~p"
+ "~n NoteStore: ~p"
+ "~n Ref: ~p"
+ "~n Master: ~p"
+ "~n Mod: ~p"
+ "~n Opts: ~p",
+ [Prio, NoteStore, Ref, Master, Mod, Opts]),
+ SupName = ?SERVER,
+ start_netif(SupName, Ref, Mod, [Prio, NoteStore, Master, Opts]).
+
+start_netif(SupName, Ref, Mod, Args) ->
+ %% make sure we start from scratch...
+ Children = supervisor:which_children(SupName),
+ case lists:keysearch({net_if, Ref}, 1, Children) of
+ {value, {_, _Pid, _, _}} ->
+ stop_net_if(Ref);
+ _ ->
+ ok
+ end,
+ NetIf = {{net_if, Ref},
+ {Mod, start_link, Args},
+ permanent, 2000, worker, [Mod]},
+ supervisor:start_child(SupName, NetIf).
+
+stop_net_if(Ref) ->
+ SupName = ?SERVER,
+ case whereis(SupName) of
+ undefined ->
+ ok;
+ _ ->
+ supervisor:terminate_child(SupName, {net_if, Ref}),
+ supervisor:delete_child(SupName, {net_if, Ref})
+ end.
+
+
+start_note_store(Prio, Ref, Opts) ->
+ ?d("start_note_store -> entry with"
+ "~n Prio: ~p"
+ "~n Ref: ~p"
+ "~n Opts: ~p", [Prio, Ref, Opts]),
+ SupName = ?SERVER,
+ start_notestore(SupName, Ref, [Prio, snmpa, Opts]).
+
+start_notestore(SupName, Ref, Args) ->
+ %% make sure we start from scratch...
+ Children = supervisor:which_children(SupName),
+ case lists:keysearch({note_store, Ref}, 1, Children) of
+ {value, {_, _Pid, _, _}} ->
+ stop_note_store(Ref);
+ _ ->
+ ok
+ end,
+ Mod = snmp_note_store,
+ Note = {{note_store, Ref},
+ {Mod, start_link, Args},
+ permanent, 2000, worker, [Mod]},
+ supervisor:start_child(SupName, Note).
+
+stop_note_store(Ref) ->
+ SupName = ?SERVER,
+ case whereis(SupName) of
+ undefined ->
+ ok;
+ _ ->
+ supervisor:terminate_child(SupName, {note_store, Ref}),
+ supervisor:delete_child(SupName, {note_store, Ref})
+ end.
+
+
+init([]) ->
+ SupFlags = {one_for_all, 0, 3600},
+ {ok, {SupFlags, []}}.
diff --git a/lib/snmp/src/agent/snmpa_mpd.erl b/lib/snmp/src/agent/snmpa_mpd.erl
new file mode 100644
index 0000000000..2e09286b87
--- /dev/null
+++ b/lib/snmp/src/agent/snmpa_mpd.erl
@@ -0,0 +1,1386 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1997-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%
+%%
+-module(snmpa_mpd).
+
+-export([init/1, reset/0, inc/1, counters/0,
+ discarded_pdu/1,
+ process_packet/6,
+ generate_response_msg/5, generate_msg/5,
+ generate_discovery_msg/4,
+ process_taddrs/1,
+ generate_req_id/0]).
+
+-define(SNMP_USE_V3, true).
+-include("snmp_types.hrl").
+-include("SNMP-MPD-MIB.hrl").
+-include("SNMPv2-TM.hrl").
+-include("SNMP-FRAMEWORK-MIB.hrl").
+
+-define(VMODULE,"MPD").
+-include("snmp_verbosity.hrl").
+
+-define(empty_msg_size, 24).
+
+-record(state, {v1 = false, v2c = false, v3 = false}).
+-record(note, {sec_engine_id,
+ sec_model,
+ sec_name,
+ sec_level,
+ ctx_engine_id,
+ ctx_name,
+ disco = false,
+ req_id}).
+
+
+%%%-----------------------------------------------------------------
+%%% This module implemets the Message Processing and Dispatch part of
+%%% the multi-lingual SNMP agent.
+%%%
+%%% The MPD is responsible for:
+%%% *) call the security module (auth/priv).
+%%% *) decoding the message into a PDU.
+%%% *) decide a suitable Access Control Model, and provide it with
+%%% the data it needs.
+%%% *) maintaining SNMP counters.
+%%%
+%%% In order to take care of the different versions of counters, it
+%%% implements and maintains the union of all SNMP counters (i.e. from
+%%% rfc1213 and from rfc1907). It is up to the administrator of the
+%%% agent to load the correct MIB. Note that this module implements
+%%% the counters only, it does not provide instrumentation functions
+%%% for the counters.
+%%%
+%%% With the terms defined in rfc2271, this module implememts part
+%%% of the Dispatcher and the Message Processing functionality.
+%%%-----------------------------------------------------------------
+init(Vsns) ->
+ ?vlog("init -> entry with"
+ "~n Vsns: ~p", [Vsns]),
+ {A,B,C} = erlang:now(),
+ random:seed(A,B,C),
+ ets:insert(snmp_agent_table, {msg_id, random:uniform(2147483647)}),
+ ets:insert(snmp_agent_table, {req_id, random:uniform(2147483647)}),
+ init_counters(),
+ init_versions(Vsns, #state{}).
+
+
+reset() ->
+ reset_counters(),
+ ok.
+
+
+%%-----------------------------------------------------------------
+%% Purpose: We must calculate the length of a
+%% message with an empty Pdu, and zero-length community
+%% string. This length is used to calculate the max
+%% pdu size allowed for each request. This size is
+%% dependent on two dynamic fields, the community string
+%% and the pdu (varbinds actually). It is calculated
+%% as EmptySize + length(CommunityString) + 4.
+%% We assume that the length of the CommunityString is
+%% less than 128 (thus requiring just one octet for the
+%% length field (the same as the zero-length community
+%% string)). 4 comes from the fact that the maximum pdu
+%% size needs 31 bits which needs 5 * 7 bits to be
+%% expressed. One 7bit octet is already present in the
+%% empty msg, leaving 4 more 7bit octets.
+%% Actually, this function is not used, we use a constant instead.
+%%-----------------------------------------------------------------
+%% Ret: 24
+%empty_msg() ->
+% M = #message{version = 'version-1', community = "", data =
+% #pdu{type = 'get-response', request_id = 1,
+% error_status = noError, error_index = 0, varbinds = []}},
+% length(snmp_pdus:enc_message(M)) + 4.
+
+%%-----------------------------------------------------------------
+%% Func: process_packet(Packet, TDomain, TAddress, State, Log) ->
+%% {ok, SnmpVsn, Pdu, PduMS, ACMData} | {discarded, Reason}
+%% Types: Packet = binary()
+%% TDomain = snmpUDPDomain | atom()
+%% TAddress = {Ip, Udp}
+%% State = #state
+%% Purpose: This is the main Message Dispatching function. (see
+%% section 4.2.1 in rfc2272)
+%%-----------------------------------------------------------------
+process_packet(Packet, TDomain, TAddress, State, NoteStore, Log) ->
+ inc(snmpInPkts),
+ case catch snmp_pdus:dec_message_only(binary_to_list(Packet)) of
+
+ #message{version = 'version-1', vsn_hdr = Community, data = Data}
+ when State#state.v1 =:= true ->
+ ?vlog("v1, community: ~s", [Community]),
+ HS = ?empty_msg_size + length(Community),
+ v1_v2c_proc('version-1', NoteStore, Community, TDomain, TAddress,
+ Data, HS, Log, Packet);
+
+ #message{version = 'version-2', vsn_hdr = Community, data = Data}
+ when State#state.v2c =:= true ->
+ ?vlog("v2c, community: ~s", [Community]),
+ HS = ?empty_msg_size + length(Community),
+ v1_v2c_proc('version-2', NoteStore, Community, TDomain, TAddress,
+ Data, HS, Log, Packet);
+
+ #message{version = 'version-3', vsn_hdr = V3Hdr, data = Data}
+ when State#state.v3 =:= true ->
+ ?vlog("v3, msgID: ~p, msgFlags: ~p, msgSecModel: ~p",
+ [V3Hdr#v3_hdr.msgID,
+ V3Hdr#v3_hdr.msgFlags,
+ V3Hdr#v3_hdr.msgSecurityModel]),
+ v3_proc(NoteStore, Packet, TDomain, TAddress, V3Hdr, Data, Log);
+
+ {'EXIT', {bad_version, Vsn}} ->
+ ?vtrace("exit: bad version: ~p",[Vsn]),
+ inc(snmpInBadVersions),
+ {discarded, snmpInBadVersions};
+
+ {'EXIT', Reason} ->
+ ?vtrace("exit: ~p", [Reason]),
+ inc(snmpInASNParseErrs),
+ {discarded, Reason};
+
+ UnknownMessage ->
+ ?vtrace("Unknown message: ~n ~p"
+ "~nwhen"
+ "~n State: ~p", [UnknownMessage, State]),
+ inc(snmpInBadVersions),
+ {discarded, snmpInBadVersions}
+ end.
+
+discarded_pdu(false) -> ok;
+discarded_pdu(Variable) -> inc(Variable).
+
+
+%%-----------------------------------------------------------------
+%% Handles a Community based message (v1 or v2c).
+%%-----------------------------------------------------------------
+v1_v2c_proc(Vsn, NoteStore, Community, snmpUDPDomain, {Ip, Udp},
+ Data, HS, Log, Packet) ->
+ TAddress = tuple_to_list(Ip) ++ [Udp div 256, Udp rem 256],
+ AgentMS = snmp_framework_mib:get_engine_max_message_size(),
+ MgrMS = snmp_community_mib:get_target_addr_ext_mms(?snmpUDPDomain,
+ TAddress),
+ PduMS = case MgrMS of
+ {ok, MMS} when MMS < AgentMS -> MMS - HS;
+ _ -> AgentMS - HS
+ end,
+ case (catch snmp_pdus:dec_pdu(Data)) of
+ Pdu when is_record(Pdu, pdu) ->
+ Log(Pdu#pdu.type, Packet),
+ inc_snmp_in_vars(Pdu),
+ #pdu{request_id = ReqId} = Pdu,
+ OkRes = {ok, Vsn, Pdu, PduMS,
+ {community, sec_model(Vsn), Community, TAddress}},
+ %% Make sure that we don't process duplicate SET request
+ %% twice. We don't know what could happen in that case.
+ %% The mgr does, so he has to generate a new SET request.
+ ?vdebug("PDU type: ~p", [Pdu#pdu.type]),
+ case Pdu#pdu.type of
+ 'set-request' ->
+ %% Check if this message has already been processed
+ Key = {agent, Ip, ReqId},
+ case snmp_note_store:get_note(NoteStore, Key) of
+ undefined ->
+ %% Set the processed note _after_ pdu processing.
+ %% This makes duplicated requests be ignored even
+ %% if pdu processing took long time.
+ snmp_note_store:set_note(NoteStore,
+ 100, Key, true),
+ %% Uses ACMData that snmpa_acm knows of.
+ %% snmpUDPDomain is implicit, since that's the only
+ %% one we handle.
+ OkRes;
+ true ->
+ {discarded, duplicate_pdu}
+ end;
+ _ ->
+ OkRes
+ end;
+ {'EXIT', Reason} ->
+ ?vtrace("PDU decode exit: ~p",[Reason]),
+ inc(snmpInASNParseErrs),
+ {discarded, Reason};
+ _TrapPdu ->
+ {discarded, trap_pdu}
+ end;
+v1_v2c_proc(_Vsn, _NoteStore, _Community, snmpUDPDomain, TAddress,
+ _Data, _HS, _Log, _Packet) ->
+ {discarded, {badarg, TAddress}};
+v1_v2c_proc(_Vsn, _NoteStore, _Community, TDomain, _TAddress,
+ _Data, _HS, _Log, _Packet) ->
+ {discarded, {badarg, TDomain}}.
+
+sec_model('version-1') -> ?SEC_V1;
+sec_model('version-2') -> ?SEC_V2C.
+
+
+%%-----------------------------------------------------------------
+%% Handles a SNMPv3 Message, following the procedures in rfc2272,
+%% section 4.2 and 7.2
+%%-----------------------------------------------------------------
+v3_proc(NoteStore, Packet, _TDomain, _TAddress, V3Hdr, Data, Log) ->
+ case (catch v3_proc(NoteStore, Packet, V3Hdr, Data, Log)) of
+ {'EXIT', Reason} ->
+ exit(Reason);
+ Result ->
+ Result
+ end.
+
+v3_proc(NoteStore, Packet, V3Hdr, Data, Log) ->
+ %% 7.2.3
+ #v3_hdr{msgID = MsgID,
+ msgMaxSize = MMS,
+ msgFlags = MsgFlags,
+ msgSecurityModel = MsgSecurityModel,
+ msgSecurityParameters = SecParams,
+ hdr_size = HdrSize} = V3Hdr,
+ ?vdebug("v3_proc -> version 3 message header:"
+ "~n msgID = ~p"
+ "~n msgMaxSize = ~p"
+ "~n msgFlags = ~p"
+ "~n msgSecurityModel = ~p"
+ "~n msgSecurityParameters = ~w",
+ [MsgID, MMS, MsgFlags, MsgSecurityModel, SecParams]),
+ %% 7.2.4
+ SecModule = get_security_module(MsgSecurityModel),
+ %% 7.2.5
+ SecLevel = check_sec_level(MsgFlags),
+ IsReportable = snmp_misc:is_reportable(MsgFlags),
+ %% 7.2.6
+ ?vtrace("v3_proc -> "
+ "~n SecModule = ~p"
+ "~n SecLevel = ~p"
+ "~n IsReportable = ~p",
+ [SecModule,SecLevel,IsReportable]),
+ SecRes = (catch SecModule:process_incoming_msg(Packet, Data,
+ SecParams, SecLevel)),
+ ?vtrace("v3_proc -> message processing result: "
+ "~n SecRes: ~p", [SecRes]),
+ {SecEngineID, SecName, ScopedPDUBytes, SecData, DiscoOrPlain} =
+ check_sec_module_result(SecRes, V3Hdr, Data, IsReportable, Log),
+ ?vtrace("v3_proc -> "
+ "~n DiscoOrPlain: ~w"
+ "~n SecEngineID: ~w"
+ "~n SecName: ~p", [DiscoOrPlain, SecEngineID, SecName]),
+ %% 7.2.7
+ #scopedPdu{contextEngineID = ContextEngineID,
+ contextName = ContextName,
+ data = PDU} =
+ case (catch snmp_pdus:dec_scoped_pdu(ScopedPDUBytes)) of
+ ScopedPDU when is_record(ScopedPDU, scopedPdu) ->
+ ?vtrace("v3_proc -> message processing result: "
+ "~n ScopedPDU: ~p", [ScopedPDU]),
+ ScopedPDU;
+ {'EXIT', Reason} ->
+ inc(snmpInASNParseErrs),
+ throw({discarded, Reason})
+ end,
+ %% We'll have to take care of the unlikely case that we receive an
+ %% v1 trappdu in a v3 message explicitly...
+ if
+ is_record(PDU, trappdu) ->
+ inc(snmpUnknownPDUHandlers),
+ throw({discarded, received_v1_trap});
+ true ->
+ ok
+ end,
+ ?vlog("7.2.7 result: "
+ "~n contextEngineID: ~w"
+ "~n ContextName: \"~s\"", [ContextEngineID, ContextName]),
+ if
+ SecLevel =:= ?'SnmpSecurityLevel_authPriv' ->
+ %% encrypted message - log decrypted pdu
+ Log(PDU#pdu.type, {V3Hdr, ScopedPDUBytes});
+ true -> % otherwise, log binary
+ Log(PDU#pdu.type, Packet)
+ end,
+ %% Make sure a get_bulk doesn't get too big.
+ AgentMS = snmp_framework_mib:get_engine_max_message_size(),
+ %% PduMMS is supposed to be the maximum total length of the response
+ %% PDU we can send. From the MMS, we need to subtract everything before
+ %% the PDU, i.e. Message and ScopedPDU.
+ %% Message: [48, TotalLen, Vsn, [Tag, LH, Hdr], [Tag, LM, MsgSec], Data]
+ %% 1 3 <----------- HdrSize ----------->
+ %% HdrSize = everything up to and including msgSecurityParameters.
+ %% ScopedPduData follows. This is
+ %% [Tag, Len, [Tag, L1, CtxName], [Tag, L2, CtxEID]]
+ %% i.e. 6 + length(CtxName) + length(CtxEID)
+ %%
+ %% Total: 1 + TotalLenOctets + 3 + ScopedPduDataLen
+ TotMMS = if AgentMS > MMS -> MMS;
+ true -> AgentMS
+ end,
+ TotalLenOctets = snmp_pdus:get_encoded_length(TotMMS - 1),
+ PduMMS = TotMMS - TotalLenOctets - 10 - HdrSize -
+ length(ContextName) - length(ContextEngineID),
+ ?vdebug("v3_proc -> PDU type: ~p", [PDU#pdu.type]),
+ case PDU#pdu.type of
+ report when DiscoOrPlain =:= discovery ->
+ %% Discovery stage 1 response
+ Key = {agent, MsgID},
+ Note = snmp_note_store:get_note(NoteStore, Key),
+ case Note of
+ #note{sec_engine_id = "",
+ sec_model = _MsgSecModel,
+ sec_name = "",
+ sec_level = _SecLevel,
+ ctx_engine_id = _CtxEngineID,
+ ctx_name = _CtxName,
+ disco = true,
+ req_id = _ReqId} ->
+ %% This is part of the discovery process initiated by us.
+ %% Response to the discovery stage 1 request
+ ?vdebug("v3_proc -> discovery stage 1 response", []),
+ {ok, 'version-3', PDU, PduMMS, {discovery, SecEngineID}};
+ #note{sec_engine_id = SecEngineID,
+ sec_model = _MsgSecModel,
+ sec_name = SecName,
+ sec_level = SecLevel,
+ ctx_engine_id = _CtxEngineID,
+ ctx_name = _CtxName,
+ disco = true,
+ req_id = _ReqId} ->
+ %% This is part of the discovery process initiated by us.
+ %% Response to the discovery stage 2 request
+ ?vdebug("v3_proc -> discovery stage 2 response", []),
+ {ok, 'version-3', PDU, PduMMS, discovery};
+ _ ->
+ %% 7.2.11
+ DiscardReason = {bad_disco_note, Key, Note},
+ throw({discarded, DiscardReason})
+ end;
+ report ->
+ %% 7.2.11
+ throw({discarded, report});
+ 'get-response' -> %% As a result of a sent inform-request?
+ %% 7.2.12
+ Key = {agent, MsgID},
+ Note = snmp_note_store:get_note(NoteStore, Key),
+ case Note of
+ #note{sec_engine_id = "",
+ sec_model = _MsgSecModel,
+ sec_name = "",
+ sec_level = _SecLevel,
+ ctx_engine_id = _CtxEngineID,
+ ctx_name = _CtxName,
+ disco = true,
+ req_id = _ReqId} ->
+ %% This is part of the discovery process initiated by us.
+ %% Response to the discovery stage 1 request
+ ?vdebug("v3_proc -> discovery stage 1 response", []),
+ {ok, 'version-3', PDU, PduMMS, {discovery, SecEngineID}};
+ #note{sec_engine_id = SecEngineID,
+ sec_model = _MsgSecModel,
+ sec_name = SecName,
+ sec_level = SecLevel,
+ ctx_engine_id = _CtxEngineID,
+ ctx_name = _CtxName,
+ disco = true,
+ req_id = _ReqId} ->
+ %% This is part of the discovery process initiated by us.
+ %% Response to the discovery stage 2 request
+ ?vdebug("v3_proc -> discovery stage 2 response", []),
+ {ok, 'version-3', PDU, PduMMS, discovery};
+ #note{sec_engine_id = SecEngineID,
+ sec_model = MsgSecurityModel,
+ sec_name = SecName,
+ sec_level = SecLevel,
+ ctx_engine_id = ContextEngineID,
+ ctx_name = ContextName,
+ disco = false,
+ req_id = _ReqId} ->
+ {ok, 'version-3', PDU, PduMMS, undefined};
+ _ ->
+ inc(snmpUnknownPDUHandlers),
+ throw({discarded, {no_outstanding_req, MsgID}})
+ end;
+ 'snmpv2-trap' ->
+ inc(snmpUnknownPDUHandlers),
+ throw({discarded, received_v2_trap});
+ Type ->
+ %% 7.2.13
+ SnmpEngineID = snmp_framework_mib:get_engine_id(),
+ ?vtrace("v3_proc -> SnmpEngineID = ~w", [SnmpEngineID]),
+ case SecEngineID of
+ SnmpEngineID when (DiscoOrPlain =:= discovery) ->
+ %% This is a discovery step 2 message!
+ ?vtrace("v3_proc -> discovery stage 2", []),
+ generate_discovery2_report_msg(MsgID,
+ MsgSecurityModel,
+ SecName,
+ SecLevel,
+ ContextEngineID,
+ ContextName,
+ SecData,
+ PDU,
+ Log);
+
+ SnmpEngineID when (DiscoOrPlain =:= plain) ->
+ %% 4.2.2.1.1 - we don't handle proxys yet => we only
+ %% handle ContextEngineID to ourselves
+ case ContextEngineID of
+ SnmpEngineID ->
+ %% Uses ACMData that snmpa_acm knows of.
+ {ok, 'version-3', PDU, PduMMS,
+ {v3, MsgID, MsgSecurityModel, SecName, SecLevel,
+ ContextEngineID, ContextName, SecData}};
+ _ ->
+ %% 4.2.2.1.2
+ NIsReportable = snmp_misc:is_reportable_pdu(Type),
+ Val = inc(snmpUnknownPDUHandlers),
+ ErrorInfo = {#varbind{oid = ?snmpUnknownPDUHandlers,
+ variabletype = 'Counter32',
+ value = Val},
+ SecName,
+ [{securityLevel, SecLevel},
+ {contextEngineID, ContextEngineID},
+ {contextName, ContextName}]},
+ case generate_v3_report_msg(MsgID,
+ MsgSecurityModel,
+ Data, ErrorInfo,
+ Log) of
+ {ok, Report} when NIsReportable =:= true ->
+ {discarded, snmpUnknownPDUHandlers, Report};
+ _ ->
+ {discarded, snmpUnknownPDUHandlers}
+ end
+ end;
+
+ "" ->
+ %% This is a discovery step 1 message!!
+ ?vtrace("v3_proc -> discovery step 1", []),
+ generate_discovery1_report_msg(MsgID,
+ MsgSecurityModel,
+ SecName,
+ SecLevel,
+ ContextEngineID,
+ ContextName,
+ SecData,
+ PDU,
+ Log);
+
+ _ ->
+ {discarded, {badSecurityEngineID, SecEngineID}}
+ end
+ end.
+
+
+get_security_module(?SEC_USM) ->
+ snmpa_usm;
+get_security_module(_) ->
+ inc(snmpUnknownSecurityModels),
+ throw({discarded, snmpUnknownSecurityModels}).
+
+check_sec_level([MsgFlag]) ->
+ SecLevel = MsgFlag band 3,
+ if
+ SecLevel == 2 ->
+ inc(snmpInvalidMsgs),
+ throw({discarded, snmpInvalidMsgs});
+ true ->
+ SecLevel
+ end;
+check_sec_level(Unknown) ->
+ ?vlog("invalid msgFlags: ~p",[Unknown]),
+ inc(snmpInvalidMsgs),
+ throw({discarded, snmpInvalidMsgs}).
+
+check_sec_module_result(Res, V3Hdr, Data, IsReportable, Log) ->
+ case Res of
+ {ok, X} ->
+ X;
+ {error, Reason, []} -> % case 7.2.6 b
+ ?vdebug("security module result [7.2.6-b]:"
+ "~n Reason: ~p", [Reason]),
+ throw({discarded, {securityError, Reason}});
+ {error, Reason, ErrorInfo} when IsReportable == true -> % case 7.2.6 a
+ ?vdebug("security module result when reportable [7.2.6-a]:"
+ "~n Reason: ~p"
+ "~n ErrorInfo: ~p", [Reason, ErrorInfo]),
+ #v3_hdr{msgID = MsgID, msgSecurityModel = MsgSecModel} = V3Hdr,
+ Pdu = get_scoped_pdu(Data),
+ case generate_v3_report_msg(MsgID, MsgSecModel, Pdu,
+ ErrorInfo, Log) of
+ {ok, Report} ->
+ throw({discarded, {securityError, Reason}, Report});
+ {discarded, _SomeOtherReason} ->
+ throw({discarded, {securityError, Reason}})
+ end;
+ {error, Reason, ErrorInfo} ->
+ ?vdebug("security module result when not reportable:"
+ "~n Reason: ~p"
+ "~n ErrorInfo: ~p", [Reason, ErrorInfo]),
+ throw({discarded, {securityError, Reason}});
+ Else ->
+ ?vdebug("security module result:"
+ "~n Else: ~p", [Else]),
+ throw({discarded, {securityError, Else}})
+ end.
+
+get_scoped_pdu(D) when is_list(D) ->
+ (catch snmp_pdus:dec_scoped_pdu(D));
+get_scoped_pdu(D) ->
+ D.
+
+
+%%-----------------------------------------------------------------
+%% Executed when a response or report message is generated.
+%%-----------------------------------------------------------------
+generate_response_msg(Vsn, RePdu, Type, ACMData, Log) ->
+ generate_response_msg(Vsn, RePdu, Type, ACMData, Log, 1).
+
+generate_response_msg(Vsn, RePdu, Type,
+ {community, _SecModel, Community, _IpUdp},
+ Log, _) ->
+ case catch snmp_pdus:enc_pdu(RePdu) of
+ {'EXIT', Reason} ->
+ user_err("failed encoding pdu: "
+ "(pdu: ~w, community: ~w): ~n~w",
+ [RePdu, Community, Reason]),
+ {discarded, Reason};
+ PduBytes ->
+ Message = #message{version = Vsn, vsn_hdr = Community,
+ data = PduBytes},
+ case catch list_to_binary(
+ snmp_pdus:enc_message_only(Message)) of
+ {'EXIT', Reason} ->
+ user_err("failed encoding message only "
+ "(pdu: ~w, community: ~w): ~n~w",
+ [RePdu, Community, Reason]),
+ {discarded, Reason};
+ Packet ->
+ MMS = snmp_framework_mib:get_engine_max_message_size(),
+ case size(Packet) of
+ Len when Len =< MMS ->
+ Log(Type, Packet),
+ inc_snmp_cnt_vars(Type, RePdu),
+ inc_snmp_out_vars(RePdu),
+ {ok, Packet};
+ Len ->
+ ?vlog("pdu to big:"
+ "~n Max message size: ~p"
+ "~n Encoded message size: ~p",
+ [MMS,Len]),
+ too_big(Vsn, RePdu, Community, Log, MMS, Len)
+ end
+ end
+ end;
+generate_response_msg(Vsn, RePdu, Type,
+ {v3, MsgID, MsgSecurityModel, SecName, SecLevel,
+ ContextEngineID, ContextName, SecData},
+ Log, N) ->
+ %% rfc2272: 7.1 steps 6-8
+ ScopedPDU = #scopedPdu{contextEngineID = ContextEngineID,
+ contextName = ContextName,
+ data = RePdu},
+ case catch snmp_pdus:enc_scoped_pdu(ScopedPDU) of
+ {'EXIT', Reason} ->
+ user_err("failed encoded scoped pdu "
+ "(pdu: ~w, contextName: ~w): ~n~w",
+ [RePdu, ContextName, Reason]),
+ {discarded, Reason};
+ ScopedPDUBytes ->
+ AgentMS = snmp_framework_mib:get_engine_max_message_size(),
+ V3Hdr = #v3_hdr{msgID = MsgID,
+ msgMaxSize = AgentMS,
+ msgFlags = snmp_misc:mk_msg_flags(Type, SecLevel),
+ msgSecurityModel = MsgSecurityModel},
+ Message = #message{version = Vsn,
+ vsn_hdr = V3Hdr,
+ data = ScopedPDUBytes},
+ %% We know that the security model is valid when we
+ %% generate a response.
+ SecModule =
+ case MsgSecurityModel of
+ ?SEC_USM ->
+ snmpa_usm
+ end,
+ SecEngineID = snmp_framework_mib:get_engine_id(),
+ ?vtrace("generate_response_msg -> SecEngineID: ~w", [SecEngineID]),
+ case (catch SecModule:generate_outgoing_msg(Message,
+ SecEngineID,
+ SecName,
+ SecData,
+ SecLevel)) of
+ {'EXIT', Reason} ->
+ config_err("~p (message: ~p)", [Reason, Message]),
+ {discarded, Reason};
+ {error, Reason} ->
+ config_err("~p (message: ~p)", [Reason, Message]),
+ {discarded, Reason};
+ OutMsg when is_list(OutMsg) ->
+ %% Check the packet size. Send the msg even
+ %% if it's larger than the mgr can handle - it
+ %% will be dropped. Just check against the
+ %% internal size. For GET-BULk responses: we
+ %% *know* that we're within the right limits,
+ %% because of the calculation we do when we
+ %% receive the bulk-request.
+ Packet = list_to_binary(OutMsg),
+ case size(Packet) of
+ Len when Len =< AgentMS ->
+ if
+ SecLevel =:= 3 ->
+ %% encrypted - log decrypted pdu
+ Log(Type, {V3Hdr, ScopedPDUBytes});
+ true ->
+ %% otherwise log the entire msg
+ Log(Type, Packet)
+ end,
+ inc_snmp_cnt_vars(Type, RePdu),
+ inc_snmp_out_vars(RePdu),
+ {ok, Packet};
+ Len when N =:= 2 ->
+ ?vlog("packet max size exceeded: "
+ "~n Max: ~p"
+ "~n Len: ~p",
+ [AgentMS,Len]),
+ inc(snmpSilentDrops),
+ {discarded, tooBig};
+ Len ->
+ ?vlog("packet max size exceeded: "
+ "~n N: ~p"
+ "~n Max: ~p"
+ "~n Len: ~p",
+ [N, AgentMS, Len]),
+ TooBigPdu = RePdu#pdu{error_status = tooBig,
+ error_index = 0,
+ varbinds = []},
+ generate_response_msg(Vsn, TooBigPdu, Type,
+ {v3, MsgID,
+ MsgSecurityModel,
+ SecName, SecLevel,
+ ContextEngineID,
+ ContextName,
+ SecData}, Log, N+1)
+ end
+ end
+ end.
+
+generate_v3_report_msg(MsgID, MsgSecurityModel, Data, ErrorInfo, Log) ->
+ {Varbind, SecName, Opts} = ErrorInfo,
+ ReqId =
+ if
+ is_record(Data, scopedPdu) ->
+ (Data#scopedPdu.data)#pdu.request_id;
+ true ->
+ 0 %% RFC2572, 7.1.3.c.4
+ end,
+ ?vtrace("Report ReqId: ~p",[ReqId]),
+ 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, ""),
+ SecData = snmp_misc:get_option(sec_data, Opts, []),
+
+ generate_response_msg('version-3', Pdu, report,
+ {v3, MsgID, MsgSecurityModel, SecName, SecLevel,
+ ContextEngineID, ContextName, SecData}, Log).
+
+%% req_id(#scopedPdu{data = #pdu{request_id = ReqId}}) ->
+%% ?vtrace("Report ReqId: ~p",[ReqId]),
+%% ReqId;
+%% req_id(_) ->
+%% 0. % RFC2572, 7.1.3.c.4
+
+
+%% maybe_generate_discovery1_report_msg() ->
+%% case (catch DiscoveryHandler:handle_discovery1(Ip, Udp, EngineId)) of
+%% {ok, Entry} when is_record(Entry, snmp_discovery_data1) ->
+%% ok;
+%% ignore ->
+%% ok;
+%% {error, Reason} ->
+
+%% Response to stage 1 discovery message (terminating, i.e. from the manager)
+generate_discovery1_report_msg(MsgID, MsgSecurityModel,
+ SecName, SecLevel,
+ ContextEngineID, ContextName,
+ {SecData, Oid, Value},
+ #pdu{request_id = ReqId}, Log) ->
+ ?vtrace("generate_discovery1_report_msg -> entry with"
+ "~n ReqId: ~p"
+ "~n Value: ~p", [ReqId, Value]),
+ Varbind = #varbind{oid = Oid,
+ variabletype = 'Counter32',
+ value = Value,
+ org_index = 1},
+ PduOut = #pdu{type = report,
+ request_id = ReqId,
+ error_status = noError,
+ error_index = 0,
+ varbinds = [Varbind]},
+ case generate_response_msg('version-3', PduOut, report,
+ {v3, MsgID, MsgSecurityModel, SecName, SecLevel,
+ ContextEngineID, ContextName, SecData}, Log) of
+ {ok, Packet} ->
+ {discovery, Packet};
+ Error ->
+ Error
+ end.
+
+%% Response to stage 2 discovery message (terminating, i.e. from the manager)
+generate_discovery2_report_msg(MsgID, MsgSecurityModel,
+ SecName, SecLevel,
+ ContextEngineID, ContextName,
+ SecData, #pdu{request_id = ReqId}, Log) ->
+ ?vtrace("generate_discovery2_report_msg -> entry with"
+ "~n ReqId: ~p", [ReqId]),
+ SecModule = get_security_module(MsgSecurityModel),
+ Vb = SecModule:current_statsNotInTimeWindows_vb(),
+ PduOut = #pdu{type = report,
+ request_id = ReqId,
+ error_status = noError,
+ error_index = 0,
+ varbinds = [Vb]},
+ case generate_response_msg('version-3', PduOut, report,
+ {v3, MsgID, MsgSecurityModel, SecName, SecLevel,
+ ContextEngineID, ContextName, SecData}, Log) of
+ {ok, Packet} ->
+ {discovery, Packet};
+ Error ->
+ Error
+ end.
+
+
+too_big(Vsn, Pdu, Community, Log, _MMS, _Len)
+ when Pdu#pdu.type =:= 'get-response' ->
+ ErrPdu =
+ if
+ Vsn =:= 'version-1' ->
+ %% In v1, the varbinds should be identical to the incoming
+ %% request. It isn't identical now!
+ %% Make acceptable (?) approximation.
+ V = set_vb_null(Pdu#pdu.varbinds),
+ Pdu#pdu{error_status = tooBig, error_index = 0, varbinds = V};
+ true ->
+ %% In v2, varbinds should be empty (reasonable!)
+ Pdu#pdu{error_status = tooBig, error_index = 0, varbinds = []}
+ end,
+
+ case catch snmp_pdus:enc_pdu(ErrPdu) of
+ {'EXIT', Reason} ->
+ user_err("failed encoding pdu (pdu: ~w, community: ~w): ~n~w",
+ [ErrPdu, Community, Reason]),
+ {discarded, Reason};
+ PduBytes ->
+ Message = #message{version = Vsn, vsn_hdr = Community,
+ data = PduBytes},
+ case catch snmp_pdus:enc_message_only(Message) of
+ {'EXIT', Reason} ->
+ user_err("failed encoding message only"
+ "(pdu: ~w, community: ~w): ~n~w",
+ [ErrPdu, Community, Reason]),
+ {discarded, Reason};
+ Packet ->
+ Bin = list_to_binary(Packet),
+ Log(Pdu#pdu.type, Bin),
+ inc_snmp_out_vars(ErrPdu),
+ {ok, Bin}
+ end
+ end;
+too_big(_Vsn, Pdu, _Community, _Log, MMS, Len) ->
+ user_err("encoded pdu, ~p bytes, exceeded "
+ "max message size of ~p bytes. Pdu: ~n~w",
+ [Len, MMS, Pdu]),
+ {discarded, tooBig}.
+
+set_vb_null([Vb | Vbs]) ->
+ [Vb#varbind{variabletype = 'NULL', value = 'NULL'} | set_vb_null(Vbs)];
+set_vb_null([]) ->
+ [].
+
+%%-----------------------------------------------------------------
+%% Executed when a message that isn't a response is generated, i.e.
+%% a trap or an inform.
+%%-----------------------------------------------------------------
+generate_msg(Vsn, _NoteStore, Pdu, {community, Community}, To) ->
+ Message = #message{version = Vsn, vsn_hdr = Community, data = Pdu},
+ case catch list_to_binary(snmp_pdus:enc_message(Message)) of
+ {'EXIT', Reason} ->
+ user_err("failed encoding message "
+ "(pdu: ~w, community: ~w): ~n~w",
+ [Pdu, Community, Reason]),
+ {discarded, Reason};
+ Packet ->
+ AgentMax = snmp_framework_mib:get_engine_max_message_size(),
+ case size(Packet) of
+ Len when Len =< AgentMax ->
+ {ok, mk_v1_v2_packet_list(To, Packet, Len, Pdu)};
+ Len ->
+ ?vlog("packet max size exceeded: "
+ "~n Max: ~p"
+ "~n Len: ~p",
+ [AgentMax, Len]),
+ {discarded, tooBig}
+ end
+ end;
+generate_msg('version-3', NoteStore, Pdu,
+ {v3, ContextEngineID, ContextName}, To) ->
+ %% rfc2272: 7.1.6
+ ScopedPDU = #scopedPdu{contextEngineID = ContextEngineID,
+ contextName = ContextName,
+ data = Pdu},
+ case (catch snmp_pdus:enc_scoped_pdu(ScopedPDU)) of
+ {'EXIT', Reason} ->
+ user_err("failed encoding scoped pdu "
+ "(pdu: ~w, contextName: ~w): ~n~w",
+ [Pdu, ContextName, Reason]),
+ {discarded, Reason};
+ ScopedPDUBytes ->
+ {ok, mk_v3_packet_list(NoteStore, To, ScopedPDUBytes, Pdu,
+ ContextEngineID, ContextName)}
+ end.
+
+
+generate_discovery_msg(NoteStore, Pdu, MsgData, To) ->
+ Timeout = 1500,
+ generate_discovery_msg(NoteStore, Pdu, MsgData, Timeout, To).
+
+generate_discovery_msg(NoteStore, Pdu, MsgData, Timeout, To) ->
+ {SecData, ContextEngineID, ContextName} = MsgData,
+ {SecModel, SecName, SecLevelFlag, TargetName} = SecData,
+ {ManagerEngineId, InitialUserName} =
+ case get_target_engine_id(TargetName) of
+ {ok, discovery} ->
+ {"", ""}; % Discovery stage 1
+ {ok, {discovery, IUN}} ->
+ {"", IUN}; % Discovery stage 1
+ {ok, TargetEngineId} ->
+ {TargetEngineId, ""} % Discovery stage 2
+ end,
+ generate_discovery_msg(NoteStore, Pdu,
+ ContextEngineID, ContextName,
+ SecModel, SecName, SecLevelFlag,
+ ManagerEngineId,
+ InitialUserName,
+ Timeout, To).
+
+generate_discovery_msg(NoteStore, Pdu,
+ ContextEngineID, ContextName,
+ SecModel, _SecName, _SecLevelFlag,
+ "" = ManagerEngineID,
+ InitialUserName,
+ Timeout, To) ->
+ %% Discovery step 1 uses SecLevel = noAuthNoPriv
+ SecName = "",
+ SecLevelFlag = 0, % ?'SnmpSecurityLevel_noAuthNoPriv',
+ generate_discovery_msg2(NoteStore, Pdu,
+ ContextEngineID, ManagerEngineID,
+ SecModel, SecName, SecLevelFlag,
+ InitialUserName,
+ ContextName, Timeout, To);
+generate_discovery_msg(NoteStore, Pdu,
+ ContextEngineID, ContextName,
+ SecModel, SecName, SecLevelFlag,
+ ManagerEngineID,
+ InitialUserName,
+ Timeout, To) ->
+ %% SecLevelFlag = 1, % ?'SnmpSecurityLevel_authNoPriv',
+ generate_discovery_msg2(NoteStore, Pdu,
+ ContextEngineID, ManagerEngineID,
+ SecModel, SecName, SecLevelFlag,
+ InitialUserName,
+ ContextName, Timeout, To).
+
+generate_discovery_msg2(NoteStore, Pdu,
+ ContextEngineID, ManagerEngineID,
+ SecModel, SecName, SecLevelFlag,
+ InitialUserName,
+ ContextName, Timeout, To) ->
+ %% rfc2272: 7.1.6
+ ScopedPDU = #scopedPdu{contextEngineID = ContextEngineID,
+ contextName = ContextName,
+ data = Pdu},
+ case (catch snmp_pdus:enc_scoped_pdu(ScopedPDU)) of
+ {'EXIT', Reason} ->
+ user_err("failed encoding scoped pdu "
+ "(pdu: ~w, contextName: ~w): ~n~w",
+ [Pdu, ContextName, Reason]),
+ {discarded, Reason};
+ ScopedPDUBytes ->
+ {ok, generate_discovery_msg(NoteStore, To,
+ Pdu, ScopedPDUBytes,
+ ContextEngineID, ManagerEngineID,
+ SecModel, SecName, SecLevelFlag,
+ InitialUserName,
+ ContextName, Timeout)}
+ end.
+
+%% Timeout is in msec but note timeout is in 1/10 seconds
+discovery_note_timeout(Timeout) ->
+ (Timeout div 100) + 1.
+
+generate_discovery_msg(NoteStore, {?snmpUDPDomain, [A,B,C,D,U1,U2]},
+ Pdu, ScopedPduBytes,
+ ContextEngineID, ManagerEngineID,
+ SecModel, SecName, SecLevelFlag,
+ InitialUserName,
+ ContextName, Timeout) ->
+ %% 7.1.7
+ ?vdebug("generate_discovery_msg -> 7.1.7 (~w)", [ManagerEngineID]),
+ MsgID = generate_msg_id(),
+ PduType = Pdu#pdu.type,
+ MsgFlags = mk_msg_flags(PduType, SecLevelFlag),
+ V3Hdr = #v3_hdr{msgID = MsgID,
+ msgMaxSize = get_max_message_size(),
+ msgFlags = MsgFlags,
+ msgSecurityModel = SecModel},
+ Message = #message{version = 'version-3',
+ vsn_hdr = V3Hdr,
+ data = ScopedPduBytes},
+ SecModule = sec_module(SecModel),
+
+ %% 7.1.9b
+ ?vdebug("generate_discovery_msg -> 7.1.9b", []),
+ case generate_sec_discovery_msg(Message, SecModule,
+ ManagerEngineID,
+ SecName, SecLevelFlag,
+ InitialUserName) of
+ {ok, Packet} ->
+ %% 7.1.9c
+ %% Store in cache for Timeout msec.
+ NoteTimeout = discovery_note_timeout(Timeout),
+ ?vdebug("generate_discovery_msg -> 7.1.9c [~w]", [NoteTimeout]),
+ %% The request id is just in case when we receive a
+ %% report with incorrect securityModel and/or securityLevel
+ Key = {agent, MsgID},
+ Note = #note{sec_engine_id = ManagerEngineID,
+ sec_model = SecModel,
+ sec_name = SecName,
+ sec_level = SecLevelFlag,
+ ctx_engine_id = ContextEngineID,
+ ctx_name = ContextName,
+ disco = true,
+ req_id = Pdu#pdu.request_id},
+ snmp_note_store:set_note(NoteStore, Timeout, Key, Note),
+ %% Log(Packet),
+ inc_snmp_out_vars(Pdu),
+ ?vdebug("generate_discovery_msg -> done", []),
+ {Packet, {{A,B,C,D}, U1 bsl 8 + U2}};
+
+ Error ->
+ throw(Error)
+ end.
+
+generate_sec_discovery_msg(Message, SecModule,
+ SecEngineID, SecName, SecLevelFlag,
+ InitialUserName) ->
+ case (catch SecModule:generate_discovery_msg(Message, SecEngineID,
+ SecName, SecLevelFlag,
+ InitialUserName)) of
+ {'EXIT', Reason} ->
+ config_err("~p (message: ~p)", [Reason, Message]),
+ {discarded, Reason};
+ {error, Reason} ->
+ config_err("~p (message: ~p)", [Reason, Message]),
+ {discarded, Reason};
+ Bin when is_binary(Bin) ->
+ {ok, Bin};
+ OutMsg when is_list(OutMsg) ->
+ case (catch list_to_binary(OutMsg)) of
+ Bin when is_binary(Bin) ->
+ {ok, Bin};
+ {'EXIT', Reason} ->
+ {error, Reason}
+ end
+ end.
+
+
+process_taddrs(Dests) ->
+ ?vtrace("process_taddrs -> entry with"
+ "~n Dests: ~p", [Dests]),
+ process_taddrs(Dests, []).
+
+process_taddrs([], Acc) ->
+ ?vtrace("process_taddrs -> entry when done with"
+ "~n Acc: ~p", [Acc]),
+ lists:reverse(Acc);
+
+%% v3
+process_taddrs([{{?snmpUDPDomain, [A,B,C,D,U1,U2]}, SecData} | T], Acc) ->
+ ?vtrace("process_taddrs -> entry when v3 with"
+ "~n A: ~p"
+ "~n B: ~p"
+ "~n C: ~p"
+ "~n D: ~p"
+ "~n U1: ~p"
+ "~n U2: ~p"
+ "~n SecData: ~p", [A, B, C, D, U1, U2, SecData]),
+ Entry = {{snmpUDPDomain, {{A,B,C,D}, U1 bsl 8 + U2}}, SecData},
+ process_taddrs(T, [Entry | Acc]);
+%% Bad v3
+process_taddrs([{{TDomain, TAddr}, _SecData} | T], Acc) ->
+ ?vtrace("process_taddrs -> entry when bad v3 with"
+ "~n TDomain: ~p"
+ "~n TAddr: ~p", [TDomain, TAddr]),
+ user_err("Bad TDomain/TAddr: ~w/~w", [TDomain, TAddr]),
+ process_taddrs(T, Acc);
+%% v1 & v2
+process_taddrs([{?snmpUDPDomain, [A,B,C,D,U1,U2]} | T], Acc) ->
+ ?vtrace("process_taddrs -> entry when v1/v2 with"
+ "~n A: ~p"
+ "~n B: ~p"
+ "~n C: ~p"
+ "~n D: ~p"
+ "~n U1: ~p"
+ "~n U2: ~p", [A, B, C, D, U1, U2]),
+ Entry = {snmpUDPDomain, {{A,B,C,D}, U1 bsl 8 + U2}},
+ process_taddrs(T, [Entry | Acc]);
+%% Bad v1 or v2
+process_taddrs([{TDomain, TAddr} | T], Acc) ->
+ ?vtrace("process_taddrs -> entry when bad v1/v2 with"
+ "~n TDomain: ~p"
+ "~n TAddr: ~p", [TDomain, TAddr]),
+ user_err("Bad TDomain/TAddr: ~w/~w", [TDomain, TAddr]),
+ process_taddrs(T, Acc);
+process_taddrs(Crap, Acc) ->
+ throw({error, {taddrs_crap, Crap, Acc}}).
+
+
+mk_v1_v2_packet_list(To, Packet, Len, Pdu) ->
+ mk_v1_v2_packet_list(To, Packet, Len, Pdu, []).
+
+mk_v1_v2_packet_list([], _Packet, _Len, _Pdu, Acc) ->
+ lists:reverse(Acc);
+
+%% This (old) clause is for backward compatibillity reasons
+%% If this is called, then the filter function is not used
+mk_v1_v2_packet_list([{?snmpUDPDomain, [A,B,C,D,U1,U2]} | T],
+ Packet, Len, Pdu, Acc) ->
+ %% Sending from default UDP port
+ inc_snmp_out_vars(Pdu),
+ Entry = {snmpUDPDomain, {{A,B,C,D}, U1 bsl 8 + U2}, Packet},
+ mk_v1_v2_packet_list(T, Packet, Len, Pdu, [Entry | Acc]);
+
+%% This is the new clause
+%% This is only called if the actual target was accepted
+%% (by the filter module)
+mk_v1_v2_packet_list([{Domain, Addr} | T],
+ Packet, Len, Pdu, Acc) ->
+ %% Sending from default UDP port
+ inc_snmp_out_vars(Pdu),
+ Entry = {Domain, Addr, Packet},
+ mk_v1_v2_packet_list(T, Packet, Len, Pdu, [Entry | Acc]).
+
+
+get_max_message_size() ->
+ snmp_framework_mib:get_engine_max_message_size().
+
+mk_msg_flags(PduType, SecLevel) ->
+ snmp_misc:mk_msg_flags(PduType, SecLevel).
+
+mk_v3_packet_entry(NoteStore, Domain, Addr,
+ {SecModel, SecName, SecLevel, TargetAddrName},
+ ScopedPDUBytes, Pdu, ContextEngineID, ContextName) ->
+ %% 7.1.7
+ ?vtrace("mk_v3_packet_entry -> entry - 7.1.7", []),
+ MsgID = generate_msg_id(),
+ PduType = Pdu#pdu.type,
+ MsgFlags = mk_msg_flags(PduType, SecLevel),
+ V3Hdr = #v3_hdr{msgID = MsgID,
+ msgMaxSize = get_max_message_size(),
+ msgFlags = MsgFlags,
+ msgSecurityModel = SecModel},
+ Message = #message{version = 'version-3',
+ vsn_hdr = V3Hdr,
+ data = ScopedPDUBytes},
+ SecModule =
+ case SecModel of
+ ?SEC_USM ->
+ snmpa_usm
+ end,
+
+ %% 7.1.9a
+ ?vtrace("mk_v3_packet_entry -> sec engine id - 7.1.9a", []),
+ SecEngineID =
+ case PduType of
+ 'snmpv2-trap' ->
+ snmp_framework_mib:get_engine_id();
+ _ ->
+ %% This is the implementation dependent target engine id
+ %% procedure.
+ case get_target_engine_id(TargetAddrName) of
+ {ok, discovery} ->
+ config_err("Discovery has not yet been performed for "
+ "snmpTargetAddrName ~p~n",
+ [TargetAddrName]),
+ throw({discarded, {discovery, TargetAddrName}});
+ {ok, TargetEngineId} ->
+ ?vtrace("TargetEngineId: ~p", [TargetEngineId]),
+ TargetEngineId;
+ undefined ->
+ config_err("Can't find engineID for "
+ "snmpTargetAddrName ~p~n",
+ [TargetAddrName]),
+ "" % this will trigger error in secmodule
+ end
+ end,
+
+ ?vdebug("mk_v3_packet_entry -> secEngineID: ~p", [SecEngineID]),
+ %% 7.1.9b
+ case catch SecModule:generate_outgoing_msg(Message, SecEngineID,
+ SecName, [], SecLevel) of
+ {'EXIT', Reason} ->
+ config_err("~p (message: ~p)", [Reason, Message]),
+ skip;
+ {error, Reason} ->
+ ?vlog("~n ~w error ~p\n", [SecModule, Reason]),
+ skip;
+ OutMsg when is_list(OutMsg) ->
+ %% 7.1.9c
+ %% Store in cache for 150 sec.
+ Packet = list_to_binary(OutMsg),
+ ?vdebug("mk_v3_packet_entry -> generated: ~w bytes",
+ [size(Packet)]),
+ Data =
+ if
+ SecLevel =:= 3 ->
+ %% encrypted - log decrypted pdu
+ {Packet, {V3Hdr, ScopedPDUBytes}};
+ true ->
+ %% otherwise log the entire msg
+ Packet
+ end,
+ CacheKey = {agent, MsgID},
+ CacheVal = #note{sec_engine_id = SecEngineID,
+ sec_model = SecModel,
+ sec_name = SecName,
+ sec_level = SecLevel,
+ ctx_engine_id = ContextEngineID,
+ ctx_name = ContextName,
+ disco = false,
+ req_id = Pdu#pdu.request_id},
+ snmp_note_store:set_note(NoteStore, 1500, CacheKey, CacheVal),
+ inc_snmp_out_vars(Pdu),
+ {ok, {Domain, Addr, Data}}
+ end.
+
+
+mk_v3_packet_list(NoteStore, To,
+ ScopedPDUBytes, Pdu, ContextEngineID, ContextName) ->
+ mk_v3_packet_list(NoteStore, To,
+ ScopedPDUBytes, Pdu,
+ ContextEngineID, ContextName, []).
+
+mk_v3_packet_list(_, [],
+ _ScopedPDUBytes, _Pdu,
+ _ContextEngineID, _ContextName,
+ Acc) ->
+ lists:reverse(Acc);
+
+%% This clause is for backward compatibillity reasons
+%% If this is called the filter function is not used
+mk_v3_packet_list(NoteStore,
+ [{{?snmpUDPDomain, [A,B,C,D,U1,U2]}, SecData} | T],
+ ScopedPDUBytes, Pdu, ContextEngineID, ContextName,
+ Acc) ->
+ case mk_v3_packet_entry(NoteStore,
+ snmpUDPDomain, {{A,B,C,D}, U1 bsl 8 + U2}, SecData,
+ ScopedPDUBytes, Pdu,
+ ContextEngineID, ContextName) of
+ skip ->
+ mk_v3_packet_list(NoteStore, T,
+ ScopedPDUBytes, Pdu,
+ ContextEngineID, ContextName,
+ Acc);
+ {ok, Entry} ->
+ mk_v3_packet_list(NoteStore, T,
+ ScopedPDUBytes, Pdu,
+ ContextEngineID, ContextName, [Entry | Acc])
+ end;
+
+%% This is the new clause
+%% This is only called if the actual target was accepted
+%% (by the filter module)
+mk_v3_packet_list(NoteStore,
+ [{{Domain, Addr}, SecData} | T],
+ ScopedPDUBytes, Pdu, ContextEngineID, ContextName,
+ Acc) ->
+ case mk_v3_packet_entry(NoteStore,
+ Domain, Addr, SecData,
+ ScopedPDUBytes, Pdu,
+ ContextEngineID, ContextName) of
+ skip ->
+ mk_v3_packet_list(NoteStore, T,
+ ScopedPDUBytes, Pdu,
+ ContextEngineID, ContextName, Acc);
+ {ok, Entry} ->
+ mk_v3_packet_list(NoteStore, T,
+ ScopedPDUBytes, Pdu,
+ ContextEngineID, ContextName, [Entry | Acc])
+ end.
+
+
+generate_msg_id() ->
+ gen(msg_id).
+
+generate_req_id() ->
+ gen(req_id).
+
+gen(Id) ->
+ case ets:update_counter(snmp_agent_table, Id, 1) of
+ N when N =< 2147483647 ->
+ N;
+ _N ->
+ ets:insert(snmp_agent_table, {Id, 0}),
+ 0
+ end.
+
+
+get_target_engine_id(TargetAddrName) ->
+ snmp_target_mib:get_target_engine_id(TargetAddrName).
+
+sec_module(?SEC_USM) ->
+ snmpa_usm.
+
+
+%%-----------------------------------------------------------------
+%% Version(s) functions
+%%-----------------------------------------------------------------
+init_versions([], S) ->
+ S;
+init_versions([v1|Vsns], S) ->
+ init_versions(Vsns, S#state{v1 = true});
+init_versions([v2|Vsns], S) ->
+ init_versions(Vsns, S#state{v2c = true});
+init_versions([v3|Vsns], S) ->
+ init_versions(Vsns, S#state{v3 = true}).
+
+
+%%-----------------------------------------------------------------
+%% Counter functions
+%%-----------------------------------------------------------------
+init_counters() ->
+ F = fun(Counter) -> maybe_create_counter(Counter) end,
+ lists:map(F, counters()).
+
+reset_counters() ->
+ F = fun(Counter) -> init_counter(Counter) end,
+ lists:map(F, counters()).
+
+maybe_create_counter(Counter) ->
+ case ets:lookup(snmp_agent_table, Counter) of
+ [_] -> ok;
+ _ -> init_counter(Counter)
+ end.
+
+init_counter(Counter) ->
+ ets:insert(snmp_agent_table, {Counter, 0}).
+
+counters() ->
+ [
+ snmpInPkts,
+ snmpOutPkts,
+ snmpInBadVersions,
+ snmpInBadCommunityNames,
+ snmpInBadCommunityUses,
+ snmpInASNParseErrs,
+ snmpInTooBigs,
+ snmpInNoSuchNames,
+ snmpInBadValues,
+ snmpInReadOnlys,
+ snmpInGenErrs,
+ snmpInTotalReqVars,
+ snmpInTotalSetVars,
+ snmpInGetRequests,
+ snmpInGetNexts,
+ snmpInSetRequests,
+ snmpInGetResponses,
+ snmpInTraps,
+ snmpOutTooBigs,
+ snmpOutNoSuchNames,
+ snmpOutBadValues,
+ snmpOutGenErrs,
+ snmpOutGetRequests,
+ snmpOutGetNexts,
+ snmpOutSetRequests,
+ snmpOutGetResponses,
+ snmpOutTraps,
+ snmpSilentDrops,
+ snmpProxyDrops,
+ %% From SNMP-MPD-MIB
+ snmpUnknownSecurityModels,
+ snmpInvalidMsgs,
+ snmpUnknownPDUHandlers
+ ].
+
+
+
+%%-----------------------------------------------------------------
+%% inc(VariableName) increments the variable (Counter) in
+%% the local mib. (e.g. snmpInPkts)
+%%-----------------------------------------------------------------
+inc(Name) -> ets:update_counter(snmp_agent_table, Name, 1).
+inc(Name, N) -> ets:update_counter(snmp_agent_table, Name, N).
+
+inc_snmp_in_vars(#pdu{type = Type}) ->
+ inc_in_type(Type).
+
+inc_snmp_cnt_vars(_, #pdu{error_status = ErrStat}) when ErrStat =/= noError ->
+ ok;
+inc_snmp_cnt_vars('get-request', #pdu{varbinds = Vbs}) ->
+ inc(snmpInTotalReqVars, length(Vbs));
+inc_snmp_cnt_vars('get-next-request', #pdu{varbinds = Vbs}) ->
+ inc(snmpInTotalReqVars, length(Vbs));
+inc_snmp_cnt_vars('set-request', #pdu{varbinds = Vbs}) ->
+ inc(snmpInTotalSetVars, length(Vbs));
+inc_snmp_cnt_vars(_, _) ->
+ ok.
+
+inc_snmp_out_vars(#pdu{type = Type,
+ error_status = ErrorStatus}) ->
+ inc(snmpOutPkts),
+ inc_out_err(ErrorStatus),
+ inc_out_vars_2(Type);
+inc_snmp_out_vars(TrapPdu) when is_record(TrapPdu, trappdu) ->
+ inc(snmpOutPkts),
+ inc(snmpOutTraps).
+
+inc_out_vars_2('get-response') -> inc(snmpOutGetResponses);
+inc_out_vars_2('get-request') -> inc(snmpOutGetRequests);
+inc_out_vars_2('get-next-request') -> inc(snmpOutGetNexts);
+inc_out_vars_2('set-request') -> inc(snmpOutSetRequests);
+inc_out_vars_2(_) -> ok.
+
+inc_out_err(genErr) -> inc(snmpOutGenErrs);
+inc_out_err(tooBig) -> inc(snmpOutTooBigs);
+inc_out_err(noSuchName) -> inc(snmpOutNoSuchNames);
+inc_out_err(badValue) -> inc(snmpOutBadValues);
+% snmpOutReadOnlys is not used any more (rfc1213)
+%inc_out_err(readOnly) -> inc(snmpOutReadOnlys);
+inc_out_err(_) -> ok.
+
+inc_in_type('get-request') -> inc(snmpInGetRequests);
+inc_in_type('get-next-request') -> inc(snmpInGetNexts);
+inc_in_type('set-request') -> inc(snmpInSetRequests);
+inc_in_type(_) -> ok.
+
+
+user_err(F, A) ->
+ snmpa_error:user_err(F, A).
+
+config_err(F, A) ->
+ snmpa_error:config_err(F, A).
diff --git a/lib/snmp/src/agent/snmpa_net_if.erl b/lib/snmp/src/agent/snmpa_net_if.erl
new file mode 100644
index 0000000000..d703e5ac55
--- /dev/null
+++ b/lib/snmp/src/agent/snmpa_net_if.erl
@@ -0,0 +1,1249 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2004-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%
+%%
+-module(snmpa_net_if).
+
+-behaviour(snmpa_network_interface).
+
+-export([start_link/4,
+ info/1,
+ verbosity/2]).
+-export([get_log_type/1, set_log_type/2]).
+-export([get_request_limit/1, set_request_limit/2]).
+-export([system_continue/3, system_terminate/4, system_code_change/4]).
+-export([init/5]).
+-export([filter_reset/1]).
+
+-include("snmp_types.hrl").
+-include("snmpa_internal.hrl").
+-include("snmpa_atl.hrl").
+-include("snmp_debug.hrl").
+-include("snmp_verbosity.hrl").
+
+-record(state, {parent,
+ note_store,
+ master_agent,
+ usock,
+ usock_opts,
+ mpd_state,
+ log,
+ reqs = [],
+ debug = false,
+ limit = infinity,
+ rcnt = [],
+ filter}).
+
+-ifndef(default_verbosity).
+-define(default_verbosity,silence).
+-endif.
+
+-define(DEFAULT_FILTER_MODULE, snmpa_net_if_filter).
+-define(DEFAULT_FILTER_OPTS, [{module, ?DEFAULT_FILTER_MODULE}]).
+
+
+%%%-----------------------------------------------------------------
+%%% This module implements the default Network Interface part
+%%% of the SNMP agent. It uses UDP, and read the agent.conf to find
+%%% the UDP port.
+%%%
+%%% Opts = [Opt]
+%%% Opt = {verbosity,silence | log | debug} |
+%%% {bind_to, bool()} |
+%%% {recbuf,integer()} |
+%%% {no_reuse, bool()} |
+%%% {req_limit, integer() | infinity}
+%%%-----------------------------------------------------------------
+start_link(Prio, NoteStore, MasterAgent, Opts) ->
+ ?d("start_link -> entry with"
+ "~n Prio: ~p"
+ "~n NoteStore: ~p"
+ "~n MasterAgent: ~p"
+ "~n Opts: ~p", [Prio, NoteStore, MasterAgent, Opts]),
+ Args = [Prio, NoteStore, MasterAgent, self(), Opts],
+ proc_lib:start_link(?MODULE, init, Args).
+
+
+info(Pid) ->
+ case call(Pid, info) of
+ Info when is_list(Info) ->
+ Info;
+ _ ->
+ []
+ end.
+
+verbosity(Pid, Verbosity) ->
+ Pid ! {verbosity, Verbosity}.
+
+get_log_type(Pid) ->
+ call(Pid, get_log_type).
+
+set_log_type(Pid, NewType) ->
+ call(Pid, {set_log_type, NewType}).
+
+get_request_limit(Pid) ->
+ call(Pid, get_request_limit).
+
+set_request_limit(Pid, NewLimit) ->
+ call(Pid, {set_request_limit, NewLimit}).
+
+get_port() ->
+ {value, UDPPort} = snmp_framework_mib:intAgentUDPPort(get),
+ UDPPort.
+
+get_address() ->
+ {value, IPAddress} = snmp_framework_mib:intAgentIpAddress(get),
+ IPAddress.
+
+filter_reset(Pid) ->
+ Pid ! filter_reset.
+
+
+%%-----------------------------------------------------------------
+%%-----------------------------------------------------------------
+
+init(Prio, NoteStore, MasterAgent, Parent, Opts) ->
+ ?d("init -> entry with"
+ "~n Prio: ~p"
+ "~n NoteStore: ~p"
+ "~n MasterAgent: ~p"
+ "~n Parent: ~p"
+ "~n Opts: ~p", [Prio, NoteStore, MasterAgent, Parent, Opts]),
+ case (catch do_init(Prio, NoteStore, MasterAgent, Parent, Opts)) of
+ {ok, State} ->
+ proc_lib:init_ack({ok, self()}),
+ loop(State);
+ {error, Reason} ->
+ config_err("failed starting net-if: ~n~p", [Reason]),
+ proc_lib:init_ack({error, Reason});
+ Error ->
+ config_err("failed starting net-if: ~n~p", [Error]),
+ proc_lib:init_ack({error, Error})
+ end.
+
+do_init(Prio, NoteStore, MasterAgent, Parent, Opts) ->
+ process_flag(trap_exit, true),
+ process_flag(priority, Prio),
+
+ %% -- Verbosity --
+ put(sname,nif),
+ put(verbosity,get_verbosity(Opts)),
+ ?vlog("starting",[]),
+
+ %% -- Port and address --
+ UDPPort = get_port(),
+ ?vdebug("port: ~w",[UDPPort]),
+ IPAddress = get_address(),
+ ?vdebug("addr: ~w",[IPAddress]),
+
+ %% -- Versions --
+ Vsns = get_vsns(Opts),
+ ?vdebug("vsns: ~w",[Vsns]),
+
+ %% Flow control --
+ Limit = get_req_limit(Opts),
+ ?vdebug("Limit: ~w", [Limit]),
+ FilterOpts = get_filter_opts(Opts),
+ FilterMod = create_filter(FilterOpts),
+ ?vdebug("FilterMod: ~w", [FilterMod]),
+
+ %% -- Audit trail log
+ Log = create_log(),
+ ?vdebug("Log: ~w",[Log]),
+
+
+ %% -- Socket --
+ IPOpts1 = ip_opt_bind_to_ip_address(Opts, IPAddress),
+ IPOpts2 = ip_opt_no_reuse_address(Opts),
+ IPOpts3 = ip_opt_recbuf(Opts),
+ IPOpts4 = ip_opt_sndbuf(Opts),
+ IPOpts = [binary | IPOpts1 ++ IPOpts2 ++ IPOpts3 ++ IPOpts4],
+ ?vdebug("open socket with options: ~w",[IPOpts]),
+ case gen_udp_open(UDPPort, IPOpts) of
+ {ok, Sock} ->
+ MpdState = snmpa_mpd:init(Vsns),
+ init_counters(),
+ active_once(Sock),
+ S = #state{parent = Parent,
+ note_store = NoteStore,
+ master_agent = MasterAgent,
+ mpd_state = MpdState,
+ usock = Sock,
+ usock_opts = IPOpts,
+ log = Log,
+ limit = Limit,
+ filter = FilterMod},
+ ?vdebug("started with MpdState: ~p", [MpdState]),
+ {ok, S};
+ {error, Reason} ->
+ ?vinfo("Failed to open UDP socket: ~p", [Reason]),
+ {error, {udp_open, UDPPort, Reason}}
+ end.
+
+create_log() ->
+ case ets:lookup(snmp_agent_table, audit_trail_log) of
+ [] ->
+ {undefined, []};
+ [{audit_trail_log, AtlOpts}] ->
+ ?vtrace("AtlOpts: ~p",[AtlOpts]),
+ Type = get_atl_type(AtlOpts),
+ Dir = get_atl_dir(AtlOpts),
+ Size = get_atl_size(AtlOpts),
+ Repair = get_atl_repair(AtlOpts),
+ Name = ?audit_trail_log_name,
+ File = filename:absname(?audit_trail_log_file, Dir),
+ case snmp_log:create(Name, File, Size, Repair, true) of
+ {ok, Log} ->
+ ?vdebug("log created: ~w",[Log]),
+ {Log, Type};
+ {error, Reason} ->
+ throw({error, {create_log, Reason}})
+ end
+ end.
+
+
+create_filter(Opts) when is_list(Opts) ->
+ case get_filter_module(Opts) of
+ ?DEFAULT_FILTER_MODULE = Mod ->
+ Mod;
+ Module ->
+ snmpa_network_interface_filter:verify(Module),
+ Module
+ end;
+create_filter(BadOpts) ->
+ throw({error, {bad_filter_opts, BadOpts}}).
+
+
+log({_, []}, _, _, _, _) ->
+ ok;
+log({Log, Types}, 'set-request', Packet, Addr, Port) ->
+ case lists:member(write, Types) of
+ true ->
+ snmp_log:log(Log, Packet, Addr, Port);
+ false ->
+ ok
+ end;
+log({Log, Types}, _, Packet, Addr, Port) ->
+ case lists:member(read, Types) of
+ true ->
+ snmp_log:log(Log, Packet, Addr, Port);
+ false ->
+ ok
+ end;
+log(_, _, _, _, _) ->
+ ok.
+
+
+gen_udp_open(Port, Opts) ->
+ case init:get_argument(snmp_fd) of
+ {ok, [[FdStr]]} ->
+ Fd = list_to_integer(FdStr),
+ gen_udp:open(0, [{fd, Fd}|Opts]);
+ error ->
+ case init:get_argument(snmpa_fd) of
+ {ok, [[FdStr]]} ->
+ Fd = list_to_integer(FdStr),
+ gen_udp:open(0, [{fd, Fd}|Opts]);
+ error ->
+ gen_udp:open(Port, Opts)
+ end
+ end.
+
+
+loop(S) ->
+ receive
+ {udp, _UdpId, Ip, Port, Packet} ->
+ ?vlog("got paket from ~w:~w",[Ip,Port]),
+ NewS = maybe_handle_recv(S, Ip, Port, Packet),
+ loop(NewS);
+
+ {info, ReplyRef, Pid} ->
+ Info = get_info(S),
+ Pid ! {ReplyRef, Info, self()},
+ loop(S);
+
+ %% response (to get/get_next/get_bulk/set requests)
+ {snmp_response, Vsn, RePdu, Type, ACMData, Dest, []} ->
+ ?vlog("reply pdu: "
+ "~n ~s",
+ [?vapply(snmp_misc, format, [256, "~w", [RePdu]])]),
+ NewS = maybe_handle_reply_pdu(S, Vsn, RePdu, Type, ACMData, Dest),
+ loop(NewS);
+
+ %% Traps/notification
+ {send_pdu, Vsn, Pdu, MsgData, To} ->
+ ?vdebug("send pdu: "
+ "~n Pdu: ~p"
+ "~n To: ~p", [Pdu, To]),
+ NewS = maybe_handle_send_pdu(S, Vsn, Pdu, MsgData, To, undefined),
+ loop(NewS);
+
+ %% Informs
+ {send_pdu_req, Vsn, Pdu, MsgData, To, From} ->
+ ?vdebug("send pdu request: "
+ "~n Pdu: ~p"
+ "~n To: ~p"
+ "~n From: ~p",
+ [Pdu, To, toname(From)]),
+ NewS = maybe_handle_send_pdu(S, Vsn, Pdu, MsgData, To, From),
+ loop(NewS);
+
+ %% Discovery Inform
+ {send_discovery, Pdu, MsgData, To, From} ->
+ ?vdebug("received send discovery request: "
+ "~n Pdu: ~p"
+ "~n To: ~p"
+ "~n From: ~p",
+ [Pdu, To, toname(From)]),
+ NewS = handle_send_discovery(S, Pdu, MsgData, To, From),
+ loop(NewS);
+
+ {discarded_pdu, _Vsn, ReqId, _ACMData, Variable, _Extra} ->
+ ?vdebug("discard PDU: ~p", [Variable]),
+ snmpa_mpd:discarded_pdu(Variable),
+ NewS = update_req_counter_outgoing(S, ReqId),
+ loop(NewS);
+
+ {get_log_type, ReplyRef, Pid} ->
+ ?vdebug("get log type: ~p", []),
+ #state{log = {_, LogType}} = S,
+ Pid ! {ReplyRef, {ok, LogType}, self()},
+ loop(S);
+
+ {{set_log_type, NewType}, ReplyRef, Pid} ->
+ ?vdebug("set log type: ~p", [NewType]),
+ {NewState, Reply} = (catch handle_set_log_type(S, NewType)),
+ Pid ! {ReplyRef, Reply, self()},
+ loop(NewState);
+
+ {get_request_limit, ReplyRef, Pid} ->
+ ?vdebug("get request limit: ~p", []),
+ #state{limit = Limit} = S,
+ Pid ! {ReplyRef, {ok, Limit}, self()},
+ loop(S);
+
+ {{set_request_limit, NewLimit}, ReplyRef, Pid} ->
+ ?vdebug("set request limit: ~p", [NewLimit]),
+ {NewState, Reply} = (catch handle_set_request_limit(S, NewLimit)),
+ Pid ! {ReplyRef, Reply, self()},
+ loop(NewState);
+
+ {disk_log, _Node, Log, Info} ->
+ ?vdebug("disk log event: ~p, ~p", [Log, Info]),
+ NewS = handle_disk_log(Log, Info, S),
+ loop(NewS);
+
+ {verbosity, Verbosity} ->
+ ?vlog("verbosity: ~p -> ~p", [get(verbosity), Verbosity]),
+ put(verbosity, snmp_verbosity:validate(Verbosity)),
+ loop(S);
+
+ filter_reset ->
+ reset_counters(),
+ loop(S);
+
+ {'EXIT', Parent, Reason} when Parent == S#state.parent ->
+ ?vlog("parent (~p) exited: "
+ "~n ~p", [Parent, Reason]),
+ exit(Reason);
+
+ {'EXIT', Port, Reason} when Port == S#state.usock ->
+ UDPPort = get_port(),
+ NewS =
+ case gen_udp_open(UDPPort, S#state.usock_opts) of
+ {ok, Id} ->
+ error_msg("Port ~p exited for reason"
+ "~n ~p"
+ "~n Re-opened (~p)", [Port, Reason, Id]),
+ S#state{usock = Id};
+ {error, ReopenReason} ->
+ error_msg("Port ~p exited for reason"
+ "~n ~p"
+ "~n Re-open failed with reason"
+ "~n ~p",
+ [Port, Reason, ReopenReason]),
+ ok
+ end,
+ loop(NewS);
+
+ {'EXIT', Port, Reason} when is_port(Port) ->
+ error_msg("Exit message from port ~p for reason ~p~n",
+ [Port, Reason]),
+ loop(S);
+
+ {'EXIT', Pid, Reason} ->
+ ?vlog("~p exited: "
+ "~n ~p", [Pid, Reason]),
+ NewS = clear_reqs(Pid, S),
+ loop(NewS);
+
+ {system, From, Msg} ->
+ ?vdebug("system event ~p from ~p", [Msg, From]),
+ sys:handle_system_msg(Msg, From, S#state.parent, ?MODULE, [], S);
+
+ _ ->
+ loop(S)
+ end.
+
+
+update_req_counter_incomming(#state{limit = infinity, usock = Sock} = S, _) ->
+ active_once(Sock), %% No limit so activate directly
+ S;
+update_req_counter_incomming(#state{limit = Limit,
+ rcnt = RCnt,
+ usock = Sock} = S, Rid)
+ when length(RCnt) + 1 == Limit ->
+ %% Ok, one more and we are at the limit.
+ %% Just make sure we are not already processing this one...
+ case lists:member(Rid, RCnt) of
+ false ->
+ %% We are at the limit, do _not_ activate socket
+ S#state{rcnt = [Rid|RCnt]};
+ true ->
+ active_once(Sock),
+ S
+ end;
+update_req_counter_incomming(#state{rcnt = RCnt,
+ usock = Sock} = S, Rid) ->
+ active_once(Sock),
+ case lists:member(Rid, RCnt) of
+ false ->
+ S#state{rcnt = [Rid|RCnt]};
+ true ->
+ S
+ end.
+
+
+update_req_counter_outgoing(#state{limit = infinity} = S, _Rid) ->
+ %% Already activated (in the incoming function)
+ S;
+update_req_counter_outgoing(#state{limit = Limit,
+ rcnt = RCnt,
+ usock = Sock} = S, Rid)
+ when length(RCnt) == Limit ->
+ ?vtrace("handle_req_counter_outgoing(~w) -> entry with"
+ "~n Rid: ~w"
+ "~n length(RCnt): ~w", [Limit, Rid, length(RCnt)]),
+ case lists:delete(Rid, RCnt) of
+ NewRCnt when length(NewRCnt) < Limit ->
+ ?vtrace("update_req_counter_outgoing -> "
+ "passed below limit: activate", []),
+ active_once(Sock),
+ S#state{rcnt = NewRCnt};
+ _ ->
+ S
+ end;
+update_req_counter_outgoing(#state{limit = Limit, rcnt = RCnt} = S,
+ Rid) ->
+ ?vtrace("handle_req_counter_outgoing(~w) -> entry with"
+ "~n Rid: ~w"
+ "~n length(RCnt): ~w", [Limit, Rid, length(RCnt)]),
+ NewRCnt = lists:delete(Rid, RCnt),
+ S#state{rcnt = NewRCnt}.
+
+
+maybe_handle_recv(#state{filter = FilterMod} = S,
+ Ip, Port, Packet) ->
+ case (catch FilterMod:accept_recv(Ip, Port)) of
+ false ->
+ %% Drop the received packet
+ inc(netIfMsgInDrops),
+ S;
+ _ ->
+ handle_recv(S, Ip, Port, Packet)
+ end.
+
+handle_discovery_response(_Ip, _Port, #pdu{request_id = ReqId} = Pdu,
+ ManagerEngineId,
+ #state{usock = Sock, reqs = Reqs} = S) ->
+ case lists:keysearch(ReqId, 1, S#state.reqs) of
+ {value, {_, Pid}} ->
+ active_once(Sock),
+ Pid ! {snmp_discovery_response_received, Pdu, ManagerEngineId},
+ NReqs = lists:keydelete(ReqId, 1, Reqs),
+ S#state{reqs = NReqs};
+ _ ->
+ %% Ouch, timeout? resend?
+ S
+ end.
+
+
+handle_recv(#state{usock = Sock,
+ mpd_state = MpdState,
+ note_store = NS,
+ log = Log} = S, Ip, Port, Packet) ->
+ put(n1, erlang:now()),
+ LogF = fun(Type, Data) ->
+ log(Log, Type, Data, Ip, Port)
+ end,
+ case (catch snmpa_mpd:process_packet(Packet, snmpUDPDomain, {Ip, Port},
+ MpdState, NS, LogF)) of
+ {ok, _Vsn, Pdu, _PduMS, {discovery, ManagerEngineId}} ->
+ handle_discovery_response(Ip, Port, Pdu, ManagerEngineId, S);
+
+ {ok, _Vsn, Pdu, _PduMS, discovery} ->
+ handle_discovery_response(Ip, Port, Pdu, undefined, S);
+
+ {ok, Vsn, Pdu, PduMS, ACMData} ->
+ ?vlog("got pdu ~s",
+ [?vapply(snmp_misc, format, [256, "~w", [Pdu]])]),
+ %% handle_recv_pdu(Ip, Port, Vsn, Pdu, PduMS, ACMData, S);
+ maybe_handle_recv_pdu(Ip, Port, Vsn, Pdu, PduMS, ACMData, S);
+
+ {discarded, Reason} ->
+ ?vlog("packet discarded for reason: ~s",
+ [?vapply(snmp_misc, format, [256, "~w", [Reason]])]),
+ active_once(Sock),
+ S;
+
+ {discarded, Reason, ReportPacket} ->
+ ?vlog("sending report for reason: "
+ "~n ~s",
+ [?vapply(snmp_misc, format, [256, "~w", [Reason]])]),
+ (catch udp_send(S#state.usock, Ip, Port, ReportPacket)),
+ active_once(Sock),
+ S;
+
+ {discovery, ReportPacket} ->
+ ?vlog("sending discovery report", []),
+ (catch udp_send(S#state.usock, Ip, Port, ReportPacket)),
+ active_once(Sock),
+ S;
+
+ Error ->
+ error_msg("processing of received message failed: "
+ "~n ~p", [Error]),
+ active_once(Sock),
+ S
+ end.
+
+maybe_handle_recv_pdu(Ip, Port, Vsn, #pdu{type = Type} = Pdu, PduMS, ACMData,
+ #state{usock = Sock, filter = FilterMod} = S) ->
+ case (catch FilterMod:accept_recv_pdu(Ip, Port, Type)) of
+ false ->
+ inc(netIfPduInDrops),
+ active_once(Sock),
+ ok;
+ _ ->
+ handle_recv_pdu(Ip, Port, Vsn, Pdu, PduMS, ACMData, S)
+ end;
+maybe_handle_recv_pdu(Ip, Port, Vsn, Pdu, PduMS, ACMData, S) ->
+ handle_recv_pdu(Ip, Port, Vsn, Pdu, PduMS, ACMData, S).
+
+handle_recv_pdu(Ip, Port, Vsn, #pdu{type = 'get-response'} = Pdu,
+ _PduMS, _ACMData, #state{usock = Sock} = S) ->
+ active_once(Sock),
+ handle_response(Vsn, Pdu, {Ip, Port}, S),
+ S;
+handle_recv_pdu(Ip, Port, Vsn, #pdu{request_id = Rid, type = Type} = Pdu,
+ PduMS, ACMData, #state{master_agent = Pid} = S)
+ when ((Type =:= 'get-request') orelse
+ (Type =:= 'get-next-request') orelse
+ (Type =:= 'get-bulk-request')) ->
+ ?vtrace("handle_recv_pdu -> received get (~w)", [Type]),
+ Pid ! {snmp_pdu, Vsn, Pdu, PduMS, ACMData, {Ip, Port}, []},
+ update_req_counter_incomming(S, Rid);
+handle_recv_pdu(Ip, Port, Vsn, Pdu, PduMS, ACMData,
+ #state{usock = Sock, master_agent = Pid} = S) ->
+ ?vtrace("handle_recv_pdu -> received other request", []),
+ active_once(Sock),
+ Pid ! {snmp_pdu, Vsn, Pdu, PduMS, ACMData, {Ip, Port}, []},
+ S.
+
+
+maybe_handle_reply_pdu(#state{filter = FilterMod} = S, Vsn,
+ #pdu{request_id = Rid} = Pdu,
+ Type, ACMData, {Ip, Port} = Dest) ->
+ S1 = update_req_counter_outgoing(S, Rid),
+ case (catch FilterMod:accept_send_pdu([{Ip, Port}], Type)) of
+ false ->
+ inc(netIfPduOutDrops),
+ ok;
+ _ ->
+ handle_reply_pdu(S1, Vsn, Pdu, Type, ACMData, Dest)
+ end,
+ S1.
+
+handle_reply_pdu(#state{log = Log,
+ usock = Sock,
+ filter = FilterMod},
+ Vsn, Pdu, Type, ACMData, {Ip, Port}) ->
+ LogF = fun(Type2, Data) ->
+ log(Log, Type2, Data, Ip, Port)
+ end,
+ case (catch snmpa_mpd:generate_response_msg(Vsn, Pdu, Type,
+ ACMData, LogF)) of
+ {ok, Packet} ->
+ ?vinfo("time in agent: ~w mysec", [time_in_agent()]),
+ maybe_udp_send(FilterMod, Sock, Ip, Port, Packet);
+ {discarded, Reason} ->
+ ?vlog("handle_reply_pdu -> "
+ "~n reply discarded for reason: ~s",
+ [?vapply(snmp_misc, format, [256, "~w", [Reason]])]),
+ ok;
+ {'EXIT', Reason} ->
+ user_err("failed generating response message: "
+ "~nPDU: ~w~n~w", [Pdu, Reason])
+ end.
+
+
+process_taddrs(To) ->
+ process_taddrs(To, []).
+
+process_taddrs([], Acc) ->
+ lists:reverse(Acc);
+%% v3
+process_taddrs([{{_Domain, AddrAndPort}, _SecData}|T], Acc) ->
+ process_taddrs(T, [AddrAndPort|Acc]);
+%% v1 & v2
+process_taddrs([{_Domain, AddrAndPort}|T], Acc) ->
+ process_taddrs(T, [AddrAndPort|Acc]).
+
+
+merge_taddrs(To1, To2) ->
+ merge_taddrs(To1, To2, []).
+
+merge_taddrs([], _To2, Acc) ->
+ lists:reverse(Acc);
+%% v3
+merge_taddrs([{{_, AddrAndPort}, _} = H|To1], To2, Acc) ->
+ case lists:member(AddrAndPort, To2) of
+ true ->
+ merge_taddrs(To1, To2, [H|Acc]);
+ false ->
+ merge_taddrs(To1, To2, Acc)
+ end;
+%% v1 & v2
+merge_taddrs([{_, AddrAndPort} = H|To1], To2, Acc) ->
+ case lists:member(AddrAndPort, To2) of
+ true ->
+ merge_taddrs(To1, To2, [H|Acc]);
+ false ->
+ merge_taddrs(To1, To2, Acc)
+ end;
+merge_taddrs([_Crap|To1], To2, Acc) ->
+ merge_taddrs(To1, To2, Acc).
+
+
+maybe_handle_send_pdu(#state{filter = FilterMod} = S,
+ Vsn, Pdu, MsgData, To0, From) ->
+
+ ?vtrace("maybe_handle_send_pdu -> entry with"
+ "~n FilterMod: ~p"
+ "~n To0: ~p", [FilterMod, To0]),
+
+ To1 = snmpa_mpd:process_taddrs(To0),
+ To2 = process_taddrs(To1),
+
+ case (catch FilterMod:accept_send_pdu(To2, pdu_type_of(Pdu))) of
+ false ->
+ inc(netIfPduOutDrops),
+ ok;
+ true ->
+ handle_send_pdu(S, Vsn, Pdu, MsgData, To1, From);
+ To3 when is_list(To3) ->
+ To4 = merge_taddrs(To1, To3),
+ ?vtrace("maybe_handle_send_pdu -> To4: "
+ "~n ~p", [To4]),
+ handle_send_pdu(S, Vsn, Pdu, MsgData, To4, From);
+ _ ->
+ handle_send_pdu(S, Vsn, Pdu, MsgData, To1, From)
+ end.
+
+handle_send_pdu(#state{note_store = NS} = S, Vsn, Pdu, MsgData, To, From) ->
+
+ ?vtrace("handle_send_pdu -> entry with"
+ "~n Pdu: ~p"
+ "~n To: ~p", [Pdu, To]),
+
+ case (catch snmpa_mpd:generate_msg(Vsn, NS, Pdu, MsgData, To)) of
+ {ok, Addresses} ->
+ handle_send_pdu(S, Pdu, Addresses);
+ {discarded, Reason} ->
+ ?vlog("handle_send_pdu -> "
+ "~n PDU ~p not sent due to ~p", [Pdu, Reason]),
+ ok;
+ {'EXIT', Reason} ->
+ user_err("failed generating message: "
+ "~nPDU: ~w~n~w", [Pdu, Reason]),
+ ok
+ end,
+ case From of
+ undefined ->
+ S;
+ Pid ->
+ ?vtrace("link to ~p and add to request list", [Pid]),
+ link(Pid),
+ NReqs = snmp_misc:keyreplaceadd(Pid, 2, S#state.reqs,
+ {Pdu#pdu.request_id, From}),
+ S#state{reqs = NReqs}
+ end.
+
+
+handle_send_discovery(#state{note_store = NS} = S,
+ Pdu, MsgData,
+ To, From) ->
+
+ ?vtrace("handle_send_discovery -> entry with"
+ "~n Pdu: ~p"
+ "~n MsgData: ~p"
+ "~n To: ~p"
+ "~n From: ~p", [Pdu, MsgData, To, From]),
+
+ case (catch snmpa_mpd:generate_discovery_msg(NS, Pdu, MsgData, To)) of
+ {ok, {Packet, {Ip, Port}}} ->
+ handle_send_discovery(S, Pdu, Packet, Ip, Port, From);
+ {discarded, Reason} ->
+ ?vlog("handle_send_discovery -> "
+ "~n Discovery PDU ~p not sent due to ~p", [Pdu, Reason]),
+ ok;
+ {'EXIT', Reason} ->
+ user_err("failed generating discovery message: "
+ "~n PDU: ~w"
+ "~n Reason: ~w", [Pdu, Reason]),
+ ok
+ end.
+
+handle_send_discovery(#state{log = Log,
+ usock = Sock,
+ reqs = Reqs} = S,
+ #pdu{type = Type,
+ request_id = ReqId},
+ Packet, Ip, Port, From)
+ when is_binary(Packet) ->
+ log(Log, Type, Packet, Ip, Port),
+ udp_send(Sock, Ip, Port, Packet),
+ ?vtrace("handle_send_discovery -> sent (~w)", [ReqId]),
+ NReqs = snmp_misc:keyreplaceadd(From, 2, Reqs, {ReqId, From}),
+ S#state{reqs = NReqs}.
+
+
+handle_send_pdu(S, #pdu{type = Type} = Pdu, Addresses) ->
+ handle_send_pdu(S, Type, Pdu, Addresses);
+handle_send_pdu(S, Trap, Addresses) ->
+ handle_send_pdu(S, trappdu, Trap, Addresses).
+
+handle_send_pdu(S, Type, Pdu, Addresses) ->
+ case (catch handle_send_pdu1(S, Type, Addresses)) of
+ {Reason, Sz} ->
+ error_msg("Cannot send message "
+ "~n size: ~p"
+ "~n reason: ~p"
+ "~n pdu: ~p",
+ [Sz, Reason, Pdu]);
+ _ ->
+ ok
+ end.
+
+handle_send_pdu1(#state{log = Log,
+ usock = Sock,
+ filter = FilterMod}, Type, Addresses) ->
+ SendFun =
+ fun({snmpUDPDomain, {Ip, Port}, Packet}) when is_binary(Packet) ->
+ ?vdebug("sending packet:"
+ "~n size: ~p"
+ "~n to: ~p:~p",
+ [sz(Packet), Ip, Port]),
+ maybe_udp_send(FilterMod, Log, Type, Sock, Ip, Port, Packet);
+
+ ({snmpUDPDomain, {Ip, Port}, {Packet, _LogData}}) when is_binary(Packet) ->
+ ?vdebug("sending encrypted packet:"
+ "~n size: ~p"
+ "~n to: ~p:~p",
+ [sz(Packet), Ip, Port]),
+ maybe_udp_send(FilterMod, Log, Type, Sock, Ip, Port, Packet);
+
+ (_X) ->
+ ?vlog("** bad res: ~p", [_X]),
+ ok
+ end,
+ lists:foreach(SendFun, Addresses).
+
+
+handle_response(Vsn, Pdu, From, S) ->
+ case lists:keysearch(Pdu#pdu.request_id, 1, S#state.reqs) of
+ {value, {_, Pid}} ->
+ ?vdebug("handle_response -> "
+ "~n send response to receiver ~p", [Pid]),
+ Pid ! {snmp_response_received, Vsn, Pdu, From};
+ _ ->
+ ?vdebug("handle_response -> "
+ "~n No receiver available for response pdu", [])
+ end.
+
+maybe_udp_send(FilterMod, Sock, Ip, Port, Packet) ->
+ case (catch FilterMod:accept_send(Ip, Port)) of
+ false ->
+ inc(netIfMsgOutDrops),
+ ok;
+ _ ->
+ (catch udp_send(Sock, Ip, Port, Packet))
+ end.
+
+maybe_udp_send(FilterMod, AtLog, Type, Sock, Ip, Port, Packet) ->
+ case (catch FilterMod:accept_send(Ip, Port)) of
+ false ->
+ inc(netIfMsgOutDrops),
+ ok;
+ _ ->
+ log(AtLog, Type, Packet, Ip, Port),
+ (catch udp_send(Sock, Ip, Port, Packet))
+ end.
+
+
+udp_send(UdpId, AgentIp, UdpPort, B) ->
+ case (catch gen_udp:send(UdpId, AgentIp, UdpPort, B)) of
+ {error, emsgsize} ->
+ %% From this message we cannot recover, so exit sending loop
+ throw({emsgsize, sz(B)});
+ {error, ErrorReason} ->
+ error_msg("[error] cannot send message "
+ "(destination: ~p:~p, size: ~p, reason: ~p)",
+ [AgentIp, UdpPort, sz(B), ErrorReason]);
+ {'EXIT', ExitReason} ->
+ error_msg("[exit] cannot send message "
+ "(destination: ~p:~p, size: ~p, reason: ~p)",
+ [AgentIp, UdpPort, sz(B), ExitReason]);
+ _ ->
+ ok
+ end.
+
+sz(L) when is_list(L) -> length(L);
+sz(B) when is_binary(B) -> size(B);
+sz(_) -> undefined.
+
+
+handle_disk_log(_Log, {wrap, NoLostItems}, State) ->
+ ?vlog("Audit Trail Log - wrapped: ~w previously logged items where lost",
+ [NoLostItems]),
+ State;
+handle_disk_log(_Log, {truncated, NoLostItems}, State) ->
+ ?vlog("Audit Trail Log - truncated: ~w items where lost when truncating",
+ [NoLostItems]),
+ State;
+handle_disk_log(_Log, full, State) ->
+ error_msg("Failure to write to Audit Trail Log (full)", []),
+ State;
+handle_disk_log(_Log, {error_status, ok}, State) ->
+ State;
+handle_disk_log(_Log, {error_status, {error, Reason}}, State) ->
+ error_msg("Error status received from Audit Trail Log: "
+ "~n~p", [Reason]),
+ State;
+handle_disk_log(_Log, _Info, State) ->
+ State.
+
+
+clear_reqs(Pid, S) ->
+ NReqs = lists:keydelete(Pid, 2, S#state.reqs),
+ S#state{reqs = NReqs}.
+
+
+toname(P) when is_pid(P) ->
+ case process_info(P, registered_name) of
+ {registered_name, Name} ->
+ Name;
+ _ ->
+ P
+ end;
+toname(Else) ->
+ Else.
+
+
+active_once(Sock) ->
+ ?vtrace("activate once", []),
+ inet:setopts(Sock, [{active, once}]).
+
+
+%%%-----------------------------------------------------------------
+
+handle_set_log_type(#state{log = {Log, OldValue}} = State, NewType)
+ when (Log /= undefined) ->
+ NewValue =
+ case NewType of
+ read ->
+ [read];
+ write ->
+ [write];
+ read_write ->
+ [read,write];
+ _ ->
+ throw({State, {error, {bad_atl_type, NewType}}})
+ end,
+ NewState = State#state{log = {Log, NewValue}},
+ OldType =
+ case {lists:member(read, OldValue),
+ lists:member(write, OldValue)} of
+ {true, true} ->
+ read_write;
+ {true, false} ->
+ read;
+ {false, true} ->
+ write;
+ {false, false} ->
+ throw({State, {error, {bad_atl_type, OldValue}}})
+ end,
+ {NewState, {ok, OldType}};
+handle_set_log_type(State, _NewType) ->
+ {State, {error, not_enabled}}.
+
+
+handle_set_request_limit(#state{limit = OldLimit} = State, NewLimit)
+ when ((is_integer(NewLimit) andalso (NewLimit >= 0)) orelse
+ (NewLimit == infinity)) ->
+ NewState = State#state{limit = NewLimit},
+ {NewState, {ok, OldLimit}};
+handle_set_request_limit(State, BadLimit) ->
+ {State, {error, {bad_request_limit, BadLimit}}}.
+
+
+%%%-----------------------------------------------------------------
+%%% System messages
+%%%-----------------------------------------------------------------
+system_continue(_Parent, _Dbg, S) ->
+ loop(S).
+
+system_terminate(Reason, _Parent, _Dbg, #state{log = Log}) ->
+ do_close_log(Log),
+ exit(Reason).
+
+system_code_change(OldState, _Module, _OldVsn, upgrade_from_pre_4_10) ->
+ {state,
+ parent = Parent,
+ note_store = NS,
+ master_agent = MA,
+ usock = Sock,
+ usock_opts = SockOpts,
+ mpd_state = MpdState,
+ log = Log,
+ reqs = Reqs,
+ debug = Dbg,
+ limit = Limit,
+ rcnt = RCNT} = OldState,
+ NewState = #state{parent = Parent,
+ note_store = NS,
+ master_agent = MA,
+ usock = Sock,
+ usock_opts = SockOpts,
+ mpd_state = MpdState,
+ log = Log,
+ reqs = Reqs,
+ debug = Dbg,
+ limit = Limit,
+ rcnt = RCNT,
+ filter = create_filter(?DEFAULT_FILTER_OPTS)},
+ {ok, NewState};
+system_code_change(OldState, _Module, _OldVsn, downgrade_to_pre_4_10) ->
+ #state{parent = Parent,
+ note_store = NS,
+ master_agent = MA,
+ usock = Sock,
+ usock_opts = SockOpts,
+ mpd_state = MpdState,
+ log = Log,
+ reqs = Reqs,
+ debug = Dbg,
+ limit = Limit,
+ rcnt = RCNT} = OldState,
+ NewState =
+ {state,
+ parent = Parent,
+ note_store = NS,
+ master_agent = MA,
+ usock = Sock,
+ usock_opts = SockOpts,
+ mpd_state = MpdState,
+ log = Log,
+ reqs = Reqs,
+ debug = Dbg,
+ limit = Limit,
+ rcnt = RCNT},
+ {ok, NewState};
+system_code_change(S, _Module, _OldVsn, _Extra) ->
+ {ok, S}.
+
+do_close_log({undefined, []}) ->
+ ok;
+do_close_log({Log, _}) ->
+ (catch snmp_log:sync(Log)),
+ (catch snmp_log:close(Log)),
+ ok;
+do_close_log(_) ->
+ ok.
+
+
+%%%-----------------------------------------------------------------
+%%% DEBUG FUNCTIONS
+%%%-----------------------------------------------------------------
+time_in_agent() ->
+ subtr(erlang:now(), get(n1)).
+
+subtr({X1,Y1,Z1}, {X1,Y1,Z2}) ->
+ Z1 - Z2;
+subtr({X1,Y1,Z1}, {X1,Y2,Z2}) ->
+ ((Y1-Y2) * 1000000) + (Z1 - Z2);
+subtr({X1,Y1,Z1}, {X2,Y2,Z2}) ->
+ ((X1 - X2) * 1000000000000) + ((Y1 - Y2) * 1000000) + (Z1 - Z2).
+
+
+%% ----------------------------------------------------------------
+
+pdu_type_of(#pdu{type = Type}) ->
+ Type;
+pdu_type_of(TrapPdu) when is_record(TrapPdu, trappdu) ->
+ trap.
+
+
+%%-----------------------------------------------------------------
+%% Counter functions
+%%-----------------------------------------------------------------
+
+init_counters() ->
+ F = fun(Counter) -> maybe_create_counter(Counter) end,
+ lists:map(F, counters()).
+
+reset_counters() ->
+ F = fun(Counter) -> init_counter(Counter) end,
+ lists:map(F, counters()).
+
+maybe_create_counter(Counter) ->
+ case ets:lookup(snmp_agent_table, Counter) of
+ [_] -> ok;
+ _ -> init_counter(Counter)
+ end.
+
+init_counter(Counter) ->
+ ets:insert(snmp_agent_table, {Counter, 0}).
+
+counters() ->
+ [
+ netIfMsgOutDrops,
+ netIfMsgInDrops,
+ netIfPduOutDrops,
+ netIfPduInDrops
+ ].
+
+inc(Name) ->
+ ets:update_counter(snmp_agent_table, Name, 1).
+
+get_counters() ->
+ Counters = counters(),
+ get_counters(Counters, []).
+
+get_counters([], Acc) ->
+ lists:reverse(Acc);
+get_counters([Counter|Counters], Acc) ->
+ case ets:lookup(snmp_agent_table, Counter) of
+ [CounterVal] ->
+ get_counters(Counters, [CounterVal|Acc]);
+ _ ->
+ get_counters(Counters, Acc)
+ end.
+
+
+%% ----------------------------------------------------------------
+
+ip_opt_bind_to_ip_address(Opts, Ip) ->
+ case get_bind_to_ip_address(Opts) of
+ true ->
+ [{ip, list_to_tuple(Ip)}];
+ _ ->
+ []
+ end.
+
+ip_opt_no_reuse_address(Opts) ->
+ case get_no_reuse_address(Opts) of
+ false ->
+ [{reuseaddr, true}];
+ _ ->
+ []
+ end.
+
+ip_opt_recbuf(Opts) ->
+ case get_recbuf(Opts) of
+ use_default ->
+ [];
+ Sz ->
+ [{recbuf, Sz}]
+ end.
+
+ip_opt_sndbuf(Opts) ->
+ case get_sndbuf(Opts) of
+ use_default ->
+ [];
+ Sz ->
+ [{sndbuf, Sz}]
+ end.
+
+
+%% ----------------------------------------------------------------
+
+get_atl_type(Opts) ->
+ case snmp_misc:get_option(type, Opts, read_write) of
+ read_write ->
+ [read,write];
+ write ->
+ [write];
+ read ->
+ [read]
+ end.
+
+get_atl_dir(Opts) ->
+ snmp_misc:get_option(dir, Opts).
+
+get_atl_size(Opts) ->
+ snmp_misc:get_option(size, Opts).
+
+get_atl_repair(Opts) ->
+ snmp_misc:get_option(repair, Opts, true).
+
+get_verbosity(Opts) ->
+ snmp_misc:get_option(verbosity, Opts, ?default_verbosity).
+
+get_vsns(Opts) ->
+ snmp_misc:get_option(versions, Opts, [v1, v2, v3]).
+
+get_req_limit(O) ->
+ snmp_misc:get_option(req_limit, O, infinity).
+
+get_filter_opts(O) ->
+ snmp_misc:get_option(filter, O, []).
+
+get_filter_module(O) ->
+ snmp_misc:get_option(module, O, ?DEFAULT_FILTER_MODULE).
+
+get_recbuf(Opts) ->
+ snmp_misc:get_option(recbuf, Opts, use_default).
+
+get_sndbuf(Opts) ->
+ snmp_misc:get_option(sndbuf, Opts, use_default).
+
+get_no_reuse_address(Opts) ->
+ snmp_misc:get_option(no_reuse, Opts, false).
+
+get_bind_to_ip_address(Opts) ->
+ snmp_misc:get_option(bind_to, Opts, false).
+
+
+%% ----------------------------------------------------------------
+
+error_msg(F,A) ->
+ ?snmpa_error("NET-IF server: " ++ F, A).
+
+%% ---
+
+user_err(F, A) ->
+ snmpa_error:user_err(F, A).
+
+config_err(F, A) ->
+ snmpa_error:config_err(F, A).
+
+
+%% ----------------------------------------------------------------
+
+call(Pid, Req) ->
+ ReplyRef = make_ref(),
+ Pid ! {Req, ReplyRef, self()},
+ receive
+ {ReplyRef, Reply, Pid} ->
+ Reply
+ after 5000 ->
+ {error, timeout}
+ end.
+
+
+%% ----------------------------------------------------------------
+
+get_info(#state{usock = Id, reqs = Reqs}) ->
+ ProcSize = proc_mem(self()),
+ PortInfo = get_port_info(Id),
+ Counters = get_counters(),
+ [{reqs, Reqs},
+ {counters, Counters},
+ {process_memory, ProcSize},
+ {port_info, PortInfo}].
+
+proc_mem(P) when is_pid(P) ->
+ case (catch erlang:process_info(P, memory)) of
+ {memory, Sz} when is_integer(Sz) ->
+ Sz;
+ _ ->
+ undefined
+ end.
+%% proc_mem(_) ->
+%% undefined.
+
+get_port_info(Id) ->
+ PortInfo =
+ case (catch erlang:port_info(Id)) of
+ PI when is_list(PI) ->
+ [{port_info, PI}];
+ _ ->
+ []
+ end,
+ PortStatus =
+ case (catch prim_inet:getstatus(Id)) of
+ {ok, PS} ->
+ [{port_status, PS}];
+ _ ->
+ []
+ end,
+ PortAct =
+ case (catch inet:getopts(Id, [active])) of
+ {ok, PA} ->
+ [{port_act, PA}];
+ _ ->
+ []
+ end,
+ PortStats =
+ case (catch inet:getstat(Id)) of
+ {ok, Stat} ->
+ [{port_stats, Stat}];
+ _ ->
+ []
+ end,
+ IfList =
+ case (catch inet:getif(Id)) of
+ {ok, IFs} ->
+ [{interfaces, IFs}];
+ _ ->
+ []
+ end,
+ BufSz =
+ case (catch inet:getopts(Id, [recbuf, sndbuf])) of
+ {ok, Sz} ->
+ [{buffer_size, Sz}];
+ _ ->
+ []
+ end,
+ [{socket, Id}] ++
+ IfList ++
+ PortStats ++
+ PortInfo ++
+ PortStatus ++
+ PortAct ++
+ BufSz.
+
+
+%% ----------------------------------------------------------------
+
+% i(F) ->
+% i(F, []).
+
+% i(F, A) ->
+% io:format("~p: " ++ F ++ "~n", [?MODULE|A]).
+
diff --git a/lib/snmp/src/agent/snmpa_net_if_filter.erl b/lib/snmp/src/agent/snmpa_net_if_filter.erl
new file mode 100644
index 0000000000..989f7c95b3
--- /dev/null
+++ b/lib/snmp/src/agent/snmpa_net_if_filter.erl
@@ -0,0 +1,52 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2007-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%
+%%
+-module(snmpa_net_if_filter).
+
+-export([accept_recv/2,
+ accept_send/2,
+ accept_recv_pdu/3,
+ accept_send_pdu/2]).
+
+-include("snmp_debug.hrl").
+
+accept_recv(_Addr, _Port) ->
+ ?d("accept_recv -> entry with"
+ "~n Addr: ~p"
+ "~n Port: ~p", [_Addr, _Port]),
+ true.
+
+accept_send(_Addr, _Port) ->
+ ?d("accept_send -> entry with"
+ "~n Addr: ~p"
+ "~n Port: ~p", [_Addr, _Port]),
+ true.
+
+accept_recv_pdu(_Addr, _Port, _PduType) ->
+ ?d("accept_recv_pdu -> entry with"
+ "~n Addr: ~p"
+ "~n Port: ~p"
+ "~n PduType: ~p", [_Addr, _Port, _PduType]),
+ true.
+
+accept_send_pdu(_Targets, _PduType) ->
+ ?d("accept_send_pdu -> entry with"
+ "~n Targets: ~p"
+ "~n PduType: ~p", [_Targets, _PduType]),
+ true.
+
diff --git a/lib/snmp/src/agent/snmpa_network_interface.erl b/lib/snmp/src/agent/snmpa_network_interface.erl
new file mode 100644
index 0000000000..887ea22549
--- /dev/null
+++ b/lib/snmp/src/agent/snmpa_network_interface.erl
@@ -0,0 +1,45 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2004-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%
+%%
+-module(snmpa_network_interface).
+
+-export([behaviour_info/1]).
+
+behaviour_info(callbacks) ->
+ [{start_link, 4},
+ {get_log_type, 1},
+ {set_log_type, 2},
+ {get_request_limit, 1},
+ {set_request_limit, 2},
+ {info, 1},
+ {verbosity, 2}];
+behaviour_info(_) ->
+ undefined.
+
+
+%% behaviour_info(callbacks) ->
+%% [{start_link, 4},
+%% {send_pdu, 5},
+%% {send_response_pdu, 6},
+%% {discard_pdu, 6},
+%% {send_pdu_req, 6},
+%% {verbosity, 2},
+%% {change_log_type, 2}];
+%% behaviour_info(_) ->
+%% undefined.
+
diff --git a/lib/snmp/src/agent/snmpa_network_interface_filter.erl b/lib/snmp/src/agent/snmpa_network_interface_filter.erl
new file mode 100644
index 0000000000..6fa131beee
--- /dev/null
+++ b/lib/snmp/src/agent/snmpa_network_interface_filter.erl
@@ -0,0 +1,54 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2007-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%
+%%
+-module(snmpa_network_interface_filter).
+
+-export([behaviour_info/1]).
+-export([verify/1]).
+
+
+behaviour_info(callbacks) ->
+ [{accept_recv, 2},
+ {accept_send, 2},
+ {accept_recv_pdu, 3},
+ {accept_send_pdu, 2}];
+behaviour_info(_) ->
+ undefined.
+
+
+%% accept_recv(address(), port()) -> boolean()
+%% Called at the receiption of a message
+%% (before *any* processing has been done).
+%%
+%% accept_send(address(), port()) -> boolean()
+%% Called before the sending of a message
+%% (after *all* processing has been done).
+%%
+%% accept_recv_pdu(Addr, Port, pdu_type()) -> boolean()
+%% Called after the basic message processing (MPD) has been done,
+%% but before the pdu is handed over to the master-agent for
+%% primary processing.
+%%
+%% accept_send_pdu(Targets, pdu_type()) -> boolean() | NewTargets
+%% Called before the basic message processing (MPD) is done,
+%% when a pdu has been received from the master-agent.
+%%
+
+
+verify(Module) ->
+ snmp_misc:verify_behaviour(?MODULE, Module).
diff --git a/lib/snmp/src/agent/snmpa_notification_delivery_info_receiver.erl b/lib/snmp/src/agent/snmpa_notification_delivery_info_receiver.erl
new file mode 100644
index 0000000000..b9ec5ff05e
--- /dev/null
+++ b/lib/snmp/src/agent/snmpa_notification_delivery_info_receiver.erl
@@ -0,0 +1,35 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2008-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%
+%%
+
+-module(snmpa_notification_delivery_info_receiver).
+
+-export([behaviour_info/1]).
+-export([verify/1]).
+
+behaviour_info(callbacks) ->
+ [
+ {delivery_targets, 3},
+ {delivery_info, 4}
+ ];
+behaviour_info(_) ->
+ undefined.
+
+
+verify(Module) ->
+ snmp_misc:verify_behaviour(?MODULE, Module).
diff --git a/lib/snmp/src/agent/snmpa_notification_filter.erl b/lib/snmp/src/agent/snmpa_notification_filter.erl
new file mode 100644
index 0000000000..199cf725fd
--- /dev/null
+++ b/lib/snmp/src/agent/snmpa_notification_filter.erl
@@ -0,0 +1,36 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2004-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%
+%%
+-module(snmpa_notification_filter).
+
+-export([behaviour_info/1]).
+
+behaviour_info(callbacks) ->
+ [{handle_notification, 2}];
+behaviour_info(_) ->
+ undefined.
+
+%% handle_notification(Notification, Data) -> Reply
+%% Notification -> notification() | trap()
+%% Data -> term()
+%% Reply -> send | {send, NewNotif} | ignore
+%% NewNotif -> notification() | trap()
+%%
+%% send -> This means it is ok for this filter to send the notification as is
+%% {send, NewNotif} -> Send this notification instead
+%% dont_sent -> Dont send this notification.
diff --git a/lib/snmp/src/agent/snmpa_set.erl b/lib/snmp/src/agent/snmpa_set.erl
new file mode 100644
index 0000000000..0f85d0aaa0
--- /dev/null
+++ b/lib/snmp/src/agent/snmpa_set.erl
@@ -0,0 +1,244 @@
+%%
+%% %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%
+%%
+-module(snmpa_set).
+
+-behaviour(snmpa_set_mechanism).
+
+-define(VMODULE,"SET").
+-include("snmp_verbosity.hrl").
+
+
+%%%-----------------------------------------------------------------
+%%% This module implements a simple, basic atomic set mechanism.
+%%%-----------------------------------------------------------------
+%%% Table of contents
+%%% =================
+%%% 1. SET REQUEST
+%%% 1.1 SET phase one
+%%% 1.2 SET phase two
+%%% 2. Misc functions
+%%%-----------------------------------------------------------------
+
+%% External exports
+-export([do_set/2, do_subagent_set/1]).
+
+%%%-----------------------------------------------------------------
+%%% 1. SET REQUEST
+%%%
+%%% 1) Perform set_phase_one for all own vars
+%%% 2) Perform set_phase_one for all SAs
+%%% IF nok THEN 2.1 ELSE 3
+%%% 2.1) Perform set_phase_two(undo) for all SAs that have performed
+%%% set_phase_one.
+%%% 3) Perform set_phase_two for all own vars
+%%% 4) Perform set_phase_two(set) for all SAs
+%%% IF nok THEN 4.1 ELSE 5
+%%% 4.1) Perform set_phase_two(undo) for all SAs that have performed
+%%% set_phase_one but not set_phase_two(set).
+%%% 5) noError
+%%%-----------------------------------------------------------------
+%%-----------------------------------------------------------------
+%% First of all - validate MibView for all varbinds. In this way
+%% we don't have to send the MibView to all SAs for validation.
+%%-----------------------------------------------------------------
+do_set(MibView, UnsortedVarbinds) ->
+ ?vtrace("do set with"
+ "~n MibView: ~p",[MibView]),
+ case snmpa_acm:validate_all_mib_view(UnsortedVarbinds, MibView) of
+ true ->
+ {MyVarbinds , SubagentVarbinds} =
+ sort_varbindlist(UnsortedVarbinds),
+ case set_phase_one(MyVarbinds, SubagentVarbinds) of
+ {noError, 0} -> set_phase_two(MyVarbinds, SubagentVarbinds);
+ {Reason, Index} -> {Reason, Index}
+ end;
+ {false, Index} ->
+ {noAccess, Index}
+ end.
+
+%%-----------------------------------------------------------------
+%% This function is called when a subagents receives a message
+%% concerning some set_phase.
+%% Mandatory messages for all subagents:
+%% [phase_one, UnsortedVarbinds]
+%% [phase_two, set, UnsortedVarbinds]
+%% [phase_two, undo, UnsortedVarbinds]
+%%-----------------------------------------------------------------
+do_subagent_set([phase_one, UnsortedVarbinds]) ->
+ ?vtrace("do subagent set, phase one",[]),
+ {MyVarbinds, SubagentVarbinds} = sort_varbindlist(UnsortedVarbinds),
+ set_phase_one(MyVarbinds, SubagentVarbinds);
+do_subagent_set([phase_two, State, UnsortedVarbinds]) ->
+ ?vtrace("do subagent set, phase two",[]),
+ {MyVarbinds, SubagentVarbinds} = sort_varbindlist(UnsortedVarbinds),
+ set_phase_two(State, MyVarbinds, SubagentVarbinds).
+
+%%%-----------------------------------------------------------------
+%%% 1.1 SET phase one
+%%%-----------------------------------------------------------------
+%%-----------------------------------------------------------------
+%% Func: set_phase_one/3
+%% Purpose: First, do set_phase_one for my own variables (i.e.
+%% variables handled by this agent). Then, do set_phase_one
+%% for all subagents. If any SA failed, do set_phase_two
+%% (undo) for all SA that have done set_phase_one.
+%% Returns: {noError, 0} | {ErrorStatus, Index}
+%%-----------------------------------------------------------------
+set_phase_one(MyVarbinds, SubagentVarbinds) ->
+ ?vtrace("set phase one: "
+ "~n MyVarbinds: ~p"
+ "~n SubagentVarbinds: ~p",
+ [MyVarbinds, SubagentVarbinds]),
+ case set_phase_one_my_variables(MyVarbinds) of
+ {noError, 0} ->
+ case set_phase_one_subagents(SubagentVarbinds, []) of
+ {noError, 0} ->
+ {noError, 0};
+ {{ErrorStatus, Index}, PerformedSubagents} ->
+ case set_phase_two_undo(MyVarbinds, PerformedSubagents) of
+ {noError, 0} ->
+ {ErrorStatus, Index};
+ {WorseErrorStatus, WorseIndex} ->
+ {WorseErrorStatus, WorseIndex}
+ end
+ end;
+ {ErrorStatus, Index} ->
+ {ErrorStatus, Index}
+ end.
+
+set_phase_one_my_variables(MyVarbinds) ->
+ ?vtrace("my variables set, phase one:"
+ "~n ~p",[MyVarbinds]),
+ case snmpa_set_lib:is_varbinds_ok(MyVarbinds) of
+ {noError, 0} ->
+ snmpa_set_lib:consistency_check(MyVarbinds);
+ {ErrorStatus, Index} ->
+ {ErrorStatus, Index}
+ end.
+
+%%-----------------------------------------------------------------
+%% Loop all subagents, and perform set_phase_one for them.
+%%-----------------------------------------------------------------
+set_phase_one_subagents([{SubAgentPid, SAVbs}|SubagentVarbinds], Done) ->
+ {_SAOids, Vbs} = sa_split(SAVbs),
+ case (catch snmpa_agent:subagent_set(SubAgentPid, [phase_one, Vbs])) of
+ {noError, 0} ->
+ set_phase_one_subagents(SubagentVarbinds,
+ [{SubAgentPid, SAVbs} | Done]);
+ {'EXIT', Reason} ->
+ user_err("Lost contact with subagent (set phase_one)"
+ "~n~w. Using genErr", [Reason]),
+ {{genErr, 0}, Done};
+ {ErrorStatus, ErrorIndex} ->
+ {{ErrorStatus, ErrorIndex}, Done}
+ end;
+set_phase_one_subagents([], _Done) ->
+ {noError, 0}.
+
+%%%-----------------------------------------------------------------
+%%% 1.2 SET phase two
+%%%-----------------------------------------------------------------
+%% returns: {ErrStatus, ErrIndex}
+set_phase_two(MyVarbinds, SubagentVarbinds) ->
+ ?vtrace("set phase two: "
+ "~n MyVarbinds: ~p"
+ "~n SubagentVarbinds: ~p",
+ [MyVarbinds, SubagentVarbinds]),
+ case snmpa_set_lib:try_set(MyVarbinds) of
+ {noError, 0} ->
+ set_phase_two_subagents(SubagentVarbinds);
+ {ErrorStatus, Index} ->
+ set_phase_two_undo_subagents(SubagentVarbinds),
+ {ErrorStatus, Index}
+ end.
+
+%%-----------------------------------------------------------------
+%% This function is called for each phase_two state in the
+%% subagents. The undo state just pass undo along to each of its
+%% subagents.
+%%-----------------------------------------------------------------
+set_phase_two(set, MyVarbinds, SubagentVarbinds) ->
+ set_phase_two(MyVarbinds, SubagentVarbinds);
+set_phase_two(undo, MyVarbinds, SubagentVarbinds) ->
+ set_phase_two_undo(MyVarbinds, SubagentVarbinds).
+
+%%-----------------------------------------------------------------
+%% Loop all subagents, and perform set_phase_two(set) for them.
+%% If any fails, perform set_phase_two(undo) for the not yet
+%% called SAs.
+%%-----------------------------------------------------------------
+set_phase_two_subagents([{SubAgentPid, SAVbs} | SubagentVarbinds]) ->
+ {_SAOids, Vbs} = sa_split(SAVbs),
+ case catch snmpa_agent:subagent_set(SubAgentPid, [phase_two, set, Vbs]) of
+ {noError, 0} ->
+ set_phase_two_subagents(SubagentVarbinds);
+ {'EXIT', Reason} ->
+ user_err("Lost contact with subagent (set)~n~w. Using genErr",
+ [Reason]),
+ set_phase_two_undo_subagents(SubagentVarbinds),
+ {genErr, 0};
+ {ErrorStatus, ErrorIndex} ->
+ set_phase_two_undo_subagents(SubagentVarbinds),
+ {ErrorStatus, ErrorIndex}
+ end;
+set_phase_two_subagents([]) ->
+ {noError, 0}.
+
+%%-----------------------------------------------------------------
+%% This function undos phase_one, own and subagent.
+%%-----------------------------------------------------------------
+set_phase_two_undo(MyVarbinds, SubagentVarbinds) ->
+ case set_phase_two_undo_my_variables(MyVarbinds) of
+ {noError, 0} ->
+ set_phase_two_undo_subagents(SubagentVarbinds);
+ {ErrorStatus, Index} ->
+ set_phase_two_undo_subagents(SubagentVarbinds),
+ {ErrorStatus, Index}
+ end.
+
+set_phase_two_undo_my_variables(MyVarbinds) ->
+ snmpa_set_lib:undo_varbinds(MyVarbinds).
+
+set_phase_two_undo_subagents([{SubAgentPid, SAVbs} | SubagentVarbinds]) ->
+ {_SAOids, Vbs} = sa_split(SAVbs),
+ case catch snmpa_agent:subagent_set(SubAgentPid, [phase_two, undo, Vbs]) of
+ {noError, 0} ->
+ set_phase_two_undo_subagents(SubagentVarbinds);
+ {'EXIT', Reason} ->
+ user_err("Lost contact with subagent (undo)~n~w. Using genErr",
+ [Reason]),
+ {genErr, 0};
+ {ErrorStatus, ErrorIndex} ->
+ {ErrorStatus, ErrorIndex}
+ end;
+set_phase_two_undo_subagents([]) ->
+ {noError, 0}.
+
+%%%-----------------------------------------------------------------
+%%% 2. Misc functions
+%%%-----------------------------------------------------------------
+sort_varbindlist(Varbinds) ->
+ snmpa_svbl:sort_varbindlist(get(mibserver), Varbinds).
+
+sa_split(SubagentVarbinds) ->
+ snmpa_svbl:sa_split(SubagentVarbinds).
+
+
+user_err(F, A) ->
+ snmpa_error:user_err(F, A).
diff --git a/lib/snmp/src/agent/snmpa_set_lib.erl b/lib/snmp/src/agent/snmpa_set_lib.erl
new file mode 100644
index 0000000000..191029f6db
--- /dev/null
+++ b/lib/snmp/src/agent/snmpa_set_lib.erl
@@ -0,0 +1,395 @@
+%%
+%% %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%
+%%
+-module(snmpa_set_lib).
+
+-include("snmp_types.hrl").
+
+-define(VMODULE,"SETLIB").
+-include("snmp_verbosity.hrl").
+
+
+%% External exports
+-export([is_varbinds_ok/1, consistency_check/1,
+ undo_varbinds/1, try_set/1]).
+
+%%%-----------------------------------------------------------------
+%%% This module implements functions common to all different set
+%%% mechanisms.
+%%%-----------------------------------------------------------------
+%% Phase 1 of the set-operation. (see rfc1905:4.2.5)
+%% Input is a sorted Varbinds list.
+%% Output is either ok or {ErrIndex, ErrCode}.
+%%* 1) IF the variable is outside the mib view THEN noAccess.
+%%* 2a) IF the varaible doesn't exist THEN notWritable.
+%% 2b) IF mib isn't able to create instances of the variable (for
+%% example in a table) THEN noCreation.
+%%* 3) IF the new value provided is of the wrong ASN.1 type THEN wrongType.
+%%* 4) IF then new value is of wrong length THEN wrongLength.
+%%# 5) IF value is incorrectly encoded THEN wrongEncoding. [nyi]
+%%* 6) IF value is outside the acceptable range THEN wrongValue.
+%% 7) IF variable does not exist and could not ever be created
+%% THEN noCreation.
+%% 8) IF variable can not be created now THEN inconsistentName.
+%% 9) IF value can not be set now THEN inconsistentValue.
+%%* 9) IF instances of the variable can not be modified THEN notWritable.
+%% 10) IF an unavailable resource is needed THEN resourceUnavailable.
+%% 11) IF any other error THEN genErr.
+%% 12) Otherwise ok!
+%% The Agent takes care of *-marked. (# should be done by the agent but is
+%% nyi.)
+%% The rest is taken care of in consistency_check that communicates with the mib
+%% (through the is_set_ok-function (for each variable)).
+%%
+%% SNMPv1 (see rfc1157:4.1.5)
+%%* 1) IF variable not available for set in the mibview THEN noSuchName.
+%%* 2) IF variable exists, but doesn't permit writeing THEN readOnly.
+%%* 3) IF provided value doesn't match ASN.1 type THEN badValue.
+%% 4) IF any other error THEN genErr.
+%% 5) Otherwise ok!
+%%
+%% Internally we use snmpv2 messages, and convert them to the appropriate
+%% v1 msg.
+%%-----------------------------------------------------------------
+%% Func: is_varbinds_ok/2
+%% Purpose: Call is_varbind_ok for each varbind
+%% Returns: {noError, 0} | {ErrorStatus, ErrorIndex}
+%%-----------------------------------------------------------------
+is_varbinds_ok([{_TableOid, TableVbs} | IVarbinds]) ->
+ is_varbinds_ok(lists:append(TableVbs, IVarbinds));
+is_varbinds_ok([IVarbind | IVarbinds]) ->
+ case catch is_varbind_ok(IVarbind) of
+ true -> is_varbinds_ok(IVarbinds);
+ ErrorStatus ->
+ Varbind = IVarbind#ivarbind.varbind,
+ ?vtrace("varbinds erroneous: ~p -> ~p",
+ [Varbind#varbind.org_index,ErrorStatus]),
+ {ErrorStatus, Varbind#varbind.org_index}
+ end;
+is_varbinds_ok([]) ->
+ ?vtrace("varbinds ok",[]),
+ {noError, 0}.
+
+%%-----------------------------------------------------------------
+%% Func: is_varbind_ok/1
+%% Purpose: Check everything we can check about the varbind against
+%% the MIB. Here we don't call any instrumentation functions.
+%% Returns: true |
+%% Fails: with an <error-atom>.
+%%-----------------------------------------------------------------
+is_varbind_ok(#ivarbind{status = Status,
+ mibentry = MibEntry,
+ varbind = Varbind}) ->
+ variableExists(Status, MibEntry, Varbind),
+ % If we get here, MibEntry /= false
+ variableIsWritable(MibEntry, Varbind),
+ checkASN1Type(MibEntry, Varbind),
+ checkValEncoding(MibEntry, Varbind),
+ true.
+
+variableExists(noError, false, _Varbind) -> throw(notWritable);
+variableExists(noError, _MibEntry, _Varbind) -> true;
+%% ErrorStatus == noSuchObject | noSuchInstance
+variableExists(noSuchObject, _MibEntry, _Varbind) -> throw(notWritable);
+variableExists(_ErrorStatus, _MibEntry, _Varbind) -> throw(noCreation).
+
+variableIsWritable(#me{access = 'read-write'}, _Varbind) -> true;
+variableIsWritable(#me{access = 'read-create'}, _Varbind) -> true;
+variableIsWritable(#me{access = 'write-only'}, _Varbind) -> true;
+variableIsWritable(_MibEntry, _Varbind) -> throw(notWritable).
+
+%% Uses make_value_a_correct_value to check type, length and range.
+%% Returns: true | <error-atom>
+checkASN1Type(#me{asn1_type = ASN1Type},
+ #varbind{variabletype = Type, value = Value})
+ when ASN1Type#asn1_type.bertype =:= Type ->
+ case make_value_a_correct_value({value, Value}, ASN1Type,
+ undef) of
+ {value, Type, Value} -> true;
+ {error, Error} when is_atom(Error) -> throw(Error)
+ end;
+
+checkASN1Type(_,_) -> throw(wrongType).
+
+
+%% tricky...
+checkValEncoding(_MibEntry, _Varbind) -> true.
+
+%%-----------------------------------------------------------------
+%% Func: consistency_check/1
+%% Purpose: Scans all vbs, and checks whether there is a is_set_ok
+%% function or not. If it exists, it is called with the
+%% vb, to check if the set-op is ok. If it doesn't exist,
+%% it is considered ok to set the variable.
+%% Returns: {noError, 0} | {ErrorStatus, ErrorIndex]
+%% PRE: #ivarbind.status == noError for each varbind
+%%-----------------------------------------------------------------
+consistency_check(Varbinds) ->
+ consistency_check(Varbinds, []).
+consistency_check([{TableOid, TableVbs} | Varbinds], Done) ->
+ ?vtrace("consistency_check -> entry with"
+ "~n TableOid: ~p"
+ "~n TableVbs: ~p",[TableOid,TableVbs]),
+ TableOpsWithShortOids = deletePrefixes(TableOid, TableVbs),
+ [#ivarbind{mibentry = MibEntry}|_] = TableVbs,
+ case is_set_ok_table(MibEntry, TableOpsWithShortOids) of
+ {noError, 0} ->
+ consistency_check(Varbinds, [{TableOid, TableVbs} | Done]);
+ {Reason, Idx} ->
+ case undo_varbinds(Done) of
+ {noError, 0} -> {Reason, find_org_index(Idx, TableVbs)};
+ Error -> Error
+ end
+ end;
+consistency_check([IVarbind | Varbinds], Done) ->
+ ?vtrace("consistency_check -> entry with"
+ "~n IVarbind: ~p",[IVarbind]),
+ #ivarbind{varbind = Varbind, mibentry = MibEntry} = IVarbind,
+ #varbind{value = Value, org_index = OrgIndex} = Varbind,
+ case is_set_ok_variable(MibEntry, Value) of
+ noError -> consistency_check(Varbinds, [IVarbind | Done]);
+ Reason ->
+ case undo_varbinds(Done) of
+ {noError, 0} -> {Reason, OrgIndex};
+ Error -> Error
+ end
+ end;
+consistency_check([], _Done) ->
+ ?vtrace("consistency_check -> done",[]),
+ {noError, 0}.
+
+deletePrefixes(Prefix, [#ivarbind{varbind = Varbind} | Vbs]) ->
+ #varbind{oid = Oid, value = Value} = Varbind,
+ [{snmp_misc:diff(Oid, Prefix), Value} | deletePrefixes(Prefix, Vbs)];
+deletePrefixes(_Prefix, []) -> [].
+
+%% Val = <a-value>
+is_set_ok_variable(#me{mfa = {Module, Func, Args} = MFA}, Val) ->
+ ?vtrace("is_set_ok_variable -> entry with"
+ "~n MFA: ~p"
+ "~n Val: ~p",[MFA,Val]),
+ case dbg_apply(Module, Func, [is_set_ok, Val | Args]) of
+ {'EXIT', {hook_undef, _}} -> noError;
+ {'EXIT', {hook_function_clause, _}} -> noError;
+ Result ->
+ ?vtrace("is_set_ok_variable -> Result: ~n ~p", [Result]),
+ validate_err(is_set_ok, Result, {Module, Func, Args})
+ end.
+
+%% ValueArg: <list-of-simple-tableops>
+is_set_ok_table(#me{mfa = {Module, Func, Args} = MFA}, ValueArg) ->
+ ?vtrace("is_set_ok_table -> entry with"
+ "~n MFA: ~p"
+ "~n ValueArg: ~p",[MFA,ValueArg]),
+ is_set_ok_all_rows(Module, Func, Args, sort_varbinds_rows(ValueArg), []).
+
+%% Try one row at a time. Sort varbinds to table-format.
+is_set_ok_all_rows(Module, Func, Args, [Row | Rows], Done) ->
+ ?vtrace("is_set_ok_all_rows -> entry with"
+ "~n MFA: ~p"
+ "~n Row: ~p"
+ "~n Done: ~p",[{Module,Func,Args},Row,Done]),
+ [{RowIndex, Cols}] = delete_org_index([Row]),
+ case dbg_apply(Module, Func, [is_set_ok, RowIndex, Cols | Args]) of
+ {'EXIT', {hook_undef, _}} ->
+ is_set_ok_all_rows(Module, Func, Args, Rows, [Row | Done]);
+ {'EXIT', {hook_function_clause, _}} ->
+ is_set_ok_all_rows(Module, Func, Args, Rows, [Row | Done]);
+ Result ->
+ case validate_err(table_is_set_ok, Result, {Module, Func, Args}) of
+ {noError, 0} ->
+ is_set_ok_all_rows(Module, Func, Args, Rows, [Row | Done]);
+ {ErrorStatus, ColNumber} ->
+ case undo_all_rows(Module, Func, Args, Done) of
+ {noError, 0} ->
+ {RowIndex, OrgCols} = Row,
+ validate_err(row_is_set_ok,
+ {ErrorStatus,
+ col_to_orgindex(ColNumber,OrgCols)},
+ {Module, Func, Args});
+ Error -> Error
+ end
+ end
+ end;
+is_set_ok_all_rows(_Module, _Func, _Args, [], _Done) ->
+ ?vtrace("is_set_ok_all_rows -> done",[]),
+ {noError, 0}.
+
+undo_varbinds([{TableOid, TableVbs} | Varbinds]) ->
+ TableOpsWithShortOids = deletePrefixes(TableOid, TableVbs),
+ [#ivarbind{mibentry = MibEntry}|_] = TableVbs,
+ case undo_table(MibEntry, TableOpsWithShortOids) of
+ {noError, 0} ->
+ undo_varbinds(Varbinds);
+ {Reason, Idx} ->
+ undo_varbinds(Varbinds),
+ {Reason, Idx}
+ end;
+undo_varbinds([IVarbind | Varbinds]) ->
+ #ivarbind{varbind = Varbind, mibentry = MibEntry} = IVarbind,
+ #varbind{value = Value, org_index = OrgIndex} = Varbind,
+ case undo_variable(MibEntry, Value) of
+ noError -> undo_varbinds(Varbinds);
+ Reason ->
+ undo_varbinds(Varbinds),
+ {Reason, OrgIndex}
+ end;
+undo_varbinds([]) -> {noError, 0}.
+
+%% Val = <a-value>
+undo_variable(#me{mfa = {Module, Func, Args}}, Val) ->
+ case dbg_apply(Module, Func, [undo, Val | Args]) of
+ {'EXIT', {hook_undef, _}} -> noError;
+ {'EXIT', {hook_function_clause, _}} -> noError;
+ Result -> validate_err(undo, Result, {Module, Func, Args})
+ end.
+
+%% ValueArg: <list-of-simple-tableops>
+undo_table(#me{mfa = {Module, Func, Args}}, ValueArg) ->
+ undo_all_rows(Module, Func, Args, sort_varbinds_rows(ValueArg)).
+
+undo_all_rows(Module, Func, Args, [Row | Rows]) ->
+ [{RowIndex, Cols}] = delete_org_index([Row]),
+ case dbg_apply(Module, Func, [undo, RowIndex, Cols | Args]) of
+ {'EXIT', {hook_undef, _}} ->
+ undo_all_rows(Module, Func, Args, Rows);
+ {'EXIT', {hook_function_clause, _}} ->
+ undo_all_rows(Module, Func, Args, Rows);
+ Result ->
+ case validate_err(table_undo, Result, {Module, Func, Args}) of
+ {noError, 0} -> undo_all_rows(Module, Func, Args, Rows);
+ {ErrorStatus, ColNumber} ->
+ {RowIndex, OrgCols} = Row,
+ undo_all_rows(Module, Func, Args, Rows),
+ OrgIdx = col_to_orgindex(ColNumber, OrgCols),
+ validate_err(row_undo, {ErrorStatus, OrgIdx},
+ {Module, Func, Args})
+ end
+ end;
+undo_all_rows(_Module, _Func, _Args, []) ->
+ {noError, 0}.
+
+try_set([{TableOid, TableVbs} | Varbinds]) ->
+ TableOpsWithShortOids = deletePrefixes(TableOid, TableVbs),
+ [#ivarbind{mibentry = MibEntry}|_] = TableVbs,
+ case set_value_to_tab_mibentry(MibEntry, TableOpsWithShortOids) of
+ {noError, 0} ->
+ try_set(Varbinds);
+ {ErrorStatus, Index} ->
+ undo_varbinds(Varbinds),
+ {ErrorStatus, find_org_index(Index, TableVbs)}
+ end;
+try_set([#ivarbind{varbind = Varbind, mibentry = MibEntry} | Varbinds]) ->
+ #varbind{value = Value, org_index = Index} = Varbind,
+ case set_value_to_var_mibentry(MibEntry, Value) of
+ noError -> try_set(Varbinds);
+ Error ->
+ undo_varbinds(Varbinds),
+ {Error, Index}
+ end;
+try_set([]) -> {noError, 0}.
+
+
+%% returns: ErrMsg
+set_value_to_var_mibentry(#me{mfa = {Module, Func, Args}},
+ SetArgs) ->
+ Result = dbg_apply(Module, Func, [set, SetArgs | Args]),
+ validate_err(set, Result, {Module, Func, Args}).
+
+%% returns: {ErrMsg, Idx}
+set_value_to_tab_mibentry(#me{mfa = {Module, Func, Args}},
+ SetArgs) ->
+ set_value_all_rows(Module, Func, Args,
+ sort_varbinds_rows(SetArgs)).
+
+
+set_value_all_rows(_Module, _Func, _Args, []) -> {noError, 0};
+set_value_all_rows(Module, Func, Args, [Row | Rows]) ->
+ [{RowIndex, Cols}] = delete_org_index([Row]),
+ Res = dbg_apply(Module, Func, [set, RowIndex, Cols | Args]),
+ case validate_err(table_set, Res, {Module, Func, Args}) of
+ {noError, 0} -> set_value_all_rows(Module, Func, Args, Rows);
+ {ErrCode, ColNumber} ->
+ {RowIndex, OrgCols} = Row,
+ OrgIndex = col_to_orgindex(ColNumber, OrgCols),
+ validate_err(row_set, {ErrCode, OrgIndex}, {Module, Func, Args})
+ end.
+
+sort_varbinds_rows(Varbinds) ->
+ snmpa_svbl:sort_varbinds_rows(Varbinds).
+delete_org_index(Indexes) ->
+ snmpa_svbl:delete_org_index(Indexes).
+col_to_orgindex(ColNumber, OrgCols) ->
+ snmpa_svbl:col_to_orgindex(ColNumber, OrgCols).
+
+find_org_index(ExternIndex, _SortedVarbinds) when ExternIndex =:= 0 -> 0;
+find_org_index(ExternIndex, SortedVarbinds) ->
+ VBs = lists:flatten(SortedVarbinds),
+ case length(VBs) of
+ Len when (ExternIndex =< Len) andalso (ExternIndex >= 1) ->
+ IVB = lists:nth(ExternIndex, VBs),
+ VB = IVB#ivarbind.varbind,
+ VB#varbind.org_index;
+ _Else ->
+ 0
+ end.
+
+validate_err(Type, Error, Mfa) ->
+ snmpa_agent:validate_err(Type, Error, Mfa).
+make_value_a_correct_value(Value, ASN1Type, Mfa) ->
+ snmpa_agent:make_value_a_correct_value(Value, ASN1Type, Mfa).
+
+%%-----------------------------------------------------------------
+%% Runtime debug support
+%%-----------------------------------------------------------------
+
+% XXX: This function match on the exakt return codes from EXIT
+% messages. As of this writing it was not decided if this is
+% the right way so don't blindly do things this way.
+%
+% We fake a real EXIT signal as the return value because the
+% result is passed to the function snmpa_agent:validate_err()
+% that expect it.
+
+dbg_apply(M,F,A) ->
+ Result =
+ case get(verbosity) of
+ false ->
+ (catch apply(M,F,A));
+ _ ->
+ ?vlog("~n apply: ~w,~w,~p~n", [M,F,A]),
+ Res = (catch apply(M,F,A)),
+ ?vlog("~n returned: ~p", [Res]),
+ Res
+ end,
+ case Result of
+ {'EXIT', {undef, [{M, F, A} | _]}} ->
+ {'EXIT', {hook_undef, {M, F, A}}};
+ {'EXIT', {function_clause, [{M, F, A} | _]}} ->
+ {'EXIT', {hook_function_clause, {M, F, A}}};
+
+ % XXX: Old format for compatibility
+ {'EXIT', {undef, {M, F, A}}} ->
+ {'EXIT', {hook_undef, {M, F, A}}};
+ {'EXIT', {function_clause, {M, F, A}}} ->
+ {'EXIT', {hook_function_clause, {M, F, A}}};
+
+ Result ->
+ Result
+ end.
+
diff --git a/lib/snmp/src/agent/snmpa_set_mechanism.erl b/lib/snmp/src/agent/snmpa_set_mechanism.erl
new file mode 100644
index 0000000000..4561fb035b
--- /dev/null
+++ b/lib/snmp/src/agent/snmpa_set_mechanism.erl
@@ -0,0 +1,42 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2004-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%
+%%
+-module(snmpa_set_mechanism).
+
+-export([behaviour_info/1]).
+
+behaviour_info(callbacks) ->
+ [{do_set, 2}, {do_subagent_set, 1}];
+behaviour_info(_) ->
+ undefined.
+
+
+%%-----------------------------------------------------------------
+%% do_set(MibView, UnsortedVarbinds)
+%%-----------------------------------------------------------------
+
+%%-----------------------------------------------------------------
+%% do_subagent_set(Args)
+%%
+%% This function is called when a subagent receives a message
+%% concerning some set_phase.
+%% Mandatory messages for all subagents:
+%% [phase_one, UnsortedVarbinds]
+%% [phase_two, set, UnsortedVarbinds]
+%% [phase_two, undo, UnsortedVarbinds]
+%%-----------------------------------------------------------------
diff --git a/lib/snmp/src/agent/snmpa_supervisor.erl b/lib/snmp/src/agent/snmpa_supervisor.erl
new file mode 100644
index 0000000000..5ef5914e18
--- /dev/null
+++ b/lib/snmp/src/agent/snmpa_supervisor.erl
@@ -0,0 +1,564 @@
+%%
+%% %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%
+%%
+-module(snmpa_supervisor).
+
+-behaviour(supervisor).
+
+%% External exports
+-export([start_link/2]).
+-export([start_sub_sup/1, start_master_sup/1]).
+-export([start_sub_agent/3, stop_sub_agent/1]).
+
+%% Internal exports
+-export([init/1, config/2]).
+
+
+-define(SERVER, ?MODULE).
+
+-include("snmpa_internal.hrl").
+-include("snmp_verbosity.hrl").
+-include("snmp_debug.hrl").
+
+
+%%-----------------------------------------------------------------
+%% Process structure
+%% =================
+%%
+%% ___________________ supervisor __________________
+%% / | | \ \
+%% ___misc_sup___ target_cache symbolic_store local_db agent_sup
+%% / | \ | |
+%% mib net_if note_store MA - SA
+%%
+%% The supervisor (one at each node) starts:
+%% snmpa_symbolic_store (one at each node)
+%% snmpa_local_db (one at each node)
+%% snmpa_target_cache (one at each node)
+%% MA - which starts
+%% own mib (hangs it under misc_sup)
+%% net_if (hangs it under misc_sup)
+%% note_store (hangs it under misc_sup)
+%% SAs - which starts
+%% own mib (hangs it under misc_sup)
+%%
+%% This structure is intended to make the agent fault tolerant. The
+%% agent processes (by far most code is in these processes) can be
+%% restarted in case of a failure, as all data needed by these procs
+%% are stored in the other procs. Any other process crash leads to
+%% that the entire snmpa_supervisor crashes. If it is restarted, all
+%% dynamically loaded mibs must be reloaded.
+%%
+%% It is up to the supervisor to configure the internal and
+%% external mibs. Note that the
+%% agent group (internal MIB) and sysObjectID *must* be configured
+%% in some way.
+%%-----------------------------------------------------------------
+
+start_link(Type, Opts) ->
+ ?d("start_link -> entry with"
+ "~n Type. ~p"
+ "~n Opts. ~p", [Type, Opts]),
+ start_link(get_agent_type(Opts), Opts, Type).
+
+start_link(sub, Opts, _Type) ->
+ start_sub_sup(Opts);
+start_link(master, Opts, normal) ->
+ start_master_sup(Opts);
+start_link(master, Opts, {takeover, Node}) ->
+ case start_master_sup(Opts) of
+ {ok, Pid} ->
+ OwnMibNames = get_own_loaded_mibs(),
+ try_load_other_loaded_mibs(Node, OwnMibNames),
+ {ok, Pid};
+ Else ->
+ Else
+ end.
+
+get_own_loaded_mibs() ->
+ AgentInfo = snmpa:info(snmp_master_agent),
+ [ Name || {Name, _, _} <- loaded_mibs(AgentInfo) ].
+
+try_load_other_loaded_mibs(Node, OwnMibs) ->
+ case rpc:call(Node, snmpa, info, [snmp_master_agent]) of
+ {badrpc, R} ->
+ error_msg("could not takeover loaded mibs: ~p", [R]);
+ AgentInfo ->
+ LoadedMibs = loaded_mibs(AgentInfo),
+ MibsToLoad = mibs_to_load(LoadedMibs, OwnMibs),
+ lists:foreach(fun(M) -> takeover_mib(M) end, MibsToLoad)
+ end.
+
+loaded_mibs(AgentInfo) ->
+ {value, {_, MibInfo}} = key1search(mib_server, AgentInfo),
+ {value, {_, LoadedMibs}} = key1search(loaded_mibs, MibInfo),
+ LoadedMibs.
+
+mibs_to_load(OtherMibs, OwnMibs) ->
+ [{N, S, F} || {N, S, F} <- OtherMibs, not lists:member(N, OwnMibs)].
+
+takeover_mib({'STANDARD-MIB', _Symbolic, _FileName}) ->
+ ok;
+takeover_mib({'SNMPv2-MIB', _Symbolic, _FileName}) ->
+ ok;
+takeover_mib({_MibName, _Symbolic, FileName}) ->
+ case snmpa:load_mibs(snmp_master_agent, [FileName]) of
+ ok ->
+ ok;
+ {error, R} ->
+ error_msg("could not reload mib ~p: ~p", [FileName, R])
+ end.
+
+
+%% ----------------------------------------------------------------
+
+start_sub_sup(Opts) ->
+ ?d("start_sub_sup -> entry with"
+ "~n Opts: ~p", [Opts]),
+ (catch do_start_sub_sup(Opts)).
+
+do_start_sub_sup(Opts) ->
+ verify_mandatory([db_dir], Opts),
+ ?d("do_start_sub_sup -> start (sub) supervisor",[]),
+ supervisor:start_link({local, ?SERVER}, ?MODULE, [sub, Opts]).
+
+start_master_sup(Opts) ->
+ (catch do_start_master_sup(Opts)).
+
+do_start_master_sup(Opts) ->
+ verify_mandatory([db_dir], Opts),
+ supervisor:start_link({local, ?SERVER}, ?MODULE, [master, Opts]).
+
+verify_mandatory([], _) ->
+ ok;
+verify_mandatory([Key|Keys], Opts) ->
+ case lists:keymember(Key, 1, Opts) of
+ true ->
+ verify_mandatory(Keys, Opts);
+ false ->
+ throw({error, {missing_mandatory_option, Key}})
+ end.
+
+
+%% ----------------------------------------------------------------
+
+start_sub_agent(ParentAgent, Subtree, Mibs)
+ when is_pid(ParentAgent) andalso is_list(Mibs) ->
+ ?d("start_sub_agent -> entry with"
+ "~n ParentAgent: ~p"
+ "~n Subtree: ~p"
+ "~n Mibs: ~p", [ParentAgent, Subtree, Mibs]),
+ snmpa_agent_sup:start_subagent(ParentAgent, Subtree, Mibs).
+
+stop_sub_agent(SubAgentPid) ->
+ snmpa_agent_sup:stop_subagent(SubAgentPid).
+
+
+%% ----------------------------------------------------------------
+
+init([AgentType, Opts]) ->
+ ?d("init -> entry with"
+ "~n AgentType: ~p"
+ "~n Opts: ~p", [AgentType, Opts]),
+
+ put(sname, asup),
+ put(verbosity,get_verbosity(Opts)),
+
+ ?vlog("starting",[]),
+
+ ?vdebug("create agent table",[]),
+ ets:new(snmp_agent_table, [set, public, named_table]),
+
+ ?vdebug("create community cache",[]),
+ ets:new(snmp_community_cache, [bag, public, named_table]),
+
+ %% Get restart type for the agent
+ Restart = get_opt(restart_type, Opts, permanent),
+ ?vdebug("agent restart type: ~w", [Restart]),
+
+ %% -- Agent type --
+ ets:insert(snmp_agent_table, {agent_type, AgentType}),
+
+ %% -- Prio --
+ Prio = get_opt(priority, Opts, normal),
+ ?vdebug("[agent table] store priority: ~p",[Prio]),
+ ets:insert(snmp_agent_table, {priority, Prio}),
+
+ %% -- Versions --
+ Vsns = get_opt(versions, Opts, [v1,v2,v3]),
+ ?vdebug("[agent table] store versions: ~p",[Vsns]),
+ ets:insert(snmp_agent_table, {versions, Vsns}),
+
+ %% -- DB-directory --
+ DbDir = get_opt(db_dir, Opts),
+ ?vdebug("[agent table] store db_dir: ~n ~p",[DbDir]),
+ ets:insert(snmp_agent_table, {db_dir, filename:join([DbDir])}),
+
+ DbInitError = get_opt(db_init_error, Opts, terminate),
+ ?vdebug("[agent table] store db_init_error: ~n ~p",[DbInitError]),
+ ets:insert(snmp_agent_table, {db_init_error, DbInitError}),
+
+ %% -- Error report module --
+ ErrorReportMod = get_opt(error_report_mod, Opts, snmpa_error_logger),
+ ?vdebug("[agent table] store error report module: ~w",[ErrorReportMod]),
+ ets:insert(snmp_agent_table, {error_report_mod, ErrorReportMod}),
+
+ %% -- mib storage --
+ MibStorage =
+ case get_opt(mib_storage, Opts, ets) of
+ dets ->
+ {dets, DbDir};
+ {dets, default} ->
+ {dets, DbDir};
+ {dets, default, Act} ->
+ {dets, DbDir, Act};
+ {ets, default} ->
+ {ets, DbDir};
+ mnesia ->
+ {mnesia, erlang:nodes()};
+ {mnesia, visible} ->
+ {mnesia, erlang:nodes(visible)};
+ {mnesia, connected} ->
+ {mnesia, erlang:nodes(connected)};
+ Other ->
+ Other
+ end,
+ ?vdebug("[agent table] store mib storage: ~w",[MibStorage]),
+ ets:insert(snmp_agent_table, {mib_storage, MibStorage}),
+
+ %% -- Agent mib storage --
+ AgentMibStorage = get_opt(agent_mib_storage, Opts, persistent),
+ %% ?vdebug("[agent table] store agent mib storage: ~w",[AgentMibStorage]),
+ ets:insert(snmp_agent_table, {agent_mib_storage, AgentMibStorage}),
+
+ %% -- System start time --
+ ?vdebug("[agent table] store system start time",[]),
+ ets:insert(snmp_agent_table, {system_start_time, snmp_misc:now(cs)}),
+
+ %% -- Symbolic store options --
+ SsOpts = get_opt(symbolic_store, Opts, []),
+ ?vdebug("[agent table] store symbolic store options: ~w",[SsOpts]),
+ ets:insert(snmp_agent_table, {symbolic_store, SsOpts}),
+
+ %% -- Local DB options --
+ LdbOpts = get_opt(local_db, Opts, []),
+ ?vdebug("[agent table] store local db options: ~w",[LdbOpts]),
+ ets:insert(snmp_agent_table, {local_db, LdbOpts}),
+
+ %% -- Target cache options --
+ TargetCacheOpts = get_opt(target_cache, Opts, []),
+ ?vdebug("[agent table] store target cache options: ~w",[TargetCacheOpts]),
+ ets:insert(snmp_agent_table, {target_cache, TargetCacheOpts}),
+
+ %% -- Specs --
+ SupFlags = {one_for_all, 0, 3600},
+
+ MiscSupSpec =
+ sup_spec(snmpa_misc_sup, [], Restart, infinity),
+
+ SymStoreOpts = [{mib_storage, MibStorage} | SsOpts],
+ SymStoreArgs = [Prio, SymStoreOpts],
+ SymStoreSpec =
+ worker_spec(snmpa_symbolic_store, SymStoreArgs, Restart, 2000),
+
+ LdbArgs = [Prio, DbDir, LdbOpts],
+ LocalDbSpec =
+ worker_spec(snmpa_local_db, LdbArgs, Restart, 5000),
+
+ ?vdebug("init VACM",[]),
+ snmpa_vacm:init(DbDir, DbInitError),
+
+ TargetCacheArgs = [Prio, TargetCacheOpts],
+ TargetCacheSpec =
+ worker_spec(snmpa_target_cache, TargetCacheArgs, transient, 2000, []),
+
+ Rest =
+ case AgentType of
+ master ->
+ % If we're starting the master, we must also
+ % configure the tables.
+
+ %% -- Config --
+ ConfOpts = get_opt(config, Opts, []),
+ ?vdebug("[agent table] store config options: ~p", [ConfOpts]),
+ ets:insert(snmp_agent_table, {config, ConfOpts}),
+
+ ConfigArgs = [Vsns, ConfOpts],
+ ConfigSpec =
+ worker_spec(config, ?MODULE, config, ConfigArgs,
+ transient, 2000, [?MODULE]),
+
+ %% -- Agent verbosity --
+ AgentVerb = get_opt(agent_verbosity, Opts, silence),
+
+ %% -- Discovery processing --
+ DiscoOpts = get_opt(discovery, Opts, []),
+ ?vdebug("[agent table] store discovery options: ~p", [DiscoOpts]),
+ ets:insert(snmp_agent_table, {discovery, DiscoOpts}),
+
+ %% -- Mibs --
+ Mibs = get_mibs(get_opt(mibs, Opts, []), Vsns),
+ ?vdebug("[agent table] store mibs: ~n ~p",[Mibs]),
+ ets:insert(snmp_agent_table, {mibs, Mibs}),
+
+ Ref = make_ref(),
+
+ %% -- Set module --
+ SetModule = get_opt(set_mechanism, Opts, snmpa_set),
+ ?vdebug("[agent table] store set-module: ~p",[SetModule]),
+ ets:insert(snmp_agent_table, {set_mechanism, ConfOpts}),
+
+ %% -- Authentication service --
+ AuthModule = get_opt(authentication_service, Opts, snmpa_acm),
+ ?vdebug("[agent table] store authentication service: ~w",
+ [AuthModule]),
+ ets:insert(snmp_agent_table,
+ {authentication_service, AuthModule}),
+
+ %% -- Multi-threaded --
+ MultiT = get_opt(multi_threaded, Opts, false),
+ ?vdebug("[agent table] store multi-threaded: ~p",[MultiT]),
+ ets:insert(snmp_agent_table, {multi_threaded, MultiT}),
+
+ %% -- Audit trail log --
+ case get_opt(audit_trail_log, Opts, not_found) of
+ not_found ->
+ ?vdebug("[agent table] no audit trail log",[]),
+ ok;
+ AtlOpts ->
+ ?vdebug("[agent table] "
+ "store audit trail log options: ~p",
+ [AtlOpts]),
+ ets:insert(snmp_agent_table,
+ {audit_trail_log, AtlOpts}),
+ ok
+ end,
+
+ %% -- MIB server --
+ MibsOpts = get_opt(mib_server, Opts, []),
+ ?vdebug("[agent table] store mib-server options: "
+ "~n ~p", [MibsOpts]),
+ ets:insert(snmp_agent_table, {mib_server, MibsOpts}),
+
+ %% -- Network interface --
+ NiOpts = get_opt(net_if, Opts, []),
+ ?vdebug("[agent table] store net-if options: "
+ "~n ~p", [NiOpts]),
+ ets:insert(snmp_agent_table, {net_if, NiOpts}),
+
+ %% -- Note store --
+ NsOpts = get_opt(note_store, Opts, []),
+ ?vdebug("[agent table] store note-store options: "
+ "~n ~p",[NsOpts]),
+ ets:insert(snmp_agent_table, {note_store, NsOpts}),
+
+ AgentOpts =
+ [{verbosity, AgentVerb},
+ {mibs, Mibs},
+ {mib_storage, MibStorage},
+ {set_mechanism, SetModule},
+ {authentication_service, AuthModule},
+ {multi_threaded, MultiT},
+ {versions, Vsns},
+ {net_if, NiOpts},
+ {mib_server, MibsOpts},
+ {note_store, NsOpts}|
+ get_opt(master_agent_options, Opts, [])],
+
+ AgentSpec =
+ worker_spec(snmpa_agent,
+ [Prio,snmp_master_agent,none,Ref,AgentOpts],
+ Restart, 15000),
+ AgentSupSpec =
+ sup_spec(snmpa_agent_sup, [AgentSpec],
+ Restart, infinity),
+ [ConfigSpec, AgentSupSpec];
+ _ ->
+ ?vdebug("[sub agent] spec for the agent supervisor",[]),
+ AgentSupSpec =
+ sup_spec(snmpa_agent_sup, [], Restart, infinity),
+ [AgentSupSpec]
+ end,
+ ?vdebug("init done",[]),
+ {ok, {SupFlags, [MiscSupSpec, SymStoreSpec, LocalDbSpec, TargetCacheSpec |
+ Rest]}}.
+
+get_mibs(Mibs, Vsns) ->
+ MibDir = filename:join(code:priv_dir(snmp), "mibs"),
+ StdMib =
+ case (lists:member(v2, Vsns) or lists:member(v3, Vsns)) of
+ true -> filename:join([MibDir, "SNMPv2-MIB"]);
+ false -> filename:join([MibDir, "STANDARD-MIB"])
+ end,
+ ?vdebug("add standard and v2 mibs",[]),
+ NMibs = add_mib(StdMib, Mibs, ["SNMPv2-MIB", "STANDARD-MIB"]),
+ case lists:member(v3, Vsns) of
+ true ->
+ ?vdebug("add v3 mibs",[]),
+ add_v3_mibs(MibDir, NMibs);
+ false ->
+ NMibs
+ end.
+
+add_v3_mibs(MibDir, Mibs) ->
+ NMibs = add_mib(filename:join(MibDir, "SNMP-FRAMEWORK-MIB"),
+ Mibs, ["SNMP-FRAMEWORK-MIB"]),
+ add_mib(filename:join(MibDir, "SNMP-MPD-MIB"),
+ NMibs, ["SNMP-MPD-MIB"]).
+
+add_mib(DefaultMib, [], _BaseNames) -> [DefaultMib];
+add_mib(DefaultMib, [Mib | T], BaseNames) ->
+ case lists:member(filename:basename(Mib), BaseNames) of
+ true -> [Mib | T]; % The user defined his own version of the mib
+ false -> [Mib | add_mib(DefaultMib, T, BaseNames)]
+ end.
+
+
+config(Vsns, Opts) ->
+ ?d("config -> entry with"
+ "~n Vsns. ~p"
+ "~n Opts. ~p", [Vsns, Opts]),
+ Verbosity = get_opt(verbosity, Opts, silence),
+ put(sname, conf),
+ put(verbosity, Verbosity),
+
+ ?vlog("starting", []),
+
+ ConfDir = get_opt(dir, Opts),
+ ForceLoad = get_opt(force_load, Opts, false),
+
+ case (catch conf(ConfDir, Vsns, ForceLoad)) of
+ ok ->
+ ?d("config -> done", []),
+ ignore;
+ {'EXIT', Reason} ->
+ ?vlog("configure failed (exit) with reason: ~p",[Reason]),
+ {error, {config_error, Reason}}
+ end.
+
+conf(Dir, Vsns, true) ->
+ conf1(Dir, Vsns, reconfigure);
+conf(Dir, Vsns, false) ->
+ conf1(Dir, Vsns, configure).
+
+conf1(Dir, Vsns, Func) ->
+ ?vlog("start ~w",[Func]),
+
+ ?vdebug("~w snmp_standard_mib",[Func]),
+ snmp_standard_mib:Func(Dir),
+ ?vdebug("init snmp_framework_mib",[]),
+ snmp_framework_mib:init(),
+ ?vdebug("configure snmp_framework_mib",[]),
+ snmp_framework_mib:configure(Dir),
+ ?vdebug("~w snmp_target_mib",[Func]),
+ snmp_target_mib:Func(Dir),
+ ?vdebug("~w snmp_notification_mib",[Func]),
+ snmp_notification_mib:Func(Dir),
+ ?vdebug("~w snmp_view_based_acm_mib",[Func]),
+ snmp_view_based_acm_mib:Func(Dir),
+ case lists:member(v1, Vsns) or lists:member(v2, Vsns) of
+ true ->
+ ?vdebug("we need to handle v1 and/or v2 =>~n"
+ " ~w snmp_community_mib",[Func]),
+ snmp_community_mib:Func(Dir);
+ false ->
+ ?vdebug("no need to handle v1 or v2",[]),
+ ok
+ end,
+ case lists:member(v3, Vsns) of
+ true ->
+ ?vdebug("we need to handle v3 =>~n"
+ " ~w snmp_user_based_sm_mib",[Func]),
+ snmp_user_based_sm_mib:Func(Dir);
+ false ->
+ ?vdebug("no need to handle v3",[]),
+ ok
+ end,
+ ?vdebug("conf done",[]),
+ ok.
+
+
+%% -------------------------------------
+
+sup_spec(Name, Args, Type, Time) ->
+ ?d("sup_spec -> entry with"
+ "~n Name: ~p"
+ "~n Args: ~p"
+ "~n Type: ~p"
+ "~n Time: ~p", [Name, Args, Type, Time]),
+ {Name,
+ {Name, start_link, Args},
+ Type, Time, supervisor, [Name, supervisor]}.
+
+worker_spec(Name, Args, Type, Time) ->
+ worker_spec(Name, Name, Args, Type, Time, []).
+
+worker_spec(Name, Args, Type, Time, Modules) ->
+ worker_spec(Name, Name, Args, Type, Time, Modules).
+
+worker_spec(Name, Mod, Args, Type, Time, Modules) ->
+ worker_spec(Name, Mod, start_link, Args, Type, Time, Modules).
+
+worker_spec(Name, Mod, Func, Args, Type, Time, Modules)
+ when is_atom(Name) andalso
+ is_atom(Mod) andalso
+ is_atom(Func) andalso
+ is_list(Args) andalso
+ is_atom(Type) andalso
+ is_list(Modules) ->
+ ?d("worker_spec -> entry with"
+ "~n Name: ~p"
+ "~n Mod: ~p"
+ "~n Func: ~p"
+ "~n Args: ~p"
+ "~n Type: ~p"
+ "~n Time: ~p"
+ "~n Modules: ~p", [Name, Mod, Func, Args, Type, Time, Modules]),
+ {Name,
+ {Mod, Func, Args},
+ Type, Time, worker, [Name] ++ Modules}.
+
+
+get_verbosity(Opts) ->
+ SupOpts = get_opt(supervisor, Opts, []),
+ get_opt(verbosity, SupOpts, silence).
+
+
+get_agent_type(Opts) ->
+ get_opt(agent_type, Opts, master).
+
+get_opt(Key, Opts) ->
+ snmp_misc:get_option(Key, Opts).
+
+get_opt(Key, Opts, Def) ->
+ snmp_misc:get_option(Key, Opts, Def).
+
+key1search(Key, List) ->
+ lists:keysearch(Key, 1, List).
+
+
+%%-----------------------------------------------------------------
+
+error_msg(F, A) ->
+ ?snmpa_error(F, A).
+
+% i(F) ->
+% i(F, []).
+
+% i(F, A) ->
+% io:format("~p:~p: " ++ F ++ "~n", [node(),?MODULE|A]).
diff --git a/lib/snmp/src/agent/snmpa_svbl.erl b/lib/snmp/src/agent/snmpa_svbl.erl
new file mode 100644
index 0000000000..9c2910580e
--- /dev/null
+++ b/lib/snmp/src/agent/snmpa_svbl.erl
@@ -0,0 +1,159 @@
+%%
+%% %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%
+%%
+-module(snmpa_svbl).
+
+-include("snmp_types.hrl").
+
+-define(VMODULE,"SVBL").
+-include("snmp_verbosity.hrl").
+
+-export([sort_varbindlist/2, sort_varbinds_rows/1, sa_split/1,
+ delete_org_index/1, col_to_orgindex/2]).
+
+%%-----------------------------------------------------------------
+%% Func: sort_varbindlist/2
+%% Args: Varbinds is a list of #varbind
+%% Purpose: Group all variablebindings that corresponds to logically
+%% the same entity, i.e. group all plain variables, all
+%% table operations for each table, all varbinds to each
+%% subagent.
+%% Returns: {VarbindsForThisAgent
+%% VarbindsForSubAgents} where
+%% VarbindsForThisAgent = List of {TableOid, List of #ivarbinds} |
+%% #ivarbinds
+%% VarbindsForSubAgents = List of {SubAgentPid,
+%% List of {SAOid, #varbinds}}
+%%-----------------------------------------------------------------
+sort_varbindlist(Mib, Varbinds) ->
+ {Vars, Tabs, Subagents} = partition(Mib, Varbinds),
+ {lists:append(Tabs, Vars), Subagents}.
+
+partition(Mib, Vbs) ->
+ partition(Mib, Vbs, [], [], []).
+partition(Mib, [Varbind | Vbs], Vars, Tabs, Subs) ->
+ #varbind{oid = Oid} = Varbind,
+ ?vtrace("partition -> Oid: ~p", [Oid]),
+ case snmpa_mib:lookup(Mib, Oid) of
+ {table_column, MibEntry, TableOid} ->
+ IVarbind = #ivarbind{varbind = fix_bits(Varbind, MibEntry),
+ mibentry = MibEntry},
+ NewTabs = insert_key(TableOid, IVarbind, Tabs),
+ partition(Mib, Vbs, Vars, NewTabs, Subs);
+ {subagent, SubagentPid, SAOid} ->
+ NewSubs = insert_key(SubagentPid, {SAOid, Varbind}, Subs),
+ partition(Mib, Vbs, Vars, Tabs, NewSubs);
+ {variable, MibEntry} ->
+ IVarbind = #ivarbind{varbind = fix_bits(Varbind, MibEntry),
+ mibentry = MibEntry},
+ partition(Mib, Vbs, [IVarbind | Vars], Tabs, Subs);
+ {false, ErrorCode} -> % ErrorCode = noSuchObject | noSuchInstance
+ IVarbind = #ivarbind{status = ErrorCode, varbind = Varbind},
+ partition(Mib, Vbs, [IVarbind | Vars], Tabs, Subs)
+ end;
+partition(_Mib, [], Vars, Subs, Tabs) ->
+ {Vars, Subs, Tabs}.
+
+% fix_bits(#varbind{bertype = 'BITS',
+% variabletype = 'OCTET STRING',
+% value = V} = VarBind, #me{asn1_type = A}) ->
+% VarBind#varbind{variabletype = 'BITS',
+% value = snmp_pdus:octet_str_to_bits(V)};
+fix_bits(VarBind, #me{asn1_type=A})
+ when ((A#asn1_type.bertype =:= 'BITS') andalso
+ (VarBind#varbind.variabletype =:= 'OCTET STRING') andalso
+ is_list(VarBind#varbind.value)) ->
+ VarBind#varbind{variabletype = 'BITS',
+ value = snmp_pdus:octet_str_to_bits(VarBind#varbind.value)};
+fix_bits(Vb,_me) -> Vb.
+
+insert_key(Key, Value, [{Key, Values} | Rest]) ->
+ [{Key, [Value | Values]} | Rest];
+insert_key(Key, Value, [{KeyX, Values} | Rest]) ->
+ [{KeyX, Values} | insert_key(Key, Value, Rest)];
+insert_key(Key, Value, []) ->
+ [{Key, [Value]}].
+
+%%-----------------------------------------------------------------
+%% Tranforms a list of {Oid, Vb} to a 2-tuple with all
+%% Oids and all Vbs. These lists will be reversed.
+%%-----------------------------------------------------------------
+sa_split(Vbs) -> sa_split(Vbs, [], []).
+sa_split([{SAOid, Vb} | T], Oids, Vbs) ->
+ sa_split(T, [SAOid | Oids], [Vb | Vbs]);
+sa_split([], Oids, Vbs) ->
+ {Oids, Vbs}.
+
+%%-----------------------------------------------------------------
+%% Func: sort_varbinds_rows/1
+%% Args: Varbinds is a list of {Oid, Value}.
+%% Pre: Varbinds is for one table.
+%% Purpose: Sorts all varbinds in Oid order, and in row order.
+%% Returns: list of Row where
+%% Row = {Indexes, List of Col} and
+%% Col = {ColNo, Value, OrgIndex} and
+%% OrgIndex is index in original varbind list.
+%%-----------------------------------------------------------------
+sort_varbinds_rows(Varbinds) ->
+ P = pack(Varbinds),
+ S = lists:keysort(1, P),
+ unpack(S).
+
+%% In: list of {Oid, Value}
+%% Out: list of {{Indexes_for_row, Col}, Val, Index}
+pack(V) -> pack(1, V).
+pack(Index, [{[Col | Rest], Val} | T]) ->
+ [{{Rest, Col}, Val, Index} | pack(Index+1, T)];
+pack(_, []) -> [].
+
+unpack([{{Rest, Col}, Val, Index} | T]) ->
+ unpack(Rest, [[{Col, Val, Index}]], T);
+unpack([]) -> [].
+
+unpack(Rest, [Row | Rows], [{{Rest, Col}, Val, Index} | T]) ->
+ unpack(Rest, [[{Col, Val, Index} | Row] | Rows], T);
+unpack(Rest, [Row | Rows], [{{Rest2, Col}, Val, Index} | T]) ->
+ unpack(Rest2, [[{Col, Val, Index}],
+ {Rest, lists:reverse(Row)} | Rows], T);
+unpack(Rest, [Row | Rows], []) ->
+ NewRow = {Rest, lists:reverse(Row)},
+ lists:reverse([NewRow | Rows]).
+
+%% OrgIndex should not be present when we call the is_set_ok/set/undo
+%% table functions. They just see the list of cols, and if an error
+%% occurs, they return the column nunber.
+%% Also, delete duplicate columns. If a SET is performed with duplicate
+%% columns, it is undefined which column to use. We just pick one.
+delete_org_index([{RowIndex, Cols} | Rows]) ->
+ [{RowIndex, doi(Cols)} | delete_org_index(Rows)];
+delete_org_index([]) -> [].
+
+doi([{Col, Val, OrgIndex}, {Col, _Val, _OrgIndex} | T]) ->
+ doi([{Col, Val, OrgIndex} | T]);
+doi([{Col, Val, _OrgIndex} | T]) ->
+ [{Col, Val} | doi(T)];
+doi([]) -> [].
+
+%% Maps the column number to OrgIndex.
+col_to_orgindex(0, _) -> 0;
+col_to_orgindex(Col, [{Col, _Val, OrgIndex}|_]) ->
+ OrgIndex;
+col_to_orgindex(Col, [_|Cols]) ->
+ col_to_orgindex(Col, Cols);
+col_to_orgindex(BadCol, _) ->
+ {false, BadCol}.
diff --git a/lib/snmp/src/agent/snmpa_symbolic_store.erl b/lib/snmp/src/agent/snmpa_symbolic_store.erl
new file mode 100644
index 0000000000..6c58ffde41
--- /dev/null
+++ b/lib/snmp/src/agent/snmpa_symbolic_store.erl
@@ -0,0 +1,711 @@
+%%
+%% %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%
+%%
+-module(snmpa_symbolic_store).
+
+%%----------------------------------------------------------------------
+%% This module implements a multipurpose symbolic store.
+%% 1) For internal and use from application: aliasname_to_value/1.
+%% If this was stored in the mib, deadlock would occur.
+%% 2 table_info/1. Getting information about a table. Used by default
+%% implementation of tables.
+%% 3) variable_info/1. Used by default implementation of variables.
+%% 4) notification storage. Used by snmpa_trap.
+%% There is one symbolic store per node and it uses the ets table
+%% snmp_agent_table, owned by the snmpa_supervisor.
+%%
+%%----------------------------------------------------------------------
+
+-include_lib("kernel/include/file.hrl").
+-include("snmp_types.hrl").
+-include("snmp_debug.hrl").
+-include("snmp_verbosity.hrl").
+-include("SNMPv2-MIB.hrl").
+
+
+%% API
+-export([start_link/2,
+ stop/0,
+ info/0,
+ backup/1,
+ aliasname_to_oid/1, oid_to_aliasname/1,
+ add_aliasnames/2, delete_aliasnames/1,
+ which_aliasnames/0,
+ which_tables/0,
+ which_variables/0,
+ enum_to_int/2, int_to_enum/2,
+ table_info/1, add_table_infos/2, delete_table_infos/1,
+ variable_info/1, add_variable_infos/2, delete_variable_infos/1,
+ get_notification/1, set_notification/2,
+ delete_notifications/1, which_notifications/0,
+ add_types/2, delete_types/1]).
+
+%% API (for quick access to the db, note that this is only reads).
+-export([get_db/0,
+ aliasname_to_oid/2, oid_to_aliasname/2,
+ enum_to_int/3, int_to_enum/3]).
+
+
+%% Internal exports
+-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2,
+ code_change/3]).
+
+-export([verbosity/1]).
+
+-define(SERVER, ?MODULE).
+
+-ifdef(snmp_debug).
+-define(GS_START_LINK(Prio, Opts),
+ gen_server:start_link({local, ?SERVER}, ?MODULE, [Prio, Opts],
+ [{debug,[trace]}])).
+-else.
+-define(GS_START_LINK(Prio, Opts),
+ gen_server:start_link({local, ?SERVER}, ?MODULE, [Prio, Opts], [])).
+-endif.
+
+-record(state, {db, backup}).
+-record(symbol, {key, mib_name, info}).
+
+
+%%-----------------------------------------------------------------
+%% Func: start_link/1
+%% Args: Prio is priority of mib-server
+%% Opts is a list of options
+%% Purpose: starts the mib server synchronized
+%% Returns: {ok, Pid} | {error, Reason}
+%%-----------------------------------------------------------------
+start_link(Prio, Opts) ->
+ ?d("start_link -> entry with"
+ "~n Prio: ~p"
+ "~n Opts: ~p", [Prio,Opts]),
+ ?GS_START_LINK(Prio,Opts).
+
+stop() ->
+ call(stop).
+
+info() ->
+ call(info).
+
+backup(BackupDir) ->
+ call({backup, BackupDir}).
+
+
+%%----------------------------------------------------------------------
+%% Returns: Db
+%%----------------------------------------------------------------------
+
+get_db() ->
+ call(get_db).
+
+
+%%----------------------------------------------------------------------
+%% Returns: {value, Oid} | false
+%%----------------------------------------------------------------------
+aliasname_to_oid(Aliasname) ->
+ call({aliasname_to_oid, Aliasname}).
+
+oid_to_aliasname(OID) ->
+ call({oid_to_aliasname, OID}).
+
+int_to_enum(TypeOrObjName, Int) ->
+ call({int_to_enum,TypeOrObjName,Int}).
+
+enum_to_int(TypeOrObjName, Enum) ->
+ call({enum_to_int,TypeOrObjName,Enum}).
+
+add_types(MibName, Types) ->
+ cast({add_types, MibName, Types}).
+
+delete_types(MibName) ->
+ cast({delete_types, MibName}).
+
+add_aliasnames(MibName, MEs) ->
+ cast({add_aliasnames, MibName, MEs}).
+
+delete_aliasnames(MibName) ->
+ cast({delete_aliasname, MibName}).
+
+which_aliasnames() ->
+ call(which_aliasnames).
+
+which_tables() ->
+ call(which_tables).
+
+which_variables() ->
+ call(which_variables).
+
+
+%%----------------------------------------------------------------------
+%% Returns: false|{value, Info}
+%%----------------------------------------------------------------------
+table_info(TableName) ->
+ call({table_info, TableName}).
+
+
+%%----------------------------------------------------------------------
+%% Returns: false|{value, Info}
+%%----------------------------------------------------------------------
+variable_info(VariableName) ->
+ call({variable_info, VariableName}).
+
+add_table_infos(MibName, TableInfos) ->
+ cast({add_table_infos, MibName, TableInfos}).
+
+delete_table_infos(MibName) ->
+ cast({delete_table_infos, MibName}).
+
+add_variable_infos(MibName, VariableInfos) ->
+ cast({add_variable_infos, MibName, VariableInfos}).
+
+delete_variable_infos(MibName) ->
+ cast({delete_variable_infos, MibName}).
+
+
+%%-----------------------------------------------------------------
+%% Store traps
+%%-----------------------------------------------------------------
+%% A notification is stored as {Key, Value}, where
+%% Key is the symbolic trap name, and Value is
+%% a #trap record.
+%%-----------------------------------------------------------------
+%% Returns: {value, Val} | undefined
+%%-----------------------------------------------------------------
+get_notification(Key) ->
+ call({get_notification, Key}).
+set_notification(Trap, MibName) ->
+ call({set_notification, MibName, Trap}).
+delete_notifications(MibName) ->
+ call({delete_notifications, MibName}).
+which_notifications() ->
+ call(which_notifications).
+
+
+verbosity(Verbosity) ->
+ cast({verbosity,Verbosity}).
+
+
+%%----------------------------------------------------------------------
+%% DB access (read) functions: Returns: {value, Oid} | false
+%%----------------------------------------------------------------------
+aliasname_to_oid(Db, Aliasname) ->
+ case snmpa_general_db:read(Db, {alias, Aliasname}) of
+ {value,#symbol{info = {Oid, _Enums}}} -> {value, Oid};
+ false -> false
+ end.
+
+oid_to_aliasname(Db,Oid) ->
+ case snmpa_general_db:read(Db, {oid, Oid}) of
+ {value,#symbol{info = Aliasname}} -> {value, Aliasname};
+ _ -> false
+ end.
+
+which_notifications(Db) ->
+ Pattern = #symbol{key = {trap, '_'}, _ = '_'},
+ Symbols = snmpa_general_db:match_object(Db, Pattern),
+ [{Name, Mib, Rec} || #symbol{key = {trap, Name},
+ mib_name = Mib,
+ info = Rec} <- Symbols].
+
+which_aliasnames(Db) ->
+ Pattern = #symbol{key = {alias, '_'}, _ = '_'},
+ Symbols = snmpa_general_db:match_object(Db, Pattern),
+ [Alias || #symbol{key = {alias, Alias}} <- Symbols].
+
+which_tables(Db) ->
+ Pattern = #symbol{key = {table_info, '_'}, _ = '_'},
+ Symbols = snmpa_general_db:match_object(Db, Pattern),
+ [Name || #symbol{key = {table_info, Name}} <- Symbols].
+
+which_variables(Db) ->
+ Pattern = #symbol{key = {variable_info, '_'}, _ = '_'},
+ Symbols = snmpa_general_db:match_object(Db, Pattern),
+ [Name || #symbol{key = {variable_info, Name}} <- Symbols].
+
+int_to_enum(Db,TypeOrObjName,Int) ->
+ case snmpa_general_db:read(Db, {alias, TypeOrObjName}) of
+ {value,#symbol{info = {_Oid, Enums}}} ->
+ case lists:keysearch(Int, 2, Enums) of
+ {value, {Enum, _Int}} -> {value, Enum};
+ false -> false
+ end;
+ false -> % Not an Aliasname ->
+ case snmpa_general_db:read(Db, {type, TypeOrObjName}) of
+ {value,#symbol{info = Enums}} ->
+ case lists:keysearch(Int, 2, Enums) of
+ {value, {Enum, _Int}} -> {value, Enum};
+ false -> false
+ end;
+ false ->
+ false
+ end
+ end.
+
+enum_to_int(Db, TypeOrObjName, Enum) ->
+ case snmpa_general_db:read(Db, {alias, TypeOrObjName}) of
+ {value,#symbol{info = {_Oid, Enums}}} ->
+ case lists:keysearch(Enum, 1, Enums) of
+ {value, {_Enum, Int}} -> {value, Int};
+ false -> false
+ end;
+ false -> % Not an Aliasname
+ case snmpa_general_db:read(Db, {type, TypeOrObjName}) of
+ {value,#symbol{info = Enums}} ->
+ case lists:keysearch(Enum, 1, Enums) of
+ {value, {_Enum, Int}} -> {value, Int};
+ false -> false
+ end;
+ false ->
+ false
+ end
+ end.
+
+
+%%----------------------------------------------------------------------
+%% DB access (read) functions: Returns: false|{value, Info}
+%%----------------------------------------------------------------------
+table_info(Db,TableName) ->
+ case snmpa_general_db:read(Db, {table_info, TableName}) of
+ {value,#symbol{info = Info}} -> {value, Info};
+ false -> false
+ end.
+
+
+%%----------------------------------------------------------------------
+%% DB access (read) functions: Returns: false|{value, Info}
+%%----------------------------------------------------------------------
+variable_info(Db,VariableName) ->
+ case snmpa_general_db:read(Db, {variable_info, VariableName}) of
+ {value,#symbol{info = Info}} -> {value, Info};
+ false -> false
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Implementation
+%%----------------------------------------------------------------------
+
+init([Prio,Opts]) ->
+ ?d("init -> entry with"
+ "~n Prio: ~p"
+ "~n Opts: ~p", [Prio,Opts]),
+ case (catch do_init(Prio, Opts)) of
+ {ok, State} ->
+ {ok, State};
+ Error ->
+ config_err("failed starting symbolic-store: ~n~p", [Error]),
+ {stop, {error, Error}}
+ end.
+
+do_init(Prio, Opts) ->
+ process_flag(priority, Prio),
+ process_flag(trap_exit, true),
+ put(sname,ss),
+ put(verbosity,get_verbosity(Opts)),
+ ?vlog("starting",[]),
+ Storage = get_mib_storage(Opts),
+ %% type = bag solves the problem with import and multiple
+ %% object/type definitions.
+ Db = snmpa_general_db:open(Storage, snmpa_symbolic_store,
+ symbol, record_info(fields,symbol), bag),
+ S = #state{db = Db},
+ ?vdebug("started",[]),
+ {ok, S}.
+
+
+handle_call(get_db, _From, #state{db = DB} = S) ->
+ ?vlog("get db",[]),
+ {reply, DB, S};
+
+handle_call({table_info, TableName}, _From, #state{db = DB} = S) ->
+ ?vlog("table info: ~p",[TableName]),
+ Res = table_info(DB, TableName),
+ ?vdebug("table info result: ~p",[Res]),
+ {reply, Res, S};
+
+handle_call({variable_info, VariableName}, _From, #state{db = DB} = S) ->
+ ?vlog("variable info: ~p",[VariableName]),
+ Res = variable_info(DB, VariableName),
+ ?vdebug("variable info result: ~p",[Res]),
+ {reply, Res, S};
+
+handle_call({aliasname_to_oid, Aliasname}, _From, #state{db = DB} = S) ->
+ ?vlog("aliasname to oid: ~p",[Aliasname]),
+ Res = aliasname_to_oid(DB,Aliasname),
+ ?vdebug("aliasname to oid result: ~p",[Res]),
+ {reply, Res, S};
+
+handle_call({oid_to_aliasname, Oid}, _From, #state{db = DB} = S) ->
+ ?vlog("oid to aliasname: ~p",[Oid]),
+ Res = oid_to_aliasname(DB, Oid),
+ ?vdebug("oid to aliasname result: ~p",[Res]),
+ {reply, Res, S};
+
+handle_call(which_aliasnames, _From, #state{db = DB} = S) ->
+ ?vlog("which aliasnames",[]),
+ Res = which_aliasnames(DB),
+ ?vdebug("which aliasnames: ~p",[Res]),
+ {reply, Res, S};
+
+handle_call(which_tables, _From, #state{db = DB} = S) ->
+ ?vlog("which tables",[]),
+ Res = which_tables(DB),
+ ?vdebug("which tables: ~p",[Res]),
+ {reply, Res, S};
+
+handle_call(which_variables, _From, #state{db = DB} = S) ->
+ ?vlog("which variables",[]),
+ Res = which_variables(DB),
+ ?vdebug("which variables: ~p",[Res]),
+ {reply, Res, S};
+
+handle_call({enum_to_int, TypeOrObjName, Enum}, _From, #state{db = DB} = S) ->
+ ?vlog("enum to int: ~p, ~p",[TypeOrObjName,Enum]),
+ Res = enum_to_int(DB, TypeOrObjName, Enum),
+ ?vdebug("enum to int result: ~p",[Res]),
+ {reply, Res, S};
+
+handle_call({int_to_enum, TypeOrObjName, Int}, _From, #state{db = DB} = S) ->
+ ?vlog("int to enum: ~p, ~p",[TypeOrObjName,Int]),
+ Res = int_to_enum(DB, TypeOrObjName, Int),
+ ?vdebug("int to enum result: ~p",[Res]),
+ {reply, Res, S};
+
+handle_call({set_notification, MibName, Trap}, _From, #state{db = DB} = S) ->
+ ?vlog("set notification:"
+ "~n ~p~n ~p", [MibName,Trap]),
+ set_notif(DB, MibName, Trap),
+ {reply, true, S};
+
+handle_call({delete_notifications, MibName}, _From, #state{db = DB} = S) ->
+ ?vlog("delete notification: ~p",[MibName]),
+ delete_notif(DB, MibName),
+ {reply, true, S};
+
+handle_call(which_notifications, _From, #state{db = DB} = S) ->
+ ?vlog("which notifications", []),
+ Reply = which_notifications(DB),
+ {reply, Reply, S};
+
+handle_call({get_notification, Key}, _From, #state{db = DB} = S) ->
+ ?vlog("get notification: ~p",[Key]),
+ Res = get_notif(DB, Key),
+ ?vdebug("get notification result: ~p",[Res]),
+ {reply, Res, S};
+
+handle_call(info, _From, #state{db = DB} = S) ->
+ ?vlog("info",[]),
+ Info = get_info(DB),
+ {reply, Info, S};
+
+handle_call({backup, BackupDir}, From, #state{db = DB} = S) ->
+ ?vlog("info to ~p",[BackupDir]),
+ Pid = self(),
+ V = get(verbosity),
+ case file:read_file_info(BackupDir) of
+ {ok, #file_info{type = directory}} ->
+ BackupServer =
+ erlang:spawn_link(
+ fun() ->
+ put(sname, albs),
+ put(verbosity, V),
+ Dir = filename:join([BackupDir]),
+ Reply = snmpa_general_db:backup(DB, Dir),
+ Pid ! {backup_done, Reply},
+ unlink(Pid)
+ end),
+ ?vtrace("backup server: ~p", [BackupServer]),
+ {noreply, S#state{backup = {BackupServer, From}}};
+ {ok, _} ->
+ {reply, {error, not_a_directory}, S};
+ Error ->
+ {reply, Error, S}
+ end;
+
+handle_call(stop, _From, S) ->
+ ?vlog("stop",[]),
+ {stop, normal, ok, S};
+
+handle_call(Req, _From, S) ->
+ info_msg("received unknown request: ~n~p", [Req]),
+ Reply = {error, {unknown, Req}},
+ {reply, Reply, S}.
+
+
+handle_cast({add_types, MibName, Types}, #state{db = DB} = S) ->
+ ?vlog("add types for ~p:",[MibName]),
+ F = fun(#asn1_type{assocList = Alist, aliasname = Name}) ->
+ case snmp_misc:assq(enums, Alist) of
+ {value, Es} ->
+ ?vlog("add type~n ~p -> ~p",[Name,Es]),
+ Rec = #symbol{key = {type, Name},
+ mib_name = MibName,
+ info = Es},
+ snmpa_general_db:write(DB, Rec);
+ false -> done
+ end
+ end,
+ lists:foreach(F, Types),
+ {noreply, S};
+
+handle_cast({delete_types, MibName}, #state{db = DB} = S) ->
+ ?vlog("delete types: ~p",[MibName]),
+ Pattern = #symbol{key = {type, '_'}, mib_name = MibName, info = '_'},
+ snmpa_general_db:match_delete(DB, Pattern),
+ {noreply, S};
+
+handle_cast({add_aliasnames, MibName, MEs}, #state{db = DB} = S) ->
+ ?vlog("add aliasnames for ~p:",[MibName]),
+ F = fun(#me{aliasname = AN, oid = Oid, asn1_type = AT}) ->
+ Enums =
+ case AT of
+ #asn1_type{assocList = Alist} ->
+ case lists:keysearch(enums, 1, Alist) of
+ {value, {enums, Es}} -> Es;
+ _ -> []
+ end;
+ _ -> []
+ end,
+ write_alias(AN, DB, Enums, MibName, Oid)
+ end,
+ lists:foreach(F, MEs),
+ {noreply, S};
+
+handle_cast({delete_aliasname, MibName}, #state{db = DB} = S) ->
+ ?vlog("delete aliasname: ~p",[MibName]),
+ Pattern1 = #symbol{key = {alias, '_'}, mib_name = MibName, info = '_'},
+ snmpa_general_db:match_delete(DB, Pattern1),
+ Pattern2 = #symbol{key = {oid, '_'}, mib_name = MibName, info = '_'},
+ snmpa_general_db:match_delete(DB, Pattern2),
+ {noreply, S};
+
+handle_cast({add_table_infos, MibName, TableInfos}, #state{db = DB} = S) ->
+ ?vlog("add table infos for ~p:",[MibName]),
+ F = fun({Name, TableInfo}) ->
+ ?vlog("add table info~n ~p -> ~p",
+ [Name, TableInfo]),
+ Rec = #symbol{key = {table_info, Name},
+ mib_name = MibName,
+ info = TableInfo},
+ snmpa_general_db:write(DB, Rec)
+ end,
+ lists:foreach(F, TableInfos),
+ {noreply, S};
+
+handle_cast({delete_table_infos, MibName}, #state{db = DB} = S) ->
+ ?vlog("delete table infos: ~p",[MibName]),
+ Pattern = #symbol{key = {table_info, '_'}, mib_name = MibName, info = '_'},
+ snmpa_general_db:match_delete(DB, Pattern),
+ {noreply, S};
+
+handle_cast({add_variable_infos, MibName, VariableInfos},
+ #state{db = DB} = S) ->
+ ?vlog("add variable infos for ~p:",[MibName]),
+ F = fun({Name, VariableInfo}) ->
+ ?vlog("add variable info~n ~p -> ~p",
+ [Name,VariableInfo]),
+ Rec = #symbol{key = {variable_info, Name},
+ mib_name = MibName,
+ info = VariableInfo},
+ snmpa_general_db:write(DB, Rec)
+ end,
+ lists:foreach(F, VariableInfos),
+ {noreply, S};
+
+handle_cast({delete_variable_infos, MibName}, #state{db = DB} = S) ->
+ ?vlog("delete variable infos: ~p",[MibName]),
+ Pattern = #symbol{key = {variable_info,'_'},
+ mib_name = MibName,
+ info = '_'},
+ snmpa_general_db:match_delete(DB, Pattern),
+ {noreply, S};
+
+handle_cast({verbosity,Verbosity}, State) ->
+ ?vlog("verbosity: ~p -> ~p",[get(verbosity),Verbosity]),
+ put(verbosity,snmp_verbosity:validate(Verbosity)),
+ {noreply, State};
+
+handle_cast(Msg, S) ->
+ info_msg("received unknown message: ~n~p", [Msg]),
+ {noreply, S}.
+
+
+handle_info({'EXIT', Pid, Reason}, #state{backup = {Pid, From}} = S) ->
+ ?vlog("backup server (~p) exited for reason ~n~p", [Pid, Reason]),
+ gen_server:reply(From, {error, Reason}),
+ {noreply, S#state{backup = undefined}};
+
+handle_info({'EXIT', Pid, Reason}, S) ->
+ %% The only other processes we should be linked to are
+ %% either the master agent or our supervisor, so die...
+ {stop, {received_exit, Pid, Reason}, S};
+
+handle_info({backup_done, Reply}, #state{backup = {_, From}} = S) ->
+ ?vlog("backup done:"
+ "~n Reply: ~p", [Reply]),
+ gen_server:reply(From, Reply),
+ {noreply, S#state{backup = undefined}};
+
+handle_info(Info, S) ->
+ info_msg("received unknown info: ~n~p", [Info]),
+ {noreply, S}.
+
+
+terminate(Reason, S) ->
+ ?vlog("terminate: ~p",[Reason]),
+ snmpa_general_db:close(S#state.db).
+
+
+%%----------------------------------------------------------
+%% Code change
+%%----------------------------------------------------------
+
+% downgrade
+code_change({down, _Vsn}, #state{db = DB, backup = B}, downgrade_to_pre_4_7) ->
+ ?d("code_change(down) -> entry", []),
+ stop_backup_server(B),
+ S = {state, DB},
+ {ok, S};
+
+% upgrade
+code_change(_Vsn, S, upgrade_from_pre_4_7) ->
+ ?d("code_change(up) -> entry", []),
+ {state, DB} = S,
+ S1 = #state{db = DB},
+ {ok, S1};
+
+code_change(_Vsn, S, _Extra) ->
+ ?d("code_change -> entry [do nothing]", []),
+ {ok, S}.
+
+
+stop_backup_server(undefined) ->
+ ok;
+stop_backup_server({Pid, _}) when is_pid(Pid) ->
+ exit(Pid, kill).
+
+
+
+%%-----------------------------------------------------------------
+%% Trap operations (write, read, delete)
+%%-----------------------------------------------------------------
+%% A notification is stored as {Key, Value}, where
+%% Key is the symbolic trap name, and Value is
+%% a #trap or a #notification record.
+%%-----------------------------------------------------------------
+%% Returns: {value, Value} | undefined
+%%-----------------------------------------------------------------
+get_notif(Db, Key) ->
+ case snmpa_general_db:read(Db, {trap, Key}) of
+ {value,#symbol{info = Value}} -> {value, Value};
+ false -> undefined
+ end.
+
+set_notif(Db, MibName, Trap) when is_record(Trap, trap) ->
+ #trap{trapname = Name} = Trap,
+ Rec = #symbol{key = {trap, Name}, mib_name = MibName, info = Trap},
+ %% convert old v1 trap to oid
+ Oid = case Trap#trap.enterpriseoid of
+ ?snmp ->
+ ?snmpTraps ++ [Trap#trap.specificcode + 1];
+ Oid0 ->
+ Oid0 ++ [0, Trap#trap.specificcode]
+ end,
+ write_alias(Name, Db, MibName, Oid),
+ snmpa_general_db:write(Db, Rec);
+set_notif(Db, MibName, Trap) ->
+ #notification{trapname = Name, oid = Oid} = Trap,
+ Rec = #symbol{key = {trap, Name}, mib_name = MibName, info = Trap},
+ write_alias(Name, Db, MibName, Oid),
+ snmpa_general_db:write(Db, Rec).
+
+delete_notif(Db, MibName) ->
+ Pattern = #symbol{key = {trap, '_'}, mib_name = MibName, info = '_'},
+ snmpa_general_db:match_delete(Db, Pattern).
+
+
+write_alias(AN, DB, MibName, Oid) ->
+ write_alias(AN, DB, [], MibName, Oid).
+
+write_alias(AN, DB, Enums, MibName, Oid) ->
+ ?vlog("add alias~n ~p -> {~p,~p}",[AN, Oid, Enums]),
+ Rec1 = #symbol{key = {alias, AN},
+ mib_name = MibName,
+ info = {Oid,Enums}},
+ snmpa_general_db:write(DB, Rec1),
+ ?vlog("add oid~n ~p -> ~p",[Oid, AN]),
+ Rec2 = #symbol{key = {oid, Oid},
+ mib_name = MibName,
+ info = AN},
+ snmpa_general_db:write(DB, Rec2).
+
+%% -------------------------------------
+
+get_info(DB) ->
+ ProcSize = proc_mem(self()),
+ DbSz = tab_size(DB),
+ [{process_memory, ProcSize}, {db_memory, DbSz}].
+
+proc_mem(P) when is_pid(P) ->
+ case (catch erlang:process_info(P, memory)) of
+ {memory, Sz} when is_integer(Sz) ->
+ Sz;
+ _ ->
+ undefined
+ end.
+%% proc_mem(_) ->
+%% undefined.
+
+tab_size(DB) ->
+ case (catch snmpa_general_db:info(DB, memory)) of
+ Sz when is_integer(Sz) ->
+ Sz;
+ _ ->
+ undefined
+ end.
+
+
+
+%% -------------------------------------
+
+get_verbosity(L) ->
+ snmp_misc:get_option(verbosity,L,?default_verbosity).
+
+get_mib_storage(L) ->
+ snmp_misc:get_option(mib_storage,L,ets).
+
+
+%% -------------------------------------
+
+call(Req) ->
+ call(Req, infinity).
+
+call(Req, Timeout) ->
+ gen_server:call(?SERVER, Req, Timeout).
+
+cast(Msg) ->
+ gen_server:cast(?SERVER, Msg).
+
+
+%% ----------------------------------------------------------------
+
+info_msg(F, A) ->
+ error_logger:info_msg("~w: " ++ F ++ "~n", [?MODULE|A]).
+
+config_err(F, A) ->
+ snmpa_error:config_err(F, A).
+
diff --git a/lib/snmp/src/agent/snmpa_target_cache.erl b/lib/snmp/src/agent/snmpa_target_cache.erl
new file mode 100644
index 0000000000..6fdecacc68
--- /dev/null
+++ b/lib/snmp/src/agent/snmpa_target_cache.erl
@@ -0,0 +1,891 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2006-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%
+%%
+-module(snmpa_target_cache).
+
+-behaviour(gen_server).
+
+%% External exports
+-export([start_link/2, stop/0, verbosity/1]).
+
+-export([
+ invalidate/0, % invalidate/1, invalidate/2,
+ targets/1, targets/2
+ ]).
+
+%% gen_server callbacks
+-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2,
+ code_change/3]).
+
+-ifdef(snmp_qc).
+-export([
+ lock/1,
+ unlock/0,
+ upgrade_lock/0,
+ downgrade_lock/0
+ ]).
+-endif.
+
+-include("snmpa_internal.hrl").
+-include("snmp_debug.hrl").
+-include("snmp_verbosity.hrl").
+
+
+-record(state,
+ {
+ active_count = 0,
+ writer = false, % Active or waiting write-lock
+ waiting = [] % Waiting lockers
+ }
+ ).
+-record(locker, {pid, from, mon_ref, type, state}).
+
+
+-define(SERVER, ?MODULE).
+-define(CACHE, ?MODULE).
+-define(LOCKER_TAB, snmpa_target_cache_locker).
+
+
+-ifndef(default_verbosity).
+-define(default_verbosity,silence).
+-endif.
+
+-ifdef(snmp_debug).
+-define(GS_START_LINK(Prio, Opts),
+ gen_server:start_link({local, ?SERVER}, ?MODULE,
+ [Prio, Opts], [{debug,[trace]}])).
+-else.
+-define(GS_START_LINK(Prio, Opts),
+ gen_server:start_link({local, ?SERVER}, ?MODULE,
+ [Prio, Opts], [])).
+-endif.
+
+
+%%%-------------------------------------------------------------------
+%%% API
+%%%-------------------------------------------------------------------
+start_link(Prio, Opts) ->
+ ?d("start_link -> entry with"
+ "~n Prio: ~p"
+ "~n Opts: ~p", [Prio, Opts]),
+ ?GS_START_LINK(Prio, Opts).
+
+
+stop() ->
+ call(stop).
+
+
+verbosity(V) ->
+ call({verbosity, V}).
+
+
+%% Targets -> notify_targets()
+%% notify_targets() -> [notify_target()]
+%% notify_target() -> {NotifyName, target()}
+%% target() -> {DestAddr, TargetName, TargetParams, NotifyType}
+
+targets(TargetsFun) when is_function(TargetsFun) ->
+ Pat = {{'_', '$1'}, '$2'},
+ get_targets(Pat, TargetsFun).
+
+targets(TargetsFun, NotifyName) when is_function(TargetsFun) ->
+ Pat = {{NotifyName, '$1'}, '$2'},
+ get_targets(Pat, TargetsFun).
+
+get_targets(Pat, TargetsFun) ->
+ lock(read), % Get a read lock
+ Targets =
+ case ets:lookup(?CACHE, state) of
+ [{state, invalid}] ->
+ upgrade_lock(), % Upgrade to write lock
+ %% Make sure it's still invalid
+ case ets:lookup(?CACHE, state) of
+ [{state, invalid}] ->
+ insert_all( TargetsFun() ),
+ ets:insert(?CACHE, {state, valid});
+ _ ->
+ ok % This means that someone got there before us
+ end,
+ downgrade_lock(), % Downgrade to read lock
+ get_targets(Pat);
+ [{state, valid}] ->
+ get_targets(Pat)
+ end,
+ unlock(), % Release the read lock
+ Targets.
+
+get_targets(Pat) ->
+ NotifyTargets = ets:match(?CACHE, Pat),
+ [{DestAddr, TargetName, TargetParams, NotifyType} ||
+ [TargetName, {DestAddr, TargetParams, NotifyType}] <-
+ NotifyTargets].
+
+invalidate() ->
+ lock(write),
+ case ets:lookup(?CACHE, state) of
+ [{state, invalid}] ->
+ ok;
+ [{state, valid}] ->
+ delete_all(),
+ ets:insert(?CACHE, {state, invalid})
+ end,
+ unlock(),
+ ok.
+
+
+%%%-------------------------------------------------------------------
+%%% Callback functions from gen_server
+%%%-------------------------------------------------------------------
+
+%%--------------------------------------------------------------------
+%% Func: init/1
+%% Returns: {ok, State} |
+%% {ok, State, Timeout} |
+%% ignore |
+%% {stop, Reason}
+%%--------------------------------------------------------------------
+init([Prio, Opts]) ->
+ case (catch do_init(Prio, Opts)) of
+ {ok, State} ->
+ ?vdebug("started",[]),
+ {ok, State};
+ {error, Reason} ->
+ config_err("failed starting target-cache server: ~n~p", [Reason]),
+ {stop, {error, Reason}};
+ Error ->
+ config_err("failed starting target-cache server: ~n~p", [Error]),
+ {stop, {error, Error}}
+ end.
+
+
+do_init(Prio, Opts) ->
+ process_flag(priority, Prio),
+ process_flag(trap_exit, true),
+ put(sname, tcs),
+ put(verbosity, get_opt(verbosity, Opts, ?default_verbosity)),
+ ?vlog("starting",[]),
+ ets:new(?CACHE, [set, named_table, public]),
+ ets:insert(?CACHE, {state, invalid}),
+ ets:new(?LOCKER_TAB, [set, named_table, {keypos, #locker.pid}]),
+ {ok, #state{}}.
+
+
+%%--------------------------------------------------------------------
+%% Func: handle_call/3
+%% Returns: {reply, Reply, State} |
+%% {reply, Reply, State, Timeout} |
+%% {noreply, State} |
+%% {noreply, State, Timeout} |
+%% {stop, Reason, Reply, State} | (terminate/2 is called)
+%% {stop, Reason, State} (terminate/2 is called)
+%%--------------------------------------------------------------------
+
+%%%-----------------------------------------------------------------
+
+%%
+%% (1) As long as there are no _waiting_ or active write locks,
+%% read-locks will allways be granted
+%% (2) When there are no active readers, write-locks will be
+%% granted.
+%% (3) When there are active readers (clients with read-locks),
+%% a write-lock will have to wait for _all_ the read-locks
+%% to be released.
+%% (4) If there is a waiting write-lock, all subsequent lock-
+%% requests will have to wait.
+%% (5) If there is an active write-lock, all subsequent lock-
+%% requests will have to wait.
+%%
+
+monitor(Pid) -> erlang:monitor(process, Pid).
+-ifdef(SNMP_R10).
+demonitor(Ref) ->
+ erlang:demonitor(Ref),
+ receive
+ {_, Ref, _, _, _} ->
+ true
+ after 0 ->
+ true
+ end.
+-else.
+demonitor(Ref) ->
+ erlang:demonitor(Ref, [flush]).
+-endif.
+
+
+%% (1) No write_lock active or waiting
+handle_call({lock, read = Type, infinity}, {Pid, _} = From,
+ #state{active_count = Cnt, writer = false} = State) ->
+ ?vlog("lock(read, infinity) -> "
+ "entry when no waiting or active writer with"
+ "~n Pid: ~p"
+ "~n Cnt: ~p", [Pid, Cnt]),
+ MonRef = monitor(Pid),
+ Locker = #locker{pid = Pid,
+ from = From,
+ mon_ref = MonRef,
+ type = Type,
+ state = active},
+ ets:insert(?LOCKER_TAB, Locker),
+%% ?vtrace("lock(read, infinity) -> done when"
+%% "~n Lockers: ~p", [ets:tab2list(?LOCKER_TAB)]),
+ {reply, ok, State#state{active_count = inc(Cnt)}};
+
+%% (4,5) There is waiting or active write locks
+handle_call({lock, read = Type, infinity}, {Pid, _} = From, State) ->
+ ?vlog("lock(read, infinity) -> "
+ "entry when active or waiting write locks with"
+ "~n Pid: ~p", [Pid]),
+ MonRef = monitor(Pid),
+ Locker = #locker{pid = Pid,
+ from = From,
+ mon_ref = MonRef,
+ type = Type,
+ state = waiting},
+ ets:insert(?LOCKER_TAB, Locker),
+ Waiting = lists:append(State#state.waiting, [Pid]),
+%% ?vtrace("lock(read, infinity) -> done when"
+%% "~n Waiting: ~p"
+%% "~n Lockers: ~p", [Waiting, ets:tab2list(?LOCKER_TAB)]),
+ {noreply, State#state{waiting = Waiting}};
+
+%% (2) No active locks
+%% Since there are no active lockers, that also means that
+%% there is no lockers waiting.
+handle_call({lock, write = Type, infinity}, {Pid, _} = From,
+ #state{active_count = 0, writer = false} = State) ->
+ ?vlog("lock(write, infinity) -> "
+ "entry when no active lockers with"
+ "~n Pid: ~p", [Pid]),
+ MonRef = monitor(Pid),
+ Locker = #locker{pid = Pid,
+ from = From,
+ mon_ref = MonRef,
+ type = Type,
+ state = active},
+ ets:insert(?LOCKER_TAB, Locker),
+%% ?vtrace("lock(write, infinity) -> done when"
+%% "~n Lockers: ~p", [ets:tab2list(?LOCKER_TAB)]),
+ {reply, ok, State#state{active_count = 1, writer = true}};
+
+%% (3) No waiting or active writers, but at least one active reader
+handle_call({lock, write = Type, infinity}, {Pid, _} = From,
+ #state{writer = false} = State) ->
+ ?vlog("lock(write, infinity) -> "
+ "entry when active lockers with"
+ "~n Pid: ~p", [Pid]),
+ MonRef = monitor(Pid),
+ Locker = #locker{pid = Pid,
+ from = From,
+ mon_ref = MonRef,
+ type = Type,
+ state = waiting},
+ ets:insert(?LOCKER_TAB, Locker),
+ Waiting = lists:append(State#state.waiting, [Pid]),
+%% ?vtrace("lock(write, infinity) -> done when"
+%% "~n Waiting: ~p"
+%% "~n Lockers: ~p", [Waiting, ets:tab2list(?LOCKER_TAB)]),
+ {noreply, State#state{waiting = Waiting, writer = true}};
+
+handle_call({lock, write = Type, infinity}, {Pid, _} = From,
+ #state{writer = true} = State) ->
+ ?vlog("lock(write, infinity) -> entry with"
+ "~n Pid: ~p", [Pid]),
+ MonRef = monitor(Pid),
+ Locker = #locker{pid = Pid,
+ from = From,
+ mon_ref = MonRef,
+ type = Type,
+ state = waiting},
+ ets:insert(?LOCKER_TAB, Locker),
+ Waiting = lists:append(State#state.waiting, [Pid]),
+%% ?vtrace("lock(write, infinity) -> done when"
+%% "~n Waiting: ~p"
+%% "~n Lockers: ~p", [Waiting, ets:tab2list(?LOCKER_TAB)]),
+ {noreply, State#state{waiting = Waiting}};
+
+handle_call({verbosity, Verbosity}, _From, State) ->
+ ?vlog("verbosity: ~p -> ~p", [get(verbosity), Verbosity]),
+ Old = put(verbosity, ?vvalidate(Verbosity)),
+ {reply, Old, State};
+
+%% If there are no more active read'ers, and no waiting,
+%% then set to writer and reply now
+handle_call({upgrade_lock, Pid}, _From,
+ #state{active_count = 1, waiting = []} = State) ->
+ ?vlog("upgrade_lock -> "
+ "entry when one active locker and no waiting with"
+ "~n Pid: ~p", [Pid]),
+ case ets:lookup(?LOCKER_TAB, Pid) of
+ [#locker{type = read} = Locker] ->
+ ets:insert(?LOCKER_TAB, Locker#locker{type = write}),
+%% ?vtrace("upgrade_lock -> done when"
+%% "~n Lockers: ~p", [ets:tab2list(?LOCKER_TAB)]),
+ {reply, ok, State#state{writer = true}};
+
+ [#locker{type = write}] ->
+ {reply, ok, State}
+ end;
+
+%% If there are no more active read'ers, and no waiting,
+%% then set to writer and reply now
+handle_call({upgrade_lock, Pid}, {Pid, _} = From,
+ #state{active_count = 1, waiting = Waiting} = State) ->
+ ?vlog("upgrade_lock -> "
+ "entry when one active locker with"
+ "~n Pid: ~p"
+ "~n Waiting: ~p", [Pid, Waiting]),
+ case ets:lookup(?LOCKER_TAB, Pid) of
+ [#locker{type = read} = Locker] ->
+ case active_waiting_writer(Waiting) of
+ {true, StillWaiting} ->
+ ?vtrace("upgrade_lock -> activated when"
+ "~n StillWaiting: ~p", [StillWaiting]),
+ ets:insert(?LOCKER_TAB, Locker#locker{from = From,
+ type = write,
+ state = waiting}),
+%% ?vtrace("upgrade_lock -> done when"
+%% "~n Lockers: ~p", [ets:tab2list(?LOCKER_TAB)]),
+ {noreply, State#state{waiting = StillWaiting ++ [Pid]}};
+ {false, []} ->
+ ?vtrace("upgrade_lock -> none activated, "
+ "so we can let the upgrader in", []),
+ ets:insert(?LOCKER_TAB, Locker#locker{type = write}),
+%% ?vtrace("upgrade_lock -> done when"
+%% "~n Lockers: ~p", [ets:tab2list(?LOCKER_TAB)]),
+ {reply, ok, State#state{writer = true,
+ waiting = []}}
+ end;
+
+ [#locker{type = write}] ->
+ {reply, ok, State};
+
+ _ ->
+ {reply, {error, not_found}, State}
+ end;
+
+%% There are active and waiting locker's
+handle_call({upgrade_lock, Pid}, {Pid, _} = From,
+ #state{active_count = Cnt, waiting = Waiting} = State) ->
+ ?vlog("upgrade_lock -> entry with"
+ "~n Pid: ~p"
+ "~n Waiting: ~p", [Pid, Waiting]),
+ case ets:lookup(?LOCKER_TAB, Pid) of
+ [#locker{type = read} = Locker] ->
+ ets:insert(?LOCKER_TAB, Locker#locker{from = From,
+ type = write,
+ state = waiting}),
+%% ?vtrace("upgrade_lock -> done when"
+%% "~n Lockers: ~p", [ets:tab2list(?LOCKER_TAB)]),
+ {noreply, State#state{active_count = dec(Cnt),
+ waiting = Waiting ++ [Pid]}};
+
+ [#locker{type = write}] ->
+ {reply, ok, State};
+
+ _ ->
+ {reply, {error, not_found}, State}
+ end;
+
+
+handle_call(stop, _From, State) ->
+ ?vlog("stop",[]),
+ {stop, normal, stopped, State};
+
+handle_call(Req, _From, State) ->
+ warning_msg("received unknown request: ~n~p", [Req]),
+ Reply = {error, {unknown, Req}},
+ {reply, Reply, State}.
+
+
+%%--------------------------------------------------------------------
+%% Func: handle_cast/2
+%% Returns: {noreply, State} |
+%% {noreply, State, Timeout} |
+%% {stop, Reason, State} (terminate/2 is called)
+%%--------------------------------------------------------------------
+handle_cast({unlock, Pid},
+ #state{active_count = Cnt, waiting = []} = State) ->
+ ?vlog("unlock -> entry when no waiting with"
+ "~n Pid: ~p"
+ "~n Cnt: ~p", [Pid, Cnt]),
+ case ets:lookup(?LOCKER_TAB, Pid) of
+ [#locker{mon_ref = MonRef, type = read}] ->
+ ?vdebug("unlock -> found read locker"
+ "~n MonRef: ~p", [MonRef]),
+ demonitor(MonRef),
+ ets:delete(?LOCKER_TAB, Pid),
+%% ?vtrace("unlock -> done when"
+%% "~n Lockers: ~p", [ets:tab2list(?LOCKER_TAB)]),
+ {noreply, State#state{active_count = dec(Cnt)}};
+ [#locker{mon_ref = MonRef, type = write}] ->
+ ?vdebug("unlock -> found write locker"
+ "~n MonRef: ~p", [MonRef]),
+ demonitor(MonRef),
+ ets:delete(?LOCKER_TAB, Pid),
+%% ?vtrace("unlock -> done when"
+%% "~n Lockers: ~p", [ets:tab2list(?LOCKER_TAB)]),
+ {noreply, State#state{active_count = dec(Cnt), writer = false}};
+ _ ->
+ {noreply, State}
+ end;
+
+handle_cast({unlock, Pid},
+ #state{active_count = Cnt, waiting = Waiting} = State) ->
+ ?vlog("unlock -> entry when waiting with"
+ "~n Pid: ~p"
+ "~n Cnt: ~p", [Pid, Cnt]),
+ case ets:lookup(?LOCKER_TAB, Pid) of
+ %% Last active reader: Time to let the waiting in
+ %% The first of the waiting _has_ to be a write-lock
+ %% (read-locks will only be set waiting if there is
+ %% a waiting or active write).
+ [#locker{mon_ref = MonRef, type = read}] when (Cnt == 1) ->
+ ?vdebug("unlock -> found read locker"
+ "~n MonRef: ~p", [MonRef]),
+ demonitor(MonRef),
+ ets:delete(?LOCKER_TAB, Pid),
+ case active_waiting_writer(Waiting) of
+ {true, StillWaiting} ->
+ ?vtrace("unlock -> activated when"
+ "~n StillWaiting: ~p", [StillWaiting]),
+%% ?vtrace("unlock -> done when"
+%% "~n Lockers: ~p", [ets:tab2list(?LOCKER_TAB)]),
+ {noreply, State#state{active_count = 1,
+ writer = true,
+ waiting = StillWaiting}};
+ {false, []} ->
+ ?vtrace("unlock -> none activated", []),
+%% ?vtrace("unlock -> done when"
+%% "~n Lockers: ~p", [ets:tab2list(?LOCKER_TAB)]),
+ {noreply, State#state{active_count = 0,
+ writer = false,
+ waiting = []}}
+ end;
+
+ [#locker{mon_ref = MonRef, type = read}] ->
+ ?vdebug("unlock -> found read locker"
+ "~n MonRef: ~p", [MonRef]),
+ demonitor(MonRef),
+ ets:delete(?LOCKER_TAB, Pid),
+%% ?vtrace("unlock -> done when"
+%% "~n Lockers: ~p", [ets:tab2list(?LOCKER_TAB)]),
+ {noreply, State#state{active_count = dec(Cnt)}};
+
+ [#locker{mon_ref = MonRef, type = write}] ->
+ %% Release the hord (maybe)
+ ?vdebug("unlock -> found write locker"
+ "~n MonRef: ~p", [MonRef]),
+ demonitor(MonRef),
+ ets:delete(?LOCKER_TAB, Pid),
+ {Active, StillWaiting, Writer} =
+ activate_waiting_readers_or_maybe_writer(Waiting),
+ ?vtrace("unlock -> new reader(s) or maybe writer activated:"
+ "~n Active: ~p"
+ "~n StillWaiting: ~p"
+ "~n Writer: ~p", [Active, StillWaiting, Writer]),
+%% ?vtrace("unlock -> done when"
+%% "~n Lockers: ~p", [ets:tab2list(?LOCKER_TAB)]),
+ {noreply, State#state{active_count = Active,
+ writer = Writer,
+ waiting = StillWaiting}};
+
+ %% If we have no active lockers, this may be a bug and therefor
+ %% see if we can activate some of the waiting
+ _ when (State#state.active_count == 0) ->
+ ?vdebug("unlock -> could not find locker", []),
+ {Active, StillWaiting, Writer} =
+ activate_waiting_readers_or_maybe_writer(Waiting),
+ ?vtrace("unlock -> new reader(s) or maybe writer activated:"
+ "~n Active: ~p"
+ "~n StillWaiting: ~p"
+ "~n Writer: ~p", [Active, StillWaiting, Writer]),
+%% ?vtrace("unlock -> done when"
+%% "~n Lockers: ~p", [ets:tab2list(?LOCKER_TAB)]),
+ {noreply,
+ State#state{active_count = Active,
+ writer = Writer,
+ waiting = StillWaiting}};
+
+ _ ->
+ {noreply, State}
+ end;
+
+
+handle_cast({downgrade_lock, Pid}, #state{waiting = Waiting} = State) ->
+ ?vlog("downgrade_lock -> entry when waiting with"
+ "~n Pid: ~p", [Pid]),
+ case ets:lookup(?LOCKER_TAB, Pid) of
+ [#locker{type = read}] ->
+ {noreply, State};
+
+ [#locker{type = write} = Locker] ->
+ %% We need to check if this is the only write(r),
+ %% in that case we must update the writer field
+ ets:insert(?LOCKER_TAB, Locker#locker{type = read}),
+ {Cnt, NewWaiting} = activate_waiting_readers(Waiting),
+ ?vtrace("downgrade_lock -> entry when waiting with"
+ "~n Cnt: ~p"
+ "~n NewWaiting: ~p", [Cnt, NewWaiting]),
+%% ?vtrace("downgrade_lock -> done when"
+%% "~n Lockers: ~p", [ets:tab2list(?LOCKER_TAB)]),
+ {noreply, State#state{active_count = Cnt,
+ waiting = NewWaiting,
+ writer = is_writer(NewWaiting)}}
+ end;
+
+
+handle_cast(Msg, State) ->
+ warning_msg("received unknown message: ~n~p", [Msg]),
+ {noreply, State}.
+
+
+
+
+%%--------------------------------------------------------------------
+%% Func: handle_info/2
+%% Returns: {noreply, State} |
+%% {noreply, State, Timeout} |
+%% {stop, Reason, State} (terminate/2 is called)
+%%--------------------------------------------------------------------
+
+%% This must be a glitch
+handle_info({'DOWN', _MonRef, process, Pid, Reason},
+ #state{active_count = 0, waiting = []} = State) ->
+ ?vlog("received DOWN message from ~p when no active and no waiting"
+ "~n exited for reason: ~n~p", [Pid, Reason]),
+ {noreply, State};
+
+handle_info({'DOWN', _MonRef, process, Pid, Reason},
+ #state{active_count = Cnt, waiting = []} = State) ->
+ ?vlog("received DOWN message from ~p when active but no waiting"
+ "~n exited for reason: ~n~p", [Pid, Reason]),
+ case handle_maybe_active_down(Cnt, Pid) of
+ {NewCnt, write} ->
+%% ?vtrace("DOWN -> done when"
+%% "~n Lockers: ~p", [ets:tab2list(?LOCKER_TAB)]),
+ {noreply, State#state{active_count = NewCnt, writer = false}};
+ {NewCnt, read} ->
+%% ?vtrace("DOWN -> done when"
+%% "~n Lockers: ~p", [ets:tab2list(?LOCKER_TAB)]),
+ {noreply, State#state{active_count = NewCnt}}
+ end;
+
+handle_info({'DOWN', _MonRef, process, Pid, Reason}, State) ->
+ ?vlog("received DOWN message from ~p"
+ "~n exited for reason: ~n~p", [Pid, Reason]),
+ NewState = handle_maybe_active_or_waiting_down(Pid, State),
+%% ?vtrace("DOWN -> done when"
+%% "~n Lockers: ~p", [ets:tab2list(?LOCKER_TAB)]),
+ {noreply, NewState};
+
+handle_info({'EXIT', Pid, Reason}, S) ->
+ %% The only other process we should be linked to is
+ %% our supervisor, so die...
+ {stop, {received_exit, Pid, Reason}, S};
+
+handle_info(Info, State) ->
+ warning_msg("received unknown info: ~n~p", [Info]),
+ {noreply, State}.
+
+
+%%--------------------------------------------------------------------
+%% Func: terminate/2
+%% Purpose: Shutdown the server
+%% Returns: any (ignored by gen_server)
+%%--------------------------------------------------------------------
+terminate(Reason, State) ->
+ ?vlog("terminate ->"
+ "~n Reason: ~p"
+ "~n State: ~p", [Reason, State]),
+ ets:delete(?CACHE),
+ ets:delete(?LOCKER_TAB),
+ ok.
+
+
+%%%-------------------------------------------------------------------
+%%% Internal functions
+%%%-------------------------------------------------------------------
+
+%% Locks are initially exclusive which means that it is possible
+%% to both read _and_ write. After a downgrade, it is only possible
+%% to read. But since, by then, the process already has a lock, it
+%% can just go ahead and read.
+
+lock(Type) ->
+ call({lock, Type, infinity}).
+
+%% Upgrade from read to lock write
+upgrade_lock() ->
+ call({upgrade_lock, self()}).
+
+%% Downgrade from write to read lock
+downgrade_lock() ->
+ cast({downgrade_lock, self()}).
+
+unlock() ->
+ cast({unlock, self()}).
+
+
+insert_all(Targets) ->
+ Fun = fun({NotifyName, Data}) -> insert(NotifyName, Data) end,
+ lists:foreach(Fun, Targets).
+
+insert(NotifyName, {DestAddr, TargetName, TargetParams, NotifyType}) ->
+ Key = {NotifyName, TargetName},
+ Data = {DestAddr, TargetParams, NotifyType},
+ ets:insert(?CACHE, {Key, Data}).
+
+delete_all() ->
+ ets:delete_all_objects(?CACHE).
+
+
+
+%%----------------------------------------------------------
+
+%% This function is called when we have active but no waiting
+%% lockers. So, if we have it stored, it's an active locker.
+handle_maybe_active_down(Cnt, Pid) ->
+ case ets:lookup(?LOCKER_TAB, Pid) of
+ [#locker{type = Type}] ->
+ ets:delete(?LOCKER_TAB, Pid),
+ {dec(Cnt), Type};
+ _ ->
+ {Cnt, read}
+ end.
+
+handle_maybe_active_or_waiting_down(Pid,
+ #state{active_count = Cnt,
+ waiting = Waiting} = State) ->
+ case ets:lookup(?LOCKER_TAB, Pid) of
+ [#locker{state = active, type = read}] when (Cnt == 1) ->
+ %% 1) This means that the writer must be waiting
+ %% 2) The last reader terminated,
+ %% time to activate the wating writer
+ %% If this was the last one, then we must
+ %% activate the waiting writer.
+ ets:delete(?LOCKER_TAB, Pid),
+ case active_waiting_writer(Waiting) of
+ {true, StillWaiting} ->
+ %% active count is still 1, so no need to update that
+ State#state{writer = true,
+ waiting = StillWaiting};
+ {false, []} ->
+ State#state{active_count = 0,
+ writer = false,
+ waiting = []}
+ end;
+
+ [#locker{state = active, type = read}] ->
+ %% 1) This means that the writer must be waiting
+ %% 2) More then one (read-) locker active, just
+ %% clean up.
+ ets:delete(?LOCKER_TAB, Pid),
+ State#state{active_count = dec(Cnt)};
+
+ [#locker{state = active, type = write}] ->
+ ets:delete(?LOCKER_TAB, Pid),
+ {Active, StillWaiting, Writer} =
+ activate_waiting_readers_or_maybe_writer(Waiting),
+ State#state{active_count = Active,
+ writer = Writer,
+ waiting = StillWaiting};
+
+ [#locker{state = waiting, type = read}] ->
+ ets:delete(?LOCKER_TAB, Pid),
+ State#state{waiting = lists:delete(Pid, Waiting)};
+
+ [#locker{state = waiting, type = write}] ->
+ %% We need to check if this is the only waiting writer.
+ %% If it is we shall set the writer field to false
+ ets:delete(?LOCKER_TAB, Pid),
+ NewWaiting = lists:delete(Pid, Waiting),
+ Writer =
+ case ets:match_object(?LOCKER_TAB,
+ #locker{state = active,
+ type = write,
+ _ = '_'}) of
+ [] ->
+ is_writer(NewWaiting);
+ _ ->
+ true
+ end,
+ State#state{writer = Writer,
+ waiting = NewWaiting};
+
+ _Other ->
+ State
+
+ end.
+
+is_writer([]) ->
+ false;
+is_writer([Pid|Pids]) ->
+ case ets:lookup(?LOCKER_TAB, Pid) of
+ [#locker{type = write}] ->
+ true;
+ _Other ->
+ is_writer(Pids)
+ end.
+
+
+%%----------------------------------------------------------
+
+%% This is just a utility function to make sure we don't
+%% end up in a lockout situation.
+active_waiting_writer([]) ->
+ {false, []};
+active_waiting_writer([H|T]) ->
+ case ets:lookup(?LOCKER_TAB, H) of
+ [#locker{from = From} = L] ->
+ ets:insert(?LOCKER_TAB, L#locker{state = active}),
+ gen_server:reply(From, ok),
+ {true, T};
+ [] ->
+ %% Oups
+ error_msg("Could not find locker record for ~p", [H]),
+ active_waiting_writer(T)
+ end.
+
+
+%% Activate waiting read(ers)
+activate_waiting_readers(Waiting) ->
+ activate_waiting_readers(Waiting, 1).
+
+activate_waiting_readers([], Cnt) ->
+ {Cnt, []};
+activate_waiting_readers([H|T] = Waiting, Cnt) ->
+ case ets:lookup(?LOCKER_TAB, H) of
+ [#locker{from = From, type = read} = L] ->
+ ets:insert(?LOCKER_TAB, L#locker{state = active}),
+ gen_server:reply(From, ok),
+ activate_waiting_readers(T, inc(Cnt));
+
+ %% Found a writer, time to stop starting readers
+ [#locker{type = write}] ->
+ {Cnt, Waiting};
+
+ [] ->
+ %% Oups
+ error_msg("Could not find locker record for ~p", [H]),
+ activate_waiting_readers(T, Cnt)
+
+ end.
+
+
+activate_waiting_readers_or_maybe_writer(Waiting) ->
+ activate_waiting_readers_or_maybe_writer(Waiting, 0).
+
+activate_waiting_readers_or_maybe_writer([], Cnt) ->
+ {Cnt, [], false};
+activate_waiting_readers_or_maybe_writer([H|T] = Waiting, Cnt) ->
+ case ets:lookup(?LOCKER_TAB, H) of
+ [#locker{from = From, type = read} = L] ->
+ ets:insert(?LOCKER_TAB, L#locker{state = active}),
+ gen_server:reply(From, ok),
+ activate_waiting_readers_or_maybe_writer(T, inc(Cnt));
+
+ %% Only active writer only if it's the first
+ [#locker{from = From, type = write} = L] when (Cnt == 0) ->
+ ets:insert(?LOCKER_TAB, L#locker{state = active}),
+ gen_server:reply(From, ok),
+ {1, T, true};
+
+ %% Found a writer, time to stop starting readers
+ [#locker{type = write}] ->
+ {Cnt, Waiting, false};
+
+ [] ->
+ %% Oups
+ error_msg("Could not find locker record for ~p", [H]),
+ activate_waiting_readers_or_maybe_writer(T, Cnt)
+
+ end.
+
+
+%%----------------------------------------------------------
+%% Code change
+%%----------------------------------------------------------
+
+%% downgrade
+%%
+%% code_change({down, _Vsn}, S1, downgrade_to_pre_4_7) ->
+%% #state{dets = D, ets = E, notify_clients = NC, backup = B} = S1,
+%% stop_backup_server(B),
+%% S2 = {state, D, E, NC},
+%% {ok, S2};
+
+%% upgrade
+%%
+%% code_change(_Vsn, S1, upgrade_from_pre_4_7) ->
+%% {state, D, E, NC} = S1,
+%% S2 = #state{dets = D, ets = E, notify_clients = NC},
+%% {ok, S2};
+
+code_change(_Vsn, State, _Extra) ->
+ {ok, State}.
+
+
+%%------------------------------------------------------------------
+
+inc(Cnt) ->
+ Cnt + 1.
+
+dec(Cnt) when (Cnt =< 0) ->
+ 0;
+dec(Cnt) ->
+ Cnt - 1.
+
+
+%%------------------------------------------------------------------
+%% This functions retrieves option values from the Options list.
+%%------------------------------------------------------------------
+
+get_opt(Key, Opts, Def) ->
+ snmp_misc:get_option(Key, Opts, Def).
+
+
+%%------------------------------------------------------------------
+
+%% info_msg(F, A) ->
+%% ?snmpa_info("Target cache server: " ++ F, A).
+
+warning_msg(F, A) ->
+ ?snmpa_warning("Target cache server: " ++ F, A).
+
+error_msg(F, A) ->
+ ?snmpa_error("Target cache server: " ++ F, A).
+
+%% ---
+
+%% user_err(F, A) ->
+%% snmpa_error:user_err(F, A).
+
+config_err(F, A) ->
+ snmpa_error:config_err(F, A).
+
+%% error(Reason) ->
+%% throw({error, Reason}).
+
+
+%% ----------------------------------------------------------------
+
+call(Req) ->
+ gen_server:call(?SERVER, Req, infinity).
+
+cast(Msg) ->
+ gen_server:cast(?SERVER, Msg).
diff --git a/lib/snmp/src/agent/snmpa_trap.erl b/lib/snmp/src/agent/snmpa_trap.erl
new file mode 100644
index 0000000000..b1096b1135
--- /dev/null
+++ b/lib/snmp/src/agent/snmpa_trap.erl
@@ -0,0 +1,1051 @@
+%%
+%% %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%
+%%
+-module(snmpa_trap).
+
+%%%-----------------------------------------------------------------
+%%% This module takes care of all trap(notification handling.
+%%%-----------------------------------------------------------------
+%% External exports
+-export([construct_trap/2,
+ try_initialise_vars/2, send_trap/6]).
+-export([send_discovery/5]).
+
+%% Internal exports
+-export([init_v2_inform/9, init_v3_inform/9, send_inform/6]).
+-export([init_discovery_inform/12, send_discovery_inform/5]).
+
+-include("snmp_types.hrl").
+-include("SNMPv2-MIB.hrl").
+-include("SNMPv2-TM.hrl").
+-include("SNMPv2-TC.hrl").
+-include("SNMP-FRAMEWORK-MIB.hrl").
+-include("SNMP-TARGET-MIB.hrl").
+-define(enterpriseSpecific, 6).
+
+
+-define(VMODULE,"TRAP").
+-include("snmp_verbosity.hrl").
+
+
+%%-----------------------------------------------------------------
+%% Trap mechanism
+%% ==============
+%% Distributed subagent (dSA) case
+%% The MIB with the TRAP-TYPE macro is loaded in dSA. This means
+%% that dSA has info on all variables defined in the TRAP-TYPE,
+%% even though some variables may be located in other SA:s (or
+%% in the MA). Other variables that may be sent in the trap,
+%% must be known by either the dSA, or some of its parent agents
+%% (e.g. the master agent), if the variable should be referred
+%% to by symbolic name. It is however possible to send other
+%% variables as well, but then the entire OID must be provided.
+%% The dSA locates the asn1 type, oid and value for as many
+%% variables as possible. This information, together with the
+%% variables for which the type, value or oid isn't known, is
+%% sent to the dSA's parent. This agent performs the same
+%% operation, and so on, until eventually the MA will receive the
+%% info. The MA then fills in the gaps, and at this point all
+%% oids and types must be known, otherwise an error is signalled,
+%% and the opertaion is aborted. For the unknown values for some
+%% oids, a get-operation is performed by the MA. This will
+%% retreive the missing values.
+%% At this point, all oid, types and values are known, so the MA
+%% can distribute the traps according to the information in the
+%% internal tables.
+%%
+%% Local subagent (lSA) case
+%% This case is similar to the case above.
+%%
+%% Master agent (MA) case
+%% This case is similar to the case above.
+%%
+%% NOTE: All trap forwarding between agents is made asynchronously.
+%%
+%% dSA: Distributed SA (the #trap is loaded here)
+%% nSA: [many] SAs between dSA and MA
+%% MA: Master Agent. (all trap info (destiniations is here))
+%% 1) application decides to send a trap.
+%% 2) dSA calls send_trap which initialises vars
+%% 3) dSA sends all to nSA
+%% 4) nSA tries to map symbolic names to oids and find the types
+%% of all variableoids with a value (and no type).
+%% 5) nSA sends all to (n-1)SA
+%% 6) MA tries to initialise vars
+%% 7) MA makes a trappdu, and sends it to all destination.
+%%
+%% Problems with this implementation
+%% =================================
+%% It's ok to send {Oid, Value} but not just Oid. (it should be for
+%% any Oid)
+%% It's ok to send {Name, Value} but not just Name. (it should be
+%% for Names in the hierarchy)
+%% This approach might be too flexible; will people use it?
+%% *NOTE*
+%% Therefore, in this version we *do not* allow extra variables
+%% in traps.
+%% *YES* In _this_ version we do.
+%%-----------------------------------------------------------------
+
+%%-----------------------------------------------------------------
+%% Func: construct_trap/2
+%% Args: Trap is an atom
+%% Varbinds is a list of
+%% {Variable, Value} | {SymbolicTableCol, RowIndex, Value}
+%% where Variable is an atom or an OID,
+%% where RowIndex is the indexes for the row.
+%% We don't check the RowIndex.
+%% Purpose: This is the initially-called function. It is called
+%% by the agent that found out that a trap should be
+%% sent.
+%% Initialize as many variables as possible.
+%% Returns: {ok, TrapRecord, <list of Var>} | error
+%% where Var is returned from initiate_vars.
+%% NOTE: Executed at the inital SA
+%%-----------------------------------------------------------------
+construct_trap(Trap, Varbinds) ->
+ ?vdebug("construct_trap -> entry with"
+ "~n Trap: ~p", [Trap]),
+ case snmpa_symbolic_store:get_notification(Trap) of
+ undefined ->
+ user_err("construct_trap got undef Trap: ~w" , [Trap]),
+ error;
+
+ {value, #trap{oidobjects = ListOfVars} = TRec} ->
+ ?vdebug("construct_trap -> trap"
+ "~n ~p", [TRec]),
+ OidVbs = [alias_to_oid(Vb) || Vb <- Varbinds],
+ LV = initiate_vars(ListOfVars, OidVbs),
+ InitiatedVars = try_initialise_vars(get(mibserver), LV),
+ {ok, TRec, InitiatedVars};
+
+ {value, #notification{oidobjects = ListOfVars} = NRec} ->
+ ?vdebug("construct_trap -> notification"
+ "~n ~p", [NRec]),
+ OidVbs = [alias_to_oid(Vb) || Vb <- Varbinds],
+ LV = initiate_vars(ListOfVars, OidVbs),
+ InitiatedVars = try_initialise_vars(get(mibserver), LV),
+ {ok, NRec, InitiatedVars}
+ end.
+
+alias_to_oid({Alias, Val}) when is_atom(Alias) ->
+ case snmpa_symbolic_store:aliasname_to_oid(Alias) of
+ {value, Oid} -> {lists:append(Oid, [0]), {value, Val}};
+ _ -> {Alias, {value, Val}}
+ end;
+alias_to_oid({Alias, RowIndex, Val}) when is_atom(Alias) ->
+ case snmpa_symbolic_store:aliasname_to_oid(Alias) of
+ {value, Oid} -> {lists:append(Oid, RowIndex), {value, Val}};
+ _ -> {Alias, RowIndex, {value, Val}}
+ end;
+alias_to_oid({Oid, Val}) -> {Oid, {value, Val}}.
+
+
+%%-----------------------------------------------------------------
+%% Func: initiate_vars/2
+%% Args: ListOfVars is a list of {Oid, #asn1_type}
+%% Varbinds is a list of
+%% {VariableOid, Value} |
+%% {VariableAtom, Value} |
+%% {TableColAtom, RowIndex, Value}
+%% Purpose: For each variable specified in the TRAP-TYPE macro
+%% (each in ListOfVars), check if it's got a value given
+%% in the Varbinds list.
+%% For each Oid:
+%% 1) It has corresponding VariableOid. Use Value.
+%% 2) No corresponding VariableOid. No value.
+%% Returns: A list of
+%% {VariableOid, #asn1_type, Value} |
+%% {VariableOid, #asn1_type} |
+%% {VariableOid, Value} |
+%% {VariableAtom, Value} |
+%% {TableColAtom, RowIndex, Value}
+%% NOTE: Executed at the inital SA
+%%-----------------------------------------------------------------
+initiate_vars([{Oid, Asn1Type} | T], Varbinds) ->
+ case delete_oid_from_varbinds(Oid, Varbinds) of
+ {undefined, _, _} ->
+ [{Oid, Asn1Type} | initiate_vars(T, Varbinds)];
+ {Value, VarOid, RestOfVarbinds} ->
+ [{VarOid, Asn1Type, Value} | initiate_vars(T, RestOfVarbinds)]
+ end;
+initiate_vars([], Varbinds) ->
+ Varbinds.
+
+delete_oid_from_varbinds(Oid, [{VarOid, Value} | T]) ->
+ case lists:prefix(Oid, VarOid) of
+ true ->
+ {Value, VarOid, T};
+ _ ->
+ {Value2, VarOid2, T2} = delete_oid_from_varbinds(Oid, T),
+ {Value2, VarOid2, [{VarOid, Value} | T2]}
+ end;
+delete_oid_from_varbinds(Oid, [H | T]) ->
+ {Value, VarOid, T2} = delete_oid_from_varbinds(Oid, T),
+ {Value, VarOid, [H | T2]};
+delete_oid_from_varbinds(_Oid, []) -> {undefined, undefined, []}.
+
+%%-----------------------------------------------------------------
+%% Func: try_initialise_vars(Mib, Varbinds)
+%% Args: Mib is the local mib process
+%% Varbinds is a list returned from initiate_vars.
+%% Purpose: Try to initialise uninitialised vars.
+%% Returns: see initiate_vars
+%% NOTE: Executed at the intermediate SAs
+%%-----------------------------------------------------------------
+try_initialise_vars(Mib, Varbinds) ->
+ V = try_map_symbolic(Varbinds),
+ try_find_type(V, Mib).
+
+%%-----------------------------------------------------------------
+%% Func: try_map_symbolic/1
+%% Args: Varbinds is a list returned from initiate_vars.
+%% Purpose: Try to map symbolic name to oid for the
+%% symbolic names left in the Varbinds list.
+%% Returns: see initiate_vars.
+%% NOTE: Executed at the intermediate SAs
+%%-----------------------------------------------------------------
+try_map_symbolic([Varbind | Varbinds]) ->
+ [localise_oid(Varbind) | try_map_symbolic(Varbinds)];
+try_map_symbolic([]) -> [].
+
+localise_oid({VariableName, Value}) when is_atom(VariableName) ->
+ alias_to_oid({VariableName, Value});
+localise_oid({VariableName, RowIndex, Value}) when is_atom(VariableName) ->
+ alias_to_oid({VariableName, RowIndex, Value});
+localise_oid(X) -> X.
+
+%%-----------------------------------------------------------------
+%% Func: try_find_type/2
+%% Args: Varbinds is a list returned from initiate_vars.
+%% Mib is a ref to the Mib process corresponding to
+%% this agent.
+%% Purpose: Try to find the type for each variableoid with a value
+%% but no type.
+%% Returns: see initiate_vars.
+%% NOTE: Executed at the intermediate SAs
+%%-----------------------------------------------------------------
+try_find_type([Varbind | Varbinds], Mib) ->
+ [localise_type(Varbind, Mib) | try_find_type(Varbinds, Mib)];
+try_find_type([], _) -> [].
+
+localise_type({VariableOid, Type}, _Mib)
+ when is_list(VariableOid) andalso is_record(Type, asn1_type) ->
+ {VariableOid, Type};
+localise_type({VariableOid, Value}, Mib) when is_list(VariableOid) ->
+ case snmpa_mib:lookup(Mib, VariableOid) of
+ {variable, ME} ->
+ {VariableOid, ME#me.asn1_type, Value};
+ {table_column, ME, _} ->
+ {VariableOid, ME#me.asn1_type, Value};
+ _ ->
+ {VariableOid, Value}
+ end;
+localise_type(X, _) -> X.
+
+%%-----------------------------------------------------------------
+%% Func: make_v1_trap_pdu/4
+%% Args: Enterprise = oid()
+%% Specific = integer()
+%% Varbinds is as returned from initiate_vars
+%% (but only {Oid, Type[, Value} permitted)
+%% SysUpTime = integer()
+%% Purpose: Make a #trappdu
+%% Checks the Varbinds to see that no symbolic names are
+%% present, and that each var has a type. Performs a get
+%% to find any missing value.
+%% Returns: {#trappdu, [byte()] | error
+%% Fails: yes
+%% NOTE: Executed at the MA
+%%-----------------------------------------------------------------
+make_v1_trap_pdu(Enterprise, Specific, VarbindList, SysUpTime) ->
+ {Enterp,Generic,Spec} =
+ case Enterprise of
+ ?snmp ->
+ {sys_object_id(),Specific,0};
+ _ ->
+ {Enterprise,?enterpriseSpecific,Specific}
+ end,
+ {value, AgentIp} = snmp_framework_mib:intAgentIpAddress(get),
+ #trappdu{enterprise = Enterp,
+ agent_addr = AgentIp,
+ generic_trap = Generic,
+ specific_trap = Spec,
+ time_stamp = SysUpTime,
+ varbinds = VarbindList}.
+
+make_discovery_pdu(Vbs) ->
+ #pdu{type = 'inform-request',
+ request_id = snmpa_mpd:generate_req_id(),
+ error_status = noError,
+ error_index = 0,
+ varbinds = Vbs}.
+
+make_v2_notif_pdu(Vbs, Type) ->
+ #pdu{type = Type,
+ request_id = snmpa_mpd:generate_req_id(),
+ error_status = noError,
+ error_index = 0,
+ varbinds = Vbs}.
+
+make_varbind_list(Varbinds) ->
+ {VariablesWithValueAndType, VariablesWithType} =
+ split_variables( order(Varbinds) ),
+ V = get_values(VariablesWithType),
+ Vars = lists:append([V, VariablesWithValueAndType]),
+ [make_varbind(Var) || Var <- unorder(lists:keysort(1, Vars))].
+
+
+%%-----------------------------------------------------------------
+%% Func: send_trap/6
+%% Args: TrapRec = #trap | #notification
+%% NotifyName = string()
+%% ContextName = string()
+%% Recv = no_receiver | {Ref, Receiver}
+%% Receiver = pid() | atom() | {M,F,A}
+%% Vbs = [varbind()]
+%% NetIf = pid()
+%% Purpose: Default trap sending function.
+%% Sends the trap to the targets pointed out by NotifyName.
+%% If NotifyName is ""; the normal procedure defined in
+%% SNMP-NOTIFICATION-MIB is used, i.e. the trap is sent to
+%% all managers.
+%% Otherwise, the NotifyName is used to find an entry in the
+%% SnmpNotifyTable which define how to send the notification
+%% (as an Inform or a Trap), and to select targets from
+%% SnmpTargetAddrTable (using the Tag).
+%%-----------------------------------------------------------------
+send_trap(TrapRec, NotifyName, ContextName, Recv, Vbs, NetIf) ->
+ (catch do_send_trap(TrapRec, NotifyName, ContextName, Recv, Vbs, NetIf)).
+
+do_send_trap(TrapRec, NotifyName, ContextName, Recv, Vbs, NetIf) ->
+ VarbindList = make_varbind_list(Vbs),
+ Dests = find_dests(NotifyName),
+ send_trap_pdus(Dests, ContextName, {TrapRec, VarbindList}, [], [], [],
+ Recv, NetIf).
+
+send_discovery(TargetName, Record, ContextName, Vbs, NetIf) ->
+ case find_dest(TargetName) of
+ {ok, Dest} ->
+ send_discovery_pdu(Dest, Record, ContextName, Vbs, NetIf);
+ Error ->
+ Error
+ end.
+
+
+get_values(VariablesWithType) ->
+ {Order, Varbinds} = extract_order(VariablesWithType, 1),
+ case snmpa_agent:do_get(snmpa_acm:get_root_mib_view(), Varbinds, true) of
+ {noError, _, NewVarbinds} ->
+ %% NewVarbinds is the result of:
+ %% first a reverse, then a sort on the oid field and finally
+ %% a reverse during the get-processing so we need to re-sort
+ %% on the org_index field again before contract-order
+ NewVarbinds1 = lists:keysort(#varbind.org_index, NewVarbinds),
+ contract_order(Order, NewVarbinds1);
+ {ErrorStatus, ErrorIndex, _} ->
+ user_err("snmpa_trap: get operation failed: ~w"
+ "~n at ~w"
+ "~n in ~w",
+ [ErrorStatus, ErrorIndex, Varbinds]),
+ throw(error)
+ end.
+
+make_varbind(Varbind) when is_record(Varbind, varbind) ->
+ Varbind;
+make_varbind({VarOid, ASN1Type, Value}) ->
+ case snmpa_agent:make_value_a_correct_value(Value, ASN1Type, undef) of
+ {value, Type, Val} ->
+ #varbind{oid = VarOid, variabletype = Type, value = Val};
+ {error, Reason} ->
+ user_err("snmpa_trap: Invalid value: ~w"
+ "~n Oid: ~w"
+ "~n Val: ~w"
+ "~n Type: ~w",
+ [Reason, VarOid, Value, ASN1Type]),
+ throw(error)
+ end.
+
+order(Varbinds) ->
+ order(Varbinds, 1).
+
+order([H | T], No) -> [{No, H} | order(T, No + 1)];
+order([], _) -> [].
+
+unorder([{_No, H} | T]) -> [H | unorder(T)];
+unorder([]) -> [].
+
+extract_order([{No, {VarOid, _Type}} | T], Index) ->
+ {Order, V} = extract_order(T, Index+1),
+ {[No | Order], [#varbind{oid = VarOid, org_index = Index} | V]};
+extract_order([], _) -> {[], []}.
+
+contract_order([No | Order], [Varbind | T]) ->
+ [{No, Varbind} | contract_order(Order, T)];
+contract_order([], []) ->
+ [].
+
+split_variables([{No, {VarOid, Type, Val}} | T]) when is_list(VarOid) ->
+ {A, B} = split_variables(T),
+ {[{No, {VarOid, Type, Val}} | A], B};
+split_variables([{No, {VarOid, Type}} | T])
+ when is_list(VarOid) andalso is_record(Type, asn1_type) ->
+ {A, B} = split_variables(T),
+ {A, [{No, {VarOid, Type}} | B]};
+split_variables([{_No, {VarName, Value}} | _T]) ->
+ user_err("snmpa_trap: Undefined variable ~w (~w)", [VarName, Value]),
+ throw(error);
+split_variables([{_No, {VarName, RowIndex, Value}} | _T]) ->
+ user_err("snmpa_trap: Undefined variable ~w ~w (~w)",
+ [VarName, RowIndex, Value]),
+ throw(error);
+split_variables([]) -> {[], []}.
+
+
+%%-----------------------------------------------------------------
+%% Func: find_dests(NotifyName) ->
+%% [{DestAddr, TargetName, TargetParams, NotifyType}]
+%% Types: NotifyType = string()
+%% DestAddr = {TDomain, TAddr}
+%% TargetName = string()
+%% TargetParams = {MpModel, SecModel, SecName, SecLevel}
+%% NotifyType = trap | {inform, Timeout, Retry}
+%% Returns: A list of all Destination addresses for this community.
+%% NOTE: This function is executed in the master agent's context
+%%-----------------------------------------------------------------
+find_dests("") ->
+ snmp_notification_mib:get_targets();
+find_dests(NotifyName) ->
+ case snmp_notification_mib:get_targets(NotifyName) of
+ [] ->
+ ?vlog("No dests found for snmpNotifyName: ~p",[NotifyName]),
+ [];
+ Dests ->
+ Dests
+ end.
+
+find_dest(TargetName) ->
+ AddrCols = [?snmpTargetAddrTDomain,
+ ?snmpTargetAddrTAddress,
+ ?snmpTargetAddrTimeout,
+ ?snmpTargetAddrRetryCount,
+ ?snmpTargetAddrParams,
+ ?snmpTargetAddrRowStatus],
+ case snmp_target_mib:snmpTargetAddrTable(get, TargetName, AddrCols) of
+ [{value, TDomain},
+ {value, TAddress},
+ {value, Timeout},
+ {value, RetryCount},
+ {value, Params},
+ {value, ?'RowStatus_active'}] ->
+ ?vtrace("find_dest -> found snmpTargetAddrTable info:"
+ "~n TDomain: ~p"
+ "~n TAddress: ~p"
+ "~n Timeout: ~p"
+ "~n RetryCount: ~p"
+ "~n Params: ~p",
+ [TDomain, TAddress, Timeout, RetryCount, Params]),
+ ParmCols = [?snmpTargetParamsMPModel,
+ ?snmpTargetParamsSecurityModel,
+ ?snmpTargetParamsSecurityName,
+ ?snmpTargetParamsSecurityLevel,
+ ?snmpTargetParamsRowStatus],
+ case snmp_target_mib:snmpTargetParamsTable(get, Params, ParmCols) of
+ [{value, ?MP_V3},
+ {value, SecModel},
+ {value, SecName},
+ {value, SecLevel},
+ {value, ?'RowStatus_active'}] ->
+ ?vtrace("find_dest -> found snmpTargetParamsTable info:"
+ "~n SecModel: ~p"
+ "~n SecName: ~p"
+ "~n SecLevel: ~p",
+ [SecModel, SecName, SecLevel]),
+ DestAddr = {TDomain, TAddress},
+ TargetParams = {SecModel, SecName, SecLevel},
+ Val = {DestAddr, TargetName, TargetParams, Timeout, RetryCount},
+ {ok, Val};
+ [{value, ?MP_V3},
+ {value, _SecModel},
+ {value, _SecName},
+ {value, _SecLevel},
+ {value, RowStatus}] ->
+ {error, {invalid_RowStatus, RowStatus, snmpTargetParamsTable}};
+ [{value, MpModel},
+ {value, _SecModel},
+ {value, _SecName},
+ {value, _SecLevel},
+ {value, ?'RowStatus_active'}] ->
+ {error, {invalid_MpModel, MpModel, snmpTargetParamsTable}};
+ [{value, _MpModel},
+ {value, _SecModel},
+ {value, _SecName},
+ {value, _SecLevel},
+ {value, RowStatus}] ->
+ {error, {invalid_RowStatus, RowStatus, snmpTargetParamsTable}};
+ Bad ->
+ ?vlog("find_dest -> "
+ "could not find snmpTargetParamsTable info: "
+ "~n Bad: ~p", [Bad]),
+ {error, {not_found, snmpTargetParamsTable}}
+ end;
+
+ [{value, _TDomain},
+ {value, _TAddress},
+ {value, _Timeout},
+ {value, _RetryCount},
+ {value, _Params},
+ {value, RowStatus}] ->
+ {error, {invalid_RowStatus, RowStatus, snmpTargetAddrTable}};
+ _ ->
+ {error, {not_found, snmpTargetAddrTable}}
+ end.
+
+send_discovery_pdu({Dest, TargetName, {SecModel, SecName, SecLevel},
+ Timeout, Retry},
+ Record, ContextName, Vbs, NetIf) ->
+ ?vdebug("send_discovery_pdu -> entry with "
+ "~n Destination address: ~p"
+ "~n Target name: ~p"
+ "~n Sec model: ~p"
+ "~n Sec name: ~p"
+ "~n Sec level: ~p"
+ "~n Timeout: ~p"
+ "~n Retry: ~p"
+ "~n Record: ~p"
+ "~n ContextName: ~p",
+ [Dest, TargetName, SecModel, SecName, SecLevel,
+ Timeout, Retry, Record, ContextName]),
+ case get_mib_view(SecModel, SecName, SecLevel, ContextName) of
+ {ok, MibView} ->
+ case check_all_varbinds(Record, Vbs, MibView) of
+ true ->
+ SysUpTime = snmp_standard_mib:sys_up_time(),
+ send_discovery_pdu(Record, Dest, Vbs,
+ SecModel, SecName, SecLevel,
+ TargetName, ContextName,
+ Timeout, Retry,
+ SysUpTime, NetIf);
+ false ->
+ {error, {mibview_validation_failed, Vbs, MibView}}
+ end;
+ {discarded, Reason} ->
+ {error, {failed_get_mibview, Reason}}
+ end.
+
+send_discovery_pdu(Record, Dest, Vbs,
+ SecModel, SecName, SecLevel, TargetName,
+ ContextName, Timeout, Retry, SysUpTime, NetIf) ->
+ {_Oid, IVbs} = mk_v2_trap(Record, Vbs, SysUpTime), % v2 refers to SMIv2;
+ Sender = proc_lib:spawn_link(?MODULE, init_discovery_inform,
+ [self(),
+ Dest,
+ SecModel, SecName, SecLevel, TargetName,
+ ContextName,
+ Timeout, Retry,
+ IVbs, NetIf,
+ get(verbosity)]),
+ {ok, Sender, SecLevel}.
+
+init_discovery_inform(Parent,
+ Dest,
+ SecModel, SecName, SecLevel, TargetName,
+ ContextName, Timeout, Retry, Vbs, NetIf, Verbosity) ->
+ put(verbosity, Verbosity),
+ put(sname, madis),
+ Pdu = make_discovery_pdu(Vbs),
+ ContextEngineId = snmp_framework_mib:get_engine_id(),
+ SecLevelFlag = mk_flag(SecLevel),
+ SecData = {SecModel, SecName, SecLevelFlag, TargetName},
+ MsgData = {SecData, ContextEngineId, ContextName},
+ Msg = {send_discovery, Pdu, MsgData, Dest, self()},
+ ?MODULE:send_discovery_inform(Parent, Timeout*10, Retry, Msg, NetIf).
+
+%% note_timeout(Timeout, Retry)
+%% when ((is_integer(Timeout) andalso (Timeout > 0)) andalso
+%% (is_integer(Retry) andalso (Retry > 0)))
+%% note_timeout(Timeout*10, Retry, 0);
+%% note_timeout(Timeout, Retry)
+%% when (is_integer(Timeout) andalso (Timeout > 0)) ->
+%% Timeout*10.
+
+%% note_timeout(_Timeout, -1, NoteTimeout) ->
+%% NoteTimeout;
+%% note_timeout(Timeout, Retry, NoteTimeout) when ->
+%% note_timeout(Timeout*2, Retry-1, NoteTimeout+Timeout).
+
+send_discovery_inform(Parent, _Timeout, -1, _Msg, _NetIf) ->
+ Parent ! {discovery_response, {error, timeout}};
+send_discovery_inform(Parent, Timeout, Retry, Msg, NetIf) ->
+ NetIf ! Msg,
+ receive
+ {snmp_discovery_response_received, Pdu, undefined} ->
+ ?vtrace("received stage 2 discovery response: "
+ "~n Pdu: ~p", [Pdu]),
+ Parent ! {discovery_response, {ok, Pdu}};
+ {snmp_discovery_response_received, Pdu, ManagerEngineId} ->
+ ?vtrace("received stage 1 discovery response: "
+ "~n Pdu: ~p"
+ "~n ManagerEngineId: ~p", [Pdu, ManagerEngineId]),
+ Parent ! {discovery_response, {ok, Pdu, ManagerEngineId}}
+ after
+ Timeout ->
+ ?MODULE:send_discovery_inform(Parent,
+ Timeout*2, Retry-1, Msg, NetIf)
+ end.
+
+
+%%-----------------------------------------------------------------
+%% NOTE: This function is executed in the master agent's context
+%% For each target, check if it has access to the objects in the
+%% notification, determine which message version (v1, v2c or v3)
+%% should be used for the target, and determine the message
+%% specific parameters to be used.
+%%-----------------------------------------------------------------
+send_trap_pdus([{DestAddr, TargetName, {MpModel, SecModel, SecName, SecLevel},
+ Type} | T],
+ ContextName,{TrapRec, Vbs}, V1Res, V2Res, V3Res, Recv, NetIf) ->
+ ?vdebug("send trap pdus: "
+ "~n Destination address: ~p"
+ "~n Target name: ~p"
+ "~n MP model: ~p"
+ "~n Type: ~p"
+ "~n V1Res: ~p"
+ "~n V2Res: ~p"
+ "~n V3Res: ~p",
+ [DestAddr, TargetName, MpModel, Type, V1Res, V2Res, V3Res]),
+ case get_mib_view(SecModel, SecName, SecLevel, ContextName) of
+ {ok, MibView} ->
+ case check_all_varbinds(TrapRec, Vbs, MibView) of
+ true when MpModel =:= ?MP_V1 ->
+ ?vtrace("send_trap_pdus -> v1 mp model",[]),
+ ContextEngineId = snmp_framework_mib:get_engine_id(),
+ case snmp_community_mib:vacm2community({SecName,
+ ContextEngineId,
+ ContextName},
+ DestAddr) of
+ {ok, Community} ->
+ ?vdebug("community found for v1 dest: ~p",
+ [element(2, DestAddr)]),
+ send_trap_pdus(T, ContextName, {TrapRec, Vbs},
+ [{DestAddr, Community} | V1Res],
+ V2Res, V3Res, Recv, NetIf);
+ undefined ->
+ ?vdebug("No community found for v1 dest: ~p",
+ [element(2, DestAddr)]),
+ send_trap_pdus(T, ContextName, {TrapRec, Vbs},
+ V1Res, V2Res, V3Res, Recv, NetIf)
+ end;
+ true when MpModel =:= ?MP_V2C ->
+ ?vtrace("send_trap_pdus -> v2c mp model",[]),
+ ContextEngineId = snmp_framework_mib:get_engine_id(),
+ case snmp_community_mib:vacm2community({SecName,
+ ContextEngineId,
+ ContextName},
+ DestAddr) of
+ {ok, Community} ->
+ ?vdebug("community found for v2c dest: ~p",
+ [element(2, DestAddr)]),
+ send_trap_pdus(T, ContextName, {TrapRec, Vbs},
+ V1Res,
+ [{DestAddr, Community, Type}|V2Res],
+ V3Res, Recv, NetIf);
+ undefined ->
+ ?vdebug("No community found for v2c dest: ~p",
+ [element(2, DestAddr)]),
+ send_trap_pdus(T, ContextName, {TrapRec, Vbs},
+ V1Res, V2Res, V3Res, Recv, NetIf)
+ end;
+ true when MpModel =:= ?MP_V3 ->
+ ?vtrace("send_trap_pdus -> v3 mp model",[]),
+ SecLevelF = mk_flag(SecLevel),
+ MsgData = {SecModel, SecName, SecLevelF, TargetName},
+ send_trap_pdus(T, ContextName, {TrapRec, Vbs},
+ V1Res, V2Res,
+ [{DestAddr, MsgData, Type} | V3Res],
+ Recv, NetIf);
+ true ->
+ ?vlog("bad MpModel ~p for dest ~p",
+ [MpModel, element(2, DestAddr)]),
+ send_trap_pdus(T, ContextName, {TrapRec, Vbs},
+ V1Res, V2Res, V3Res, Recv, NetIf);
+ _ ->
+ ?vlog("no access for dest: "
+ "~n ~p in target ~p",
+ [element(2, DestAddr), TargetName]),
+ send_trap_pdus(T, ContextName, {TrapRec, Vbs},
+ V1Res, V2Res, V3Res, Recv, NetIf)
+ end;
+ {discarded, Reason} ->
+ ?vlog("mib view error ~p for"
+ "~n dest: ~p"
+ "~n SecName: ~w",
+ [Reason, element(2, DestAddr), SecName]),
+ send_trap_pdus(T, ContextName, {TrapRec, Vbs},
+ V1Res, V2Res, V3Res, Recv, NetIf)
+ end;
+send_trap_pdus([], ContextName, {TrapRec, Vbs}, V1Res, V2Res, V3Res,
+ Recv, NetIf) ->
+ SysUpTime = snmp_standard_mib:sys_up_time(),
+ ?vdebug("send trap pdus with sysUpTime ~p", [SysUpTime]),
+ InformRecvs = get_inform_recvs(V2Res ++ V3Res),
+ InformTargets = [Addr || {Addr, _, _, _} <- InformRecvs],
+ deliver_recv(Recv, snmp_targets, InformTargets),
+ send_v1_trap(TrapRec, V1Res, Vbs, NetIf, SysUpTime),
+ send_v2_trap(TrapRec, V2Res, Vbs, Recv, NetIf, SysUpTime),
+ send_v3_trap(TrapRec, V3Res, Vbs, Recv, NetIf, SysUpTime, ContextName).
+
+send_v1_trap(_TrapRec, [], _Vbs, _NetIf, _SysUpTime) ->
+ ok;
+send_v1_trap(#trap{enterpriseoid = Enter, specificcode = Spec},
+ V1Res, Vbs, NetIf, SysUpTime) ->
+ ?vdebug("prepare to send v1 trap "
+ "~n '~p'"
+ "~n with"
+ "~n ~p"
+ "~n to"
+ "~n ~p", [Enter, Spec, V1Res]),
+ TrapPdu = make_v1_trap_pdu(Enter, Spec, Vbs, SysUpTime),
+ AddrCommunities = mk_addr_communities(V1Res),
+ lists:foreach(fun({Community, Addrs}) ->
+ ?vtrace("send v1 trap pdu to ~p",[Addrs]),
+ NetIf ! {send_pdu, 'version-1', TrapPdu,
+ {community, Community}, Addrs}
+ end, AddrCommunities);
+send_v1_trap(#notification{oid = Oid}, V1Res, Vbs, NetIf, SysUpTime) ->
+ %% Use alg. in rfc2089 to map a v2 trap to a v1 trap
+ % delete Counter64 objects from vbs
+ ?vdebug("prepare to send v1 trap '~p'",[Oid]),
+ NVbs = [Vb || Vb <- Vbs, Vb#varbind.variabletype =/= 'Counter64'],
+ {Enter,Spec} =
+ case Oid of
+ [1,3,6,1,6,3,1,1,5,Specific] ->
+ {?snmp,Specific - 1};
+ _ ->
+ case lists:reverse(Oid) of
+ [Last, 0 | First] ->
+ {lists:reverse(First),Last};
+ [Last | First] ->
+ {lists:reverse(First),Last}
+ end
+ end,
+ TrapPdu = make_v1_trap_pdu(Enter, Spec, NVbs, SysUpTime),
+ AddrCommunities = mk_addr_communities(V1Res),
+ lists:foreach(fun({Community, Addrs}) ->
+ ?vtrace("send v1 trap to ~p",[Addrs]),
+ NetIf ! {send_pdu, 'version-1', TrapPdu,
+ {community, Community}, Addrs}
+ end, AddrCommunities).
+
+send_v2_trap(_TrapRec, [], _Vbs, _Recv, _NetIf, _SysUpTime) ->
+ ok;
+send_v2_trap(TrapRec, V2Res, Vbs, Recv, NetIf, SysUpTime) ->
+ ?vdebug("prepare to send v2 trap",[]),
+ {_Oid, IVbs} = mk_v2_trap(TrapRec, Vbs, SysUpTime),
+ TrapRecvs = get_trap_recvs(V2Res),
+ InformRecvs = get_inform_recvs(V2Res),
+ do_send_v2_trap(TrapRecvs, IVbs, NetIf),
+ do_send_v2_inform(InformRecvs, IVbs, Recv, NetIf).
+
+send_v3_trap(_TrapRec, [], _Vbs, _Recv, _NetIf, _SysUpTime, _ContextName) ->
+ ok;
+send_v3_trap(TrapRec, V3Res, Vbs, Recv, NetIf, SysUpTime, ContextName) ->
+ ?vdebug("prepare to send v3 trap",[]),
+ {_Oid, IVbs} = mk_v2_trap(TrapRec, Vbs, SysUpTime), % v2 refers to SMIv2;
+ TrapRecvs = get_trap_recvs(V3Res), % same SMI for v3
+ InformRecvs = get_inform_recvs(V3Res),
+ do_send_v3_trap(TrapRecvs, ContextName, IVbs, NetIf),
+ do_send_v3_inform(InformRecvs, ContextName, IVbs, Recv, NetIf).
+
+
+mk_v2_trap(#notification{oid = Oid}, Vbs, SysUpTime) ->
+ ?vtrace("make v2 notification '~p'",[Oid]),
+ mk_v2_notif(Oid, Vbs, SysUpTime);
+mk_v2_trap(#trap{enterpriseoid = Enter, specificcode = Spec}, Vbs, SysUpTime) ->
+ %% Use alg. in rfc1908 to map a v1 trap to a v2 trap
+ ?vtrace("make v2 trap for '~p' with ~p",[Enter,Spec]),
+ {Oid,Enterp} =
+ case Enter of
+ ?snmp ->
+ {?snmpTraps ++ [Spec + 1],sys_object_id()};
+ _ ->
+ {Enter ++ [0, Spec],Enter}
+ end,
+ ExtraVb = #varbind{oid = ?snmpTrapEnterprise_instance,
+ variabletype = 'OBJECT IDENTIFIER',
+ value = Enterp},
+ mk_v2_notif(Oid, Vbs ++ [ExtraVb], SysUpTime).
+
+mk_v2_notif(Oid, Vbs, SysUpTime) ->
+ IVbs = [#varbind{oid = ?sysUpTime_instance,
+ variabletype = 'TimeTicks',
+ value = SysUpTime},
+ #varbind{oid = ?snmpTrapOID_instance,
+ variabletype = 'OBJECT IDENTIFIER',
+ value = Oid} | Vbs],
+ {Oid, IVbs}.
+
+get_trap_recvs(TrapRecvs) ->
+ [{Addr, MsgData} || {Addr, MsgData, trap} <- TrapRecvs].
+
+get_inform_recvs(InformRecvs) ->
+ [{Addr, MsgData, Timeout, Retry} ||
+ {Addr, MsgData, {inform, Timeout, Retry}} <- InformRecvs].
+
+do_send_v2_trap([], _Vbs, _NetIf) ->
+ ok;
+do_send_v2_trap(Recvs, Vbs, NetIf) ->
+ TrapPdu = make_v2_notif_pdu(Vbs, 'snmpv2-trap'),
+ AddrCommunities = mk_addr_communities(Recvs),
+ lists:foreach(fun({Community, Addrs}) ->
+ ?vtrace("~n send v2 trap to ~p",[Addrs]),
+ NetIf ! {send_pdu, 'version-2', TrapPdu,
+ {community, Community}, Addrs}
+ end, AddrCommunities),
+ ok.
+
+do_send_v2_inform([], _Vbs, _Recv, _NetIf) ->
+ ok;
+do_send_v2_inform(Recvs, Vbs, Recv, NetIf) ->
+ lists:foreach(
+ fun({Addr, Community, Timeout, Retry}) ->
+ ?vtrace("~n start inform sender to send v2 inform to ~p",
+ [Addr]),
+ proc_lib:spawn_link(?MODULE, init_v2_inform,
+ [Addr, Timeout, Retry, Vbs,
+ Recv, NetIf, Community,
+ get(verbosity), get(sname)])
+ end,
+ Recvs).
+
+do_send_v3_trap([], _ContextName, _Vbs, _NetIf) ->
+ ok;
+do_send_v3_trap(Recvs, ContextName, Vbs, NetIf) ->
+ TrapPdu = make_v2_notif_pdu(Vbs, 'snmpv2-trap'), % Yes, v2
+ ContextEngineId = snmp_framework_mib:get_engine_id(),
+ lists:foreach(fun(Recv) ->
+ ?vtrace("~n send v3 notif to ~p",[Recv]),
+ NetIf ! {send_pdu, 'version-3', TrapPdu,
+ {v3, ContextEngineId, ContextName}, [Recv]}
+ end, Recvs),
+ ok.
+
+do_send_v3_inform([], _ContextName, _Vbs, _Recv, _NetIf) ->
+ ok;
+do_send_v3_inform(Recvs, ContextName, Vbs, Recv, NetIf) ->
+ lists:foreach(
+ fun({Addr, MsgData, Timeout, Retry}) ->
+ ?vtrace("~n start inform sender to send v3 inform to ~p",
+ [Addr]),
+ proc_lib:spawn_link(?MODULE, init_v3_inform,
+ [{Addr, MsgData}, Timeout, Retry, Vbs,
+ Recv, NetIf, ContextName,
+ get(verbosity), get(sname)])
+ end,
+ Recvs).
+
+%% New process
+init_v2_inform(Addr, Timeout, Retry, Vbs, Recv, NetIf, Community,V,S) ->
+ %% Make a new Inform for each recipient; they need unique
+ %% request-ids!
+ put(verbosity,V),
+ put(sname,inform_sender_short_name(S)),
+ ?vdebug("~n starting with timeout = ~p and retry = ~p",
+ [Timeout,Retry]),
+ InformPdu = make_v2_notif_pdu(Vbs, 'inform-request'),
+ Msg = {send_pdu_req, 'version-2', InformPdu, {community, Community},
+ [Addr], self()},
+ ?MODULE:send_inform(Addr, Timeout*10, Retry, Msg, Recv, NetIf).
+
+
+%% New process
+init_v3_inform(Addr, Timeout, Retry, Vbs, Recv, NetIf, ContextName,V,S) ->
+ %% Make a new Inform for each recipient; they need unique
+ %% request-ids!
+ put(verbosity,V),
+ put(sname,inform_sender_short_name(S)),
+ ?vdebug("~n starting with timeout = ~p and retry = ~p",
+ [Timeout,Retry]),
+ InformPdu = make_v2_notif_pdu(Vbs, 'inform-request'), % Yes, v2
+ ContextEngineId = snmp_framework_mib:get_engine_id(),
+ Msg = {send_pdu_req, 'version-3', InformPdu,
+ {v3, ContextEngineId, ContextName}, [Addr], self()},
+ ?MODULE:send_inform(Addr, Timeout*10, Retry, Msg, Recv, NetIf).
+
+send_inform(Addr, _Timeout, -1, _Msg, Recv, _NetIf) ->
+ ?vinfo("~n Delivery of send-pdu-request to net-if failed: reply timeout",
+ []),
+ deliver_recv(Recv, snmp_notification, {no_response, Addr});
+send_inform(Addr, Timeout, Retry, Msg, Recv, NetIf) ->
+ ?vtrace("deliver send-pdu-request to net-if when"
+ "~n Timeout: ~p"
+ "~n Retry: ~p",[Timeout, Retry]),
+ NetIf ! Msg,
+ receive
+ {snmp_response_received, _Vsn, _Pdu, _From} ->
+ ?vtrace("received response for ~p (when Retry = ~p)",
+ [Recv, Retry]),
+ deliver_recv(Recv, snmp_notification, {got_response, Addr})
+ after
+ Timeout ->
+ ?MODULE:send_inform(Addr, Timeout*2, Retry-1, Msg, Recv, NetIf)
+ end.
+
+% A nasty bit of verbosity setup...
+inform_sender_short_name(ma) -> mais;
+inform_sender_short_name(maw) -> mais;
+inform_sender_short_name(mats) -> mais;
+inform_sender_short_name(_) -> sais.
+
+deliver_recv(no_receiver, _MsgId, _Result) ->
+ ?vtrace("deliver_recv -> no receiver", []),
+ ok;
+deliver_recv(#snmpa_notification_delivery_info{tag = Tag,
+ mod = Mod,
+ extra = Extra},
+ snmp_targets, TAddrs) when is_list(TAddrs) ->
+ ?vtrace("deliver_recv(snmp_targets) -> entry with"
+ "~n Tag: ~p"
+ "~n Mod: ~p"
+ "~n Extra: ~p"
+ "~n TAddrs: ~p"
+ "", [Tag, Mod, Extra, TAddrs]),
+ Addrs = transform_taddrs(TAddrs),
+ (catch Mod:delivery_targets(Tag, Addrs, Extra));
+deliver_recv(#snmpa_notification_delivery_info{tag = Tag,
+ mod = Mod,
+ extra = Extra},
+ snmp_notification, {DeliveryResult, TAddr}) ->
+ ?vtrace("deliver_recv -> entry with"
+ "~n Tag: ~p"
+ "~n Mod: ~p"
+ "~n Extra: ~p"
+ "~n DeliveryResult: ~p"
+ "~n TAddr: ~p"
+ "", [Tag, Mod, Extra, DeliveryResult, TAddr]),
+ Addr = transform_taddr(TAddr),
+ (catch Mod:delivery_info(Tag, Addr, DeliveryResult, Extra));
+deliver_recv({Tag, Receiver}, MsgId, Result) ->
+ ?vtrace("deliver_recv -> entry with"
+ "~n Tag: ~p"
+ "~n Receiver: ~p"
+ "~n MsgId: ~p"
+ "~n Result: ~p"
+ "", [Tag, Receiver, MsgId, Result]),
+ Msg = {MsgId, Tag, Result},
+ case Receiver of
+ Pid when is_pid(Pid) ->
+ Pid ! Msg;
+ Name when is_atom(Name) ->
+ catch Name ! Msg;
+ {M, F, A} ->
+ catch M:F([Msg | A]);
+ Else ->
+ ?vinfo("~n Cannot deliver acknowledgment: bad receiver = '~p'",
+ [Else]),
+ user_err("snmpa: bad receiver, ~w\n", [Else])
+ end;
+deliver_recv(Else, _MsgId, _Result) ->
+ ?vinfo("~n Cannot deliver acknowledgment: bad receiver = '~p'",
+ [Else]),
+ user_err("snmpa: bad receiver, ~w\n", [Else]).
+
+transform_taddrs(Addrs) ->
+ [transform_taddr(Addr) || Addr <- Addrs].
+
+transform_taddr({?snmpUDPDomain, [A1, A2, A3, A4, P1, P2]}) -> % v2
+ Addr = {A1, A2, A3, A4},
+ Port = P1 bsl 8 + P2,
+ {Addr, Port};
+transform_taddr({{?snmpUDPDomain, [A1, A2, A3, A4, P1, P2]}, _MsgData}) -> % v3
+ Addr = {A1, A2, A3, A4},
+ Port = P1 bsl 8 + P2,
+ {Addr, Port}.
+
+
+check_all_varbinds(#notification{oid = Oid}, Vbs, MibView) ->
+ case snmpa_acm:validate_mib_view(Oid, MibView) of
+ true -> check_all_varbinds(Vbs, MibView);
+ false -> false
+ end;
+check_all_varbinds(#trap{enterpriseoid = Enter, specificcode = Spec},
+ Vbs, MibView) ->
+ %% Use alg. in rfc1908 to map a v1 trap to a v2 trap
+ Oid = case Enter of
+ ?snmp -> ?snmpTraps ++ [Spec + 1];
+ _ -> Enter ++ [0, Spec]
+ end,
+ case snmpa_acm:validate_mib_view(Oid, MibView) of
+ true -> check_all_varbinds(Vbs, MibView);
+ false -> false
+ end.
+
+check_all_varbinds([#varbind{oid = Oid} | Vbs], MibView) ->
+ case snmpa_acm:validate_mib_view(Oid, MibView) of
+ true -> check_all_varbinds(Vbs, MibView);
+ false -> false
+ end;
+check_all_varbinds([], _MibView) ->
+ true.
+
+
+%%--------------------------------------------------
+%% Functions to access the local mib.
+%%--------------------------------------------------
+sys_object_id() ->
+ case snmpa_agent:do_get(snmpa_acm:get_root_mib_view(),
+ [#varbind{oid = ?sysObjectID_instance}],
+ true) of
+ {noError, _, [#varbind{value = Value}]} ->
+ Value;
+ X ->
+ user_err("sysObjectID bad return value ~w", [X])
+ end.
+
+%% Collect all ADDRs for each community together.
+%% In: [{Addr, Community}]
+%% Out: [{Community, [Addr]}]
+mk_addr_communities(Recvs) ->
+ [{Addr, Comm} | T] = lists:keysort(2, Recvs),
+ mic(T, Comm, [Addr], []).
+
+mic([{Addr, Comm} | T], CurComm, AddrList, Res) when Comm == CurComm ->
+ mic(T, CurComm, [Addr | AddrList], Res);
+mic([{Addr, Comm} | T], CurComm, AddrList, Res) ->
+ mic(T, Comm, [Addr], [{CurComm, AddrList} | Res]);
+mic([], CurComm, AddrList, Res) ->
+ [{CurComm, AddrList} | Res].
+
+%%-----------------------------------------------------------------
+%% Convert the SecurityLevel into a flag value used by snmpa_mpd
+%%-----------------------------------------------------------------
+mk_flag(?'SnmpSecurityLevel_noAuthNoPriv') -> 0;
+mk_flag(?'SnmpSecurityLevel_authNoPriv') -> 1;
+mk_flag(?'SnmpSecurityLevel_authPriv') -> 3.
+
+
+%%--------------------------------------------------
+%% Mib view wrapper
+%%--------------------------------------------------
+get_mib_view(SecModel, SecName, SecLevel, ContextName) ->
+ snmpa_vacm:get_mib_view(notify,
+ SecModel, SecName, SecLevel, ContextName).
+
+
+user_err(F, A) ->
+ snmpa_error:user_err(F, A).
diff --git a/lib/snmp/src/agent/snmpa_usm.erl b/lib/snmp/src/agent/snmpa_usm.erl
new file mode 100644
index 0000000000..a8c395534f
--- /dev/null
+++ b/lib/snmp/src/agent/snmpa_usm.erl
@@ -0,0 +1,745 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1999-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%
+%%
+-module(snmpa_usm).
+
+-export([
+ process_incoming_msg/4,
+ generate_outgoing_msg/5,
+ generate_discovery_msg/4, generate_discovery_msg/5,
+ current_statsNotInTimeWindows_vb/0
+ ]).
+
+-define(SNMP_USE_V3, true).
+-include("snmp_types.hrl").
+-include("SNMP-USER-BASED-SM-MIB.hrl").
+-include("SNMP-USM-AES-MIB.hrl").
+-include("SNMPv2-TC.hrl").
+
+-define(VMODULE,"A-USM").
+-include("snmp_verbosity.hrl").
+
+
+%%-----------------------------------------------------------------
+%% This module implements the User Based Security Model for SNMP,
+%% as defined in rfc2274.
+%%-----------------------------------------------------------------
+
+%% Columns not accessible via SNMP
+-define(usmUserAuthKey, 14).
+-define(usmUserPrivKey, 15).
+
+-define(i32(Int), (Int bsr 24) band 255, (Int bsr 16) band 255, (Int bsr 8) band 255, Int band 255).
+-define(i64(Int), (Int bsr 56) band 255, (Int bsr 48) band 255, (Int bsr 40) band 255, (Int bsr 32) band 255, (Int bsr 24) band 255, (Int bsr 16) band 255, (Int bsr 8) band 255, Int band 255).
+
+
+%%-----------------------------------------------------------------
+%% Func: process_incoming_msg(Packet, Data, SecParams, SecLevel) ->
+%% {ok, {SecEngineID, SecName, ScopedPDUBytes, SecData}} |
+%% {error, Reason} | {error, Reason, ErrorInfo}
+%% Return value may be throwed.
+%% Types: Reason -> term()
+%% Purpose:
+%%-----------------------------------------------------------------
+
+process_incoming_msg(Packet, Data, SecParams, SecLevel) ->
+ TermDiscoEnabled = is_terminating_discovery_enabled(),
+ TermTriggerUsername = terminating_trigger_username(),
+ %% 3.2.1
+ ?vtrace("process_incoming_msg -> check security parms: 3.2.1",[]),
+ UsmSecParams =
+ case catch snmp_pdus:dec_usm_security_parameters(SecParams) of
+ {'EXIT', Reason} ->
+ inc(snmpInASNParseErrs),
+ error({parseError, Reason}, []);
+ Res ->
+ Res
+ end,
+ case UsmSecParams of
+ #usmSecurityParameters{msgAuthoritativeEngineID = MsgAuthEngineID,
+ msgUserName = TermTriggerUsername} when TermDiscoEnabled =:= true ->
+ %% Step 1 discovery message
+ ?vtrace("process_incoming_msg -> [~p] discovery step 1",
+ [TermTriggerUsername]),
+ process_discovery_msg(MsgAuthEngineID, Data, SecLevel);
+
+ #usmSecurityParameters{msgAuthoritativeEngineID = MsgAuthEngineID,
+ msgUserName = MsgUserName} ->
+ ?vlog("process_incoming_msg -> USM security parms: "
+ "~n msgAuthEngineID: ~w"
+ "~n userName: ~p", [MsgAuthEngineID, MsgUserName]),
+ %% 3.2.3
+ ?vtrace("process_incoming_msg -> check engine id: 3.2.3",[]),
+ case snmp_user_based_sm_mib:is_engine_id_known(MsgAuthEngineID) of
+ true ->
+ ok;
+ false ->
+ SecData1 = [MsgUserName],
+ error(usmStatsUnknownEngineIDs,
+ ?usmStatsUnknownEngineIDs_instance, %% OTP-3542
+ undefined, [{sec_data, SecData1}])
+ end,
+ %% 3.2.4
+ ?vtrace("process_incoming_msg -> retrieve usm user: 3.2.4",[]),
+ UsmUser =
+ case snmp_user_based_sm_mib:get_user(MsgAuthEngineID,
+ MsgUserName) of
+ User when element(?usmUserStatus, User) =:= ?'RowStatus_active' ->
+ User;
+ {_, Name,_,_,_,_,_,_,_,_,_,_,_, RowStatus,_,_} ->
+ ?vdebug("process_incoming_msg -> "
+ "found user ~p with wrong row status: ~p",
+ [Name, RowStatus]),
+ SecData2 = [MsgUserName],
+ error(usmStatsUnknownUserNames,
+ ?usmStatsUnknownUserNames_instance, %% OTP-3542
+ undefined, [{sec_data, SecData2}]);
+ _ -> % undefined or not active user
+ SecData2 = [MsgUserName],
+ error(usmStatsUnknownUserNames,
+ ?usmStatsUnknownUserNames_instance, %% OTP-3542
+ undefined, [{sec_data, SecData2}])
+ end,
+ SecName = element(?usmUserSecurityName, UsmUser),
+ ?vtrace("process_incoming_msg -> securityName: ~p",[SecName]),
+ %% 3.2.5 - implicit in following checks
+ %% 3.2.6 - 3.2.7
+ ?vtrace("process_incoming_msg -> "
+ "authenticate incoming: 3.2.5 - 3.2.7"
+ "~n ~p",[UsmUser]),
+ DiscoOrPlain = authenticate_incoming(Packet,
+ UsmSecParams, UsmUser,
+ SecLevel),
+ %% 3.2.8
+ ?vtrace("process_incoming_msg -> "
+ "decrypt scoped data: 3.2.8",[]),
+ ScopedPDUBytes =
+ decrypt(Data, UsmUser, UsmSecParams, SecLevel),
+ %% 3.2.9
+ %% Means that if AuthKey/PrivKey are changed;
+ %% the old values will be used.
+ ?vtrace("process_incoming_msg -> "
+ "AuthKey/PrivKey are changed - "
+ "use old values: 3.2.9",[]),
+ CachedSecData = {MsgUserName,
+ element(?usmUserAuthProtocol, UsmUser),
+ element(?usmUserPrivProtocol, UsmUser),
+ element(?usmUserAuthKey, UsmUser),
+ element(?usmUserPrivKey, UsmUser)},
+ {ok, {MsgAuthEngineID, SecName, ScopedPDUBytes,
+ CachedSecData, DiscoOrPlain}}
+ end.
+
+%% Process a step 1 discovery message
+process_discovery_msg(MsgAuthEngineID, Data, SecLevel) ->
+ ?vtrace("process_discovery_msg -> entry with"
+ "~n Data: ~p"
+ "~n SecLevel: ~p", [Data, SecLevel]),
+ case (not snmp_misc:is_priv(SecLevel)) of
+ true -> % noAuthNoPriv
+ ?vtrace("process_discovery_msg -> noAuthNoPriv", []),
+ ScopedPDUBytes = Data,
+ SecData = {"", usmNoAuthProtocol, "", usmNoPrivProtocol, ""},
+ NewData = {SecData,
+ ?usmStatsUnknownEngineIDs_instance,
+ get_counter(usmStatsUnknownEngineIDs)},
+ {ok, {MsgAuthEngineID, "", ScopedPDUBytes, NewData, discovery}};
+ false ->
+ error(usmStatsUnknownEngineIDs,
+ ?usmStatsUnknownEngineIDs_instance,
+ undefined, [{sec_data, ""}])
+ end.
+
+
+authenticate_incoming(Packet, UsmSecParams, UsmUser, SecLevel) ->
+ %% 3.2.6
+ ?vtrace("authenticate_incoming -> 3.2.6", []),
+ AuthProtocol = element(?usmUserAuthProtocol, UsmUser),
+ #usmSecurityParameters{msgAuthoritativeEngineID = MsgAuthEngineID,
+ msgAuthoritativeEngineBoots = MsgAuthEngineBoots,
+ msgAuthoritativeEngineTime = MsgAuthEngineTime,
+ msgAuthenticationParameters = MsgAuthParams} =
+ UsmSecParams,
+ ?vtrace("authenticate_incoming -> Sec params: "
+ "~n MsgAuthEngineID: ~w"
+ "~n MsgAuthEngineBoots: ~p"
+ "~n MsgAuthEngineTime: ~p",
+ [MsgAuthEngineID, MsgAuthEngineBoots, MsgAuthEngineTime]),
+ case snmp_misc:is_auth(SecLevel) of
+ true ->
+ SecName = element(?usmUserSecurityName, UsmUser),
+ case is_auth(AuthProtocol,
+ element(?usmUserAuthKey, UsmUser),
+ MsgAuthParams,
+ Packet,
+ SecName,
+ MsgAuthEngineID,
+ MsgAuthEngineBoots,
+ MsgAuthEngineTime) of
+ discovery ->
+ discovery;
+ true ->
+ plain;
+ false ->
+ error(usmStatsWrongDigests,
+ ?usmStatsWrongDigests_instance, % OTP-5464
+ SecName)
+ end;
+
+ false -> % noAuth
+ plain
+ end.
+
+authoritative(SecName, MsgAuthEngineBoots, MsgAuthEngineTime) ->
+ ?vtrace("authoritative -> entry with"
+ "~n SecName: ~p"
+ "~n MsgAuthEngineBoots: ~p"
+ "~n MsgAuthEngineTime: ~p",
+ [SecName, MsgAuthEngineBoots, MsgAuthEngineTime]),
+ SnmpEngineBoots = snmp_framework_mib:get_engine_boots(),
+ ?vtrace("authoritative -> SnmpEngineBoots: ~p", [SnmpEngineBoots]),
+ SnmpEngineTime = snmp_framework_mib:get_engine_time(),
+ ?vtrace("authoritative -> SnmpEngineTime: ~p", [SnmpEngineTime]),
+ InTimeWindow =
+ if
+ SnmpEngineBoots =:= 2147483647 -> false;
+ MsgAuthEngineBoots =/= SnmpEngineBoots -> false;
+ MsgAuthEngineTime + 150 < SnmpEngineTime -> false;
+ MsgAuthEngineTime - 150 > SnmpEngineTime -> false;
+ true -> true
+ end,
+ case InTimeWindow of
+ true ->
+ true;
+ false ->
+ %% OTP-4090 (OTP-3542)
+ ?vinfo("NOT in time window: "
+ "~n SecName: ~p"
+ "~n SnmpEngineBoots: ~p"
+ "~n MsgAuthEngineBoots: ~p"
+ "~n SnmpEngineTime: ~p"
+ "~n MsgAuthEngineTime: ~p",
+ [SecName,
+ SnmpEngineBoots, MsgAuthEngineBoots,
+ SnmpEngineTime, MsgAuthEngineTime]),
+ error(usmStatsNotInTimeWindows,
+ ?usmStatsNotInTimeWindows_instance,
+ SecName,
+ [{securityLevel, 1}]) % authNoPriv
+ end.
+
+non_authoritative(SecName,
+ MsgAuthEngineID, MsgAuthEngineBoots, MsgAuthEngineTime) ->
+ ?vtrace("non_authoritative -> entry with"
+ "~n SecName: ~p"
+ "~n MsgAuthEngineID: ~p"
+ "~n MsgAuthEngineBoots: ~p"
+ "~n MsgAuthEngineTime: ~p",
+ [SecName,
+ MsgAuthEngineID, MsgAuthEngineBoots, MsgAuthEngineTime]),
+ SnmpEngineBoots = get_engine_boots(MsgAuthEngineID),
+ SnmpEngineTime = get_engine_time(MsgAuthEngineID),
+ LatestRecvTime = get_engine_latest_time(MsgAuthEngineID),
+ ?vtrace("non_authoritative -> "
+ "~n SnmpEngineBoots: ~p"
+ "~n SnmpEngineTime: ~p"
+ "~n LatestRecvTime: ~p",
+ [SnmpEngineBoots, SnmpEngineTime, LatestRecvTime]),
+ UpdateLCD =
+ if
+ MsgAuthEngineBoots > SnmpEngineBoots -> true;
+ ((MsgAuthEngineBoots =:= SnmpEngineBoots) andalso
+ (MsgAuthEngineTime > LatestRecvTime)) -> true;
+ true -> false
+ end,
+ case UpdateLCD of
+ true -> %% 3.2.7b1
+ ?vtrace("non_authoritative -> "
+ "update msgAuthoritativeEngineID: 3.2.7b1",
+ []),
+ set_engine_boots(MsgAuthEngineID, MsgAuthEngineBoots),
+ set_engine_time(MsgAuthEngineID, MsgAuthEngineTime),
+ set_engine_latest_time(MsgAuthEngineID, MsgAuthEngineTime);
+ false ->
+ ok
+ end,
+ %% 3.2.7.b2
+ ?vtrace("non_authoritative -> "
+ "check if message is outside time window: 3.2.7b2", []),
+ InTimeWindow =
+ if
+ SnmpEngineBoots =:= 2147483647 ->
+ false;
+ MsgAuthEngineBoots < SnmpEngineBoots ->
+ false;
+ ((MsgAuthEngineBoots =:= SnmpEngineBoots) andalso
+ (MsgAuthEngineTime < (SnmpEngineTime - 150))) ->
+ false;
+ true -> true
+ end,
+ case InTimeWindow of
+ false ->
+ ?vinfo("NOT in time window: "
+ "~n SecName: ~p"
+ "~n SnmpEngineBoots: ~p"
+ "~n MsgAuthEngineBoots: ~p"
+ "~n SnmpEngineTime: ~p"
+ "~n MsgAuthEngineTime: ~p",
+ [SecName,
+ SnmpEngineBoots, MsgAuthEngineBoots,
+ SnmpEngineTime, MsgAuthEngineTime]),
+ error(notInTimeWindow, []);
+ true ->
+ %% If the previous values where all zero's this is the
+ %% second stage discovery message
+ if
+ ((SnmpEngineBoots =:= 0) andalso
+ (SnmpEngineTime =:= 0) andalso
+ (LatestRecvTime =:= 0)) ->
+ ?vtrace("non_authoritative -> "
+ "[maybe] originating discovery stage 2", []),
+ discovery;
+ true ->
+ true
+ end
+ end.
+
+
+is_auth(?usmNoAuthProtocol, _, _, _, SecName, _, _, _) -> % 3.2.5
+ error(usmStatsUnsupportedSecLevels,
+ ?usmStatsUnsupportedSecLevels_instance, SecName); % OTP-5464
+is_auth(AuthProtocol, AuthKey, AuthParams, Packet, SecName,
+ MsgAuthEngineID, MsgAuthEngineBoots, MsgAuthEngineTime) ->
+ TermDiscoEnabled = is_terminating_discovery_enabled(),
+ TermDiscoStage2 = terminating_discovery_stage2(),
+ IsAuth = auth_in(AuthProtocol, AuthKey, AuthParams, Packet),
+ ?vtrace("is_auth -> IsAuth: ~p", [IsAuth]),
+ case IsAuth of
+ true ->
+ %% 3.2.7
+ ?vtrace("is_auth -> "
+ "retrieve EngineBoots and EngineTime: 3.2.7",[]),
+ SnmpEngineID = snmp_framework_mib:get_engine_id(),
+ ?vtrace("is_auth -> SnmpEngineID: ~p", [SnmpEngineID]),
+ case MsgAuthEngineID of
+ SnmpEngineID when ((MsgAuthEngineBoots =:= 0) andalso
+ (MsgAuthEngineTime =:= 0) andalso
+ (TermDiscoEnabled =:= true) andalso
+ (TermDiscoStage2 =:= discovery)) -> %% 3.2.7a
+ ?vtrace("is_auth -> terminating discovery stage 2 - discovery",[]),
+ discovery;
+ SnmpEngineID when ((MsgAuthEngineBoots =:= 0) andalso
+ (MsgAuthEngineTime =:= 0) andalso
+ (TermDiscoEnabled =:= true) andalso
+ (TermDiscoStage2 =:= plain)) -> %% 3.2.7a
+ ?vtrace("is_auth -> terminating discovery stage 2 - plain",[]),
+ %% This will *always* result in the manager *not*
+ %% beeing in timewindow
+ authoritative(SecName,
+ MsgAuthEngineBoots, MsgAuthEngineTime);
+
+ SnmpEngineID -> %% 3.2.7a
+ ?vtrace("is_auth -> we are authoritative: 3.2.7a", []),
+ authoritative(SecName,
+ MsgAuthEngineBoots, MsgAuthEngineTime);
+
+ _ -> %% 3.2.7b - we're non-authoritative
+ ?vtrace("is_auth -> we are non-authoritative: 3.2.7b",[]),
+ non_authoritative(SecName,
+ MsgAuthEngineID,
+ MsgAuthEngineBoots, MsgAuthEngineTime)
+ end;
+
+ false ->
+ false
+ end.
+
+
+decrypt(Data, UsmUser, UsmSecParams, SecLevel) ->
+ case snmp_misc:is_priv(SecLevel) of
+ true ->
+ do_decrypt(Data, UsmUser, UsmSecParams);
+ false ->
+ Data
+ end.
+
+do_decrypt(Data, UsmUser, UsmSecParams) ->
+ EncryptedPDU = snmp_pdus:dec_scoped_pdu_data(Data),
+ SecName = element(?usmUserSecurityName, UsmUser),
+ PrivP = element(?usmUserPrivProtocol, UsmUser),
+ PrivKey = element(?usmUserPrivKey, UsmUser),
+ ?vtrace("do_decrypt -> try decrypt with: "
+ "~n SecName: ~p"
+ "~n PrivP: ~p", [SecName, PrivP]),
+ try_decrypt(PrivP, PrivKey, UsmSecParams, EncryptedPDU, SecName).
+
+try_decrypt(?usmNoPrivProtocol, _, _, _, SecName) -> % 3.2.5
+ error(usmStatsUnsupportedSecLevels,
+ ?usmStatsUnsupportedSecLevels_instance, SecName); % OTP-5464
+try_decrypt(?usmDESPrivProtocol,
+ PrivKey, UsmSecParams, EncryptedPDU, SecName) ->
+ case (catch des_decrypt(PrivKey, UsmSecParams, EncryptedPDU)) of
+ {ok, DecryptedData} ->
+ DecryptedData;
+ _ ->
+ error(usmStatsDecryptionErrors,
+ ?usmStatsDecryptionErrors_instance, % OTP-5464
+ SecName)
+ end;
+try_decrypt(?usmAesCfb128Protocol,
+ PrivKey, UsmSecParams, EncryptedPDU, SecName) ->
+ case (catch aes_decrypt(PrivKey, UsmSecParams, EncryptedPDU)) of
+ {ok, DecryptedData} ->
+ DecryptedData;
+ _ ->
+ error(usmStatsDecryptionErrors,
+ ?usmStatsDecryptionErrors_instance, % OTP-5464
+ SecName)
+ end.
+
+
+generate_outgoing_msg(Message, SecEngineID, SecName, SecData, SecLevel) ->
+ %% 3.1.1
+ ?vtrace("generate_outgoing_msg -> [3.1.1] entry with"
+ "~n SecEngineID: ~p"
+ "~n SecName: ~p"
+ "~n SecLevel: ~w",
+ [SecEngineID, SecName, SecLevel]),
+ {UserName, AuthProtocol, PrivProtocol, AuthKey, PrivKey} =
+ case SecData of
+ [] -> % 3.1.1b
+ %% Not a response - read from LCD
+ case snmp_user_based_sm_mib:get_user_from_security_name(
+ SecEngineID, SecName) of
+ User when element(?usmUserStatus, User) =:=
+ ?'RowStatus_active' ->
+ {element(?usmUserName, User),
+ element(?usmUserAuthProtocol, User),
+ element(?usmUserPrivProtocol, User),
+ element(?usmUserAuthKey, User),
+ element(?usmUserPrivKey, User)};
+ {_, Name,_,_,_,_,_,_,_,_,_,_,_, RowStatus,_,_} ->
+ ?vdebug("generate_outgoing_msg -> "
+ "found user ~p with wrong row status: ~p",
+ [Name, RowStatus]),
+ error(unknownSecurityName);
+ _ ->
+ error(unknownSecurityName)
+ end;
+ [MsgUserName] ->
+ %% This means the user at the engine is unknown
+ {MsgUserName, ?usmNoAuthProtocol, ?usmNoPrivProtocol, "", ""};
+ _ -> % 3.1.1a
+ SecData
+ end,
+ %% 3.1.4
+ ?vtrace("generate_outgoing_msg -> [3.1.4]"
+ "~n UserName: ~p"
+ "~n AuthProtocol: ~p"
+ "~n PrivProtocol: ~p",
+ [UserName, AuthProtocol, PrivProtocol]),
+ ScopedPduBytes = Message#message.data,
+ {ScopedPduData, MsgPrivParams} =
+ encrypt(ScopedPduBytes, PrivProtocol, PrivKey, SecLevel),
+ SnmpEngineID = snmp_framework_mib:get_engine_id(),
+ ?vtrace("generate_outgoing_msg -> SnmpEngineID: ~p [3.1.6]",
+ [SnmpEngineID]),
+ %% 3.1.6
+ {MsgAuthEngineBoots, MsgAuthEngineTime} =
+ case snmp_misc:is_auth(SecLevel) of
+ false when SecData =:= [] -> % not a response
+ {0, 0};
+ false when UserName =:= "" -> % reply (report) to discovery step 1
+ {0, 0};
+ true when SecEngineID =/= SnmpEngineID ->
+ {get_engine_boots(SecEngineID),
+ get_engine_time(SecEngineID)};
+ _ ->
+ {snmp_framework_mib:get_engine_boots(),
+ snmp_framework_mib:get_engine_time()}
+ end,
+ %% 3.1.5 - 3.1.7
+ ?vtrace("generate_outgoing_msg -> [3.1.5 - 3.1.7]",[]),
+ UsmSecParams =
+ #usmSecurityParameters{msgAuthoritativeEngineID = SecEngineID,
+ msgAuthoritativeEngineBoots = MsgAuthEngineBoots,
+ msgAuthoritativeEngineTime = MsgAuthEngineTime,
+ msgUserName = UserName,
+ msgPrivacyParameters = MsgPrivParams},
+ Message2 = Message#message{data = ScopedPduData},
+ %% 3.1.8
+ ?vtrace("generate_outgoing_msg -> [3.1.8]",[]),
+ authenticate_outgoing(Message2, UsmSecParams,
+ AuthKey, AuthProtocol, SecLevel).
+
+
+generate_discovery_msg(Message, SecEngineID, SecName, SecLevel) ->
+ generate_discovery_msg(Message, SecEngineID, SecName, SecLevel, "").
+
+generate_discovery_msg(Message,
+ SecEngineID, SecName, SecLevel,
+ InitialUserName) ->
+ ?vtrace("generate_discovery_msg -> entry with"
+ "~n SecEngineID: ~p"
+ "~n SecName: ~p"
+ "~n SecLevel: ~p"
+ "~n InitialUserName: ~p",
+ [SecEngineID, SecName, SecLevel, InitialUserName]),
+ {UserName, AuthProtocol, AuthKey, PrivProtocol, PrivKey} =
+ case SecEngineID of
+ "" ->
+ %% Discovery step 1
+ %% Nothing except the user name will be used in this
+ %% tuple in this step, but since we need some values,
+ %% we fill in proper ones just in case
+ %% {"initial", usmNoAuthProtocol, "", usmNoPrivProtocol, ""};
+ %% {"", usmNoAuthProtocol, "", usmNoPrivProtocol, ""};
+ {InitialUserName,
+ usmNoAuthProtocol, "", usmNoPrivProtocol, ""};
+
+ _ ->
+ %% Discovery step 2
+ case snmp_user_based_sm_mib:get_user_from_security_name(
+ SecEngineID, SecName) of
+ User when element(?usmUserStatus, User) =:=
+ ?'RowStatus_active' ->
+ {element(?usmUserName, User),
+ element(?usmUserAuthProtocol, User),
+ element(?usmUserAuthKey, User),
+ element(?usmUserPrivProtocol, User),
+ element(?usmUserPrivKey, User)};
+ {_, Name,_,_,_,_,_,_,_,_,_,_,_, RowStatus,_,_} ->
+ ?vdebug("generate_discovery_msg -> "
+ "found user ~p with wrong row status: ~p",
+ [Name, RowStatus]),
+ error(unknownSecurityName);
+ _ ->
+ error(unknownSecurityName)
+ end
+ end,
+ ScopedPduBytes = Message#message.data,
+ {ScopedPduData, MsgPrivParams} =
+ encrypt(ScopedPduBytes, PrivProtocol, PrivKey, SecLevel),
+ UsmSecParams =
+ #usmSecurityParameters{msgAuthoritativeEngineID = SecEngineID,
+ msgAuthoritativeEngineBoots = 0, % Boots,
+ msgAuthoritativeEngineTime = 0, % Time,
+ msgUserName = UserName,
+ msgPrivacyParameters = MsgPrivParams},
+ Message2 = Message#message{data = ScopedPduData},
+ authenticate_outgoing(Message2, UsmSecParams,
+ AuthKey, AuthProtocol, SecLevel).
+
+
+%% Ret: {ScopedPDU, MsgPrivParams} - both are already encoded as OCTET STRINGs
+encrypt(Data, PrivProtocol, PrivKey, SecLevel) ->
+ case snmp_misc:is_priv(SecLevel) of
+ false -> % 3.1.4b
+ ?vtrace("encrypt -> 3.1.4b",[]),
+ {Data, []};
+ true -> % 3.1.4a
+ ?vtrace("encrypt -> 3.1.4a",[]),
+ case (catch try_encrypt(PrivProtocol, PrivKey, Data)) of
+ {ok, ScopedPduData, MsgPrivParams} ->
+ ?vtrace("encrypt -> encode tag",[]),
+ {snmp_pdus:enc_oct_str_tag(ScopedPduData), MsgPrivParams};
+ {error, Reason} ->
+ error(Reason);
+ _Error ->
+ error(encryptionError)
+ end
+ end.
+
+try_encrypt(?usmNoPrivProtocol, _PrivKey, _Data) -> % 3.1.2
+ error(unsupportedSecurityLevel);
+try_encrypt(?usmDESPrivProtocol, PrivKey, Data) ->
+ des_encrypt(PrivKey, Data);
+try_encrypt(?usmAesCfb128Protocol, PrivKey, Data) ->
+ aes_encrypt(PrivKey, Data).
+
+
+authenticate_outgoing(Message, UsmSecParams,
+ AuthKey, AuthProtocol, SecLevel) ->
+ Message2 =
+ case snmp_misc:is_auth(SecLevel) of
+ true ->
+ auth_out(AuthProtocol, AuthKey, Message, UsmSecParams);
+ false ->
+ set_msg_auth_params(Message, UsmSecParams)
+ end,
+ ?vtrace("authenticate_outgoing -> encode message only",[]),
+ snmp_pdus:enc_message_only(Message2).
+
+
+
+%%-----------------------------------------------------------------
+%% Auth and priv algorithms
+%%-----------------------------------------------------------------
+auth_in(AuthProtocol, AuthKey, AuthParams, Packet) ->
+ snmp_usm:auth_in(AuthProtocol, AuthKey, AuthParams, Packet).
+
+auth_out(AuthProtocol, AuthKey, Message, UsmSecParams) ->
+ snmp_usm:auth_out(AuthProtocol, AuthKey, Message, UsmSecParams).
+
+set_msg_auth_params(Message, UsmSecParams) ->
+ snmp_usm:set_msg_auth_params(Message, UsmSecParams, []).
+
+des_encrypt(PrivKey, Data) ->
+ snmp_usm:des_encrypt(PrivKey, Data, fun get_des_salt/0).
+
+des_decrypt(PrivKey, UsmSecParams, EncData) ->
+ #usmSecurityParameters{msgPrivacyParameters = PrivParms} = UsmSecParams,
+ snmp_usm:des_decrypt(PrivKey, PrivParms, EncData).
+
+get_des_salt() ->
+ SaltInt =
+ case catch ets:update_counter(snmp_agent_table, usm_des_salt, 1) of
+ N when N =< 4294967295 ->
+ N;
+ N when is_integer(N) -> % wrap
+ ets:insert(snmp_agent_table, {usm_des_salt, 0}),
+ 0;
+ _ -> % it doesn't exist, initialize
+ {A1,A2,A3} = erlang:now(),
+ random:seed(A1,A2,A3),
+ R = random:uniform(4294967295),
+ ets:insert(snmp_agent_table, {usm_des_salt, R}),
+ R
+ end,
+ EngineBoots = snmp_framework_mib:get_engine_boots(),
+ [?i32(EngineBoots), ?i32(SaltInt)].
+
+aes_encrypt(PrivKey, Data) ->
+ snmp_usm:aes_encrypt(PrivKey, Data, fun get_aes_salt/0).
+
+aes_decrypt(PrivKey, UsmSecParams, EncData) ->
+ #usmSecurityParameters{msgPrivacyParameters = PrivParams,
+ msgAuthoritativeEngineTime = EngineTime,
+ msgAuthoritativeEngineBoots = EngineBoots} =
+ UsmSecParams,
+ snmp_usm:aes_decrypt(PrivKey, PrivParams, EncData,
+ EngineBoots, EngineTime).
+
+get_aes_salt() ->
+ SaltInt =
+ case catch ets:update_counter(snmp_agent_table, usm_aes_salt, 1) of
+ N when N =< 36893488147419103231 ->
+ N;
+ N when is_integer(N) -> % wrap
+ ets:insert(snmp_agent_table, {usm_aes_salt, 0}),
+ 0;
+ _ -> % it doesn't exist, initialize
+ {A1,A2,A3} = erlang:now(),
+ random:seed(A1,A2,A3),
+ R = random:uniform(36893488147419103231),
+ ets:insert(snmp_agent_table, {usm_aes_salt, R}),
+ R
+ end,
+ [?i64(SaltInt)].
+
+
+
+%%-----------------------------------------------------------------
+%% Discovery wrapper functions
+%%-----------------------------------------------------------------
+
+is_terminating_discovery_enabled() ->
+ snmpa_agent:is_terminating_discovery_enabled().
+
+terminating_discovery_stage2() ->
+ snmpa_agent:terminating_discovery_stage2().
+
+terminating_trigger_username() ->
+ snmpa_agent:terminating_trigger_username().
+
+current_statsNotInTimeWindows_vb() ->
+ #varbind{oid = ?usmStatsNotInTimeWindows_instance,
+ variabletype = 'Counter32',
+ value = get_counter(usmStatsNotInTimeWindows)}.
+
+
+%%-----------------------------------------------------------------
+%% We cache the local values of all non-auth engines we know.
+%% Keep the values in the snmp_agent_table.
+%% See section 2.3 of the RFC.
+%%-----------------------------------------------------------------
+get_engine_boots(SnmpEngineID) ->
+ case ets:lookup(snmp_agent_table, {usm_eboots, SnmpEngineID}) of
+ [{_Key, Boots}] -> Boots;
+ _ -> 0
+ end.
+
+get_engine_time(SnmpEngineID) ->
+ case ets:lookup(snmp_agent_table, {usm_etime, SnmpEngineID}) of
+ [{_Key, Diff}] -> snmp_misc:now(sec) - Diff;
+ _ -> 0
+ end.
+
+get_engine_latest_time(SnmpEngineID) ->
+ case ets:lookup(snmp_agent_table, {usm_eltime, SnmpEngineID}) of
+ [{_Key, Time}] -> Time;
+ _ -> 0
+ end.
+
+
+set_engine_boots(SnmpEngineID, EngineBoots) ->
+ ets:insert(snmp_agent_table, {{usm_eboots, SnmpEngineID}, EngineBoots}).
+
+set_engine_time(SnmpEngineID, EngineTime) ->
+ Diff = snmp_misc:now(sec) - EngineTime,
+ ets:insert(snmp_agent_table, {{usm_etime, SnmpEngineID}, Diff}).
+
+set_engine_latest_time(SnmpEngineID, EngineTime) ->
+ ets:insert(snmp_agent_table, {{usm_eltime, SnmpEngineID}, EngineTime}).
+
+
+%%-----------------------------------------------------------------
+%% Utility functions
+%%-----------------------------------------------------------------
+error(Reason) ->
+ throw({error, Reason}).
+
+error(Reason, ErrorInfo) ->
+ throw({error, Reason, ErrorInfo}).
+
+error(Variable, Oid, SecName) ->
+ error(Variable, Oid, SecName, []).
+error(Variable, Oid, SecName, Opts) ->
+ Val = inc(Variable),
+ ErrorInfo = {#varbind{oid = Oid,
+ variabletype = 'Counter32',
+ value = Val},
+ SecName,
+ Opts},
+ throw({error, Variable, ErrorInfo}).
+
+inc(Name) -> ets:update_counter(snmp_agent_table, Name, 1).
+
+
+get_counter(Name) ->
+ case (catch ets:lookup(snmp_agent_table, Name)) of
+ [{_, Val}] ->
+ Val;
+ _ ->
+ 0
+ end.
+
+
+
+
+
diff --git a/lib/snmp/src/agent/snmpa_vacm.erl b/lib/snmp/src/agent/snmpa_vacm.erl
new file mode 100644
index 0000000000..2eacea4301
--- /dev/null
+++ b/lib/snmp/src/agent/snmpa_vacm.erl
@@ -0,0 +1,399 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1999-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%
+%%
+-module(snmpa_vacm).
+
+-export([get_mib_view/5]).
+-export([init/1, init/2, backup/1]).
+-export([delete/1, get_row/1, get_next_row/1, insert/1, insert/2,
+ dump_table/0]).
+
+-include("SNMPv2-TC.hrl").
+-include("SNMP-VIEW-BASED-ACM-MIB.hrl").
+-include("SNMP-FRAMEWORK-MIB.hrl").
+-include("snmp_types.hrl").
+-include("snmpa_vacm.hrl").
+
+-define(VMODULE,"VACM").
+-include("snmp_verbosity.hrl").
+
+
+%%%-----------------------------------------------------------------
+%%% Access Control Module for VACM (see also snmpa_acm)
+%%% This module implements:
+%%% 1. access control functions for VACM
+%%% 2. vacmAccessTable as an ordered ets table
+%%%
+%%% This version of VACM handles v1, v2c and v3.
+%%%-----------------------------------------------------------------
+
+%%%-----------------------------------------------------------------
+%%% 1. access control functions for VACM
+%%%-----------------------------------------------------------------
+%%-----------------------------------------------------------------
+%% Func: get_mib_view/5 -> {ok, ViewName} |
+%% {discarded, Reason}
+%% Types: ViewType = read | write | notify
+%% SecModel = ?SEC_* (see snmp_types.hrl)
+%% SecName = string()
+%% SecLevel = ?'SnmpSecurityLevel_*' (see SNMP-FRAMEWORK-MIB.hrl)
+%% ContextName = string()
+%% Purpose: This function is used to map VACM parameters to a mib
+%% view.
+%%-----------------------------------------------------------------
+get_mib_view(ViewType, SecModel, SecName, SecLevel, ContextName) ->
+ check_auth(catch auth(ViewType, SecModel, SecName, SecLevel, ContextName)).
+
+
+%% Follows the procedure in rfc2275
+auth(ViewType, SecModel, SecName, SecLevel, ContextName) ->
+ % 3.2.1 - Check that the context is known to us
+ ?vdebug("check that the context (~p) is known to us",[ContextName]),
+ case snmp_view_based_acm_mib:vacmContextTable(get, ContextName,
+ [?vacmContextName]) of
+ [_Found] ->
+ ok;
+ _ ->
+ snmpa_mpd:inc(snmpUnknownContexts),
+ throw({discarded, noSuchContext})
+ end,
+ % 3.2.2 - Check that the SecModel and SecName is valid
+ ?vdebug("check that SecModel (~p) and SecName (~p) is valid",
+ [SecModel,SecName]),
+ GroupName =
+ case snmp_view_based_acm_mib:get(vacmSecurityToGroupTable,
+ [SecModel, length(SecName) | SecName],
+ [?vacmGroupName, ?vacmSecurityToGroupStatus]) of
+ [{value, GN}, {value, ?'RowStatus_active'}] ->
+ GN;
+ [{value, _GN}, {value, RowStatus}] ->
+ ?vlog("valid SecModel and SecName but wrong row status:"
+ "~n RowStatus: ~p", [RowStatus]),
+ throw({discarded, noGroupName});
+ _ ->
+ throw({discarded, noGroupName})
+ end,
+ % 3.2.3-4 - Find an access entry and its view name
+ ?vdebug("find an access entry and its view name",[]),
+ ViewName =
+ case get_view_name(ViewType, GroupName, ContextName,
+ SecModel, SecLevel) of
+ {ok, VN} -> VN;
+ Error -> throw(Error)
+ end,
+ % 3.2.5a - Find the corresponding mib view
+ ?vdebug("find the corresponding mib view (for ~p)",[ViewName]),
+ get_mib_view(ViewName).
+
+check_auth({'EXIT', Error}) -> exit(Error);
+check_auth({discarded, Reason}) -> {discarded, Reason};
+check_auth(Res) -> {ok, Res}.
+
+%%-----------------------------------------------------------------
+%% Returns a list of {ViewSubtree, ViewMask, ViewType}
+%% The view table is index by ViewIndex, ViewSubtree,
+%% so a next on ViewIndex returns the first
+%% key in the table >= ViewIndex.
+%%-----------------------------------------------------------------
+get_mib_view(ViewName) ->
+ ViewKey = [length(ViewName) | ViewName],
+ case snmp_view_based_acm_mib:table_next(vacmViewTreeFamilyTable,
+ ViewKey) of
+ endOfTable ->
+ {discarded, noSuchView};
+ Indexes ->
+ case split_prefix(ViewKey, Indexes) of
+ {ok, Subtree} ->
+ loop_mib_view(ViewKey, Subtree, Indexes, []);
+ false ->
+ {discarded, noSuchView}
+ end
+ end.
+
+split_prefix([H|T], [H|T2]) -> split_prefix(T,T2);
+split_prefix([], Rest) -> {ok, Rest};
+split_prefix(_, _) -> false.
+
+
+%% ViewName is including length from now on
+loop_mib_view(ViewName, Subtree, Indexes, MibView) ->
+ [{value, Mask}, {value, Type}, {value, Status}] =
+ snmp_view_based_acm_mib:vacmViewTreeFamilyTable(
+ get, Indexes,
+ [?vacmViewTreeFamilyMask,
+ ?vacmViewTreeFamilyType,
+ ?vacmViewTreeFamilyStatus]),
+ NextMibView =
+ case Status of
+ ?'RowStatus_active' ->
+ [_Length | Tree] = Subtree,
+ [{Tree, Mask, Type} | MibView];
+ _ ->
+ MibView
+ end,
+ case snmp_view_based_acm_mib:table_next(vacmViewTreeFamilyTable,
+ Indexes) of
+ endOfTable -> NextMibView;
+ NextIndexes ->
+ case split_prefix(ViewName, NextIndexes) of
+ {ok, NextSubTree} ->
+ loop_mib_view(ViewName, NextSubTree, NextIndexes,
+ NextMibView);
+ false ->
+ NextMibView
+ end
+ end.
+
+%%%-----------------------------------------------------------------
+%%% 1b. The ordered ets table that implements vacmAccessTable
+%%%-----------------------------------------------------------------
+
+init(Dir) ->
+ init(Dir, terminate).
+
+init(Dir, InitError) ->
+ FName = filename:join(Dir, "snmpa_vacm.db"),
+ case file:read_file_info(FName) of
+ {ok, _} ->
+ %% File exists - we must check this, since ets doesn't tell
+ %% us the reason in case of error...
+ case ets:file2tab(FName) of
+ {ok, _Tab} ->
+ gc_tab([]);
+ {error, Reason} ->
+ user_err("Corrupt VACM database ~p", [FName]),
+ case InitError of
+ terminate ->
+ throw({error, {file2tab, FName, Reason}});
+ _ ->
+ %% Rename old file (for later analyzes)
+ Saved = FName ++ ".saved",
+ file:rename(FName, Saved),
+ ets:new(snmpa_vacm,
+ [public, ordered_set, named_table])
+ end
+ end;
+ {error, _} ->
+ ets:new(snmpa_vacm, [public, ordered_set, named_table])
+ end,
+ ets:insert(snmp_agent_table, {snmpa_vacm_file, FName}),
+ {ok, FName}.
+
+
+backup(BackupDir) ->
+ BackupFile = filename:join(BackupDir, "snmpa_vacm.db"),
+ ets:tab2file(snmpa_vacm, BackupFile).
+
+
+%% Ret: {ok, ViewName} | {error, Reason}
+get_view_name(ViewType, GroupName, ContextName, SecModel, SecLevel) ->
+ GroupKey = [length(GroupName) | GroupName],
+ case get_access_row(GroupKey, ContextName, SecModel, SecLevel) of
+ undefined ->
+ {discarded, noAccessEntry};
+ Row ->
+ ?vtrace("get_view_name -> Row: ~n ~p", [Row]),
+ ViewName =
+ case ViewType of
+ read -> element(?vacmAReadViewName, Row);
+ write -> element(?vacmAWriteViewName, Row);
+ notify -> element(?vacmANotifyViewName, Row)
+ end,
+ case ViewName of
+ "" ->
+ ?vtrace("get_view_name -> not found when"
+ "~n ViewType: ~p"
+ "~n GroupName: ~p"
+ "~n ContextName: ~p"
+ "~n SecModel: ~p"
+ "~n SecLevel: ~p", [ViewType, GroupName,
+ ContextName, SecModel,
+ SecLevel]),
+ {discarded, noSuchView};
+ _ -> {ok, ViewName}
+ end
+ end.
+
+
+get_row(Key) ->
+ case ets:lookup(snmpa_vacm, Key) of
+ [{_Key, Row}] -> {ok, Row};
+ _ -> false
+ end.
+
+get_next_row(Key) ->
+ case ets:next(snmpa_vacm, Key) of
+ '$end_of_table' -> false;
+ NextKey ->
+ case ets:lookup(snmpa_vacm, NextKey) of
+ [Entry] -> Entry;
+ _ -> false
+ end
+ end.
+
+insert(Entries) -> insert(Entries, true).
+
+insert(Entries, Dump) ->
+ lists:foreach(fun(Entry) -> ets:insert(snmpa_vacm, Entry) end, Entries),
+ dump_table(Dump).
+
+delete(Key) ->
+ ets:delete(snmpa_vacm, Key),
+ dump_table().
+
+dump_table(true) ->
+ dump_table();
+dump_table(_) ->
+ ok.
+
+dump_table() ->
+ [{_, FName}] = ets:lookup(snmp_agent_table, snmpa_vacm_file),
+ TmpName = FName ++ ".tmp",
+ case ets:tab2file(snmpa_vacm, TmpName) of
+ ok ->
+ case file:rename(TmpName, FName) of
+ ok ->
+ ok;
+ Else -> % What is this? Undocumented return code...
+ user_err("Warning: could not move VACM db ~p"
+ " (~p)", [FName, Else])
+ end;
+ {error, Reason} ->
+ user_err("Warning: could not save vacm db ~p (~p)",
+ [FName, Reason])
+ end.
+
+
+%%-----------------------------------------------------------------
+%% Alg.
+%% Procedure is defined in the descr. of vacmAccessTable.
+%%
+%% for (each entry with matching group name, context, secmodel and seclevel)
+%% {
+%% rate the entry; if it's score is > prev max score, keep it
+%% }
+%%
+%% Rating: The procedure says to keep entries in order
+%% 1. matching secmodel ('any'(0) or same(1) is ok)
+%% 2. matching contextprefix (exact(1) or prefix(0) is ok)
+%% 3. longest prefix (0..32)
+%% 4. highest secLevel (noAuthNoPriv(0) < authNoPriv(1) < authPriv(2))
+%% We give each entry a single rating number according to this order.
+%% The number is chosen so that a higher number gives a better
+%% entry, according to the order above.
+%% The number is:
+%% secLevel + (3 * prefix_len) + (99 * match_prefix) + (198 * match_secmodel)
+%%
+%% Optimisation: Maybe the most common case is that there
+%% is just one matching entry, and it matches exact. We could do
+%% an exact lookup for this entry; if we find one, use it, otherwise
+%% perform this alg.
+%%-----------------------------------------------------------------
+get_access_row(GroupKey, ContextName, SecModel, SecLevel) ->
+ %% First, try the optimisation...
+ ExactKey =
+ GroupKey ++ [length(ContextName) | ContextName] ++ [SecModel,SecLevel],
+ case ets:lookup(snmpa_vacm, ExactKey) of
+ [{_Key, Row}] ->
+ Row;
+ _ -> % Otherwise, perform the alg
+ get_access_row(GroupKey, GroupKey, ContextName,
+ SecModel, SecLevel, 0, undefined)
+ end.
+
+get_access_row(Key, GroupKey, ContextName, SecModel, SecLevel, Score, Found) ->
+ case get_next_row(Key) of
+ {NextKey, Row}
+ when element(?vacmAStatus, Row) == ?'RowStatus_active'->
+ case catch score(NextKey, GroupKey, ContextName,
+ element(?vacmAContextMatch, Row),
+ SecModel, SecLevel) of
+ {ok, NScore} when NScore > Score ->
+ get_access_row(NextKey, GroupKey, ContextName,
+ SecModel, SecLevel, NScore, Row);
+ {ok, _} -> % e.g. a throwed {ok, 0}
+ get_access_row(NextKey, GroupKey, ContextName,
+ SecModel, SecLevel, Score, Found);
+ false ->
+ Found
+ end;
+ {NextKey, _InvalidRow} ->
+ get_access_row(NextKey, GroupKey, ContextName, SecModel,
+ SecLevel, Score, Found);
+ false ->
+ Found
+ end.
+
+
+
+score(Key, GroupKey, ContextName, Match, SecModel, SecLevel) ->
+ [CtxLen | Rest1] = chop_off_group(GroupKey, Key),
+ {NPrefix, [VSecModel, VSecLevel]} =
+ chop_off_context(ContextName, Rest1, 0, CtxLen, Match),
+ %% Make sure the vacmSecModel is valid (any or matching)
+ NSecModel = case VSecModel of
+ SecModel -> 198;
+ ?SEC_ANY -> 0;
+ _ -> throw({ok, 0})
+ end,
+ %% Make sure the vacmSecLevel is less than the requested
+ NSecLevel = if
+ VSecLevel =< SecLevel -> VSecLevel - 1;
+ true -> throw({ok, 0})
+ end,
+ {ok, NSecLevel + 3*CtxLen + NPrefix + NSecModel}.
+
+
+
+chop_off_group([H|T], [H|T2]) -> chop_off_group(T, T2);
+chop_off_group([], Rest) -> Rest;
+chop_off_group(_, _) -> throw(false).
+
+chop_off_context([H|T], [H|T2], Cnt, Len, Match) when Cnt < Len ->
+ chop_off_context(T, T2, Cnt+1, Len, Match);
+chop_off_context([], Rest, _Len, _Len, _Match) ->
+ %% We have exact match; don't care about Match
+ {99, Rest};
+chop_off_context(_, Rest, Len, Len, ?vacmAccessContextMatch_prefix) ->
+ %% We have a prefix match
+ {0, Rest};
+chop_off_context(_Ctx, _Rest, _Cnt, _Len, _Match) ->
+ %% Otherwise, it didn't match!
+ throw({ok, 0}).
+
+
+gc_tab(Oid) ->
+ case get_next_row(Oid) of
+ {NextOid, Row} ->
+ case element(?vacmAStorageType, Row) of
+ ?'StorageType_volatile' ->
+ ets:delete(snmpa_vacm, NextOid),
+ gc_tab(NextOid);
+ _ ->
+ gc_tab(NextOid)
+ end;
+ false ->
+ ok
+ end.
+
+
+user_err(F, A) ->
+ snmpa_error:user_err(F, A).
+
+% config_err(F, A) ->
+% snmpa_error:config_err(F, A).
diff --git a/lib/snmp/src/agent/snmpa_vacm.hrl b/lib/snmp/src/agent/snmpa_vacm.hrl
new file mode 100644
index 0000000000..681591d212
--- /dev/null
+++ b/lib/snmp/src/agent/snmpa_vacm.hrl
@@ -0,0 +1,24 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1999-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%
+%%
+-define(vacmAContextMatch, 1).
+-define(vacmAReadViewName, 2).
+-define(vacmAWriteViewName, 3).
+-define(vacmANotifyViewName, 4).
+-define(vacmAStorageType, 5).
+-define(vacmAStatus, 6).
diff --git a/lib/snmp/src/app/Makefile b/lib/snmp/src/app/Makefile
new file mode 100644
index 0000000000..d89eb4e723
--- /dev/null
+++ b/lib/snmp/src/app/Makefile
@@ -0,0 +1,141 @@
+#-*-makefile-*- ; force emacs to enter makefile-mode
+
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2003-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%
+
+include $(ERL_TOP)/make/target.mk
+
+EBIN = ../../ebin
+
+include $(ERL_TOP)/make/$(TARGET)/otp.mk
+
+# ----------------------------------------------------
+# Application version
+# ----------------------------------------------------
+include ../../vsn.mk
+
+VSN = $(SNMP_VSN)
+
+# ----------------------------------------------------
+# Release directory specification
+# ----------------------------------------------------
+RELSYSDIR = $(RELEASE_PATH)/lib/snmp-$(VSN)
+
+
+# ----------------------------------------------------
+# Target Specs
+# ----------------------------------------------------
+
+include modules.mk
+
+ERL_FILES = $(MODULES:%=%.erl)
+
+HRL_FILES = $(HRLS:%=%.hrl)
+
+TARGET_FILES = $(MODULES:%=$(EBIN)/%.$(EMULATOR))
+
+EXT_HRL_FILES = \
+ ../../include/snmp_types.hrl \
+ ../../include/snmp_tables.hrl
+
+APP_FILE = snmp.app
+APPUP_FILE = snmp.appup
+
+APP_SRC = $(APP_FILE).src
+APP_TARGET = $(EBIN)/$(APP_FILE)
+
+APPUP_SRC = $(APPUP_FILE).src
+APPUP_TARGET = $(EBIN)/$(APPUP_FILE)
+
+# ----------------------------------------------------
+# SNMP FLAGS
+# ----------------------------------------------------
+ifeq ($(SNMP_DEFAULT_VERBOSITY),)
+ SNMP_FLAGS = -Ddefault_verbosity=silence
+else
+ SNMP_FLAGS = -Ddefault_verbosity=$(SNMP_DEFAULT_VERBOSITY)
+endif
+
+ifeq ($(SNMP_DEBUG),d)
+ SNMP_FLAGS += -Dsnmp_debug
+endif
+
+
+# ----------------------------------------------------
+# FLAGS
+# ----------------------------------------------------
+
+ifeq ($(WARN_UNUSED_VARS),true)
+ERL_COMPILE_FLAGS += +warn_unused_vars
+endif
+
+ERL_COMPILE_FLAGS += -I../misc \
+ -Dversion=\"$(VSN)$(PRE_VSN)\" \
+ +'{parse_transform,sys_pre_attributes}' \
+ +'{attribute,insert,app_vsn,$(APP_VSN)}' \
+ -I$(ERL_TOP)/lib/stdlib \
+ $(SNMP_FLAGS)
+
+# ----------------------------------------------------
+# Targets
+# ----------------------------------------------------
+
+debug:
+ @$(MAKE) TYPE=debug opt
+
+opt: $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET)
+
+
+clean:
+ rm -f $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET)
+ rm -f core *~
+
+docs:
+
+info:
+ @echo "VSN: $(VSN)"
+ @echo "APP_VSN: $(APP_VSN)"
+
+
+# ----------------------------------------------------
+# Special Build Targets
+# ----------------------------------------------------
+
+$(APP_TARGET): $(APP_SRC) ../../vsn.mk
+ sed -e 's;%VSN%;$(VSN);' $< > $@
+
+$(APPUP_TARGET): $(APPUP_SRC) ../../vsn.mk
+ sed -e 's;%VSN%;$(VSN);' $< > $@
+
+# ----------------------------------------------------
+# Release Target
+# ----------------------------------------------------
+include $(ERL_TOP)/make/otp_release_targets.mk
+
+release_spec: opt
+ $(INSTALL_DIR) $(RELSYSDIR)/src
+ $(INSTALL_DIR) $(RELSYSDIR)/src/app
+ $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) $(RELSYSDIR)/src/app
+ $(INSTALL_DIR) $(RELSYSDIR)/ebin
+ $(INSTALL_DATA) $(TARGET_FILES) $(APP_TARGET) $(APPUP_TARGET) \
+ $(RELSYSDIR)/ebin
+ $(INSTALL_DIR) $(RELSYSDIR)/include
+ $(INSTALL_DATA) $(EXT_HRL_FILES) $(RELSYSDIR)/include
+
+release_docs_spec:
+
+include depend.mk
diff --git a/lib/snmp/src/app/depend.mk b/lib/snmp/src/app/depend.mk
new file mode 100644
index 0000000000..1080cb5693
--- /dev/null
+++ b/lib/snmp/src/app/depend.mk
@@ -0,0 +1,29 @@
+#-*-makefile-*- ; force emacs to enter makefile-mode
+
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2004-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%
+
+$(EBIN)/snmp.$(EMULATOR): \
+ snmp.erl
+
+$(EBIN)/snmp_app.$(EMULATOR): \
+ snmp_app.erl
+
+$(EBIN)/snmp_app_sup.$(EMULATOR): \
+ snmp_app_sup.erl
+
+
diff --git a/lib/snmp/src/app/modules.mk b/lib/snmp/src/app/modules.mk
new file mode 100644
index 0000000000..678f15de5c
--- /dev/null
+++ b/lib/snmp/src/app/modules.mk
@@ -0,0 +1,28 @@
+#-*-makefile-*- ; force emacs to enter makefile-mode
+
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2004-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%
+
+MODULES = \
+ snmp \
+ snmp_app \
+ snmp_app_sup
+
+HRLS = \
+ snmp_internal
+
+
diff --git a/lib/snmp/src/app/snmp.app.src b/lib/snmp/src/app/snmp.app.src
new file mode 100644
index 0000000000..a880a14696
--- /dev/null
+++ b/lib/snmp/src/app/snmp.app.src
@@ -0,0 +1,134 @@
+%%
+%% %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%
+%%
+
+{application, snmp,
+ [{description, "SNMP CXC 138 13"},
+ {vsn, "%VSN%"},
+ {modules, [
+ %% Compiler modules (not in the runtime part of the app)
+% snmpc,
+% snmpc_lib,
+% snmpc_mib_gram,
+% snmpc_mib_to_hrl,
+% snmpc_misc,
+% snmpc_tok,
+
+ %% Application modules
+ snmp,
+ snmp_app,
+ snmp_app_sup,
+
+ %% Agent modules
+ snmpa,
+ snmpa_acm,
+ snmpa_agent,
+ snmpa_agent_sup,
+ snmpa_app,
+ snmpa_authentication_service,
+ snmpa_conf,
+ snmpa_error,
+ snmpa_discovery_handler,
+ snmpa_discovery_handler_default,
+ snmpa_error_io,
+ snmpa_error_logger,
+ snmpa_error_report,
+ snmpa_general_db,
+ snmpa_local_db,
+ snmpa_mib,
+ snmpa_mib_data,
+ snmpa_mib_lib,
+ snmpa_misc_sup,
+ snmpa_mpd,
+ snmpa_net_if,
+ snmpa_net_if_filter,
+ snmpa_network_interface,
+ snmpa_network_interface_filter,
+ snmpa_notification_delivery_info_receiver,
+ snmpa_notification_filter,
+ snmpa_set,
+ snmpa_set_lib,
+ snmpa_set_mechanism,
+ snmpa_supervisor,
+ snmpa_svbl,
+ snmpa_symbolic_store,
+ snmpa_target_cache,
+ snmpa_trap,
+ snmpa_usm,
+ snmpa_vacm,
+ snmp_community_mib,
+ snmp_framework_mib,
+ snmp_generic,
+ snmp_generic_mnesia,
+ snmp_index,
+ snmp_notification_mib,
+ snmp_shadow_table,
+ snmp_standard_mib,
+ snmp_target_mib,
+ snmp_user_based_sm_mib,
+ snmp_view_based_acm_mib,
+
+ %% Manager modules:
+ snmpm,
+ snmpm_conf,
+ snmpm_config,
+ snmpm_misc_sup,
+ snmpm_mpd,
+ snmpm_net_if,
+ snmpm_net_if_filter,
+ snmpm_network_interface,
+ snmpm_network_interface_filter,
+ snmpm_server,
+ snmpm_server_sup,
+ snmpm_supervisor,
+ snmpm_user,
+ snmpm_user_default,
+ snmpm_user_old,
+ snmpm_usm,
+
+ %% Misc modules
+ snmp_conf,
+ snmp_config,
+ snmp_log,
+ snmp_mini_mib,
+ snmp_misc,
+ snmp_note_store,
+ snmp_pdus,
+ snmp_usm,
+ snmp_verbosity
+
+ ]},
+ %% Which registered process exist depend on the configuration:
+ %% If an agent is configured, then the following processes is
+ %% also started: snmp_agent_sup, snmp_local_db, snmp_master_agent,
+ %% snmp_misc_sup, snmpa_supervisor and
+ %% snmp_symbolic_store
+ %% If an manager is configured, the the following processes is
+ %% also started: snmpm_supervisor, snmpm_config, snmpm_server,
+ %% snmpm_net_if
+ %%
+ %%
+ {registered, [snmp_app_sup]},
+ {env, []},
+ %% If v3 authentication or encryption is used, 'crypto' must be started
+ %% before snmp.
+ %% The SNMP application _may_ also depend on mnesia (depends on the
+ %% configuration and use), and in that case mnesia must also be started,
+ %% before snmp.
+ {applications, [kernel, stdlib]},
+ {mod, {snmp_app, []}}]}.
diff --git a/lib/snmp/src/app/snmp.appup.src b/lib/snmp/src/app/snmp.appup.src
new file mode 100644
index 0000000000..3abce3d759
--- /dev/null
+++ b/lib/snmp/src/app/snmp.appup.src
@@ -0,0 +1,73 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1999-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%
+%%
+
+{"%VSN%",
+
+%% ----- U p g r a d e -------------------------------------------------------
+
+ [
+ {"4.14",
+ [
+ {load_module, snmpm_user, soft_purge, soft_purge, []},
+ {load_module, snmpm_user_default, soft_purge, soft_purge, [snmpm_user]},
+ {update, snmpm_server, soft, soft_purge, soft_purge,
+ [snmpm_user_default]}
+ ]
+ },
+ {"4.13.5",
+ [
+ {load_module, snmpm_user, soft_purge, soft_purge, []},
+ {load_module, snmpm_user_default, soft_purge, soft_purge, [snmpm_user]},
+ {load_module, snmpa_mib_data, soft_purge, soft_purge, []},
+ {update, snmpa_agent, soft, soft_purge, soft_purge, []},
+ {update, snmpa_net_if, soft, soft_purge, soft_purge, []},
+ {update, snmpm_config, soft, soft_purge, soft_purge, []},
+ {update, snmpm_server, soft, soft_purge, soft_purge, [snmpm_user_default]},
+ {add_module, snmpm_net_if_filter},
+ {add_module, snmpm_network_interface_filter}
+ ]
+ }
+ ],
+
+%% ------D o w n g r a d e ---------------------------------------------------
+
+ [
+ {"4.14",
+ [
+ {load_module, snmpm_user, soft_purge, soft_purge, []},
+ {load_module, snmpm_user_default, soft_purge, soft_purge, [snmpm_user]},
+ {update, snmpm_server, soft, soft_purge, soft_purge, [snmpm_user_default]}
+ ]
+ },
+ {"4.13.5",
+ [
+ {load_module, snmpm_user, soft_purge, soft_purge, []},
+ {load_module, snmpm_user_default, soft_purge, soft_purge, [snmpm_user]},
+ {load_module, snmpa_mib_data, soft_purge, soft_purge, []},
+ {update, snmpa_agent, soft, soft_purge, soft_purge, []},
+ {update, snmpa_net_if, soft, soft_purge, soft_purge, []},
+ {update, snmpm_config, soft, soft_purge, soft_purge, []},
+ {update, snmpm_server, soft, soft_purge, soft_purge, [snmpm_user_default]},
+ {remove, {snmpm_net_if_filter, soft_purge, brutal_purge}},
+ {remove, {snmpm_network_interface_filter, soft_purge, brutal_purge}}
+ ]
+ }
+ ]
+}.
+
diff --git a/lib/snmp/src/app/snmp.config b/lib/snmp/src/app/snmp.config
new file mode 100644
index 0000000000..b66ef5d7df
--- /dev/null
+++ b/lib/snmp/src/app/snmp.config
@@ -0,0 +1,154 @@
+%% Example snmp (node) config file
+%% [{snmp, [snmp_app()]
+%% snmp_app() -> {agent, agent_opts()} | {manager, manager_opts()}
+%%
+%% -- Agent types --
+%% agent_opts() -> [agent_opt()]
+%% agent_opt() -> {agent_type, agent_type()} |
+%% {agent_verbosity, verbosity()} |
+%% {versions, versions()} |
+%% {priority, atom()} |
+%% {set_mechanism, module()} |
+%% {authentication_service, module()} |
+%% {multi_threaded, bool()} |
+%% {db_dir, dir()} |
+%% {local_db, local_db_opts()} |
+%% {net_if, net_if_opts()} |
+%% {mibs, [string()]} |
+%% {mib_storage, mib_storage()} |
+%% {mib_server, mib_server_opts()} |
+%% {audit_trail_log, audit_trail_log_opts()} |
+%% {error_report_mod, module()} |
+%% {note_store, note_store_opts()} |
+%% {symbolic_store, symbolic_store_opts()} |
+%% {config, config_opts()}
+%% {supervisor, supervisor_opts()}
+%% agent_type() -> master | sub
+%% local_db_opts() -> [local_db_opt()]
+%% local_db_opt() -> {repair, repair()} |
+%% {auto_save, auto_save()} |
+%% {verbosity, verbosity()}
+%% repair() -> true | false | force
+%% auto_save() -> integer() | infinity
+%% net_if_opts() -> [net_if_opt()]
+%% net_if_opt() -> {module, atom()} |
+%% {verbosity, verbosity()} |
+%% {options, net_if_options()}
+%% net_if_options() -> [net_if_option()]
+%% net_if_option() -> Note that these are basically dependant on which net-if
+%% module is beeing used, but the options described here
+%% are the ones that snmp_net_if (the default value for
+%% the module option) handles:
+%% {bind_to, bool()} |
+%% {recbuf, integer()} |
+%% {no_reuse, bool()}
+%% {req_limit, integer() | infinity}
+%% mib_server_opts() -> [mib_server_opt()]
+%% mib_server_opt() -> {mibentry_override, bool()} |
+%% {trapentry_override, bool()} |
+%% {verbosity, verbosity()}
+%% mib_storage() -> ets |
+%% {dets, dir()} | {dets, dir(), action()} |
+%% {mnesia, [node()]} |
+%% {mnesia, [node()], action()} |
+%% action() -> clear | keep
+%% symbolic_store_opts() -> [symbolic_store_opt()]
+%% symbolic_store_opt() -> {verbosity, verbosity()}
+%% supervisor_opts() -> [supervisor_opt()]
+%% supervisor_opt() -> {verbosity, verbosity()}
+%% config_opts() -> [config_opt()]
+%% config_opt() -> {dir, dir()} |
+%% {force_load, bool()} |
+%% {verbosity, verbosity()}
+%%
+%%
+%% -- Manager types --
+%% manager_options() -> [manager_option()]
+%% manager_option() -> {net_if, mgr_net_if_opts()} |
+%% {note_store, note_store_opts()} |
+%% {config, mgr_config_opts()} |
+%% {mibs, [string()]} |
+%% {priority, priority()} |
+%% {audit_trail_log, audit_trail_log_opts()} |
+%% {versions, versions()}
+%% mgr_net_if_opts() -> [mgr_net_if_opt()]
+%% mgr_net_if_opt() -> {module, atom()} |
+%% {verbosity, verbosity()} |
+%% {options, mgr_net_if_options()}
+%% mgr_net_if_options() -> [mgr_net_if_option()]
+%% mgr_net_if_option() -> Note that these are basically dependant on which
+%% net-if module is beeing used, but the options
+%% described here are the ones of the snmpm_net_if
+%% (the default value for the module option):
+%% {recbuf, integer()} |
+%% {bind_to, bool()} |
+%% {no_reuse, bool()}
+%% mgr_config_opts() -> {dir, dir()} |
+%% {verbosity, verbosity()}
+%%
+%% -- Common types --
+%% module() -> atom()
+%% verbosity() -> silence | info | log | debug | trace
+%% versions() -> [version()]
+%% version() -> v1 | v2 | v3
+%% audit_trail_log_opts() -> [audit_trail_log_opt()]
+%% audit_trail_log_opt() -> {type, atl_type()} |
+%% {dir, atl_dir()} |
+%% {size, atl_size()} |
+%% {repair, atl_repair()}
+%% atl_type() -> read | write | read_write
+%% atl_dir() -> dir()
+%% atl_size() -> {max_bytes(), max_files()}
+%% atl_repair() -> true | false | truncate
+%% max_bytes() -> integer()
+%% max_files() -> integer()
+%% dir() -> string()
+%% note_store_opts() -> [note_store_opt()]
+%% note_store_opt() -> {verbosity, verbosity()} |
+%% {timeout, integer()}
+%%
+
+[{snmp,
+ [
+ {agent,
+ [{agent_type, master},
+ {agent_verbosity, trace},
+ {priority, normal},
+ {versions, [v1,v2,v3]},
+ {multi_threaded, true},
+ {config, [{verbosity, trace},
+ {dir, "/ldisk/snmp/agent/conf"},
+ {force_load, true}]},
+ {db_dir, "/ldisk/snmp/agent/db"},
+ {local_db, [{repair, true},
+ {verbosity, silence}]},
+ {net_if,
+ [{module, snmp_net_if},
+ {verbosity, log},
+ {options, [{recbuf, 10240}, {req_limit, 32}]}]},
+ {audit_trail_log, [{type, read_write_log},
+ {dir, "/ldisk/snmp/agent/log"}]},
+ {mib_storage, {dets, "/ldisk/snmp/agent/mibs", clear}},
+ {mib_server, [{mibentry_override,true},
+ {trapentry_override,true},
+ {verbosity,info}]}
+ ]
+ },
+ {manager,
+ [{priority, normal},
+ {versions, [v1,v2,v3]},
+ {config, [{dir, "/ldisk/snmp/manager/conf"},
+ {verbosity, trace}]},
+ {server, [{verbosity, trace}]},
+ {net_if,
+ [{module, snmpm_net_if},
+ {verbosity, log},
+ {options, [{recbuf, 10240}]}]},
+ {audit_trail_log, [{dir, "/ldisk/snmp/manager/log"},
+ {size, {10,10240}},
+ {repair, true}]}
+ ]
+ }
+ ]
+ }
+].
diff --git a/lib/snmp/src/app/snmp.erl b/lib/snmp/src/app/snmp.erl
new file mode 100644
index 0000000000..3e0f05e604
--- /dev/null
+++ b/lib/snmp/src/app/snmp.erl
@@ -0,0 +1,939 @@
+%%
+%% %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%
+%%
+-module(snmp).
+
+
+%%----------------------------------------------------------------------
+%% This module contains the user interface to the snmp toolkit.
+%%----------------------------------------------------------------------
+
+%% Application exports
+-export([start/0, start/1, stop/0,
+ start_agent/0, start_agent/1,
+ start_manager/0, start_manager/1,
+ config/0,
+
+ versions1/0, versions2/0,
+ print_versions/1, print_versions/2,
+ print_version_info/0, print_version_info/1,
+
+ date_and_time/0,
+ universal_time_to_date_and_time/1,
+ local_time_to_date_and_time_dst/1,
+ date_and_time_to_universal_time_dst/1,
+ validate_date_and_time/1, validate_date_and_time/2,
+ date_and_time_to_string/1, date_and_time_to_string/2,
+ date_and_time_to_string2/1,
+
+ str_apply/1,
+
+ sys_up_time/1, system_start_time/1,
+
+ passwd2localized_key/3, localize_key/3,
+
+ read_mib/1,
+
+ log_to_txt/5, log_to_txt/6, log_to_txt/7,
+ change_log_size/2,
+
+ octet_string_to_bits/1, bits_to_octet_string/1,
+
+ enable_trace/0, disable_trace/0,
+ set_trace/1, reset_trace/1,
+ set_trace/2, set_trace/3]).
+
+%% Compiler exports
+-export([c/1, c/2, is_consistent/1, mib_to_hrl/1,
+ compile/3]).
+
+%% Agent exports (Dont use these, they will be removed eventually)
+-export([current_request_id/0, current_community/0, current_address/0,
+ current_context/0, current_net_if_data/0,
+
+ get_symbolic_store_db/0,
+ name_to_oid/1, name_to_oid/2,
+ oid_to_name/1, oid_to_name/2,
+ int_to_enum/2, int_to_enum/3,
+ enum_to_int/2, enum_to_int/3,
+
+ get/2,
+ info/1,
+ load_mibs/2, unload_mibs/2, dump_mibs/0, dump_mibs/1,
+
+ register_subagent/3, unregister_subagent/2,
+
+ send_notification/3, send_notification/4, send_notification/5,
+ send_notification/6,
+ send_trap/3, send_trap/4,
+
+ add_agent_caps/2, del_agent_caps/1, get_agent_caps/0,
+
+ log_to_txt/2, log_to_txt/3, log_to_txt/4,
+ change_log_size/1
+
+ ]).
+
+%% This is for XREF
+-deprecated([{c, 1, eventually},
+ {c, 2, eventually},
+ {compile, 3, eventually},
+ {is_consistent, 1, eventually},
+ {mib_to_hrl, 1, eventually},
+
+ {change_log_size, 1, eventually},
+ {log_to_txt, 2, eventually},
+ {log_to_txt, 3, eventually},
+ {log_to_txt, 4, eventually},
+
+ {current_request_id, 0, eventually},
+ {current_community, 0, eventually},
+ {current_address, 0, eventually},
+ {current_context, 0, eventually},
+ {current_net_if_data, 0, eventually},
+
+ {get_symbolic_store_db, 0, eventually},
+ {name_to_oid, 1, eventually},
+ {name_to_oid, 2, eventually},
+ {oid_to_name, 1, eventually},
+ {oid_to_name, 2, eventually},
+ {int_to_enum, 2, eventually},
+ {int_to_enum, 3, eventually},
+ {enum_to_int, 2, eventually},
+ {enum_to_int, 3, eventually},
+
+ {get, 2, eventually},
+ {info, 1, eventually},
+ {load_mibs, 2, eventually},
+ {unload_mibs, 2, eventually},
+ {dump_mibs, 0, eventually},
+ {dump_mibs, 1, eventually},
+
+ {register_subagent, 3, eventually},
+ {unregister_subagent, 2, eventually},
+
+ {send_notification, 3, eventually},
+ {send_notification, 4, eventually},
+ {send_notification, 5, eventually},
+ {send_notification, 6, eventually},
+ {send_trap, 3, eventually},
+ {send_trap, 4, eventually},
+
+ {add_agent_caps, 2, eventually},
+ {del_agent_caps, 1, eventually},
+ {get_agent_caps, 0, eventually}]).
+
+
+-define(APPLICATION, snmp).
+
+
+%%-----------------------------------------------------------------
+%% Application
+%%-----------------------------------------------------------------
+
+start() ->
+ application:start(?APPLICATION).
+
+stop() ->
+ application:stop(?APPLICATION).
+
+start(p) ->
+ start(permanent);
+start(tr) ->
+ start(transient);
+start(te) ->
+ start(temporary);
+start(Type) ->
+ application:start(?APPLICATION, Type).
+
+
+start_agent() ->
+ snmp_app:start_agent().
+
+start_agent(Type) ->
+ snmp_app:start_agent(Type).
+
+start_manager() ->
+ snmp_app:start_manager().
+
+start_manager(Type) ->
+ snmp_app:start_manager(Type).
+
+
+config() -> snmp_config:config().
+
+
+%%-----------------------------------------------------------------
+
+enable_trace() ->
+ HandleSpec = {fun handle_trace_event/2, dummy},
+ dbg:tracer(process, HandleSpec).
+
+disable_trace() ->
+ dbg:stop().
+
+set_trace(Module) when is_atom(Module) ->
+ set_trace([Module]);
+set_trace(Modules) when is_list(Modules) ->
+ Opts = [], % Use default values for all options
+ set_trace(Modules, Opts).
+
+reset_trace(Module) when is_atom(Module) ->
+ set_trace(Module, disable);
+reset_trace(Modules) when is_list(Modules) ->
+ set_trace(Modules, disable).
+
+set_trace(Module, disable) when is_atom(Module) ->
+ dbg:ctp(Module);
+set_trace(Module, Opts) when is_atom(Module) andalso is_list(Opts) ->
+ (catch set_trace(all, Module, Opts));
+set_trace(Modules, Opts) when is_list(Modules) ->
+ (catch set_trace(all, Modules, Opts)).
+
+set_trace(Item, Module, Opts) when is_atom(Module) ->
+ set_trace(Item, [{Module, []}], Opts);
+set_trace(_Item, Modules, disable) when is_list(Modules) ->
+ DisableTrace =
+ fun(Module) when is_atom(Module) ->
+ dbg:ctp(Module);
+ (_) ->
+ ok
+ end,
+ lists:foreach(DisableTrace, Modules);
+set_trace(Item, Modules, Opts) when is_list(Modules) ->
+ Mods = parse_modules(Modules, Opts),
+ SetTrace =
+ fun({Module, ModOpts}) ->
+ set_module_trace(Module, ModOpts)
+ end,
+ lists:foreach(SetTrace, Mods),
+ Flags =
+ case lists:keysearch(timestamp, 1, Opts) of
+ {value, {timestamp, false}} ->
+ [call];
+ _ ->
+ [call, timestamp]
+ end,
+ case dbg:p(Item, Flags) of
+ {ok, _} ->
+ ok;
+ Error ->
+ Error
+ end.
+
+set_module_trace(Module, disable) ->
+ dbg:ctp(Module);
+set_module_trace(Module, Opts) ->
+ ReturnTrace =
+ case lists:keysearch(return_trace, 1, Opts) of
+ {value, {return_trace, false}} ->
+ [];
+ _ ->
+ %% Default is allways to include return values
+ [{return_trace}]
+ end,
+ TraceRes =
+ case lists:keysearch(scope, 1, Opts) of
+ {value, {scope, all_functions}} ->
+ dbg:tpl(Module, [{'_', [], ReturnTrace}]);
+ {value, {scope, exported_functions}} ->
+ dbg:tp(Module, [{'_', [], ReturnTrace}]);
+ {value, {scope, Func}} when is_atom(Func) ->
+ dbg:tpl(Module, Func, [{'_', [], ReturnTrace}]);
+ {value, {scope, {Func, Arity}}} when is_atom(Func) andalso
+ is_integer(Arity) ->
+ dbg:tpl(Module, Func, Arity, [{'_', [], ReturnTrace}]);
+ false ->
+ %% Default scope is exported functions
+ dbg:tp(Module, [{'_', [], ReturnTrace}])
+ end,
+ case TraceRes of
+ {error, Reason} ->
+ throw({error, {failed_enabling_trace, Module, Opts, Reason}});
+ _ ->
+ ok
+ end.
+
+
+parse_modules(Modules, Opts) ->
+ parse_modules(Modules, Opts, []).
+
+parse_modules([], _Opts, Acc) ->
+ lists:reverse(Acc);
+
+parse_modules([Module|Modules], Opts, Acc)
+ when is_atom(Module) andalso is_list(Opts) ->
+ parse_modules(Modules, Opts, [{Module, Opts}|Acc]);
+
+parse_modules([{Module, ModOpts}|Modules], Opts, Acc)
+ when is_atom(Module) andalso is_list(ModOpts) andalso is_list(Opts) ->
+ NewModOpts = update_trace_options(Opts, ModOpts),
+ parse_modules(Modules, Opts, [{Module, NewModOpts}|Acc]);
+
+parse_modules([_|Modules], Opts, Acc) ->
+ parse_modules(Modules, Opts, Acc).
+
+
+update_trace_options([], Opts) ->
+ Opts;
+update_trace_options([{Key, _} = Opt|Opts], ModOpts) ->
+ case lists:keysearch(Key, 1, ModOpts) of
+ {value, _} ->
+ update_trace_options(Opts, ModOpts);
+ _ ->
+ update_trace_options(Opts, [Opt|ModOpts])
+ end;
+update_trace_options([_|Opts], ModOpts) ->
+ update_trace_options(Opts, ModOpts).
+
+
+handle_trace_event({trace, Who, call, Event}, Data) ->
+ io:format("*** call trace event *** "
+ "~n Who: ~p"
+ "~n Event: ~p"
+ "~n", [Who, Event]),
+ Data;
+handle_trace_event({trace, Who, return_from, Func, Value}, Data) ->
+ io:format("*** return trace event *** "
+ "~n Who: ~p"
+ "~n Function: ~p"
+ "~n Value: ~p"
+ "~n", [Who, Func, Value]),
+ Data;
+handle_trace_event({trace_ts, Who, call, {Mod, Func, Args}, Ts}, Data)
+ when is_atom(Mod) andalso is_atom(Func) andalso is_list(Args) ->
+ io:format("*** call trace event ~s *** "
+ "~n Who: ~p"
+ "~n Mod: ~p"
+ "~n Func: ~p"
+ "~n Args: ~p"
+ "~n", [format_timestamp(Ts), Who, Mod, Func, Args]),
+ Data;
+handle_trace_event({trace_ts, Who, call, Event, Ts}, Data) ->
+ io:format("*** call trace event ~s *** "
+ "~n Who: ~p"
+ "~n Event: ~p"
+ "~n", [format_timestamp(Ts), Who, Event]),
+ Data;
+handle_trace_event({trace_ts, Who, return_from, {Mod, Func, Arity}, Value, Ts},
+ Data)
+ when is_atom(Mod) andalso is_atom(Func) andalso is_integer(Arity) ->
+ io:format("*** return trace event ~s *** "
+ "~n Who: ~p"
+ "~n Mod: ~p"
+ "~n Func: ~p"
+ "~n Arity: ~p"
+ "~n Value: ~p"
+ "~n", [format_timestamp(Ts), Who, Mod, Func, Arity, Value]),
+ Data;
+handle_trace_event({trace_ts, Who, return_from, Func, Value, Ts}, Data) ->
+ io:format("*** return trace event ~s *** "
+ "~n Who: ~p"
+ "~n Function: ~p"
+ "~n Value: ~p"
+ "~n", [format_timestamp(Ts), Who, Func, Value]),
+ Data;
+handle_trace_event(TraceEvent, Data) ->
+ io:format("*** trace event *** "
+ "~n TraceEvent: ~p"
+ "~n", [TraceEvent]),
+ Data.
+
+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).
+
+
+%%-----------------------------------------------------------------
+%% {ok, Vs} = snmp:versions1(), snmp:print_versions(Vs).
+
+print_version_info() ->
+ {ok, Vs} = versions1(),
+ print_versions(Vs).
+
+print_version_info(Prefix) ->
+ {ok, Vs} = versions1(),
+ print_versions(Prefix, Vs).
+
+print_versions(Versions) ->
+ print_versions("", Versions).
+
+print_versions(Prefix, Versions)
+ when is_list(Prefix) andalso is_list(Versions) ->
+ do_print_versions(Prefix, Versions);
+print_versions(Prefix, Versions)
+ when (is_integer(Prefix) andalso (Prefix >= 0)) andalso is_list(Versions) ->
+ do_print_versions(lists:duplicate(Prefix, $ ), Versions);
+print_versions(Prefix, BadVersions)
+ when is_list(Prefix) orelse (is_integer(Prefix) andalso (Prefix >= 0)) ->
+ {error, {bad_versions, BadVersions}};
+print_versions(Prefix, BadVersions)
+ when is_list(BadVersions) ->
+ {error, {bad_prefix, Prefix}};
+print_versions(Prefix, BadVersions) ->
+ {error, {bad_args, Prefix, BadVersions}}.
+
+do_print_versions(Prefix, Versions) ->
+ print_sys_info(Prefix, Versions),
+ print_os_info(Prefix, Versions),
+ print_mods_info(Prefix, Versions).
+
+print_sys_info(Prefix, Versions) ->
+ case key1search(sys_info, Versions) of
+ {value, SysInfo} when is_list(SysInfo) ->
+ {value, Arch} = key1search(arch, SysInfo, "Not found"),
+ {value, Ver} = key1search(ver, SysInfo, "Not found"),
+ io:format("~sSystem info: "
+ "~n~s Arch: ~s"
+ "~n~s Ver: ~s"
+ "~n", [Prefix,
+ Prefix, Arch,
+ Prefix, Ver]),
+ ok;
+ _ ->
+ io:format("System info: Not found~n", []),
+ not_found
+ end.
+
+print_os_info(Prefix, Versions) ->
+ case key1search(os_info, Versions) of
+ {value, OsInfo} when is_list(OsInfo) ->
+ Fam =
+ case key1search(fam, OsInfo, "Not found") of
+ {value, F} when is_atom(F) ->
+ atom_to_list(F);
+ {value, LF} when is_list(LF) ->
+ LF;
+ {value, XF} ->
+ lists:flatten(io_lib:format("~p", [XF]))
+ end,
+ Name =
+ case key1search(name, OsInfo) of
+ {value, N} when is_atom(N) ->
+ "[" ++ atom_to_list(N) ++ "]";
+ {value, LN} when is_list(LN) ->
+ "[" ++ LN ++ "]";
+ not_found ->
+ ""
+ end,
+ Ver =
+ case key1search(ver, OsInfo, "Not found") of
+ {value, T} when is_tuple(T) ->
+ tversion(T);
+ {value, LV} when is_list(LV) ->
+ LV;
+ {value, XV} ->
+ lists:flatten(io_lib:format("~p", [XV]))
+ end,
+ io:format("~sOS info: "
+ "~n~s Family: ~s ~s"
+ "~n~s Ver: ~s"
+ "~n", [Prefix,
+ Prefix, Fam, Name,
+ Prefix, Ver]),
+ ok;
+ _ ->
+ io:format("~sOS info: Not found~n", [Prefix]),
+ not_found
+ end.
+
+tversion(T) ->
+ L = tuple_to_list(T),
+ lversion(L).
+
+lversion([]) ->
+ "";
+lversion([A]) ->
+ integer_to_list(A);
+lversion([A|R]) ->
+ integer_to_list(A) ++ "." ++ lversion(R).
+
+print_mods_info(Prefix, Versions) ->
+ case key1search(mod_info, Versions) of
+ {value, ModsInfo} when is_list(ModsInfo) ->
+ io:format("~sModule info: ~n", [Prefix]),
+ F = fun(MI) -> print_mod_info(Prefix, MI) end,
+ lists:foreach(F, ModsInfo);
+ _ ->
+ io:format("~sModule info: Not found~n", [Prefix]),
+ not_found
+ end.
+
+print_mod_info(Prefix, {Module, Info}) ->
+ Vsn =
+ case key1search(vsn, Info) of
+ {value, I} when is_integer(I) ->
+ integer_to_list(I);
+ _ ->
+ "Not found"
+ end,
+ AppVsn =
+ case key1search(app_vsn, Info) of
+ {value, S1} when is_list(S1) ->
+ S1;
+ _ ->
+ "Not found"
+ end,
+ CompVer =
+ case key1search(compiler_version, Info) of
+ {value, S2} when is_list(S2) ->
+ S2;
+ _ ->
+ "Not found"
+ end,
+ CompDate =
+ case key1search(compile_time, Info) of
+ {value, {Year, Month, Day, Hour, Min, Sec}} ->
+ lists:flatten(
+ io_lib:format("~w-~2..0w-~2..0w ~2..0w:~2..0w:~2..0w",
+ [Year, Month, Day, Hour, Min, Sec]));
+ _ ->
+ "Not found"
+ end,
+ io:format("~s ~w:~n"
+ "~s Vsn: ~s~n"
+ "~s App vsn: ~s~n"
+ "~s Compiler ver: ~s~n"
+ "~s Compile time: ~s~n",
+ [Prefix, Module,
+ Prefix, Vsn,
+ Prefix, AppVsn,
+ Prefix, CompVer,
+ Prefix, CompDate]),
+ ok.
+
+key1search(Key, Vals) ->
+ case lists:keysearch(Key, 1, Vals) of
+ {value, {Key, Val}} ->
+ {value, Val};
+ false ->
+ not_found
+ end.
+
+key1search(Key, Vals, Def) ->
+ case key1search(Key, Vals) of
+ not_found ->
+ {value, Def};
+ Value ->
+ Value
+ end.
+
+
+%%-----------------------------------------------------------------
+
+versions1() ->
+ case ms1() of
+ {ok, Mods} ->
+ {ok, version_info(Mods)};
+ Error ->
+ Error
+ end.
+
+versions2() ->
+ case ms2() of
+ {ok, Mods} ->
+ {ok, version_info(Mods)};
+ Error ->
+ Error
+ end.
+
+version_info(Mods) ->
+ SysInfo = sys_info(),
+ OsInfo = os_info(),
+ ModInfo = [mod_version_info(Mod) || Mod <- Mods],
+ [{sys_info, SysInfo}, {os_info, OsInfo}, {mod_info, ModInfo}].
+
+mod_version_info(Mod) ->
+ Info = Mod:module_info(),
+ {value, {attributes, Attr}} = lists:keysearch(attributes, 1, Info),
+ {value, {vsn, [Vsn]}} = lists:keysearch(vsn, 1, Attr),
+ {value, {app_vsn, AppVsn}} = lists:keysearch(app_vsn, 1, Attr),
+ {value, {compile, Comp}} = lists:keysearch(compile, 1, Info),
+ {value, {version, Ver}} = lists:keysearch(version, 1, Comp),
+ {value, {time, Time}} = lists:keysearch(time, 1, Comp),
+ {Mod, [{vsn, Vsn},
+ {app_vsn, AppVsn},
+ {compiler_version, Ver},
+ {compile_time, Time}]}.
+
+sys_info() ->
+ SysArch = string:strip(erlang:system_info(system_architecture),right,$\n),
+ SysVer = string:strip(erlang:system_info(system_version),right,$\n),
+ [{arch, SysArch}, {ver, SysVer}].
+
+os_info() ->
+ V = os:version(),
+ case os:type() of
+ {OsFam, OsName} ->
+ [{fam, OsFam}, {name, OsName}, {ver, V}];
+ OsFam ->
+ [{fam, OsFam}, {ver, V}]
+ end.
+
+ms1() ->
+ App = ?APPLICATION,
+ LibDir = code:lib_dir(App),
+ File = filename:join([LibDir, "ebin", atom_to_list(App) ++ ".app"]),
+ case file:consult(File) of
+ {ok, [{application, App, AppFile}]} ->
+ case lists:keysearch(modules, 1, AppFile) of
+ {value, {modules, Mods}} ->
+ {ok, Mods};
+ _ ->
+ {error, {invalid_format, modules}}
+ end;
+ Error ->
+ {error, {invalid_format, Error}}
+ end.
+
+ms2() ->
+ application:get_key(?APPLICATION, modules).
+
+
+%%-----------------------------------------------------------------
+%% Returns: current time as a DateAndTime type (defined in rfc1903)
+%%-----------------------------------------------------------------
+date_and_time() ->
+ UTC = calendar:universal_time(),
+ Local = calendar:universal_time_to_local_time(UTC),
+ date_and_time(Local, UTC).
+
+date_and_time(Local, UTC) ->
+ DiffSecs = calendar:datetime_to_gregorian_seconds(Local) -
+ calendar:datetime_to_gregorian_seconds(UTC),
+ short_time(Local) ++ diff(DiffSecs).
+
+short_time({{Y,M,D},{H,Mi,S}}) ->
+ [y1(Y), y2(Y), M, D, H, Mi, S, 0].
+
+%% This function will only be called if there has been some
+%% validation error, and as it is strict, it allways returns
+%% false.
+strict_validation(_What, _Data) ->
+ false.
+
+kiribati_validation(diff, Diff) ->
+ check_kiribati_diff(Diff);
+kiribati_validation(_What, _Data) ->
+ false.
+
+check_kiribati_diff([$+, H, M])
+ when ((0 =< H) andalso (H < 14) andalso (0 =< M) andalso (M < 60)) orelse
+ ((H =:= 14) andalso (M =:= 0)) ->
+ true;
+check_kiribati_diff([$-, H, M])
+ when ((0 =< H) andalso (H < 14) andalso (0 =< M) andalso (M < 60)) orelse
+ ((H =:= 14) andalso (M =:= 0)) ->
+ true;
+check_kiribati_diff(_) ->
+ false.
+
+
+date_and_time_to_string2(DAT) ->
+ Validate = fun(What, Data) -> kiribati_validation(What, Data) end,
+ date_and_time_to_string(DAT, Validate).
+
+date_and_time_to_string(DAT) ->
+ Validate = fun(What, Data) -> strict_validation(What, Data) end,
+ date_and_time_to_string(DAT, Validate).
+date_and_time_to_string(DAT, Validate) when is_function(Validate) ->
+ case validate_date_and_time(DAT, Validate) of
+ true ->
+ dat2str(DAT);
+ false ->
+ exit({badarg, {?MODULE, date_and_time_to_string, [DAT]}})
+ end.
+
+dat2str([Y1,Y2, Mo, D, H, M, S, Ds | Diff]) ->
+ lists:flatten(io_lib:format("~w-~w-~w,~w:~w:~w.~w",
+ [y(Y1,Y2),Mo,D,H,M,S,Ds]) ++
+ case Diff of
+ [Sign,Hd,Md] ->
+ io_lib:format(",~c~w:~w",
+ [Sign,Hd,Md]);
+ _ -> []
+ end).
+
+
+y1(Y) -> (Y bsr 8) band 255.
+y2(Y) -> Y band 255.
+
+y(Y1, Y2) -> 256 * Y1 + Y2.
+
+diff(Secs) ->
+ case calendar:seconds_to_daystime(Secs) of
+ {0, {H, M,_}} ->
+ [$+, H, M];
+ {-1, _} ->
+ {0, {H, M, _}} = calendar:seconds_to_daystime(-Secs),
+ [$-, H, M]
+ end.
+
+universal_time_to_date_and_time(UTC) ->
+ short_time(UTC) ++ [$+, 0, 0].
+
+local_time_to_date_and_time_dst(Local) ->
+ case calendar:local_time_to_universal_time_dst(Local) of
+ [] ->
+ [];
+ [UTC] ->
+ [date_and_time(Local, UTC)];
+ [UTC1, UTC2] ->
+ [date_and_time(Local, UTC1), date_and_time(Local, UTC2)]
+ end.
+
+date_and_time_to_universal_time_dst([Y1, Y2, Mo, D, H, M, S, _Ds]) ->
+ %% Local time specified, convert to UTC
+ Local = {{y(Y1,Y2), Mo, D}, {H, M, S}},
+ calendar:local_time_to_universal_time_dst(Local);
+date_and_time_to_universal_time_dst([Y1, Y2, Mo, D, H, M, S, _Ds, Sign, Hd, Md]) ->
+ %% Time specified as local time + diff from UTC. Conv to UTC.
+ Local = {{y(Y1,Y2), Mo, D}, {H, M, S}},
+ LocalSecs = calendar:datetime_to_gregorian_seconds(Local),
+ Diff = (Hd*60 + Md)*60,
+ UTCSecs = if Sign == $+ -> LocalSecs - Diff;
+ Sign == $- -> LocalSecs + Diff
+ end,
+ [calendar:gregorian_seconds_to_datetime(UTCSecs)].
+
+
+validate_date_and_time(DateAndTime) ->
+ Validate = fun(What, Data) -> strict_validation(What, Data) end,
+ validate_date_and_time(DateAndTime, Validate).
+
+validate_date_and_time(DateAndTime, Validate) when is_function(Validate) ->
+ do_validate_date_and_time(DateAndTime, Validate).
+
+do_validate_date_and_time([Y1,Y2, Mo, D, H, M, S, Ds | Diff], Validate)
+ when ((0 =< Y1) andalso (0 =< Y2)) andalso
+ ((0 < Mo) andalso (Mo < 13)) andalso
+ ((0 < D) andalso (D < 32) andalso (0 =< H)) andalso
+ (H < 24) andalso
+ ((0 =< M) andalso (M < 60)) andalso
+ ((0 =< S) andalso (S < 61)) andalso
+ ((0 =< Ds) andalso (Ds < 10)) ->
+ case check_diff(Diff, Validate) of
+ true ->
+ Year = y(Y1,Y2),
+ case calendar:valid_date(Year, Mo, D) of
+ true ->
+ true;
+ _ ->
+ Validate(valid_date, {Year, Mo, D})
+ end;
+ false ->
+ false
+ end;
+do_validate_date_and_time([Y1,Y2, Mo, D, H, M, S, Ds | Diff], Validate) ->
+ Valid =
+ Validate(year, {Y1, Y2}) andalso
+ Validate(month, Mo) andalso
+ Validate(day, D) andalso
+ Validate(hour, H) andalso
+ Validate(minute, M) andalso
+ Validate(seconds, S) andalso
+ Validate(deci_seconds, Ds),
+ if
+ Valid =:= true ->
+ case check_diff(Diff, Validate) of
+ true ->
+ Year = y(Y1,Y2),
+ case calendar:valid_date(Year, Mo, D) of
+ true ->
+ true;
+ _ ->
+ Validate(valid_date, {Year, Mo, D})
+ end;
+ false ->
+ false
+ end;
+ true ->
+ false
+ end;
+do_validate_date_and_time(_, _) ->
+ false.
+
+%% OTP-4206 (now according to RFC-2579)
+check_diff([], _) ->
+ true;
+check_diff([$+, H, M], _)
+ when (0 =< H) andalso (H < 14) andalso (0 =< M) andalso (M < 60) ->
+ true;
+check_diff([$-, H, M], _)
+ when (0 =< H) andalso (H < 14) andalso (0 =< M) andalso (M < 60) ->
+ true;
+check_diff(Diff, Validate) ->
+ Validate(diff, Diff).
+
+
+%%-----------------------------------------------------------------
+%% System start- and up-time
+%%-----------------------------------------------------------------
+
+system_start_time(agent) ->
+ snmpa:system_start_time();
+system_start_time(manager) ->
+ snmpm:system_start_time().
+
+sys_up_time(agent) ->
+ snmpa:sys_up_time();
+sys_up_time(manager) ->
+ snmpm:sys_up_time().
+
+
+
+%%-----------------------------------------------------------------
+%% Utility functions for OCTET-STRING / BITS conversion.
+%%-----------------------------------------------------------------
+
+octet_string_to_bits(S) ->
+ snmp_pdus:octet_str_to_bits(S).
+
+bits_to_octet_string(B) ->
+ snmp_pdus:bits_to_str(B).
+
+
+%%%-----------------------------------------------------------------
+%%% USM functions
+%%%-----------------------------------------------------------------
+
+passwd2localized_key(Alg, Passwd, EngineID) ->
+ snmp_usm:passwd2localized_key(Alg, Passwd, EngineID).
+
+localize_key(Alg, Key, EngineID) ->
+ snmp_usm:localize_key(Alg, Key, EngineID).
+
+
+%%%-----------------------------------------------------------------
+%%% Read a mib
+%%%-----------------------------------------------------------------
+
+read_mib(FileName) ->
+ snmp_misc:read_mib(FileName).
+
+
+%%%-----------------------------------------------------------------
+%%% Audit Trail Log functions
+%%%-----------------------------------------------------------------
+
+log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile) ->
+ snmp_log:log_to_txt(LogName, LogFile, LogDir, Mibs, OutFile).
+log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Start) ->
+ snmp_log:log_to_txt(LogName, LogFile, LogDir, Mibs, OutFile, Start).
+log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Start, Stop) ->
+ snmp_log:log_to_txt(LogName, LogFile, LogDir, Mibs, OutFile, Start, Stop).
+
+
+change_log_size(LogName, NewSize) ->
+ snmp_log:change_size(LogName, NewSize).
+
+
+%%%-----------------------------------------------------------------
+%%% Misc
+%%%-----------------------------------------------------------------
+
+%% Usage: erl -s snmp str_apply '{Mod,Func,ArgList}'
+str_apply([Atom]) ->
+ Str = atom_to_list(Atom),
+ {Mod,Func,Args} = to_erlang_term(Str),
+ apply(Mod,Func,Args).
+
+to_erlang_term(String) ->
+ {ok, Tokens, _} = erl_scan:string(lists:append([String, ". "])),
+ {ok,Term} = erl_parse:parse_term(Tokens),
+ Term.
+
+
+%%%-----------------------------------------------------------------
+%%% BACKWARD COMPATIBILLITY CRAP
+%%%-----------------------------------------------------------------
+
+c(File) -> snmpc:compile(File).
+c(File, Options) -> snmpc:compile(File, Options).
+
+is_consistent(Filenames) ->
+ snmpc:is_consistent(Filenames).
+
+mib_to_hrl(MibName) ->
+ snmpc:mib_to_hrl(MibName).
+
+compile(Input, Output, Options) ->
+ snmpc:compile(Input, Output, Options).
+
+get_symbolic_store_db() -> snmpa:get_symbolic_store_db().
+
+name_to_oid(Name) -> snmpa:name_to_oid(Name).
+name_to_oid(Db, Name) -> snmpa:name_to_oid(Db, Name).
+oid_to_name(OID) -> snmpa:oid_to_name(OID).
+oid_to_name(Db, OID) -> snmpa:oid_to_name(Db, OID).
+enum_to_int(Name, Enum) -> snmpa:enum_to_int(Name, Enum).
+enum_to_int(Db, Name, Enum) -> snmpa:enum_to_int(Db, Name, Enum).
+int_to_enum(Name, Int) -> snmpa:int_to_enum(Name, Int).
+int_to_enum(Db, Name, Int) -> snmpa:int_to_enum(Db, Name, Int).
+
+current_request_id() -> snmpa:current_request_id().
+current_context() -> snmpa:current_context().
+current_community() -> snmpa:current_community().
+current_address() -> snmpa:current_address().
+current_net_if_data() -> snmpa:current_net_if_data().
+
+get(Agent, Vars) -> snmpa:get(Agent, Vars).
+info(Agent) -> snmpa:info(Agent).
+dump_mibs() -> snmpa:dump_mibs().
+dump_mibs(File) -> snmpa:dump_mibs(File).
+load_mibs(Agent, Mibs) -> snmpa:load_mibs(Agent, Mibs).
+unload_mibs(Agent, Mibs) -> snmpa:unload_mibs(Agent, Mibs).
+send_notification(Agent, Notification, Recv) ->
+ snmpa:send_notification(Agent, Notification, Recv).
+send_notification(Agent, Notification, Recv, Varbinds) ->
+ snmpa:send_notification(Agent, Notification, Recv, Varbinds).
+send_notification(Agent, Notification, Recv, NotifyName, Varbinds) ->
+ snmpa:send_notification(Agent, Notification, Recv, NotifyName, Varbinds).
+send_notification(Agent, Notification, Recv, NotifyName,
+ ContextName, Varbinds) ->
+ snmpa:send_notification(Agent, Notification, Recv, NotifyName,
+ ContextName, Varbinds).
+send_trap(Agent, Trap, Community) ->
+ snmpa:send_trap(Agent, Trap, Community).
+send_trap(Agent, Trap, Community, Varbinds) ->
+ snmpa:send_trap(Agent, Trap, Community, Varbinds).
+register_subagent(Agent, SubTree, SubAgent) ->
+ snmpa:register_subagent(Agent, SubTree, SubAgent).
+unregister_subagent(Agent, SubOidOrPid) ->
+ snmpa:unregister_subagent(Agent, SubOidOrPid).
+
+add_agent_caps(Oid, Descr) -> snmpa:add_agent_caps(Oid, Descr).
+del_agent_caps(Index) -> snmpa:del_agent_caps(Index).
+get_agent_caps() -> snmpa:get_agent_caps().
+
+log_to_txt(LogDir, Mibs) ->
+ snmpa:log_to_txt(LogDir, Mibs).
+log_to_txt(LogDir, Mibs, OutFile) ->
+ snmpa:log_to_txt(LogDir, Mibs, OutFile).
+log_to_txt(LogDir, Mibs, OutFile, LogName) ->
+ snmpa:log_to_txt(LogDir, Mibs, OutFile, LogName).
+change_log_size(NewSize) ->
+ snmpa:change_log_size(NewSize).
+
+
+
diff --git a/lib/snmp/src/app/snmp_app.erl b/lib/snmp/src/app/snmp_app.erl
new file mode 100644
index 0000000000..deb42cc373
--- /dev/null
+++ b/lib/snmp/src/app/snmp_app.erl
@@ -0,0 +1,175 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2003-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%
+%%
+-module(snmp_app).
+
+-behaviour(application).
+
+-include("snmp_debug.hrl").
+
+
+%%%-----------------------------------------------------------------
+%%% This module implements the SNMP application.
+%%%-----------------------------------------------------------------
+-export([start/2, stop/0, stop/1, config_change/3]).
+-export([start_agent/0, start_agent/1, start_agent/2]).
+-export([start_manager/0, start_manager/1, start_manager/2]).
+
+start(Type, []) ->
+ ?d("start -> entry with"
+ "~n Type. ~p", [Type]),
+ %% This is the new snmp application config format
+ %% First start the (new) central supervisor,
+ {ok, Pid} = snmp_app_sup:start_link(),
+ Entities = entities(),
+ ok = start_entities(Type, Entities),
+ {ok, Pid}.
+
+entities() ->
+ entities([agent, manager], []).
+
+entities([], []) ->
+ ?d("entities -> entry when no entities", []),
+
+ %% Could be old style snmp (agent) application config format
+ %% but could also be a skeleton start, which means that neither
+ %% agent nor manager config has been specified
+
+ case get_env() of
+ [] ->
+ %% Skeleton start
+ ?d("entities -> skeleton start", []),
+ [];
+ OldConf when is_list(OldConf) ->
+ ?d("entities -> old style config: ~n~p", [OldConf]),
+ %% Old style snmp (agent) application config format
+ Conf = snmpa_app:convert_config(OldConf),
+ ?d("entities -> converted config: ~n~p", [Conf]),
+ [{agent, Conf}]
+ end;
+entities([], E) ->
+ ?d("entities -> done", []),
+ lists:reverse(E);
+entities([ET|ETs], E) ->
+ ?d("entities -> entry with"
+ "~n ET: ~p", [ET]),
+ case application:get_env(snmp, ET) of
+ {ok, Conf} ->
+ entities(ETs, [{ET, Conf}|E]);
+ _ ->
+ entities(ETs, E)
+ end.
+
+start_entities(_Type, []) ->
+ ok;
+start_entities(Type, [{agent, Opts}|Entities]) ->
+ case start_agent(Type, Opts) of
+ ok ->
+ start_entities(Type, Entities);
+ Error ->
+ Error
+ end;
+start_entities(Type, [{manager, Opts}|Entities]) ->
+ case start_manager(Type, Opts) of
+ ok ->
+ start_entities(Type, Entities);
+ Error ->
+ Error
+ end;
+start_entities(Type, [BadEntity|Entities]) ->
+ error_msg("Bad snmp configuration: ~n: ~p", [BadEntity]),
+ start_entities(Type, Entities).
+
+
+start_agent() ->
+ start_agent(normal).
+
+start_agent(Type) when is_atom(Type) ->
+ case application:get_env(snmp, agent) of
+ {ok, Opts} ->
+ start_agent(Type, Opts);
+ _ ->
+ {error, missing_config}
+ end;
+start_agent(Opts) when is_list(Opts) ->
+ start_agent(normal, Opts);
+start_agent(BadArg) ->
+ {error, {bad_arg, BadArg}}.
+
+start_agent(Type, Opts) ->
+ ?d("start_agent -> entry", []),
+ case snmp_app_sup:start_agent(Type, Opts) of
+ {ok, _} ->
+ ok;
+ Error ->
+ Error
+ end.
+
+start_manager() ->
+ start_manager(normal).
+
+start_manager(Type) when is_atom(Type) ->
+ case application:get_env(snmp, manager) of
+ {ok, Opts} ->
+ start_manager(Type, Opts);
+ _ ->
+ {error, missing_config}
+ end;
+start_manager(Opts) when is_list(Opts) ->
+ start_manager(normal, Opts);
+start_manager(BadArg) ->
+ {error, {bad_arg, BadArg}}.
+
+start_manager(Type, Opts) ->
+ ?d("start manager -> entry", []),
+ case snmp_app_sup:start_manager(Type, Opts) of
+ {ok, _} ->
+ ok;
+ Error ->
+ Error
+ end.
+
+
+stop(_) ->
+ ok.
+
+stop() ->
+ snmp_app_sup:stop().
+
+
+get_env() ->
+ Env = application:get_all_env(snmp),
+ DeleteElem = [included_applications],
+ F = fun({Key, _}) -> lists:member(Key, DeleteElem) end,
+ lists:dropwhile(F, Env).
+
+
+%%-----------------------------------------------------------------
+%% The presence of this function means that we will accept changes
+%% in the configuration parameters. However, we won't react upon
+%% those changes until the app is restarted. So we just return
+%% ok.
+%%-----------------------------------------------------------------
+config_change(_Changed, _New, _Removed) ->
+ ok.
+
+%% ---------------------------------------------------------------------
+
+error_msg(F, A) ->
+ error_logger:error_msg("~w: " ++ F ++ "~n", [?MODULE|A]).
+
diff --git a/lib/snmp/src/app/snmp_app_sup.erl b/lib/snmp/src/app/snmp_app_sup.erl
new file mode 100644
index 0000000000..d0c190b51f
--- /dev/null
+++ b/lib/snmp/src/app/snmp_app_sup.erl
@@ -0,0 +1,119 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2003-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%
+%%
+-module(snmp_app_sup).
+
+-include("snmp_debug.hrl").
+
+-behaviour(supervisor).
+
+
+%% External exports
+-export([start_link/0, start_agent/2, start_manager/2]).
+
+%% Internal exports
+-export([stop/0]).
+
+
+%% supervisor callbacks
+-export([init/1]).
+
+-define(SERVER, ?MODULE).
+
+
+%%%-------------------------------------------------------------------
+%%% API
+%%%-------------------------------------------------------------------
+start_link() ->
+ ?d("start_link -> entry",[]),
+ SupName = {local, ?MODULE},
+ supervisor:start_link(SupName, ?MODULE, []).
+
+stop() ->
+ ?d("stop -> entry", []),
+ case whereis(?SERVER) of
+ Pid when is_pid(Pid) ->
+ ?d("stop -> Pid: ~p", [Pid]),
+ exit(Pid, shutdown),
+ ?d("stop -> stopped", []),
+ ok;
+ _ ->
+ ?d("stop -> not running", []),
+ not_running
+ end.
+
+
+start_agent(Type, Opts) ->
+ ?d("start_agent -> entry with"
+ "~n Type: ~p"
+ "~n Opts: ~p", [Type, Opts]),
+ Restart = get_restart(Opts, permanent),
+ start_sup_child(snmpa_supervisor, Restart, [Type, Opts]).
+
+
+start_manager(Type, Opts) ->
+ ?d("start_manager -> entry with"
+ "~n Type: ~p"
+ "~n Opts: ~p", [Type, Opts]),
+ Restart = get_restart(Opts, transient),
+ start_sup_child(snmpm_supervisor, Restart, [Type, Opts]).
+
+
+%%%-------------------------------------------------------------------
+%%% Callback functions from supervisor
+%%%-------------------------------------------------------------------
+
+%%--------------------------------------------------------------------
+%% Func: init/1
+%% Returns: {ok, {SupFlags, [ChildSpec]}} |
+%% ignore |
+%% {error, Reason}
+%%--------------------------------------------------------------------
+init(_Args) ->
+ ?d("init -> entry", []),
+ Flags = {one_for_one, 0, 1},
+ Sups = [],
+ {ok, {Flags, Sups}}.
+
+
+%%%-------------------------------------------------------------------
+%%% Internal functions
+%%%-------------------------------------------------------------------
+
+get_restart(Opts, Def) ->
+ get_opt(Opts, restart_type, Def).
+
+get_opt(Opts, Key, Def) ->
+ snmp_misc:get_option(Key, Opts, Def).
+
+start_sup_child(Mod, Type, Args) ->
+ Spec = sup_spec(Mod, Type, Args),
+ supervisor:start_child(?MODULE, Spec).
+
+sup_spec(Name, Type, Args) ->
+ {Name,
+ {Name, start_link, Args},
+ Type, 2000, supervisor, [Name, supervisor]}.
+
+
+% i(F) ->
+% i(F, []).
+
+% i(F, A) ->
+% io:format("~p: " ++ F ++ "~n", [?MODULE|A]).
+
diff --git a/lib/snmp/src/app/snmp_internal.hrl b/lib/snmp/src/app/snmp_internal.hrl
new file mode 100644
index 0000000000..5ff715e0b7
--- /dev/null
+++ b/lib/snmp/src/app/snmp_internal.hrl
@@ -0,0 +1,40 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2006-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%
+%%
+
+-ifndef(snmp_internal).
+-define(snmp_internal, true).
+
+-ifndef(APPLICATION).
+-define(APPLICATION, snmp).
+-endif.
+
+-define(snmp_info(C, F, A), ?snmp_msg(info_msg, C, F, A)).
+-define(snmp_warning(C, F, A), ?snmp_msg(warning_msg, C, F, A)).
+-define(snmp_error(C, F, A), ?snmp_msg(error_msg, C, F, A)).
+
+-define(snmp_msg(Func, Component, Format, Args),
+%% io:format("[ ~w : ~s : ~w : ~p ] ~n" ++ Format ++ "~n",
+%% [?APPLICATION, Component, ?MODULE, self() | Args]),
+ (catch error_logger:Func("[ ~w : ~s : ~w : ~p ] ~n" ++ Format ++ "~n",
+ [?APPLICATION, Component, ?MODULE, self() | Args]))).
+
+-endif. % -ifdef(snmp_internal).
+
+
+
diff --git a/lib/snmp/src/compile/Makefile b/lib/snmp/src/compile/Makefile
new file mode 100644
index 0000000000..4be60e1835
--- /dev/null
+++ b/lib/snmp/src/compile/Makefile
@@ -0,0 +1,125 @@
+#-*-makefile-*- ; force emacs to enter makefile-mode
+
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 1997-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%
+
+include $(ERL_TOP)/make/target.mk
+
+EBIN = ../../ebin
+
+include $(ERL_TOP)/make/$(TARGET)/otp.mk
+
+
+# ----------------------------------------------------
+# Application version
+# ----------------------------------------------------
+include ../../vsn.mk
+
+VSN = $(SNMP_VSN)
+
+
+# ----------------------------------------------------
+# Release directory specification
+# ----------------------------------------------------
+RELSYSDIR = $(RELEASE_PATH)/lib/snmp-$(VSN)
+
+
+# ----------------------------------------------------
+# Target Specs
+# ----------------------------------------------------
+
+include modules.mk
+
+ERL_FILES = $(MODULES:%=%.erl)
+
+TARGET_FILES = $(MODULES:%=$(EBIN)/%.$(EMULATOR))
+
+GENERATED_PARSER = $(PARSER_MODULE:%=%.erl)
+
+PARSER_TARGET = $(PARSER_MODULE).$(EMULATOR)
+
+
+# ----------------------------------------------------
+# FLAGS
+# ----------------------------------------------------
+ifeq ($(WARN_UNUSED_VARS),true)
+ERL_COMPILE_FLAGS += +warn_unused_vars
+endif
+
+ERL_COMPILE_FLAGS += -I../../include \
+ -Dversion=\"$(VSN)$(PRE_VSN)\" \
+ +'{parse_transform,sys_pre_attributes}' \
+ +'{attribute,insert,app_vsn,$(APP_VSN)}' \
+ -I$(ERL_TOP)/lib/stdlib
+
+YRL_FLAGS = -o .
+
+
+# ----------------------------------------------------
+# Targets
+# ----------------------------------------------------
+
+debug:
+ @${MAKE} TYPE=debug opt
+
+opt: $(TARGET_FILES)
+
+clean:
+ rm -f $(TARGET_FILES) $(GENERATED_PARSER)
+ rm -f core *~
+
+docs:
+
+info:
+ @echo "PARSER_SRC: $(PARSER_SRC)"
+ @echo "PARSER_MODULE: $(PARSER_MODULE)"
+ @echo ""
+ @echo "GENERATED_PARSER: $(GENERATED_PARSER)"
+ @echo "PARSER_TARGET: $(PARSER_TARGET)"
+ @echo ""
+ @echo "MODULES: $(MODULES)"
+ @echo ""
+ @echo "TARGET_FILES: $(TARGET_FILES)"
+ @echo ""
+ @echo "EBIN: $(EBIN)"
+ @echo ""
+ @echo ""
+
+# ----------------------------------------------------
+# Special Build Targets
+# ----------------------------------------------------
+
+parser: $(PARSER_TARGET)
+
+$(GENERATED_PARSER): $(PARSER_SRC)
+
+# ----------------------------------------------------
+# Release Target
+# ----------------------------------------------------
+include $(ERL_TOP)/make/otp_release_targets.mk
+
+release_spec: opt
+ $(INSTALL_DIR) $(RELSYSDIR)/src
+ $(INSTALL_DIR) $(RELSYSDIR)/src/compiler
+ $(INSTALL_DATA) $(PARSER_SRC) $(ERL_FILES) $(INTERNAL_HRL_FILES) $(RELSYSDIR)/src/compiler
+ $(INSTALL_DIR) $(RELSYSDIR)/ebin
+ $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin
+
+release_docs_spec:
+
+include depend.mk
+
diff --git a/lib/snmp/src/compile/depend.mk b/lib/snmp/src/compile/depend.mk
new file mode 100644
index 0000000000..75af1bf293
--- /dev/null
+++ b/lib/snmp/src/compile/depend.mk
@@ -0,0 +1,46 @@
+#-*-makefile-*- ; force emacs to enter makefile-mode
+
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2004-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%
+
+snmpc_mib_gram.erl: snmpc_mib_gram.yrl
+
+$(EBIN)/snmpc.$(EMULATOR): \
+ ../../include/snmp_types.hrl \
+ snmpc.erl \
+ snmpc.hrl
+
+$(EBIN)/snmpc_lib.$(EMULATOR): \
+ ../../include/snmp_types.hrl \
+ snmpc_lib.erl \
+ snmpc.hrl
+
+$(EBIN)/snmpc_tok.$(EMULATOR): \
+ snmpc_tok.erl
+
+$(EBIN)/snmpc_misc.$(EMULATOR): \
+ ../../include/snmp_types.hrl \
+ snmpc_misc.erl
+
+$(EBIN)/snmpc_mib_to_hrl.$(EMULATOR): \
+ ../../include/snmp_types.hrl \
+ snmpc_mib_to_hrl.erl
+
+$(EBIN)/snmpc_mib_gram.$(EMULATOR): \
+ ../../include/snmp_types.hrl \
+ snmpc_mib_gram.erl
+
diff --git a/lib/snmp/src/compile/modules.mk b/lib/snmp/src/compile/modules.mk
new file mode 100644
index 0000000000..6365b0e694
--- /dev/null
+++ b/lib/snmp/src/compile/modules.mk
@@ -0,0 +1,36 @@
+#-*-makefile-*- ; force emacs to enter makefile-mode
+
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2004-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%
+
+PARSER_SRC = snmpc_mib_gram.yrl
+
+PARSER_MODULE = $(PARSER_SRC:%.yrl=%)
+
+MODULES = \
+ $(PARSER_MODULE) \
+ snmpc \
+ snmpc_lib \
+ snmpc_mib_to_hrl \
+ snmpc_misc \
+ snmpc_tok
+
+
+INTERNAL_HRL_FILES = \
+ snmpc.hrl \
+ snmpc_lib.hrl \
+ snmpc_misc.hrl
diff --git a/lib/snmp/src/compile/snmpc.erl b/lib/snmp/src/compile/snmpc.erl
new file mode 100644
index 0000000000..8a1f15d4a4
--- /dev/null
+++ b/lib/snmp/src/compile/snmpc.erl
@@ -0,0 +1,1358 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1997-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%
+%%
+-module(snmpc).
+
+%% API
+-export([compile/1, compile/2, compile/3,
+ mib_to_hrl/1, mib_to_hrl/3,
+ is_consistent/1]).
+
+%% Debug
+-export([look_at/1]).
+
+%% Internal Exports
+-export([init/3]).
+
+-include_lib("stdlib/include/erl_compile.hrl").
+-include("snmp_types.hrl").
+-include("snmpc.hrl").
+-include("snmpc_lib.hrl").
+
+
+look_at(Mib) ->
+ io:format("~p ~n", [snmpc_lib:look_at(Mib)]).
+
+
+%%-----------------------------------------------------------------
+%% Misc compiler stuff
+%%-----------------------------------------------------------------
+
+is_consistent(Filenames) ->
+ snmpc_lib:is_consistent(Filenames).
+
+mib_to_hrl(MibName) ->
+ snmpc_mib_to_hrl:convert(MibName).
+
+mib_to_hrl(MibName, HrlFile, Opts) ->
+ snmpc_mib_to_hrl:compile(MibName, HrlFile, Opts).
+
+
+%%%-----------------------------------------------------------------
+%%% Interface for erl_compile.
+%%%-----------------------------------------------------------------
+
+compile(Input, _Output, Options) ->
+ case compile(Input, make_options(Options)) of
+ {ok, _} ->
+ ok;
+ {error, Reason} ->
+ io:format("~p", [Reason]),
+ error
+ end.
+
+%% Converts generic options to format expected by compile/2
+
+make_options(#options{includes = Incs,
+ outdir = Outdir,
+ warning = Warning,
+ specific = Spec}) ->
+
+ OutdirOpt = {outdir, Outdir},
+
+ WarningOpt =
+ case Warning of
+ 0 -> {warnings, false};
+ _ -> {warnings, true}
+ end,
+
+ IncludeOpt =
+ {i, case Incs of
+ [] ->
+ [""];
+ _ ->
+ lists:map(fun(Dir) -> Dir++"/" end, Incs)
+ end},
+
+ [WarningOpt, OutdirOpt, IncludeOpt | Spec].
+
+%% Returns: {ok, File}|{error, Reason}
+compile([AtomFilename]) when is_atom(AtomFilename) ->
+ compile(atom_to_list(AtomFilename), []), % from cmd line
+ halt();
+compile(FileName) ->
+ compile(FileName, []).
+
+
+%%----------------------------------------------------------------------
+%% Options:
+%% {deprecated, bool()} true
+%% {group_check, bool()} true
+%% {db, volatile|persistent|mnesia} volatile
+%% {i, [import_dir_string()]} ["./"]
+%% {il, [import_lib_dir_string()]} []
+%% {warnings, bool()} true
+%% {outdir, string()} "./"
+%% description
+%% reference
+%% imports
+%% module_identity
+%% {module, string()}
+%% no_defs
+%% (hidden) {verbosity, trace|debug|log|info|silence} silence
+%% (hidden) version
+%% (hidden) options
+%%----------------------------------------------------------------------
+
+compile(FileName, Options) when is_list(FileName) ->
+ true = snmpc_misc:is_string(FileName),
+ DefOpts = [{deprecated, true},
+ {group_check, true},
+ {i, ["./"]},
+ {db, volatile},
+ {warnings, true},
+ {outdir, "./"},
+ {il, []}],
+ Opts = update_options(DefOpts, Options),
+ case check_options(Opts) of
+ ok ->
+ maybe_display_version(Opts),
+ maybe_display_options(Opts),
+ Pid = spawn_link(?MODULE,init,[self(),FileName,Opts]),
+ receive
+ {compile_result,R} -> R;
+ {'EXIT',Pid, Reason} when Reason =/= normal ->
+ exit(Reason)
+ end;
+ {error, Reason} ->
+ {error, Reason}
+ end.
+
+maybe_display_version(Opts) ->
+ case lists:member(version, Opts) of
+ true ->
+ Vsn = (catch get_version()),
+ io:format("version: ~s~n", [Vsn]);
+ false ->
+ ok
+ end.
+
+get_version() ->
+ MI = ?MODULE:module_info(),
+ Attr = get_info(attributes, MI),
+ Vsn = get_info(app_vsn, Attr),
+ Comp = get_info(compile, MI),
+ Time = get_info(time, Comp),
+ {Year, Month, Day, Hour, Min, Sec} = Time,
+ io_lib:format("~s [~.4w-~.2.0w-~.2.0w ~.2.0w:~.2.0w:~.2.0w]",
+ [Vsn, Year, Month, Day, Hour, Min, Sec]).
+
+maybe_display_options(Opts) ->
+ case lists:member(options, Opts) of
+ true ->
+ {F, A} = get_options(Opts, [], []),
+ io:format("options: " ++ F ++ "~n", A);
+ false ->
+ ok
+ end.
+
+get_options([], Formats, Args) ->
+ {lists:concat(lists:reverse(Formats)), lists:reverse(Args)};
+get_options([{deprecated, Val}|Opts], Formats, Args) ->
+ get_options(Opts, ["~n deprecated: ~w"|Formats], [Val|Args]);
+get_options([{group_check, Val}|Opts], Formats, Args) ->
+ get_options(Opts, ["~n group_check: ~w"|Formats], [Val|Args]);
+get_options([{db, Val}|Opts], Formats, Args) ->
+ get_options(Opts, ["~n db: ~w"|Formats], [Val|Args]);
+get_options([{i, Val}|Opts], Formats, Args) ->
+ get_options(Opts, ["~n i: ~p"|Formats], [Val|Args]);
+get_options([{il, Val}|Opts], Formats, Args) ->
+ get_options(Opts, ["~n il: ~p"|Formats], [Val|Args]);
+get_options([{outdir, Val}|Opts], Formats, Args) ->
+ get_options(Opts, ["~n outdir: ~s"|Formats], [Val|Args]);
+get_options([{description, Val}|Opts], Formats, Args) ->
+ get_options(Opts, ["~n description: ~w"|Formats], [Val|Args]);
+get_options([description|Opts], Formats, Args) ->
+ get_options(Opts, ["~n description"|Formats], Args);
+get_options([{reference, Val}|Opts], Formats, Args) ->
+ get_options(Opts, ["~n reference: ~w"|Formats], [Val|Args]);
+get_options([reference|Opts], Formats, Args) ->
+ get_options(Opts, ["~n reference"|Formats], Args);
+get_options([{warnings, Val}|Opts], Formats, Args) ->
+ get_options(Opts, ["~n warnings: ~w"|Formats], [Val|Args]);
+get_options([{verbosity, Val}|Opts], Formats, Args) ->
+ get_options(Opts, ["~n verbosity: ~w"|Formats], [Val|Args]);
+get_options([imports|Opts], Formats, Args) ->
+ get_options(Opts, ["~n imports"|Formats], Args);
+get_options([module_identity|Opts], Formats, Args) ->
+ get_options(Opts, ["~n module_identity"|Formats], Args);
+get_options([_|Opts], Formats, Args) ->
+ get_options(Opts, Formats, Args).
+
+
+get_info(Key, Info) ->
+ case lists:keysearch(Key, 1, Info) of
+ {value, {Key, Val}} ->
+ Val;
+ false ->
+ throw("undefined")
+ end.
+
+% p(F, A) ->
+% io:format("DBG: " ++ F ++ "~n", A).
+
+update_options([], Options) ->
+ Options;
+update_options([{Key,DefVal}|DefOpts], Options) ->
+ case snmpc_misc:assq(Key, Options) of
+ false ->
+ update_options(DefOpts, [{Key,DefVal}|Options]);
+ {value, Val} when Key =:= i ->
+ Options1 =
+ lists:keyreplace(Key, 1, Options, {Key, Val++DefVal}),
+ update_options(DefOpts, Options1);
+ {value, Val} when Key =:= il ->
+ Options1 =
+ lists:keyreplace(Key, 1, Options, {Key, Val++DefVal}),
+ update_options(DefOpts, Options1);
+ {value, DefVal} -> %% Same value, no need to update
+ update_options(DefOpts, Options);
+ {value, Val} -> %% New value, so update
+ Options1 =
+ lists:keyreplace(Key, 1, Options, {Key, Val}),
+ update_options(DefOpts, Options1)
+ end.
+
+check_options([]) -> ok;
+check_options([no_symbolic_info|T]) -> check_options(T);
+check_options([{outdir, Str} | T]) when is_list(Str) ->
+ check_options(T);
+check_options([{debug, Atom} | T]) when is_atom(Atom) ->
+ check_options(T);
+check_options([{deprecated, Atom} | T]) when is_atom(Atom) ->
+ check_options(T);
+check_options([{group_check, Atom} | T]) when is_atom(Atom) ->
+ check_options(T);
+check_options([{warnings, Bool} | T]) ->
+ check_bool(warnings, Bool),
+ check_options(T);
+check_options([{db, volatile} | T]) ->
+ check_options(T);
+check_options([{db, persistent} | T]) ->
+ check_options(T);
+check_options([{db, mnesia} | T]) ->
+ check_options(T);
+check_options([{i, [Str|_]} | T]) when is_list(Str) ->
+ check_options(T);
+check_options([{il, []} | T]) ->
+ check_options(T);
+check_options([{il, [Str|_]} | T]) when is_list(Str) ->
+ check_options(T);
+check_options([{description, Bool}| T]) ->
+ check_bool(description, Bool),
+ check_options(T);
+check_options([description| T]) -> %% same as {description, true}
+ check_options(T);
+check_options([{reference, Bool}| T]) ->
+ check_bool(reference, Bool),
+ check_options(T);
+check_options([reference| T]) -> %% same as {reference, true}
+ check_options(T);
+check_options([{verbosity, V} | T]) when is_atom(V) ->
+ snmpc_lib:vvalidate(V),
+ check_options(T);
+check_options([version| T]) ->
+ check_options(T);
+check_options([options| T]) ->
+ check_options(T);
+check_options([imports| T]) ->
+ check_options(T);
+check_options([module_identity| T]) ->
+ check_options(T);
+check_options([{module, M} | T]) when is_atom(M) ->
+ check_options(T);
+check_options([no_defs| T]) ->
+ check_options(T);
+check_options([Opt|_]) ->
+ {error, {invalid_option, Opt}}.
+
+
+check_bool(_Key, Bool) when (Bool =:= true) orelse (Bool =:= false) ->
+ ok;
+check_bool(Key, Val) ->
+ {error, {invalid_option, {Key, Val}}}.
+
+get_group_check(Options) ->
+ snmpc_lib:key1search(group_check, Options, true).
+
+get_deprecated(Options) ->
+ snmpc_lib:key1search(deprecated, Options, true).
+
+get_description(Options) ->
+ get_bool_option(description, Options).
+
+get_reference(Options) ->
+ get_bool_option(reference, Options).
+
+get_bool_option(Option, Options) ->
+ case lists:member(Option, Options) of
+ false ->
+ snmpc_lib:key1search(Option, Options, false);
+ true ->
+ true
+ end.
+
+make_description(Message) ->
+ case get(description) of
+ true ->
+ Message;
+ _ ->
+ undefined
+ end.
+
+make_reference(undefined) ->
+ [];
+make_reference(Reference) ->
+ case get(reference) of
+ true ->
+ [{reference, Reference}];
+ _ ->
+ []
+ end.
+
+
+
+%%----------------------------------------------------------------------
+%% verbosity stuff
+%%----------------------------------------------------------------------
+
+%% Verbosity level is selected from three (historical reasons)
+%% options: warnings, debug and verbosity
+%% - If warnings is true, then verbosity is _atleast_ warning
+%% (even if the verbosity flag is set to silence)
+%% - If debug is true, the verbosity is _atleast_ log
+%% - Otherwise, verbosity is used as is.
+get_verbosity(Options) ->
+ WarningsSeverity =
+ case snmpc_lib:key1search(warnings, Options) of
+ true ->
+ warning;
+ _ ->
+ silence
+ end,
+ case snmpc_lib:key1search(verbosity, Options) of
+ undefined ->
+ %% Backward compatible: If not defined then try debug and convert
+ case snmpc_lib:key1search(debug, Options, false) of
+ true ->
+ log;
+ false ->
+ WarningsSeverity
+ end;
+ silence ->
+ WarningsSeverity;
+ Verbosity ->
+ Verbosity
+ end.
+
+
+%%----------------------------------------------------------------------
+%% The compile process.
+%%----------------------------------------------------------------------
+
+init(From, MibFileName, Options) ->
+ {A,B,C} = now(),
+ random:seed(A,B,C),
+ put(options, Options),
+ put(verbosity, get_verbosity(Options)),
+ put(description, get_description(Options)),
+ put(reference, get_reference(Options)),
+ File = filename:rootname(MibFileName, ".mib"),
+ put(filename, filename:basename(File ++ ".mib")),
+ R = case catch c_impl(File) of
+ {ok, OutFile} -> {ok, OutFile};
+ {'EXIT',error} -> {error, compilation_failed};
+ Error -> exit(Error)
+ end,
+ From ! {compile_result, R}.
+
+
+c_impl(File) ->
+ {ok, PData} = parse(File),
+ ?vtrace("Syntax analysis:"
+ "~n PData: ~p", [PData]),
+ MibName = compile_parsed_data(PData),
+ ?vtrace("Compiler output:"
+ "~n CDATA: ~p", [get(cdata)]),
+ save(File, MibName, get(options)).
+
+compile_parsed_data(#pdata{mib_name = MibName,
+ imports = Imports,
+ defs = Definitions}) ->
+ snmpc_lib:import(Imports),
+ update_imports(Imports),
+ Deprecated = get_deprecated(get(options)),
+ definitions_loop(Definitions, Deprecated),
+ MibName.
+
+update_imports(Imports) ->
+ case lists:member(imports, get(options)) of
+ true ->
+ IMPs = do_update_imports(Imports, []),
+ CDATA = get(cdata),
+ put(cdata, CDATA#cdata{imports = IMPs});
+ false ->
+ ok
+ end.
+
+do_update_imports([], Acc) ->
+ lists:reverse(Acc);
+do_update_imports([{{Mib, ImportsFromMib0},_Line}|Imports], Acc) ->
+ ImportsFromMib = [Name || {_, Name} <- ImportsFromMib0],
+ Import = {Mib, ImportsFromMib},
+ do_update_imports(Imports, [Import|Acc]).
+
+
+update_status(Name, Status) ->
+ #cdata{status_ets = Ets} = get(cdata),
+ ets:insert(Ets, {Name, Status}).
+
+
+%% A deprecated object
+definitions_loop([{#mc_object_type{name = ObjName, status = deprecated},
+ Line}|T],
+ false) ->
+ %% May be implemented but the compiler chooses not to.
+ ?vinfo2("object_type ~w is deprecated => ignored", [ObjName], Line),
+ update_status(ObjName, deprecated),
+ definitions_loop(T, false);
+
+%% A obsolete object
+definitions_loop([{#mc_object_type{name = ObjName, status = obsolete},
+ Line}|T],
+ Deprecated) ->
+ ?vlog2("object_type ~w is obsolete => ignored", [ObjName], Line),
+ %% No need to implement a obsolete object
+ update_status(ObjName, obsolete),
+ ensure_macro_imported('OBJECT-TYPE', Line),
+ definitions_loop(T, Deprecated);
+
+%% Defining a table
+definitions_loop([{#mc_object_type{name = NameOfTable,
+ syntax = {{sequence_of, SeqName}, _},
+ max_access = Taccess,
+ kind = Kind,
+ status = Tstatus,
+ description = Desc1,
+ units = Tunits,
+ reference = Ref,
+ name_assign = Tindex},
+ Tline},
+ {#mc_object_type{name = NameOfEntry,
+ syntax = {{type, SeqName}, TEline},
+ max_access = 'not-accessible',
+ kind = {table_entry, IndexingInfo},
+ status = Estatus,
+ description = Desc2,
+ units = Eunits,
+ name_assign = {NameOfTable,[1]}},
+ Eline},
+ {#mc_sequence{name = SeqName,
+ fields = FieldList},
+ Sline}|ColsEtc],
+ Deprecated) ->
+ ?vlog("defloop -> "
+ "[object_type(sequence_of),object_type(type,[1]),sequence]:"
+ "~n NameOfTable: ~p"
+ "~n SeqName: ~p"
+ "~n Taccess: ~p"
+ "~n Kind: ~p"
+ "~n Tstatus: ~p"
+ "~n Tindex: ~p"
+ "~n Tunits: ~p"
+ "~n Tline: ~p"
+ "~n NameOfEntry: ~p"
+ "~n TEline: ~p"
+ "~n IndexingInfo: ~p"
+ "~n Estatus: ~p"
+ "~n Eunits: ~p"
+ "~n Ref: ~p"
+ "~n Eline: ~p"
+ "~n FieldList: ~p"
+ "~n Sline: ~p",
+ [NameOfTable,SeqName,Taccess,Kind,Tstatus,
+ Tindex,Tunits,Tline,
+ NameOfEntry,TEline,IndexingInfo,Estatus,Eunits,Ref,Eline,
+ FieldList,Sline]),
+ update_status(NameOfTable, Tstatus),
+ update_status(NameOfEntry, Estatus),
+ update_status(SeqName, undefined),
+ ensure_macro_imported('OBJECT-TYPE', Tline),
+ test_table(NameOfTable,Taccess,Kind,Tindex,Tline),
+ {Tfather,Tsubindex} = Tindex,
+ snmpc_lib:register_oid(Tline,NameOfTable,Tfather,Tsubindex),
+ Description1 = make_description(Desc1),
+ TableME = #me{aliasname = NameOfTable,
+ entrytype = table,
+ access = 'not-accessible',
+ description = Description1,
+ units = Tunits},
+ snmpc_lib:register_oid(TEline,NameOfEntry,NameOfTable,[1]),
+ Description2 = make_description(Desc2),
+ TableEntryME = #me{aliasname = NameOfEntry,
+ entrytype = table_entry,
+ assocList = [{table_entry_with_sequence, SeqName}],
+ access = 'not-accessible',
+ description = Description2,
+ units = Eunits},
+ {ColMEs, RestObjs} =
+ define_cols(ColsEtc, 1, FieldList, NameOfEntry, NameOfTable, []),
+ TableInfo = snmpc_lib:make_table_info(Eline, NameOfTable,
+ IndexingInfo, ColMEs),
+ snmpc_lib:add_cdata(#cdata.mes,
+ [TableEntryME,
+ TableME#me{assocList=[{table_info,
+ TableInfo} | make_reference(Ref)]} |
+ ColMEs]),
+ definitions_loop(RestObjs, Deprecated);
+
+definitions_loop([{#mc_object_type{name = NameOfTable,
+ syntax = {{sequence_of, SeqName},_},
+ max_access = Taccess,
+ kind = Kind,
+ status = Tstatus,
+ description = Desc1,
+ units = Tunits,
+ reference = Ref,
+ name_assign = Tindex}, Tline},
+ {#mc_object_type{name = NameOfEntry,
+ syntax = {{type, SeqName},_},
+ max_access = 'not-accessible',
+ kind = {table_entry,IndexingInfo},
+ status = Estatus,
+ description = Desc2,
+ units = Eunits,
+ name_assign = BadOID}, Eline},
+ {#mc_sequence{name = SeqName,
+ fields = FieldList}, Sline}|ColsEtc],
+ Deprecated) ->
+ ?vlog("defloop -> "
+ "[object_type(sequence_of),object_type(type),sequence(fieldList)]:"
+ "~n NameOfTable: ~p"
+ "~n SeqName: ~p"
+ "~n Taccess: ~p"
+ "~n Kind: ~p"
+ "~n Tstatus: ~p"
+ "~n Tindex: ~p"
+ "~n Tunits: ~p"
+ "~n Tline: ~p"
+ "~n NameOfEntry: ~p"
+ "~n IndexingInfo: ~p"
+ "~n Estatus: ~p"
+ "~n BadOID: ~p"
+ "~n Eunits: ~p"
+ "~n Ref: ~p"
+ "~n Eline: ~p"
+ "~n FieldList: ~p"
+ "~n Sline: ~p",
+ [NameOfTable,SeqName,Taccess,Kind,Tstatus,
+ Tindex,Tunits,Tline,
+ NameOfEntry,IndexingInfo,Estatus,BadOID,Eunits,Ref,Eline,
+ FieldList,Sline]),
+ update_status(NameOfTable, Tstatus),
+ update_status(NameOfEntry, Estatus),
+ update_status(SeqName, undefined),
+ ensure_macro_imported('OBJECT-TYPE', Tline),
+ snmpc_lib:print_error("Bad TableEntry OID definition (~w)",
+ [BadOID],Eline),
+ test_table(NameOfTable,Taccess,Kind,Tindex,Tline),
+ {Tfather,Tsubindex} = Tindex,
+ snmpc_lib:register_oid(Tline,NameOfTable,Tfather,Tsubindex),
+ Description1 = make_description(Desc1),
+ TableME = #me{aliasname = NameOfTable,
+ entrytype = table,
+ access = 'not-accessible',
+ description = Description1,
+ units = Tunits},
+ Description2 = make_description(Desc2),
+ TableEntryME = #me{aliasname = NameOfEntry,
+ entrytype = table_entry,
+ access = 'not-accessible',
+ assocList = [{table_entry_with_sequence,SeqName}],
+ description = Description2,
+ units = Eunits},
+ {ColMEs, RestObjs} =
+ define_cols(ColsEtc, 1, FieldList, NameOfEntry, NameOfTable, []),
+ TableInfo = snmpc_lib:make_table_info(Eline, NameOfTable,
+ IndexingInfo, ColMEs),
+ snmpc_lib:add_cdata(#cdata.mes,
+ [TableEntryME,
+ TableME#me{assocList=[{table_info,
+ TableInfo} | make_reference(Ref)]} |
+ ColMEs]),
+ definitions_loop(RestObjs, Deprecated);
+
+definitions_loop([{#mc_new_type{name = NewTypeName,
+ macro = Macro,
+ syntax = OldType,
+ display_hint = DisplayHint},Line}|T],
+ Deprecated) ->
+ ?vlog2("defloop -> new_type:"
+ "~n Macro: ~p"
+ "~n NewTypeName: ~p"
+ "~n OldType: ~p"
+ "~n DisplayHint: ~p",
+ [Macro, NewTypeName, OldType, DisplayHint], Line),
+ ensure_macro_imported(Macro,Line),
+ Types = (get(cdata))#cdata.asn1_types,
+ case lists:keysearch(NewTypeName, #asn1_type.aliasname, Types) of
+ {value,_} ->
+ snmpc_lib:print_error("Type ~w already defined.",
+ [NewTypeName],Line);
+ false ->
+ %% NameOfOldType = element(2,OldType),
+ ASN1 = snmpc_lib:make_ASN1type(OldType),
+ snmpc_lib:add_cdata(#cdata.asn1_types,
+ [ASN1#asn1_type{aliasname = NewTypeName,
+ imported = false,
+ display_hint = DisplayHint}])
+ end,
+ definitions_loop(T, Deprecated);
+
+%% Plain variable
+definitions_loop([{#mc_object_type{name = NewVarName,
+ syntax = Type,
+ max_access = Access,
+ kind = {variable, DefVal},
+ status = Status,
+ description = Desc1,
+ units = Units,
+ name_assign = {Parent,SubIndex}},Line} |T],
+ Deprecated) ->
+ ?vlog2("defloop -> object_type (variable):"
+ "~n NewVarName: ~p"
+ "~n Type: ~p"
+ "~n Access: ~p"
+ "~n DefVal: ~p"
+ "~n Status: ~p"
+ "~n Units: ~p"
+ "~n Parent: ~p"
+ "~n SubIndex: ~p",
+ [NewVarName, Type, Access, DefVal,
+ Status, Units, Parent, SubIndex], Line),
+ update_status(NewVarName, Status),
+ snmpc_lib:test_father(Parent, NewVarName, SubIndex, Line),
+ ASN1type = snmpc_lib:make_ASN1type(Type),
+ snmpc_lib:register_oid(Line, NewVarName, Parent, SubIndex),
+ Description1 = make_description(Desc1),
+ NewME = #me{aliasname = NewVarName,
+ asn1_type = ASN1type,
+ entrytype = variable,
+ access = Access,
+ description = Description1,
+ units = Units,
+ assocList = DefVal},
+ NewME2 = snmpc_lib:resolve_defval(NewME),
+ %% hmm, should this be done in resolve_defval?
+ VI = snmpc_lib:make_variable_info(NewME2),
+ snmpc_lib:add_cdata(#cdata.mes,
+ [NewME2#me{assocList = [{variable_info, VI}]}]),
+ definitions_loop(T, Deprecated);
+
+definitions_loop([{#mc_module_identity{name = NewVarName,
+ last_updated = LU,
+ organization = Org,
+ contact_info = CI,
+ description = Desc,
+ revisions = Revs0,
+ name_assign = {Parent, SubIndex}},
+ Line}|T],
+ Deprecated) ->
+ ?vlog2("defloop -> module-identity: "
+ "~n NewVarName: ~p"
+ "~n LU: ~p"
+ "~n Org: ~p"
+ "~n CI: ~p"
+ "~n Desc: ~p"
+ "~n Revs0: ~p"
+ "~n Parent: ~p"
+ "~n SubIndex: ~p",
+ [NewVarName, LU, Org, CI, Desc, Revs0, Parent, SubIndex], Line),
+ ensure_macro_imported('MODULE-IDENTITY', Line),
+ snmpc_lib:register_oid(Line, NewVarName, Parent, SubIndex),
+ Revs = [{R,D}||#mc_revision{revision = R,description = D} <- Revs0],
+ MI = #module_identity{last_updated = LU,
+ organization = Org,
+ contact_info = CI,
+ description = Desc,
+ revisions = Revs},
+ CDATA = get(cdata),
+ put(cdata, CDATA#cdata{module_identity = MI}),
+ snmpc_lib:add_cdata(
+ #cdata.mes,
+ [snmpc_lib:makeInternalNode2(false, NewVarName)]),
+ definitions_loop(T, Deprecated);
+
+definitions_loop([{#mc_internal{name = NewVarName,
+ macro = Macro,
+ parent = Parent,
+ sub_index = SubIndex},Line}|T],
+ Deprecated) ->
+ ?vlog2("defloop -> internal:"
+ "~n NewVarName: ~p"
+ "~n Macro: ~p"
+ "~n Parent: ~p"
+ "~n SubIndex: ~p",
+ [NewVarName, Macro, Parent, SubIndex], Line),
+ ensure_macro_imported(Macro, Line),
+ snmpc_lib:register_oid(Line, NewVarName, Parent, SubIndex),
+ snmpc_lib:add_cdata(
+ #cdata.mes,
+ [snmpc_lib:makeInternalNode2(false, NewVarName)]),
+ definitions_loop(T, Deprecated);
+
+%% A trap message
+definitions_loop([{#mc_trap{name = TrapName,
+ enterprise = EnterPrise,
+ vars = Variables,
+ description = Desc1,
+ num = SpecificCode}, Line}|T],
+ Deprecated) ->
+ ?vlog2("defloop -> trap:"
+ "~n TrapName: ~p"
+ "~n EnterPrise: ~p"
+ "~n Variables: ~p"
+ "~n SpecificCode: ~p",
+ [TrapName, EnterPrise, Variables, SpecificCode], Line),
+ update_status(TrapName, undefined),
+ CDATA = get(cdata),
+ snmpc_lib:check_trap_name(EnterPrise, Line, CDATA#cdata.mes),
+ Descriptions = make_description(Desc1),
+ Trap = #trap{trapname = TrapName,
+ enterpriseoid = EnterPrise,
+ specificcode = SpecificCode,
+ %% oidobjects: Store Variables temporary here.
+ %% This will be replaced later in the
+ %% get_final_mib function by a call to
+ %% the update_trap_objects function.
+ oidobjects = Variables,
+ description = Descriptions},
+ lists:foreach(fun(Trap2) -> snmpc_lib:check_trap(Trap2, Trap, Line) end,
+ CDATA#cdata.traps),
+ snmpc_lib:add_cdata(#cdata.traps, [Trap]),
+ definitions_loop(T, Deprecated);
+
+definitions_loop([{#mc_object_type{name = NameOfEntry,
+ syntax = Type,
+ max_access = Eaccess,
+ kind = {table_entry, Index},
+ status = Estatus,
+ name_assign = SubIndex},Eline}|T],
+ Deprecated) ->
+ ?vlog("defloop -> object_type (table_entry):"
+ "~n NameOfEntry: ~p"
+ "~n Type: ~p"
+ "~n Eaccess: ~p"
+ "~n Index: ~p"
+ "~n Estatus: ~p"
+ "~n SubIndex: ~p"
+ "~n SubIndex: ~p"
+ "~n Eline: ~p",
+ [NameOfEntry, Type, Eaccess, Index, Estatus, SubIndex, Eline]),
+ update_status(NameOfEntry, Estatus),
+ snmpc_lib:print_error("Misplaced TableEntry definition (~w)",
+ [NameOfEntry], Eline),
+ definitions_loop(T, Deprecated);
+
+definitions_loop([{#mc_notification{name = TrapName,
+ status = deprecated}, Line}|T],
+ false) ->
+ ?vinfo2("defloop -> notification ~w is deprecated => ignored",
+ [TrapName], Line),
+ update_status(TrapName, deprecated),
+ ensure_macro_imported('NOTIFICATION-TYPE', Line),
+ definitions_loop(T, false);
+
+definitions_loop([{#mc_notification{name = TrapName,
+ status = obsolete}, Line}|T],
+ Deprecated) ->
+ ?vlog2("defloop -> notification ~w is obsolete => ignored",
+ [TrapName], Line),
+ update_status(TrapName, obsolete),
+ ensure_macro_imported('NOTIFICATION-TYPE', Line),
+ definitions_loop(T, Deprecated);
+
+definitions_loop([{#mc_notification{name = TrapName,
+ vars = Variables,
+ status = Status,
+ description = Desc,
+ name_assign = {Parent, SubIndex}},Line}|T],
+ Deprecated) ->
+ ?vlog2("defloop -> notification:"
+ "~n TrapName: ~p"
+ "~n Variables: ~p"
+ "~n Status: ~p"
+ "~n Parent: ~p"
+ "~n SubIndex: ~p",
+ [TrapName, Variables, Status, Parent, SubIndex], Line),
+ update_status(TrapName, Status),
+ ensure_macro_imported('NOTIFICATION-TYPE', Line),
+ CDATA = get(cdata),
+ snmpc_lib:register_oid(Line, TrapName, Parent, SubIndex),
+ Descriptions = make_description(Desc),
+ Notif = #notification{trapname = TrapName,
+ description = Descriptions,
+ %% oidobjects: Store Variables temporary here.
+ %% This will be replaced later in the
+ %% get_final_mib function by a call to
+ %% the update_trap_objects function.
+ oidobjects = Variables},
+ snmpc_lib:check_notification(Notif, Line, CDATA#cdata.traps),
+ snmpc_lib:add_cdata(#cdata.traps, [Notif]),
+ definitions_loop(T, Deprecated);
+
+definitions_loop([{#mc_module_compliance{name = Name},Line}|T], Deprecated) ->
+ ?vlog2("defloop -> module_compliance:"
+ "~n Name: ~p", [Name], Line),
+ ensure_macro_imported('MODULE-COMPLIANCE', Line),
+ definitions_loop(T, Deprecated);
+
+definitions_loop([{#mc_object_group{name = Name,
+ objects = GroupObjects,
+ status = Status,
+ description = Desc,
+ reference = Ref,
+ name_assign = {Parent,SubIndex}}, Line}|T],
+ Deprecated) ->
+ ?vlog2("defloop -> object_group ~p:"
+ "~n GroupObjects: ~p"
+ "~n Status: ~p"
+ "~n Desc: ~p"
+ "~n Ref: ~p"
+ "~n Parent: ~p"
+ "~n SubIndex: ~p",
+ [Name, GroupObjects, Status, Desc, Ref, Parent, SubIndex], Line),
+ ensure_macro_imported('OBJECT-GROUP', Line),
+ GroupBool = get_group_check(get(options)),
+ case GroupBool of
+ true ->
+ snmpc_lib:add_cdata(#cdata.objectgroups,
+ [{Name,GroupObjects,Line}]),
+ %% Check that the group members has been defined
+ %% and that they have the correct status
+ snmpc_lib:check_object_group(Name, GroupObjects,
+ Line, Status);
+ _ ->
+ ok
+ end,
+
+ update_status(Name, Status),
+ snmpc_lib:test_father(Parent, Name, SubIndex, Line),
+ snmpc_lib:register_oid(Line, Name, Parent, SubIndex),
+ Description = make_description(Desc),
+ NewME = #me{aliasname = Name,
+ entrytype = group,
+ access = 'not-accessible',
+ description = Description,
+ assocList = [{kind, object},
+ {objects, GroupObjects}]},
+ snmpc_lib:add_cdata(#cdata.mes, [NewME]),
+
+ definitions_loop(T, Deprecated);
+
+definitions_loop([{#mc_notification_group{name = Name,
+ objects = GroupObjects,
+ status = Status,
+ description = Desc,
+ reference = Ref,
+ name_assign = {Parent,SubIndex}},
+ Line}
+ |T], Deprecated) ->
+ ?vlog2("defloop -> notification_group ~p:"
+ "~n GroupObjects: ~p"
+ "~n Status: ~p"
+ "~n Desc: ~p"
+ "~n Ref: ~p"
+ "~n Parent: ~p"
+ "~n SubIndex: ~p",
+ [Name, GroupObjects, Status, Desc, Ref, Parent, SubIndex], Line),
+ ensure_macro_imported('NOTIFICATION-GROUP', Line),
+ GroupBool = get_group_check(get(options)),
+ case GroupBool of
+ true ->
+ snmpc_lib:add_cdata(#cdata.notificationgroups,
+ [{Name,GroupObjects,Line}]),
+
+ %% Check that the group members has been defined
+ %% and that they have the correct status
+ snmpc_lib:check_notification_group(Name, GroupObjects,
+ Line, Status);
+ _ ->
+ ok
+ end,
+
+ update_status(Name, Status),
+ snmpc_lib:test_father(Parent, Name, SubIndex, Line),
+ snmpc_lib:register_oid(Line, Name, Parent, SubIndex),
+ Description = make_description(Desc),
+ NewME = #me{aliasname = Name,
+ entrytype = group,
+ access = 'not-accessible',
+ description = Description,
+ assocList = [{kind, notification},
+ {objects, GroupObjects}]},
+ snmpc_lib:add_cdata(#cdata.mes, [NewME]),
+
+ definitions_loop(T, Deprecated);
+
+definitions_loop([{#mc_object_type{name = NameOfTable,
+ syntax = {{sequence_of, SeqName},_},
+ status = Tstatus},Tline},
+ Entry, Seq|T],
+ Deprecated) ->
+ ?vlog("defloop -> object_type (sequence_of): "
+ "~n NameOfTable: ~p"
+ "~n SeqName: ~p"
+ "~n Tline: ~p"
+ "~n Entry: ~p"
+ "~n Seq: ~p",
+ [NameOfTable, SeqName, Tline, Entry, Seq]),
+ update_status(NameOfTable, Tstatus),
+ case Entry of
+ {#mc_object_type{syntax = {{type, SeqName},_line},
+ max_access = 'not-accessible',
+ kind = {table_entry, _IndexingInfo},
+ name_assign = {_NameOfTable,[1]}}, _Eline} ->
+ case Seq of
+ {#mc_sequence{name = SeqName}, Sline} ->
+ snmpc_lib:error("Internal error. Correct incorrect "
+ "table (~p,~w).",[SeqName,Sline],
+ Tline);
+ _ ->
+ ?vinfo("defloop -> Invalid sequence: ~p", [Seq]),
+ snmpc_lib:print_error(
+ "Invalid SEQUENCE OF '~p'.",
+ [safe_elem(1,safe_elem(2,Seq))],Tline)
+ end;
+ Else ->
+ ?vinfo("defloop -> Invalid table entry: "
+ "~n ~p", [Else]),
+ snmpc_lib:print_error(
+ "Invalid TableEntry '~p' (check STATUS, Sequence name, Oid)",
+ [safe_elem(1,safe_elem(2,Entry))],Tline)
+ end,
+ definitions_loop(T, Deprecated);
+
+definitions_loop([{#mc_object_type{name = NameOfTable,
+ syntax = {{sequence_of, SeqName},_},
+ status = Tstatus},Tline}|T],
+ Deprecated) ->
+ ?vlog("defloop -> object_type (sequence_of):"
+ "~n object_type: ~p"
+ "~n sequence_of: ~p"
+ "~n Tline: ~p", [NameOfTable, SeqName, Tline]),
+ update_status(NameOfTable, Tstatus),
+ snmpc_lib:print_error("Invalid statements following table ~p.",
+ [NameOfTable],Tline),
+ definitions_loop(T, Deprecated);
+
+definitions_loop([{#mc_sequence{name = SeqName,
+ fields = _FieldList},Line}|T],
+ Deprecated) ->
+ ?vwarning2("Unexpected SEQUENCE ~w => ignoring", [SeqName], Line),
+ definitions_loop(T, Deprecated);
+
+definitions_loop([{Obj,Line}|T], Deprecated) ->
+ ?vinfo2("defloop -> unknown error"
+ "~n Obj: ~p", [Obj], Line),
+ snmpc_lib:print_error("Unknown Error in MIB. "
+ "Can't describe the error better than this: ~999p ignored."
+ " Please send a trouble report to [email protected].",
+ [Obj], Line),
+ definitions_loop(T, Deprecated);
+
+definitions_loop([], _Deprecated) ->
+ ?vlog("defloop -> done", []),
+ ok.
+
+safe_elem(N,T) ->
+ case catch(element(N,T)) of
+ {'EXIT',_} ->
+ "no more information available";
+ X -> X
+ end.
+
+%% A correct column
+define_cols([{#mc_object_type{name = NameOfCol,
+ syntax = Type1,
+ max_access = Access,
+ kind = {variable,Defval},
+ status = Status,
+ description = Desc,
+ units = Units,
+ name_assign = {NameOfEntry,[SubIndex]}},
+ Oline}|Rest],
+ SubIndex,
+ [{NameOfCol,Type2}|Fields], NameOfEntry, TableName, ColMEs) ->
+ ?vlog("defcols -> object_type (variable):"
+ "~n NameOfCol: ~p"
+ "~n Type1: ~p"
+ "~n Access: ~p"
+ "~n Defval: ~p"
+ "~n Status ~p"
+ "~n Units ~p"
+ "~n NameOfEntry ~p"
+ "~n Oline: ~p",
+ [NameOfCol, Type1, Access, Defval, Status, Units,
+ NameOfEntry, Oline]),
+ update_status(NameOfCol, Status),
+ Deprecated = get_deprecated(get(options)),
+ ASN1type = snmpc_lib:make_ASN1type(Type1),
+ case (snmpc_lib:make_ASN1type(Type2))#asn1_type.bertype of
+ T2 when T2 == ASN1type#asn1_type.bertype -> ok;
+ _Else ->
+ snmpc_lib:error(
+ "Types for ~p differs from the SEQUENCE definition. ",
+ [NameOfCol],Oline)
+ end,
+ NewAccess = % a simple way to get the obsolete behaviour
+ if
+ Status =:= obsolete ->
+ %% Be quiet and don't implement
+ 'not-accessible';
+ (Status =:= deprecated) andalso (Deprecated =:= false) ->
+ %% The compiler chooses not to implement the column.
+ ?vinfo2("object_type ~w is deprecated => ignored",
+ [NameOfCol], Oline),
+ 'not-accessible';
+ true -> Access
+ end,
+ snmpc_lib:register_oid(Oline,NameOfCol,NameOfEntry,[SubIndex]),
+ Description = make_description(Desc),
+ ColumnME = snmpc_lib:resolve_defval(
+ #me{oid = SubIndex,
+ aliasname = NameOfCol,
+ asn1_type = ASN1type,
+ entrytype = table_column,
+ access = NewAccess,
+ description = Description,
+ units = Units, %% Propably not usefull
+ assocList = [{table_name,TableName} | Defval]}),
+ define_cols(Rest,SubIndex+1,Fields,NameOfEntry,TableName,
+ [ColumnME|ColMEs]);
+
+%% A "hole" (non-consecutive columns) in the table.
+%% Implemented as a not-accessible column so Col always is index in
+%% row tuple.
+define_cols([{#mc_object_type{name = NameOfCol,
+ syntax = Type1,
+ max_access = Access,
+ kind = Kind,
+ status = Status,
+ name_assign = {NameOfEntry,[SubIndex]}},
+ Oline}|Rest],
+ ExpectedSubIndex, Fields, NameOfEntry, TableName, ColMEs)
+ when SubIndex > ExpectedSubIndex ->
+ ?vlog("defcols -> object_type (non consecutive cols):"
+ "~n NameOfCol: ~p"
+ "~n Type1: ~p"
+ "~n Access: ~p"
+ "~n Status ~p"
+ "~n NameOfEntry ~p"
+ "~n Oline: ~p",
+ [NameOfCol, Type1, Access, Status, NameOfEntry, Oline]),
+ update_status(NameOfCol, Status),
+ Int = {{type, 'INTEGER'},Oline},
+ GeneratedColumn =
+ %% be sure to use an invalid column name here!
+ {#mc_object_type{name = '$no_name$',
+ syntax = Int,
+ max_access = 'not-accessible',
+ kind = {variable, [{defval,0}]},
+ status = current,
+ description = undefined,
+ name_assign = {NameOfEntry, [ExpectedSubIndex]}},
+ Oline},
+ define_cols([GeneratedColumn,
+ {#mc_object_type{name = NameOfCol,
+ syntax = Type1,
+ max_access = Access,
+ kind = Kind,
+ status = Status,
+ description = undefined,
+ name_assign = {NameOfEntry,[SubIndex]}},
+ Oline}|Rest], ExpectedSubIndex,
+ [{'$no_name$', Int}|Fields], NameOfEntry, TableName,ColMEs) ;
+
+%% Ok. done. All fields are eaten.
+define_cols(Rest, _SubIndex, [], _NameOfEntry, _TableName, ColMEs) ->
+ {ColMEs, Rest};
+
+
+%% Error Handling
+
+%% The name of the field and object is the same
+define_cols([{#mc_object_type{name = NameOfCol,
+ kind = Kind,
+ name_assign = SubIndex}, Oline}|Rest],
+ SubIndex2, [{NameOfCol, _Type2}|Fields],
+ NameOfEntry, TableName, ColMEs) ->
+ ?vlog("defcols -> object_type (name of field and object is the same):"
+ "~n NameOfCol: ~p"
+ "~n Kind: ~p"
+ "~n SubIndex: ~p"
+ "~n Oline: ~p"
+ "~n SubIndex2: ~p"
+ "~n NameOfEntry ~p"
+ "~n TableName ~p",
+ [NameOfCol,Kind,SubIndex,Oline,SubIndex2,NameOfEntry,TableName]),
+ SIok = case SubIndex of
+ {Parent,[_SI]} when Parent =/= NameOfEntry ->
+ snmpc_lib:print_error(
+ "Invalid parent ~p for table column ~p (should be ~p).",
+ [Parent,NameOfCol,NameOfEntry],Oline),
+ error;
+ {NameOfEntry,[SubIndex2]} ->
+ ok;
+ {NameOfEntry,[SI]} ->
+ snmpc_lib:print_error(
+ "Invalid column number ~p for column ~p.",
+ [SI, NameOfCol], Oline),
+ error;
+ _Q ->
+ snmpc_lib:print_error(
+ "Invalid parent for column ~p.",[NameOfCol],Oline),
+ error
+ end,
+ Kok = case Kind of
+ {variable,_} ->
+ ok;
+ _Q2 ->
+ snmpc_lib:print_error(
+ "Expected a table column.",[],Oline),
+ error
+ end,
+ case {SIok, Kok} of
+ {ok, ok} ->
+ snmpc_lib:print_error("Invalid table column definition for"
+ " ~p.",[NameOfCol],Oline);
+ _Q4 ->
+ done % already reported
+ end,
+ define_cols(Rest,SubIndex2+1,Fields,NameOfEntry,TableName,ColMEs);
+
+%% It's an object-type but everything else is wrong
+define_cols([{#mc_object_type{name = NameOfCol},Oline}|Rest],SubIndex2,Fields,
+ NameOfEntry,TableName,ColMEs) ->
+ snmpc_lib:print_error(
+ "Number of columns differs from SEQUENCE definition (object:~p).",
+ [NameOfCol],Oline),
+ define_cols(Rest,SubIndex2+1,Fields,NameOfEntry,TableName,ColMEs);
+
+define_cols([{Obj,Line}|Tl], _SubIndex,_,_,_,ColMEs) ->
+ snmpc_lib:print_error("Corrupt table definition.",[],Line),
+ {ColMEs,[{Obj,Line}|Tl]};
+define_cols(Rest, _SubIndex,_,_,_,ColMEs) ->
+ snmpc_lib:print_error("Corrupt table definition.",[]),
+ {ColMEs,Rest}.
+
+ensure_macro_imported(dummy, _Line) -> ok;
+ensure_macro_imported(Macro, Line) ->
+ Macros = (get(cdata))#cdata.imported_macros,
+ case lists:member(Macro, Macros) of
+ true -> ok;
+ false ->
+ snmpc_lib:print_error("Macro ~p not imported.", [Macro],
+ Line)
+ end.
+
+test_table(NameOfTable, Taccess, Kind, _Tindex, Tline) ->
+ if
+ Taccess =/= 'not-accessible' ->
+ snmpc_lib:print_error(
+ "Table ~w must have STATUS not-accessible",
+ [NameOfTable],Tline),
+ error;
+ Kind =/= {variable,[]} ->
+ snmpc_lib:print_error(
+ "Bad table definition (~w).",
+ [NameOfTable],Tline),
+ error;
+ true ->
+ ok
+ end.
+
+save(Filename, MibName, Options) ->
+ R = filename:rootname(Filename),
+ File1 = filename:basename(R),
+ File3 = snmpc_misc:to_upper(File1),
+ case snmpc_misc:to_upper(atom_to_list(MibName)) of
+ File3 ->
+ {value, OutDirr} = snmpc_misc:assq(outdir, Options),
+ OutDir = snmpc_misc:ensure_trailing_dir_delimiter(OutDirr),
+ File2 = (OutDir ++ File1) ++ ".bin",
+ {ok, MIB} = snmpc_lib:get_final_mib(File1, Options),
+ case get(errors) of
+ undefined ->
+ case file:write_file(File2, term_to_binary(MIB)) of
+ ok ->
+ {ok, File2};
+ _Err ->
+ snmpc_lib:error(
+ "Couldn't write file \"~s\".",[File2])
+ end;
+ E ->
+ ?vlog("save failed: "
+ "~n ~p", [E]),
+ {'EXIT',error}
+ end;
+ MibNameL ->
+ snmpc_lib:error("Mibname (~s) differs from filename (~s).",
+ [MibNameL, File1])
+ end.
+
+%% parse takes a text file as a input and the output is a list of tokens.
+%% Input: FileName (file of mibs)
+%% Output: {ok, Mib} where MIB is a tuple of Tokens.
+%% {error, {LineNbr, Mod, Msg} an error on line number LineNb.
+
+
+parse(FileName) ->
+ case snmpc_tok:start_link(reserved_words(),
+ [{file, FileName ++ ".mib"},
+ {forget_stringdata, true}]) of
+ {error,ReasonStr} ->
+ snmpc_lib:error(lists:flatten(ReasonStr),[]);
+ {ok, TokPid} ->
+ Toks = snmpc_tok:get_all_tokens(TokPid),
+ set_version(Toks),
+ %% io:format("parse -> lexical analysis: ~n~p~n", [Toks]),
+ %% t("parse -> lexical analysis: ~n~p", [Toks]),
+ CDataArg =
+ case lists:keysearch(module, 1, get(options)) of
+ {value, {module, M}} -> {module, M};
+ _ -> {file, FileName ++ ".funcs"}
+ end,
+ put(cdata,snmpc_lib:make_cdata(CDataArg)),
+ snmpc_tok:stop(TokPid),
+ Res = if
+ is_list(Toks) ->
+ snmpc_mib_gram:parse(Toks);
+ true ->
+ Toks
+ end,
+ %% t("parse -> parsed: ~n~p", [Res]),
+ case Res of
+ {ok, PData} ->
+ {ok, PData};
+ {error, {LineNbr, Mod, Msg}} ->
+ case catch format_yecc_error(LineNbr, Msg) of
+ {Line, Format, Data} ->
+ snmpc_lib:error(Format,Data,Line);
+ _Q -> % sorry, have to use ugly yecc printouts
+ Str = apply(Mod, format_error, [Msg]),
+ snmpc_lib:error("~s",[Str],LineNbr)
+ end
+ end
+ end.
+
+set_version(Toks) when is_list(Toks) ->
+%% MODULE-IDENTITY _must_ be invoked in SNMPv2 according to RFC1908
+ case lists:keymember('MODULE-IDENTITY',1,Toks) of
+ true ->
+ put(snmp_version,2);
+ false ->
+ put(snmp_version,1)
+ end;
+set_version(_) ->
+ put(snmp_version,1).
+
+
+%% YeccGeneratedFile:format_error/1 is bad.
+format_yecc_error(Line, [ErrMsg, [${,Category, $,, _LineStr,$,, Value, $}]]) ->
+ {Line, "~s \"~s\" (~s).", [ErrMsg, Value, Category]}.
+
+%% The same as the (quoted) Terminals in the snmpc_mib_gram.yrl
+reserved_words() ->
+ [
+ 'ACCESS',
+ 'BEGIN',
+ 'BIT',
+ 'CONTACT-INFO',
+ 'Counter',
+ 'DEFINITIONS',
+ 'DEFVAL',
+ 'DESCRIPTION',
+ 'DISPLAY-HINT',
+ 'END',
+ 'ENTERPRISE',
+ 'FROM',
+ 'Gauge',
+ 'IDENTIFIER',
+ 'IDENTIFIER',
+ 'IMPORTS',
+ 'INDEX',
+ 'INTEGER',
+ 'IpAddress',
+ 'LAST-UPDATED',
+ 'NetworkAddress',
+ 'OBJECT',
+ 'OBJECT',
+ 'OBJECT-TYPE',
+ 'OCTET',
+ 'OF',
+ 'Opaque',
+ 'REFERENCE',
+ 'SEQUENCE',
+ 'SIZE',
+ 'STATUS',
+ 'STRING',
+ 'SYNTAX',
+ 'TRAP-TYPE',
+ 'TimeTicks',
+ 'VARIABLES',
+
+ %% v2
+ 'LAST-UPDATED',
+ 'ORGANIZATION',
+ 'CONTACT-INFO',
+ 'MODULE-IDENTITY',
+ 'NOTIFICATION-TYPE',
+ 'MODULE-COMPLIANCE',
+ 'OBJECT-GROUP',
+ 'NOTIFICATION-GROUP',
+ 'REVISION',
+ 'OBJECT-IDENTITY',
+ 'MAX-ACCESS',
+ 'UNITS',
+ 'AUGMENTS',
+ 'IMPLIED',
+ 'OBJECTS',
+ 'TEXTUAL-CONVENTION',
+ 'OBJECT-GROUP',
+ 'NOTIFICATION-GROUP',
+ 'NOTIFICATIONS',
+ 'MODULE-COMPLIANCE',
+ 'MODULE',
+ 'MANDATORY-GROUPS',
+ 'GROUP',
+ 'WRITE-SYNTAX',
+ 'MIN-ACCESS',
+ 'BITS'
+ ]
+.
diff --git a/lib/snmp/src/compile/snmpc.hrl b/lib/snmp/src/compile/snmpc.hrl
new file mode 100644
index 0000000000..eb896cde6b
--- /dev/null
+++ b/lib/snmp/src/compile/snmpc.hrl
@@ -0,0 +1,153 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1997-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%
+%%
+
+%% Parser output
+-record(pdata, {mib_version,
+ mib_name,
+ imports,
+ defs}).
+
+%% compilation information record
+-record(cdata, {module_identity,
+ asn1_types = [],
+ mes = [],
+ traps = [],
+ mibfuncs,
+ sequences = [],
+ imported_macros = [],
+ objectgroups = [],
+ notificationgroups = [],
+ imports,
+ oid_ets,
+ status_ets}).
+
+
+-record(mc_module_identity,
+ {name,
+ last_updated,
+ organization,
+ contact_info,
+ description,
+ revisions = [], %% A list of mc_revision
+ name_assign
+ }
+ ).
+
+-record(mc_revision,
+ {revision,
+ description
+ }
+ ).
+
+-record(mc_object_type,
+ {name,
+ syntax,
+ units,
+ max_access,
+ status,
+ description,
+ reference,
+ kind,
+ name_assign
+ }
+ ).
+
+
+-record(mc_new_type,
+ {name,
+ macro,
+ status,
+ description,
+ reference,
+ display_hint,
+ syntax
+ }
+ ).
+
+
+-record(mc_trap,
+ {name,
+ enterprise,
+ vars,
+ description,
+ reference,
+ num
+ }
+ ).
+
+
+-record(mc_notification,
+ {name,
+ vars,
+ status,
+ description,
+ reference,
+ name_assign
+ }
+ ).
+
+
+-record(mc_module_compliance,
+ {name,
+ status,
+ description,
+ reference,
+ module,
+ name_assign
+ }
+ ).
+
+
+-record(mc_object_group,
+ {name,
+ objects,
+ status,
+ description,
+ reference,
+ name_assign
+ }
+ ).
+
+
+-record(mc_notification_group,
+ {name,
+ objects,
+ status,
+ description,
+ reference,
+ name_assign
+ }
+ ).
+
+
+-record(mc_sequence,
+ {name,
+ fields
+ }
+ ).
+
+
+-record(mc_internal,
+ {name,
+ macro,
+ parent,
+ sub_index
+ }
+ ).
+
diff --git a/lib/snmp/src/compile/snmpc_lib.erl b/lib/snmp/src/compile/snmpc_lib.erl
new file mode 100644
index 0000000000..b7e84e7d6b
--- /dev/null
+++ b/lib/snmp/src/compile/snmpc_lib.erl
@@ -0,0 +1,1819 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1997-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%
+%%
+
+-module(snmpc_lib).
+
+%% API
+-export([test_father/4, make_ASN1type/1, import/1, makeInternalNode2/2,
+ is_consistent/1, resolve_defval/1, make_variable_info/1,
+ check_trap_name/3, make_table_info/4, get_final_mib/2, set_dir/2,
+ look_at/1, add_cdata/2,
+ check_object_group/4, check_notification_group/4,
+ check_notification/3,
+ register_oid/4,
+ error/2, error/3,
+ %% warning/2, warning/3,
+ print_error/2, print_error/3,
+ make_cdata/1,
+ key1search/2, key1search/3]).
+
+%% internal exports
+-export([check_of/1, check_trap/2, check_trap/3, get_elem/2]).
+
+%% debug exports
+-export([vvalidate/1, vprint/6]).
+
+
+-include("snmp_types.hrl").
+-include("snmpc.hrl").
+-include("snmpc_lib.hrl").
+
+
+%%----------------------------------------------------------------------------
+%% Some basic types
+%%----------------------------------------------------------------------------
+
+-type severity() :: 'silence' | 'warning' | 'info' | 'log' | 'debug' | 'trace'.
+
+
+test_father(FatherName, NewVarName, SubIndex, Line) ->
+ CDATA = get(cdata),
+ case lists:keysearch(FatherName, #me.aliasname, CDATA#cdata.mes) of
+ {value, #me{entrytype = table, aliasname = TableName}} ->
+ print_error("Variable '~w' (sub-index '~w') cannot "
+ "be defined under table '~w'.",
+ [NewVarName, SubIndex, TableName],Line);
+ {value, #me{entrytype = table_entry, aliasname = TableName}} ->
+ print_error("Variable '~w' (sub-index '~w') cannot "
+ "be defined under table entry '~w'.",
+ [NewVarName, SubIndex, TableName], Line);
+
+ _X -> %% internal or variable
+ case lists:last(SubIndex) of
+ 0 ->
+ print_error("'~w'. A zero-valued final subidentifier is reserved for future use. (RFC1902, 7.10)",[NewVarName],Line);
+ _ -> ok
+ end
+ end.
+
+make_ASN1type({{type,Type},Line}) ->
+ case lookup_vartype(Type) of
+ {value, ASN1type} ->
+ ASN1type;
+ false ->
+ print_error("Undefined type '~w'",[Type],Line),
+ guess_integer_type()
+ end;
+make_ASN1type({{type_with_size,Type,{range,Lo,Hi}},Line}) ->
+ case lookup_vartype(Type) of
+ {value,ASN1type} ->
+ case allow_size_rfc1902(BaseType = ASN1type#asn1_type.bertype) of
+ true ->
+ ok;
+ false ->
+ print_error(
+ "Size refinement is not allowed for subclass from ~w.",
+ [BaseType],Line)
+ end,
+ ASN1type#asn1_type{lo = Lo, hi = Hi};
+ false ->
+ print_error("Undefined type '~w'",[Type],Line),
+ guess_string_type()
+ end;
+make_ASN1type({{integer_with_enum,Type,Enums},Line}) ->
+ case lookup_vartype(Type) of
+ {value,ASN1type} -> ASN1type#asn1_type{assocList = [{enums, Enums}]};
+ false ->
+ print_error("Undefined type '~w'",[Type],Line),
+ guess_integer_type()
+ end;
+make_ASN1type({{bits,Kibbles},Line}) ->
+ case get(snmp_version) of
+ 2 ->
+ {value,Bits} = lookup_vartype('BITS'),
+ Kibbles2 = test_kibbles(Kibbles, Line),
+ Bits#asn1_type{assocList = [{kibbles, Kibbles2}]};
+ _ ->
+ guess_integer_type()
+ end;
+make_ASN1type({{sequence_of, _Type},Line}) ->
+ print_error("Use of SEQUENCE OF in non-table context.",[],Line),
+ guess_integer_type().
+
+test_kibbles([], Line) ->
+ print_error("No kibbles found.",[],Line),
+ [];
+test_kibbles(Kibbles,Line) ->
+ test_kibbles2(R = lists:keysort(2,Kibbles),0,Line),
+ R.
+
+test_kibbles2([],_,_) ->
+ ok;
+test_kibbles2([{_KibbleName,BitNo}|Ks],BitNo,Line) ->
+ test_kibbles2(Ks,BitNo+1,Line);
+test_kibbles2([{_KibbleName,BitNo}|_Ks],ExpectBitNo,Line) ->
+ print_error("Expected kibble no ~p but got ~p.",[ExpectBitNo,BitNo],Line).
+
+
+allow_size_rfc1902('INTEGER') -> true;
+allow_size_rfc1902('Integer32') -> true;
+allow_size_rfc1902('Unsigned32') -> true;
+allow_size_rfc1902('OCTET STRING') -> true;
+allow_size_rfc1902('Gauge32') -> true;
+allow_size_rfc1902(_) -> false.
+
+guess_integer_type() ->
+ {value,ASN1int} = lookup_vartype('INTEGER'),
+ ASN1int.
+
+guess_string_type() ->
+ {value,ASN1str} = lookup_vartype('OCTET STRING'),
+ ASN1str.
+
+lookup_vartype(Type) ->
+ CDATA = get(cdata),
+ lists:keysearch(Type, #asn1_type.aliasname, CDATA#cdata.asn1_types).
+
+
+
+
+%%--------------------------------------------------
+%% Reads the oid-function files.
+%% Out: A list of {oid, entry}.
+%% oid is here either a Oid with integers, or
+%% with symbolic names.
+%% entry is {M,F,A}.
+%%--------------------------------------------------
+read_funcs(FileName) ->
+ case snmpc_misc:read_noexit(FileName, fun check_of/1) of
+ {ok, Res} -> Res;
+ {error, LineNo, Reason} ->
+ print_error("~p: ~w: Syntax error: ~p",
+ [FileName, LineNo, Reason]),
+ [];
+ {error, open_file} -> []
+ end.
+
+check_of({module, M}) when is_atom(M) ->
+ {ok, {module, M}};
+check_of({Oid, {M, F, A}}) when is_atom(M) andalso is_atom(F) andalso is_list(A) ->
+ {ok, {Oid, {M, F, A}}};
+check_of({_Oid, {M, F, A}}) ->
+ {invalid_argument, {M, F, A}};
+check_of(X) ->
+ {invalid_func, X}.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Section for IMPORT implementation
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+import(ImportList) ->
+ %% Register some well known top-nodes (directly under the root)
+ WellKnownNodes = [ makeInternalNode(ccitt, [0]),
+ makeInternalNode(iso, [1]),
+ makeInternalNode('joint-iso-ccitt', [2]) ],
+ lists:foreach(
+ fun(#me{aliasname = AliasName, oid = Oid}) ->
+ register_oid(undef, AliasName, root, Oid)
+ end,
+ WellKnownNodes),
+ lists:foreach(fun import_mib/1, ImportList).
+
+
+%%----------------------------------------------------------------------
+%% Returns: <nothing> only side effect stuff.
+%%----------------------------------------------------------------------
+import_mib({{'SNMPv2-SMI', ImportsFromMib},Line}) ->
+ Nodes = [makeInternalNode(internet, [1,3,6,1]),
+ makeInternalNode(directory, [1,3,6,1,1]),
+ makeInternalNode(mgmt, [1,3,6,1,2]),
+ makeInternalNode('mib-2', [1,3,6,1,2,1]),
+ makeInternalNode(transmission, [1,3,6,1,2,1,10]),
+ makeInternalNode(experimental, [1,3,6,1,3]),
+ makeInternalNode(private, [1,3,6,1,4]),
+ makeInternalNode(enterprises, [1,3,6,1,4,1]),
+ makeInternalNode(zeroDotZero, [0,0]),
+ makeInternalNode(security, [1,3,6,1,5]),
+ makeInternalNode(snmpV2, [1,3,6,1,6]),
+ makeInternalNode(snmpDomains, [1,3,6,1,6,1]),
+ makeInternalNode(snmpProxys, [1,3,6,1,6,2]),
+ makeInternalNode(snmpModules, [1,3,6,1,6,3])],
+ Types = [#asn1_type{bertype = 'Integer32',
+ aliasname = 'Integer32',
+ lo = -2147483648, hi = 2147483647},
+ #asn1_type{bertype = 'IpAddress',
+ aliasname = 'IpAddress',
+ lo = 4, hi = 4},
+ #asn1_type{bertype = 'Counter32',
+ aliasname = 'Counter32',
+ lo = 0, hi = 4294967295},
+ #asn1_type{bertype = 'Gauge32',
+ aliasname = 'Gauge32',
+ lo = 0, hi = 4294967295},
+ #asn1_type{bertype = 'Unsigned32',
+ aliasname = 'Unsigned32',
+ lo = 0, hi = 4294967295},
+ #asn1_type{bertype = 'TimeTicks',
+ aliasname = 'TimeTicks',
+ lo = 0, hi=4294967295},
+ #asn1_type{bertype = 'Opaque',
+ aliasname = 'Opaque'},
+ #asn1_type{bertype = 'Counter64',
+ aliasname = 'Counter64',
+ lo = 0, hi = 18446744073709551615}],
+ Macros = ['MODULE-IDENTITY','OBJECT-IDENTITY','OBJECT-TYPE',
+ 'NOTIFICATION-TYPE'],
+ import_built_in_loop(ImportsFromMib,Nodes,Types,Macros,'SNMPv2-SMI',Line);
+import_mib({{'RFC-1215', ImportsFromMib},Line}) ->
+ Macros = ['TRAP-TYPE'],
+ import_built_in_loop(ImportsFromMib, [],[],Macros,'RFC-1215', Line);
+import_mib({{'RFC-1212', ImportsFromMib},Line}) ->
+ Macros = ['OBJECT-TYPE'],
+ import_built_in_loop(ImportsFromMib, [],[],Macros,'RFC-1212', Line);
+import_mib({{'SNMPv2-TC', ImportsFromMib},Line}) ->
+ Nodes = [],
+ Types = [#asn1_type{aliasname = 'DisplayString',
+ bertype = 'OCTET STRING',
+ lo = 0, hi = 255},
+ #asn1_type{aliasname = 'PhysAddress',
+ bertype = 'OCTET STRING'},
+ #asn1_type{aliasname = 'MacAddress',
+ bertype = 'OCTET STRING',
+ lo = 6, hi = 6},
+ #asn1_type{aliasname = 'TruthValue',
+ bertype = 'INTEGER',
+ assocList = [{enums,[{false,2},{true,1}]}]},
+ #asn1_type{aliasname = 'TestAndIncr',
+ bertype = 'INTEGER',
+ lo = 0, hi = 2147483647},
+ #asn1_type{aliasname = 'AutonomousType',
+ bertype = 'OBJECT IDENTIFIER'},
+ #asn1_type{aliasname = 'InstancePointer',
+ bertype = 'OBJECT IDENTIFIER'},
+ #asn1_type{aliasname = 'VariablePointer',
+ bertype = 'OBJECT IDENTIFIER'},
+ #asn1_type{aliasname = 'RowPointer',
+ bertype = 'OBJECT IDENTIFIER'},
+ #asn1_type{aliasname = 'RowStatus',
+ bertype = 'INTEGER',
+ assocList = [{enums,[{destroy, 6},
+ {createAndWait, 5},
+ {createAndGo, 4},
+ {notReady, 3},
+ {notInService, 2},
+ {active, 1}]}]},
+ #asn1_type{aliasname = 'TimeStamp',
+ bertype = 'TimeTicks'},
+ #asn1_type{aliasname = 'TimeInterval',
+ bertype = 'INTEGER',
+ lo = 0, hi = 2147483647},
+ #asn1_type{aliasname = 'DateAndTime',
+ bertype = 'OCTET STRING',
+ lo = 8, hi = 11}, %% Actually 8 | 11
+ #asn1_type{aliasname = 'StorageType',
+ bertype = 'INTEGER',
+ assocList = [{enums,[{readOnly, 5},
+ {permanent, 4},
+ {nonVolatile, 3},
+ {volatile, 2},
+ {other, 1}]}]},
+ #asn1_type{aliasname = 'TDomain',
+ bertype = 'OBJECT IDENTIFIER'},
+ #asn1_type{aliasname = 'TAddress',
+ bertype = 'OCTET STRING',
+ lo = 1, hi = 255}
+ ],
+ Macros = ['TEXTUAL-CONVENTION'],
+ import_built_in_loop(ImportsFromMib,Nodes,Types,Macros,'SNMPv2-TC',Line);
+import_mib({{'SNMPv2-CONF', ImportsFromMib},Line}) ->
+ Macros = ['OBJECT-GROUP','NOTIFICATION-GROUP','MODULE-COMPLIANCE'],
+ import_built_in_loop(ImportsFromMib,[],[],Macros,'SNMPv2-CONF',Line);
+import_mib({{'RFC1155-SMI', ImportsFromMib},Line}) ->
+ Nodes = [makeInternalNode(internet, [1,3,6,1]),
+ makeInternalNode(directory, [1,3,6,1,1]),
+ makeInternalNode(mgmt, [1,3,6,1,2]),
+ makeInternalNode(experimental, [1,3,6,1,3]),
+ makeInternalNode(private, [1,3,6,1,4]),
+ makeInternalNode(enterprises, [1,3,6,1,4,1])],
+ Types = [#asn1_type{bertype = 'NetworkAddress',
+ aliasname = 'NetworkAddress', lo = 4, hi = 4},
+ #asn1_type{bertype='Counter',aliasname='Counter',
+ lo=0,hi=4294967295},
+ #asn1_type{bertype='Gauge',aliasname='Gauge',
+ lo = 0, hi = 4294967295},
+ #asn1_type{bertype='IpAddress',aliasname='IpAddress',lo=4,hi=4},
+ #asn1_type{bertype = 'TimeTicks', aliasname = 'TimeTicks',
+ lo = 0, hi=4294967295},
+ #asn1_type{bertype = 'Opaque', aliasname = 'Opaque'}],
+ Macros = ['OBJECT-TYPE'],
+ import_built_in_loop(ImportsFromMib,Nodes,Types,Macros,'RFC1155-SMI',Line);
+import_mib({{MibName, ImportsFromMib},Line}) ->
+ import_from_file({{MibName, ImportsFromMib},Line}).
+
+import_built_in_loop(Objs, Nodes, Types, Macros, MibName, Line) ->
+ lists:foreach(fun (Obj) ->
+ import_built_in(Obj,Nodes,Types,Macros,MibName,Line)
+ end, Objs).
+
+import_from_file({{_MibName, []}, _Line}) ->
+ done;
+import_from_file({{MibName, ImportsFromMib},Line}) ->
+ Filename = atom_to_list(MibName) ++ ".bin",
+ {value, Path} = snmpc_misc:assq(i, get(options)),
+ {value, LibPath} = snmpc_misc:assq(il,get(options)),
+ LibPath2 = include_lib(LibPath),
+ Path2 = Path++LibPath2++[filename:join(code:priv_dir(snmp),"mibs"),
+ "./"],
+ ImportedMib = case read_mib(Line,Filename, Path2) of
+ error ->
+ error("Could not import ~p from mib ~s. "
+ "File not found. "
+ "Check that the MIB to be IMPORTED "
+ "is compiled and present in the import path.",
+ [ImportsFromMib, Filename], Line);
+ Mib ->
+ Mib
+ end,
+ lists:foreach(fun (ImpObj) -> import(ImpObj,ImportedMib) end,
+ ImportsFromMib).
+
+import_built_in({_tag,Obj}, Nodes, Types, Macros, MibName, Line) ->
+ case lookup(Obj, Nodes) of
+ {value, ME} ->
+ register_oid(undef, ME#me.aliasname, root, ME#me.oid),
+ add_cdata(#cdata.mes, [ME#me{imported = true, oid = undefined}]);
+ false ->
+ case lists:keysearch(Obj, #asn1_type.aliasname, Types) of
+ {value, ASN1Type} ->
+ add_cdata(#cdata.asn1_types,
+ [ASN1Type#asn1_type{imported=true}]);
+ false ->
+ case lists:member(Obj, Macros) of
+ true ->
+ add_cdata(#cdata.imported_macros,[Obj]);
+ false ->
+ print_error("Cannot find '~w' in mib '~s'.",
+ [Obj, MibName], Line)
+ end
+ end
+ end.
+
+include_lib([]) -> [];
+include_lib([Dir|Dirs]) ->
+ [Appl|Path] = filename:split(Dir),
+ case code:lib_dir(list_to_atom(Appl)) of
+ {error, _Reason} ->
+ include_lib(Dirs);
+ DirPath ->
+ [filename:join(DirPath,filename:join(Path))|include_lib(Dirs)]
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Returns: #mib
+%%----------------------------------------------------------------------
+read_mib(_Line, _Filename, []) ->
+ error;
+read_mib(Line, Filename, [Dir|Path]) ->
+ Dir2 = snmpc_misc:ensure_trailing_dir_delimiter(Dir),
+ case snmpc_misc:read_mib(AbsFile=lists:append(Dir2, Filename)) of
+ {ok, MIB} -> MIB;
+ {error, enoent} ->
+ read_mib(Line, Filename, Path);
+ {error, Reason} ->
+ ?vwarning("~s found but not imported: "
+ "~n Reason: ~p", [AbsFile,Reason]),
+ read_mib(Line, Filename, Path)
+ end.
+
+
+%%----------------------------------------------------------------------
+%% imports ME or Type from other Mib into current compilation data.
+%%----------------------------------------------------------------------
+import({node, NodeName}, #mib{mes = IMES, name = MibName}) ->
+ case lookup(NodeName, IMES) of
+ {value, ME} when ME#me.imported == false ->
+ register_oid(undef, ME#me.aliasname, root, ME#me.oid),
+ add_cdata(#cdata.mes, [ME#me{imported = true}]);
+ _ ->
+ print_error("Cannot find '~w' among the objects in the mib '~s'.",
+ [NodeName, MibName])
+ end;
+import({type, TypeName}, #mib{asn1_types = Types, name = MibName}) ->
+ case lists:keysearch(TypeName, #asn1_type.aliasname, Types) of
+ {value, ASN1Type} when is_record(ASN1Type, asn1_type) andalso
+ (ASN1Type#asn1_type.imported =:= false) ->
+ add_cdata(#cdata.asn1_types, [ASN1Type#asn1_type{imported=true,
+ aliasname=TypeName}]);
+ _X ->
+ print_error("Cannot find '~w' among the types in the mib '~s'.",
+ [TypeName, MibName])
+ end;
+import({builtin, Obj}, #mib{}) ->
+ print_error("~p should be imported from a standard mib.",[Obj]).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Section for initialisation
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Types defined in rfc1155 (SMI) are hard coded.
+init_types() ->
+ VerDep = case get(snmp_version) of
+ 1 -> [];
+ 2 ->
+ [#asn1_type{imported=true,bertype='BITS',aliasname='BITS'}]
+ end,
+ [#asn1_type{imported = true, bertype = 'INTEGER', aliasname = 'INTEGER'},
+ #asn1_type{imported=true,bertype='OCTET STRING',aliasname='OCTET STRING'},
+ #asn1_type{imported=true,bertype='BIT STRING',aliasname='BIT STRING'},
+ #asn1_type{imported = true, bertype = 'OBJECT IDENTIFIER',
+ aliasname = 'OBJECT IDENTIFIER'} | VerDep].
+
+makeInternalNode(Name, Oid) ->
+ makeInternalNode3(false, Name, Oid).
+
+makeInternalNode2(Imported, Name) ->
+ #me{imported = Imported, aliasname = Name, entrytype = internal}.
+
+makeInternalNode3(Imported, Name, Oid) ->
+ #me{imported = Imported, oid = Oid, aliasname = Name, entrytype = internal}.
+
+make_cdata(CDataArg) ->
+ MibFuncs =
+ case CDataArg of
+ {module, _Mod} -> [CDataArg];
+ {file, MibFuncsFile} -> read_funcs(MibFuncsFile)
+ end,
+ #cdata{mibfuncs = MibFuncs,
+ asn1_types = init_types(),
+ oid_ets = ets:new(oid_ets, [set, private]),
+ status_ets = ets:new(status_ets, [set, private])}.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Section for Intermib consistency checking
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+is_consistent(Filenames) ->
+ case catch check_all_consistency(Filenames) of
+ ok ->
+ ok;
+ {undef, Format, Data} ->
+ ok = io:format(Format, Data),
+ io:format("~n"),
+ {error, inconsistent}
+ end.
+
+check_all_consistency(Filenames) ->
+ MIBs = [load_mib(Filename) || Filename <- Filenames],
+ check_oid_conflicts(MIBs),
+ check_trap_conflicts(MIBs),
+ ok.
+
+check_oid_conflicts(MIBs) ->
+ MEs = lists:append( [get_elem(MIB, #mib.mes) || MIB <- MIBs] ),
+ SortedMEs = lists:keysort(#me.oid, MEs),
+ search_for_dublettes2(#me{aliasname=dummy_init}, SortedMEs).
+
+check_trap_conflicts(MIBs) ->
+ Traps = lists:append( [get_elem(MIB, #mib.traps) || MIB <- MIBs] ),
+ [check_trap(Trap, Traps) || Trap <- Traps].
+
+check_trap(Trap, Traps) ->
+ %% check_trap/3 -> error | ok
+ Checked = [check_trap(T, Trap, undef) || T <- lists:delete(Trap, Traps)],
+ case lists:member(error, Checked) of
+ true ->
+ throw({undef,"",[]});
+ false ->
+ ok
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Returns: {Oid, ASN1Type}
+%%----------------------------------------------------------------------
+trap_variable_info(Variable, Type, MEs) ->
+ case lookup(Variable, MEs) of
+ false ->
+ error("Error in ~s definition. Cannot find object '~w'.",
+ [Type, Variable]);
+ {value, ME} when ME#me.entrytype == variable ->
+ {{variable, ME#me.aliasname}, ME#me.asn1_type};
+ {value, ME} ->
+ {{column, ME#me.aliasname}, ME#me.asn1_type}
+ end.
+
+get_elem(MIB, Idx) ->
+ element(Idx, MIB).
+
+load_mib(Filename) ->
+ F1 = snmpc_misc:strip_extension_from_filename(Filename, ".mib"),
+ F2 = lists:append(F1, ".bin"),
+ case snmpc_misc:read_mib(F2) of
+ {error, Reason} ->
+ throw({undef, "Error reading file: ~w. Reason:~w", [F1, Reason]});
+ {ok, Mib} ->
+ Mib
+ end.
+
+search_for_dublettes2(_PrevME, []) -> ok;
+search_for_dublettes2(PrevME, [ME|MEs])
+ when ME#me.imported==true ->
+ search_for_dublettes2(PrevME, MEs);
+search_for_dublettes2(PrevME, [ME|MEs])
+ when PrevME#me.oid == ME#me.oid ->
+ if PrevME#me.entrytype == internal, ME#me.entrytype == internal,
+ PrevME#me.aliasname == ME#me.aliasname ->
+ search_for_dublettes2(ME, MEs);
+ true ->
+ throw({undef,"Multiple used object with OBJECT IDENTIFIER '~w'"
+ " Used by '~w' and '~w' ", [PrevME#me.oid,
+ PrevME#me.aliasname,
+ ME#me.aliasname]})
+ end;
+search_for_dublettes2(_PrevME, [ME|MEs]) ->
+ search_for_dublettes2(ME, MEs).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Section for handling of default value resolving
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+resolve_defval(ME) ->
+ case has_complex_defval(ME) of
+ true ->
+ CDATA = get(cdata),
+ resolve_complex_defval(ME, CDATA#cdata.mes);
+ false -> ME
+ end.
+
+has_complex_defval(#me{aliasname = N,
+ assocList = AssocList,
+ asn1_type = #asn1_type{bertype = BT}})
+ when is_list(AssocList) ->
+ case snmpc_misc:assq(defval, AssocList) of
+ {value, Int} when is_integer(Int) ->
+ false;
+ {value, Val} when is_atom(Val) andalso (BT =:= 'OBJECT IDENTIFIER') ->
+ false; % resolved in update_me_oids
+ {value, Val} when is_atom(Val) andalso (BT =:= 'INTEGER') ->
+ true;
+ {value, Bits} when is_list(Bits) andalso (BT =:= 'BITS') ->
+ true;
+ {value, Str} when is_list(Str) andalso (BT =:= 'OCTET STRING') ->
+ false; % but ok
+ {value, Str} when is_list(Str) andalso (BT =:= 'Opaque') ->
+ false; % but ok
+ {value, Str} when is_list(Str) andalso
+ (length(Str) =:= 4) andalso
+ (BT =:= 'IpAddress') ->
+ false; % but ok
+ {value, Shit} ->
+ print_error("Bad default value for ~p: ~p [~p]",[N,Shit,BT]),
+ false;
+ false -> %% no defval (or strings nyi)
+ false
+ end;
+has_complex_defval(_) -> false.
+
+resolve_complex_defval(ME, _AllMEs)
+ when (ME#me.asn1_type)#asn1_type.bertype == 'INTEGER' ->
+ #me{aliasname = MEName, assocList = AssocList} = ME,
+ {value, DefVal} = snmpc_misc:assq(defval, AssocList),
+ #asn1_type{bertype = TypeName,
+ assocList = AssocListForASN1Type} = ME#me.asn1_type,
+ case snmpc_misc:assq(enums, AssocListForASN1Type) of
+ false ->
+ print_error("Type '~w' has no defined enums. "
+ "Used in DEFVAL for '~w'.", [TypeName, MEName]),
+ ME;
+ {value, Enums} ->
+ case snmpc_misc:assq(DefVal, Enums) of
+ false ->
+ print_error("Enum '~w' not found. "
+ "Used in DEFVAL for '~w'.", [DefVal, MEName]),
+ ME;
+ {value, IntVal} when is_integer(IntVal) ->
+ ME#me{assocList = lists:keyreplace(defval, 1, AssocList,
+ {defval, IntVal})}
+ end
+ end;
+
+resolve_complex_defval(ME, _AllMEs)
+ when (ME#me.asn1_type)#asn1_type.bertype =:= 'BITS' ->
+ #me{aliasname = MEName, assocList = AssocList} = ME,
+ {value, DefVal} = snmpc_misc:assq(defval, AssocList),
+ #asn1_type{assocList = AssocListForASN1Type} = ME#me.asn1_type,
+ {value, Kibbles} = snmpc_misc:assq(kibbles, AssocListForASN1Type),
+ case snmpc_misc:bits_to_int(DefVal,Kibbles) of
+ error->
+ print_error("Invalid default value ~w for ~w.",[DefVal, MEName]),
+ ME;
+ IntVal when is_integer(IntVal) ->
+ ME#me{assocList = lists:keyreplace(defval, 1, AssocList,
+ {defval, IntVal})}
+ end.
+
+
+make_variable_info(#me{asn1_type = Asn1Type, assocList = Alist}) ->
+ Defval =
+ case snmpc_misc:assq(defval, Alist) of
+ {value, Val} ->
+ Val;
+ _ ->
+ get_def(Asn1Type)
+ end,
+ #variable_info{defval = Defval}.
+
+get_def(#asn1_type{bertype = BT, lo = LO, assocList = AL}) ->
+ ?vtrace("get_def -> entry with"
+ "~n BT: ~p"
+ "~n LO: ~p"
+ "~n AL: ~p", [BT, LO, AL]),
+ get_def(BT, LO, AL).
+
+get_def('INTEGER', Lo, _) when is_integer(Lo) -> Lo;
+get_def('INTEGER', _, AL) ->
+ case snmpc_misc:assq(enums, AL) of
+ {value, Enums} ->
+ case lists:keysort(2, Enums) of
+ [{_, Val}|_] ->
+ Val;
+ _ ->
+ 0
+ end;
+ _ ->
+ 0
+ end;
+get_def('Counter', _, _) -> 0;
+get_def('Gauge', _, _) -> 0;
+get_def('TimeTicks', _, _) -> 0;
+get_def('OCTET STRING', _, _) -> "";
+get_def('IpAddress', _, _) -> [0,0,0,0];
+get_def('NetworkAddress', _, _) -> [0,0,0,0];
+get_def('OBJECT IDENTIFIER', _, _) -> [0, 0];
+get_def('Opaque', _, _) -> "";
+%v2
+get_def('Integer32',Lo, _) when is_integer(Lo) -> Lo;
+get_def('Integer32',_, _) -> 0;
+get_def('Counter32',_, _) -> 0;
+get_def('Gauge32',_, _) -> 0;
+get_def('Unsigned32',_, _) -> 0;
+get_def('BITS',_, _) -> 0;
+get_def('Counter64',_, _) -> 0.
+
+check_trap_name(EnterpriseName, Line, MEs) ->
+ case lists:keysearch(EnterpriseName, #me.aliasname, MEs) of
+ false ->
+ error("Error in trap definition. Cannot find object '~w'.",
+ [EnterpriseName],Line);
+ {value, _} ->
+ true
+ end.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Section for table functions
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%%----------------------------------------------------------------------
+%% This information is needed to be able to create default instrumentation
+%% functions for tables.
+%%----------------------------------------------------------------------
+make_table_info(Line, _TableName, {augments,SrcTableEntry}, ColumnMEs) ->
+ ColMEs = lists:keysort(#me.oid, ColumnMEs),
+ %% Nbr_of_Cols = length(ColMEs),
+ MEs = ColMEs ++ (get(cdata))#cdata.mes,
+ Aug = case lookup(SrcTableEntry,MEs) of
+ false ->
+ print_error("Cannot AUGMENT the non-existing table entry ~p",
+ [SrcTableEntry],Line),
+ {augments, error};
+ {value,ME} ->
+ {augments, {SrcTableEntry,translate_type(ME#me.asn1_type)}}
+ end,
+ #table_info{index_types = Aug};
+make_table_info(Line, TableName, {indexes,[]}, _ColumnMEs) ->
+ print_error("Table ~w lacks indexes.", [TableName],Line),
+ #table_info{};
+make_table_info(Line, TableName, {indexes,Indexes}, ColumnMEs) ->
+ ColMEs = lists:keysort(#me.oid, ColumnMEs),
+ NonImpliedIndexes = lists:map(fun non_implied_name/1, Indexes),
+ test_read_create_access(ColMEs, Line, dummy),
+ NonIndexCol = test_index_positions(Line, NonImpliedIndexes, ColMEs),
+ Nbr_of_Cols = length(ColMEs),
+ ASN1Indexes = find_asn1_types_for_indexes(Indexes, ColMEs, Line),
+ FA = first_accessible(TableName, ColMEs),
+ StatCol = find_status_col(Line, TableName, ColMEs),
+ NoAccs = list_not_accessible(NonIndexCol,ColMEs),
+ case lists:member(StatCol,NoAccs) of
+ true ->
+ print_error("Status column cannot be not-accessible. In table ~p.",
+ [TableName],Line);
+ false -> ok
+ end,
+ #table_info{nbr_of_cols = Nbr_of_Cols,
+ first_own_index = find_first_own_index(NonImpliedIndexes,
+ ColMEs, 1),
+ status_col = StatCol,
+ first_accessible = FA,
+ not_accessible = NoAccs,
+ index_types = ASN1Indexes}.
+
+%% Perkins p110
+test_read_create_access([#me{aliasname = N, access = 'read-create'}|_ColMEs],
+ Line, 'read-write') ->
+ print_error("Column ~p cannot be read-create when another is read-write.",
+ [N], Line);
+test_read_create_access([#me{aliasname = N, access = 'read-write'}|_ColMEs],
+ Line, 'read-create') ->
+ print_error("Column ~p cannot be read-write when another is read-create.",
+ [N], Line);
+test_read_create_access([#me{access = 'read-write'}|ColMEs],
+ Line, _OtherStat) ->
+ test_read_create_access(ColMEs,Line,'read-write');
+test_read_create_access([#me{access = 'read-create'}|ColMEs],
+ Line, _OtherStat) ->
+ test_read_create_access(ColMEs,Line,'read-create');
+test_read_create_access([_ME|ColMEs],Line,OtherStat) ->
+ test_read_create_access(ColMEs,Line,OtherStat);
+test_read_create_access([], _Line, _) ->
+ ok.
+
+find_status_col(_Line, _TableName, []) ->
+ undefined;
+find_status_col(_Line, _TableName,
+ [#me{asn1_type=#asn1_type{aliasname='RowStatus'}}|_]) ->
+ 1;
+find_status_col(Line, TableName, [_ShitME | MEs]) ->
+ case find_status_col(Line, TableName, MEs) of
+ undefined -> undefined;
+ N -> 1+N
+ end.
+
+list_not_accessible(none,_) -> [];
+list_not_accessible(NonIndexCol, ColMEs) when is_integer(NonIndexCol) ->
+ list_not_accessible(lists:nthtail(NonIndexCol - 1,ColMEs)).
+
+list_not_accessible([#me{access='not-accessible', oid=Col}|ColMEs]) ->
+ [Col | list_not_accessible(ColMEs)];
+list_not_accessible([_ColME|ColMEs]) ->
+ list_not_accessible(ColMEs);
+list_not_accessible([]) ->
+ [].
+
+%%----------------------------------------------------------------------
+%% See definition of first_own_index in the table_info record definition.
+%%----------------------------------------------------------------------
+find_first_own_index([], _ColMEs, _FOI) -> 0;
+find_first_own_index([NameOfIndex | Indexes], ColMEs, FOI) ->
+ case lists:keysearch(NameOfIndex, #me.aliasname, ColMEs) of
+ {value, _ME} ->
+ FOI;
+ false ->
+ find_first_own_index(Indexes, ColMEs, FOI + 1)
+ end.
+
+first_accessible(TableName, []) ->
+ error("Table '~w' must have at least one accessible column.",[TableName]);
+first_accessible(TableName, [#me{access = 'not-accessible'} | T]) ->
+ first_accessible(TableName, T);
+first_accessible(_TableName, [#me{oid = Col} | _]) ->
+ Col.
+
+get_defvals(ColMEs) ->
+ lists:keysort(1,
+ lists:filter(fun drop_undefined/1,
+ lists:map(fun column_and_defval/1, ColMEs))).
+
+find_asn1_types_for_indexes(Indexes, ColMEs,Line) ->
+ MEs = ColMEs ++ (get(cdata))#cdata.mes,
+ test_implied(Indexes, Line),
+ lists:map(fun (ColumnName) ->
+ translate_type(get_asn1_type(ColumnName, MEs,Line))
+ end,
+ Indexes).
+
+test_implied([],_) -> ok;
+test_implied([{implied, _Type}, _OtherIndexElem|_], Line) ->
+ print_error("Implied must be last.", [], Line);
+test_implied([{implied, _Type}], _Line) ->
+ ok;
+test_implied([_H|T], Line) ->
+ test_implied(T, Line).
+
+drop_undefined({_X, undefined}) -> false;
+drop_undefined({_X, _Y}) -> true;
+drop_undefined(undefined) -> false;
+drop_undefined(_X) -> true.
+
+%% returns: {ColumnNo, Defval}
+column_and_defval(#me{oid = Oid, assocList = AssocList}) ->
+ ColumnNo = lists:last(Oid),
+ case snmpc_misc:assq(defval, AssocList) of
+ false -> {ColumnNo, undefined};
+ {value, DefVal} -> {ColumnNo, DefVal}
+ end.
+
+%% returns: an asn1_type if ColME is an indexfield, otherwise undefined.
+get_asn1_type({implied,ColumnName}, MEs, Line) ->
+ case lookup(ColumnName, MEs) of
+ {value,#me{asn1_type=A}} when A#asn1_type.bertype =:=
+ 'OCTET STRING' ->
+ A#asn1_type{implied = true};
+ {value,#me{asn1_type=A}} when A#asn1_type.bertype =:=
+ 'OBJECT IDENTIFIER' ->
+ A#asn1_type{implied = true};
+ Shit ->
+ print_error("Only OCTET STRINGs and OIDs can be IMPLIED.(~w)",
+ [Shit], Line)
+ end;
+get_asn1_type(ColumnName, MEs, Line) ->
+ case lookup(ColumnName, MEs) of
+ {value,ME} -> ME#me.asn1_type;
+ false -> error("Can't find object ~p. Used as INDEX in table.",
+ [ColumnName],Line)
+ end.
+
+test_index_positions(Line, Indexes, ColMEs) ->
+ TLI = lists:filter(fun (IndexName) ->
+ is_table_local_index(IndexName,ColMEs) end,
+ Indexes),
+ test_index_positions_impl(Line, TLI, ColMEs).
+
+%% Returns the first non-index column | none
+test_index_positions_impl(_Line, [], []) -> none;
+test_index_positions_impl(_Line, [], [#me{oid=Col}|_ColMEs]) ->
+ Col;
+test_index_positions_impl(Line, Indexes,
+ [#me{aliasname = Name,
+ asn1_type = Asn1} | ColMEs]) ->
+ case lists:member(Name, Indexes) of
+ true ->
+ if
+ Asn1#asn1_type.bertype =:= 'BITS' ->
+ print_error("Invalid data type 'BITS' for index '~w'.",
+ [Name],Line);
+ true -> true
+ end,
+ test_index_positions_impl(Line,
+ lists:delete(Name, Indexes), ColMEs);
+ false ->
+ ?vwarning2("Index columns must be first for "
+ "the default functions to work properly. "
+ "~w is no index column.", [Name], Line),
+ none
+ end.
+
+is_table_local_index(IndexName, ColMEs) ->
+ case lists:keysearch(IndexName, #me.aliasname, ColMEs) of
+ false -> false;
+ _Q -> true
+ end.
+
+non_implied_name({implied, IndexColumnName}) -> IndexColumnName;
+non_implied_name(IndexColumnName) -> IndexColumnName.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Section for generationg the final mib
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% returns: {ok,
+% {snmp_mib, MEs, traps, list of {TrapOid, list of oids (objects)}}}
+get_final_mib(Name, Options) ->
+ ?vdebug("get_final_mib -> entry", []),
+ CDATA = get(cdata),
+ #cdata{mes = MEs,
+ mibfuncs = MibFuncs,
+ asn1_types = Types,
+ traps = Traps0,
+ oid_ets = OidEts} = CDATA,
+
+ ?vdebug("get_final_mib -> resolve oids", []),
+ resolve_oids(OidEts),
+ %% Reverse so that we get report on objects earlier in the file
+ %% before later objects.
+ UMEs = update_me_oids(lists:reverse(MEs), OidEts, []),
+ ?vtrace("get_final_mib -> "
+ "~n UMEs: ~p", [UMEs]),
+
+ Traps1 = update_trap_objects(Traps0, MEs, []),
+ Traps2 = update_trap_oids(Traps1, OidEts, []),
+ ?vtrace("get_final_mib -> "
+ "~n Traps2: ~p", [Traps2]),
+
+ SortedMEs = lists:keysort(#me.oid,UMEs),
+ ?vdebug("get_final_mib -> search for dublettes", []),
+ search_for_dublettes(#me{aliasname=dummy_init}, SortedMEs),
+
+ ?vdebug("get_final_mib -> search for oid conflicts", []),
+ search_for_oid_conflicts(Traps2, SortedMEs),
+
+ ?vdebug("get_final_mib -> resolve oid", []),
+ %% FIXME: use list comprehension instead
+ MibFs = lists:keysort(1,
+ lists:zf(fun({module, _Mod}) -> false;
+ (MF) -> {true, resolve_oid(MF,SortedMEs)}
+ end, MibFuncs)),
+ ?vtrace("get_final_mib -> "
+ "~n MibFs: ~p", [MibFs]),
+ {value, DBName} = snmpc_misc:assq(db, Options),
+ Module = key1search(module, MibFuncs, undefined),
+ MEsWithMFA = insert_mfa(MibFs, SortedMEs, DBName, Module),
+ Misc = [{snmp_version,get(snmp_version)}
+ | case lists:member(no_symbolic_info,Options) of
+ true -> [no_symbolic_info];
+ false -> []
+ end],
+ {value, GroupBool} = snmpc_misc:assq(group_check, Options),
+ case GroupBool of
+ true ->
+ case get(snmp_version) =:= 2 of
+ true ->
+ ?vdebug("get_final_mib -> check object groups:"
+ "~n ~p", [CDATA#cdata.objectgroups]),
+ check_group(CDATA#cdata.mes,
+ CDATA#cdata.objectgroups),
+ ?vdebug("get_final_mib -> check notifications group:"
+ "~n ~p", [CDATA#cdata.notificationgroups]),
+ check_notification(Traps2,
+ CDATA#cdata.notificationgroups);
+ false ->
+ ok
+ end;
+ false ->
+ ok
+ end,
+ MI = module_identity(CDATA),
+ Mib = #mib{name = Name,
+ misc = Misc,
+ module_identity = MI,
+ mes = lists:map(fun(ME) -> translate_me_type(ME) end,
+ MEsWithMFA),
+ variable_infos = extract_variable_infos(MEsWithMFA),
+ table_infos = extract_table_infos(MEsWithMFA),
+ traps = lists:map(fun(T) -> translate_trap_type(T) end,
+ Traps2),
+ asn1_types = lists:map(fun(T) -> translate_type(T) end,
+ Types),
+ imports = CDATA#cdata.imports},
+ ?vdebug("get_final_mib -> done", []),
+ {ok, Mib}.
+
+
+module_identity(#cdata{module_identity = MI}) ->
+ case lists:member(module_identity, get(options)) of
+ true ->
+ MI;
+ false ->
+ undefined
+ end.
+
+
+update_trap_objects([], _MEs, Acc) ->
+ ?vtrace("update_trap_objects -> done", []),
+ lists:reverse(Acc);
+update_trap_objects([#trap{trapname = Name,
+ oidobjects = Variables} = Trap|Traps], MEs, Acc) ->
+ ?vtrace("update_trap_objects -> update objects for trap ~p:"
+ "~n ~p", [Name, Variables]),
+ OidObjects =
+ [trap_variable_info(Var, "trap", MEs) || Var <- Variables],
+ UpdTrap = Trap#trap{oidobjects = OidObjects},
+ update_trap_objects(Traps, MEs, [UpdTrap|Acc]);
+update_trap_objects([#notification{trapname = Name,
+ oidobjects = Variables} = Notif|Traps],
+ MEs, Acc) ->
+ ?vtrace("update_trap_objects -> update objects for notification ~p:"
+ "~n ~p", [Name, Variables]),
+ OidObjects =
+ [trap_variable_info(Var, "notification", MEs) || Var <- Variables],
+ UpdNotif = Notif#notification{oidobjects = OidObjects},
+ update_trap_objects(Traps, MEs, [UpdNotif|Acc]);
+update_trap_objects([_|Traps], MEs, Acc) ->
+ update_trap_objects(Traps, MEs, Acc).
+
+
+%% We don't want a zillion aliases for INTEGER (etc),
+%% and since they are encoded with the same tag we can treat them as
+%% equivalent.
+%% The reason for having them at compile time is for example that
+%% Unsigned32 is allowed as INDEX but not Gauge.
+%% The compiler might want to ensure this and more...
+translate_me_type(ME) ->
+ ME#me{asn1_type = translate_type(ME#me.asn1_type)}.
+
+translate_trap_type(Trap) when is_record(Trap, notification) ->
+ translate_trap_type_notif(Trap);
+translate_trap_type(Trap) when is_record(Trap, trap) ->
+ translate_trap_type_trap(Trap).
+
+translate_trap_type_notif(Trap)->
+ NewOidobjects =
+ lists:map(fun({Oid,ASN1type}) ->{Oid,translate_type(ASN1type)} end,
+ Trap#notification.oidobjects),
+ Trap#notification{oidobjects=NewOidobjects}.
+
+translate_trap_type_trap(Trap)->
+ NewOidobjects =
+ lists:map(fun({Oid,ASN1type}) ->
+ {Oid, translate_type(ASN1type)}
+ end,
+ Trap#trap.oidobjects),
+ Trap#trap{oidobjects = NewOidobjects}.
+
+translate_type(ASN1type) when ASN1type#asn1_type.bertype =:= 'NetworkAddress' ->
+ ASN1type#asn1_type{bertype = 'IpAddress'};
+translate_type(ASN1type) when ASN1type#asn1_type.bertype =:= 'Integer32' ->
+ ASN1type#asn1_type{bertype = 'INTEGER'};
+translate_type(ASN1type) when ASN1type#asn1_type.bertype =:= 'Counter' ->
+ ASN1type#asn1_type{bertype = 'Counter32'};
+translate_type(ASN1type) when ASN1type#asn1_type.bertype =:= 'Gauge' ->
+ ASN1type#asn1_type{bertype = 'Unsigned32'};
+translate_type(ASN1type) when ASN1type#asn1_type.bertype =:= 'Gauge32' ->
+ ASN1type#asn1_type{bertype = 'Unsigned32'};
+translate_type(ASN1type) -> ASN1type.
+
+%% Check for both NOTIFICATION-GROUP and OBJECT-GROUP
+
+check_notification_group(Name, GroupObjects, Line, Status) ->
+ #cdata{traps = Traps, status_ets = Ets} = get(cdata),
+ Objects = get_notification_names(Traps),
+ check_def(notification, Name, Line, Status, GroupObjects, Objects, Ets).
+
+get_notification_names(Traps) when is_list(Traps) ->
+ [Name || #notification{trapname = Name} <- Traps].
+
+check_object_group(Name, GroupObjects, Line, Status) ->
+ #cdata{mes = MEs, status_ets = Ets} = get(cdata),
+ Objects = get_object_names(MEs),
+ check_def(object, Name, Line, Status, GroupObjects, Objects, Ets).
+
+get_object_names([])->[];
+get_object_names([#me{access=A, entrytype=T, aliasname=N}|MEs])
+ when (A =/= 'not-accessible') andalso (T =/= 'internal') ->
+ [N|get_object_names(MEs)];
+get_object_names([_ME|Rest]) ->
+ get_object_names(Rest).
+
+%% Strictly we should not need to check more then the status
+%% table, but since error do happen...
+check_def(Type, Name, Line, Status, [GroupObject|GroupObjects], Objects, Ets) ->
+ ?vdebug2("check definition of ~p [~p]: presumed member of ~p [~p]",
+ [GroupObject, Type, Name, Status], Line),
+ case lists:member(GroupObject, Objects) of
+ true ->
+ ?vtrace("~p is a member of ~p", [GroupObject, Name]),
+ %% Lucky so far, now lets check that the status is valid
+ case ets:lookup(Ets, GroupObject) of
+ [{GroupObject, ObjectStatus}] ->
+ ?vtrace("check that the object status (~p) is valid",
+ [ObjectStatus]),
+ check_group_member_status(Name, Status,
+ GroupObject, ObjectStatus);
+ _ ->
+ print_error("group (~w) member ~w not found"
+ " in status table - status check failed",
+ [Name, GroupObject])
+ end;
+ false ->
+ %% Ok, this could be because the status is obsolete or
+ %% deprecated (with the deprecated flag = false)
+ ?vtrace("~p is not a member of ~p "
+ "[object status could be obsolete]",
+ [GroupObject, Name]),
+ case ets:lookup(Ets, GroupObject) of
+ [{GroupObject, ObjectStatus}] ->
+ ?vtrace("check that the object status (~p) is valid",
+ [ObjectStatus]),
+ check_group_member_status(Name, Status,
+ GroupObject, ObjectStatus);
+ _ ->
+ group_member_error(Type, GroupObject, Line)
+ end
+ end,
+ check_def(Type, Name, Line, Status, GroupObjects, Objects, Ets);
+check_def(_, _, _, _, [], _, _) ->
+ ok.
+
+group_member_error(object, Name, Line) ->
+ print_error("OBJECT-TYPE definition missing or "
+ "'not-accessible' for '~w'", [Name],Line);
+group_member_error(notification, Name, Line) ->
+ print_error("NOTIFICATION-TYPE definition missing for '~w'",
+ [Name], Line).
+
+
+check_group_member_status(_GroupName, _GroupStatus, _Member, undefined) ->
+ ok;
+check_group_member_status(_GroupName, current, _Member, current) ->
+ ok;
+check_group_member_status(GroupName, current, Member, MemberStatus) ->
+ group_member_status_error(GroupName, current, Member, MemberStatus,
+ "current");
+check_group_member_status(_GroupName, deprecated, _Member, MemberStatus)
+ when (MemberStatus =:= deprecated) orelse (MemberStatus =:= current) ->
+ ok;
+check_group_member_status(GroupName, deprecated, Member, MemberStatus) ->
+ group_member_status_error(GroupName, deprecated, Member, MemberStatus,
+ "deprecated or current");
+check_group_member_status(_GroupName, obsolete, _Member, MemberStatus)
+ when (MemberStatus =:= obsolete) orelse
+ (MemberStatus =:= deprecated) orelse
+ (MemberStatus =:= current) ->
+ ok;
+check_group_member_status(GroupName, obsolete, Member, MemberStatus) ->
+ group_member_status_error(GroupName, obsolete, Member, MemberStatus,
+ "obsolete, deprecated or current");
+check_group_member_status(_GroupName, _GroupStatus, _Member, _MemberStatus) ->
+ ok.
+
+group_member_status_error(Name, Status, Member, MemberStatus, Expected) ->
+ snmpc_lib:print_error("Invalid status of group member ~p "
+ "in group ~p. "
+ "Group status is ~p "
+ "and member status is ~p "
+ "(should be ~s)",
+ [Member, Name, Status, MemberStatus, Expected]).
+
+
+
+% check_def(Objects,[GroupObject|GroupObjects],Line)->
+% case lists:member(GroupObject,Objects) of
+% false ->
+% print_error("OBJECT-TYPE definition missing or "
+% "'not-accessible' for '~w'", [GroupObject],Line),
+% check_def(Objects,GroupObjects,Line);
+% true ->
+% check_def(Objects,GroupObjects,Line)
+% end;
+% check_def(_Objects,[],_Line) ->
+% ok.
+
+%% Checking the definition of OBJECT-GROUP
+
+%%-----------------------------
+check_group([#me{imported = true} | T],GroupObjects)->
+ ?vtrace("check_group(imported) -> skip", []),
+ check_group(T,GroupObjects);
+check_group([],_GroupObjects) ->
+ ?vtrace("check_group -> done", []),
+ ok;
+check_group([#me{access = A,
+ entrytype = T,
+ aliasname = N}|MEs], GroupObjects)
+ when ((A =/= 'not-accessible') andalso
+ (T =/= 'internal') andalso
+ (T =/= group)) ->
+ ?vtrace("check_group -> "
+ "~n access: ~p"
+ "~n entrytype: ~p"
+ "~n aliasname: ~p", [A, T, N]),
+ check_member_group(N, GroupObjects),
+ check_group(MEs,GroupObjects);
+check_group([_|MEs],GroupObjects) ->
+ check_group(MEs,GroupObjects).
+
+check_member_group(Aliasname, [])->
+ print_error("'~w' missing in OBJECT-GROUP",[Aliasname]);
+check_member_group(Aliasname, [{Name,GroupObject,Line}|Tl])->
+ ?vtrace2("check_member_group -> entry with"
+ "~n Aliasname: ~p"
+ "~n Name: ~p"
+ "~n GroupObject: ~p", [Aliasname, Name, GroupObject], Line),
+ case lists:member(Aliasname,GroupObject) of
+ true ->
+ ok;
+ false ->
+ check_member_group(Aliasname,Tl)
+ end.
+
+
+%% Checking definition in NOTIFICATION-GROUP
+
+%%--------------------------
+check_notification([],_NotificationObjects) ->
+ ok;
+check_notification([#notification{trapname=Aliasname}|Traps],
+ NotificationObjects) ->
+ check_member_notification(Aliasname, NotificationObjects),
+ check_notification(Traps,NotificationObjects);
+check_notification([_|Traps],NotificationObjects) ->
+ check_notification(Traps,NotificationObjects).
+
+check_member_notification(Aliasname,[])->
+ print_error("'~w' missing in NOTIFICATION-GROUP",[Aliasname]);
+check_member_notification(Aliasname,[{_Name,NotificationObject,_Line}|Tl]) ->
+ case lists:member(Aliasname, NotificationObject) of
+ true ->
+ ok;
+ false ->
+ check_member_notification(Aliasname,Tl)
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Purpose: Resolves oids for aliasnames used in .funcs file.
+%% Returns: {Oid, X}
+%%----------------------------------------------------------------------
+resolve_oid({NameOrOid, X}, MEs) ->
+ case lookup(NameOrOid, MEs) of
+ {value, #me{oid=Oid,entrytype=variable}} -> {Oid, X};
+ {value, #me{oid=Oid,entrytype=table}} -> {Oid, X};
+ {value, #me{entrytype=table_entry}} ->
+ error("Cannot associate an instrumentation function with a "
+ "Table Entry: ~w (must be table or variable)",
+ [NameOrOid]);
+ {value, #me{entrytype=table_column}} ->
+ error("Cannot associate an instrumentation function with a "
+ "Table Column: ~w (must be table or variable)",
+ [NameOrOid]);
+ _Q ->
+ error("Cannot find OBJECT-TYPE definition for '~w'.",
+ [NameOrOid])
+ end.
+
+%%----------------------------------------------------------------------
+%% Fs is list of {Oid, {M,F,A}}
+%% returns: MEs with access-functions.
+%% Pre: Fs, MEs are sorted (on Oid) (then we can traverse mib efficiently)
+%%----------------------------------------------------------------------
+insert_mfa(Fs, [ME | MEs], DBName, Mod)
+ when ME#me.imported =:= true ->
+ [ME | insert_mfa(Fs, MEs, DBName, Mod)];
+
+insert_mfa(Fs, [ME | MEs], DBName, Mod)
+ when ME#me.entrytype =:= internal ->
+ [ME | insert_mfa(Fs, MEs, DBName, Mod)];
+
+insert_mfa(Fs, [ME|MEs], DBName, Mod)
+ when ME#me.entrytype =:= group ->
+ [ME | insert_mfa(Fs, MEs, DBName, Mod)];
+
+insert_mfa([X | Fs], [ME | MEs], DBName, Mod)
+ when ME#me.entrytype =:= variable ->
+ {Oid, {M,F,A}} = X,
+ case ME#me.oid of
+ Oid ->
+ [ME#me{mfa = {M,F,A}} | insert_mfa(Fs, MEs, DBName, Mod)];
+ _Q ->
+ [insert_default_mfa(ME, DBName, Mod) |
+ insert_mfa([X | Fs], MEs, DBName, Mod)]
+ end;
+
+insert_mfa([X | Fs], [TableME | MEs], DBName, Mod)
+ when TableME#me.entrytype =:= table ->
+ {Oid, {M,F,A}} = X,
+ {TableMEs, RestMEs} = collect_mes_for_table(TableME, [TableME | MEs]),
+ [TableEntryME | ColMEs] = tl(TableMEs),
+ DefVals = get_defvals(ColMEs),
+ {value,TableInfo} = snmpc_misc:assq(table_info,TableME#me.assocList),
+ NAssocList = [{table_info, TableInfo#table_info{defvals = DefVals}} |
+ lists:keydelete(table_info, 1, TableME#me.assocList)],
+ NTableME = TableME#me{assocList = NAssocList},
+ case is_same_table(Oid, NTableME#me.oid) of
+ true -> % use mfa from .funcs
+ lists:append([NTableME,
+ TableEntryME#me{mfa = {M, F, A}}
+ | ColMEs],
+ insert_mfa(Fs, RestMEs, DBName, Mod));
+ false ->
+ lists:append(insert_default_mfa([NTableME | tl(TableMEs)],
+ DBName, Mod),
+ insert_mfa([X|Fs], RestMEs, DBName, Mod))
+ end;
+
+insert_mfa([], [ME|MEs], DBName, Mod)
+ when ME#me.entrytype =:= variable ->
+ [insert_default_mfa(ME, DBName, Mod) | insert_mfa([], MEs, DBName, Mod)];
+
+insert_mfa([], [ME|MEs], DBName, Mod)
+ when ME#me.entrytype =:= table ->
+ {TableMEs, RestMEs} = collect_mes_for_table(ME, [ME|MEs]),
+ [TableME, _TableEntryME | ColMEs] = TableMEs,
+ DefVals = get_defvals(ColMEs),
+ {value,TableInfo} = snmpc_misc:assq(table_info,TableME#me.assocList),
+ NAssocList = [{table_info, TableInfo#table_info{defvals = DefVals}} |
+ lists:keydelete(table_info, 1, TableME#me.assocList)],
+ NTableME = TableME#me{assocList = NAssocList},
+ NewTableMEs = insert_default_mfa([NTableME | tl(TableMEs)], DBName, Mod),
+ lists:append(NewTableMEs, insert_mfa([], RestMEs, DBName, Mod));
+
+insert_mfa([], [], _DBName, _Mod) ->
+ [];
+insert_mfa([], [ME|_MEs], _DBName, _Mod) ->
+ error("Missing access-functions for '~w'.",[ME#me.aliasname]).
+
+%%----------------------------------------------------------------------
+%% Returns: {[TableME, TableEntryME | ColumnMEs], RestMEs}
+%%----------------------------------------------------------------------
+collect_mes_for_table(_TableME, []) ->
+ {[], []};
+
+collect_mes_for_table(TableME, [ME|MEs]) ->
+ case is_same_table(TableME#me.oid, ME#me.oid) of
+ true ->
+ {TableMEs, RestMEs} = collect_mes_for_table(TableME, MEs),
+ {[ME | TableMEs], RestMEs};
+ false ->
+ {[], [ME | MEs]}
+ end.
+
+%% returns: MibEntry with access-functions.
+insert_default_mfa(ME, DBName, undefined) when is_record(ME, me)->
+ case lists:member(no_defs, get(options)) of
+ true ->
+ error("Missing access function for ~s", [ME#me.aliasname]);
+ false ->
+ ?vinfo("No accessfunction for '~w' => using default",
+ [ME#me.aliasname]),
+ set_default_function(ME, DBName)
+ end;
+
+insert_default_mfa(ME, _DBName, Mod) when is_record(ME, me)->
+ ME#me{mfa = {Mod, ME#me.aliasname, []}};
+
+insert_default_mfa([TableME, EntryME | Columns], DBName, undefined) ->
+ case lists:member(no_defs, get(options)) of
+ true ->
+ error("Missing access function for ~s", [TableME#me.aliasname]);
+ false ->
+ ?vinfo("No accessfunction for '~w' => using default",
+ [TableME#me.aliasname]),
+ set_default_function([TableME, EntryME | Columns], DBName)
+ end;
+
+insert_default_mfa([TableME, EntryME | Columns], _DBName, Mod) ->
+ [TableME,
+ EntryME#me{mfa = {Mod, TableME#me.aliasname, []}} |
+ Columns].
+
+
+%% returns boolean.
+is_same_table(Oid, TableOid) ->
+ lists:prefix(Oid, TableOid).
+
+%% returns false | {value, ME}
+lookup(UniqName, MEs) when is_atom(UniqName) ->
+ lists:keysearch(UniqName, #me.aliasname, MEs);
+lookup(Oid, MEs) when is_list(Oid) ->
+ lists:keysearch(Oid, #me.oid, MEs).
+
+search_for_dublettes(PrevME, [ME|_MEs])
+ when PrevME#me.oid =:= ME#me.oid ->
+ error("Multiple used object with OBJECT IDENTIFIER '~w'. "
+ "Used in '~w' and '~w'.", [PrevME#me.oid,
+ PrevME#me.aliasname,
+ ME#me.aliasname]);
+search_for_dublettes(PrevME, [ME|MEs])
+ when ((PrevME#me.entrytype =:= variable) andalso
+ (ME#me.entrytype =:= variable)) ->
+ case lists:prefix(PrevME#me.oid, ME#me.oid) of
+ true ->
+ error("Variable '~w' (~w) defined below other "
+ "variable '~w' (~w). ",
+ [ME#me.aliasname, ME#me.oid,
+ PrevME#me.aliasname, PrevME#me.oid]);
+ false ->
+ search_for_dublettes(ME, MEs)
+ end;
+search_for_dublettes(_PrevME, [ME|MEs]) ->
+ search_for_dublettes(ME, MEs);
+search_for_dublettes(_PrevME, []) ->
+ ok.
+
+
+search_for_oid_conflicts([Rec|Traps],MEs) when is_record(Rec,notification) ->
+ #notification{oid = Oid, trapname = Name} = Rec,
+ case search_for_oid_conflicts1(Oid,MEs) of
+ {error,ME} ->
+ error("Notification with OBJECT IDENTIFIER '~w'. "
+ "Used in '~w' and '~w'.", [Oid,Name,ME#me.aliasname]);
+ ok ->
+ search_for_oid_conflicts(Traps,MEs)
+ end;
+search_for_oid_conflicts([_Trap|Traps],MEs) ->
+ search_for_oid_conflicts(Traps,MEs);
+search_for_oid_conflicts([],_MEs) ->
+ ok.
+
+search_for_oid_conflicts1(_Oid,[]) ->
+ ok;
+search_for_oid_conflicts1(Oid,[ME|_MEs]) when Oid == ME#me.oid ->
+ {error,ME};
+search_for_oid_conflicts1(Oid,[_ME|MEs]) ->
+ search_for_oid_conflicts1(Oid,MEs).
+
+set_default_function([TableMe, EntryMe | ColMes], DBName) ->
+ #me{aliasname = Name} = TableMe,
+ check_rowstatus(TableMe),
+ [TableMe,
+ EntryMe#me{mfa = {snmp_generic, table_func, [{Name, DBName}]}} |
+ ColMes];
+
+set_default_function(MibEntry,DBName) when MibEntry#me.entrytype == variable ->
+ #me{aliasname = Aname} = MibEntry,
+ MibEntry#me{mfa = {snmp_generic, variable_func, [{Aname, DBName}]}}.
+
+check_rowstatus(TableME) ->
+ {value,TableInfo} = snmpc_misc:assq(table_info,TableME#me.assocList),
+ case TableInfo#table_info.status_col of
+ undefined ->
+ ?vwarning("No RowStatus column in table ~w => "
+ "The default functions won't work properly",
+ [TableME#me.aliasname]);
+ _Q -> ok
+ end.
+
+check_trap(#trap{trapname=N1, specificcode=C, enterpriseoid=E},
+ #trap{trapname=N2, specificcode=C, enterpriseoid=E},Line) ->
+ print_error("Trap code collision. Enterprise: ~w. Trapcode: ~w, "
+ "Name of traps: ~w, ~w.", [E, C, N1, N2],Line),
+ error;
+check_trap(#trap{trapname=N, specificcode=C1, enterpriseoid=E1},
+ #trap{trapname=N, specificcode=C2, enterpriseoid=E2},Line) ->
+ print_error("Trap name collision. Name: ~w Enterprises: ~w, ~w. "
+ "Trapcodes: ~w, ~w", [N, E1, E2, C1, C2],Line),
+ error;
+check_trap(_OldTrap, _ThisTrap, _Line) ->
+ ok.
+
+check_notification(Notif, Line, Notifs) ->
+ lists:map(fun (OtherNotif) ->
+ check_notification1(Notifs,OtherNotif,Line)
+ end, lists:delete(Notif,Notifs)).
+
+check_notification1(#notification{trapname=N},#notification{trapname=N},Line)->
+ print_error("Trap name collision for '~w.",[N],Line);
+check_notification1(#notification{oid=Oid},#notification{oid=Oid},Line)->
+ print_error("Trap oid collision for '~w.",[Oid],Line);
+check_notification1(_T1, _T2, _L) ->
+ ok.
+
+%%----------------------------------------------------------------------
+%% Returns: list of {VariableName, variable_info-record}
+%%----------------------------------------------------------------------
+extract_variable_infos([]) -> [];
+extract_variable_infos([#me{entrytype = variable,
+ assocList = AL,
+ aliasname = Name} | T]) ->
+ {value, VI} = snmpc_misc:assq(variable_info, AL),
+ [{Name, VI} | extract_variable_infos(T)];
+extract_variable_infos([_ME | T]) ->
+ extract_variable_infos(T).
+
+%%----------------------------------------------------------------------
+%% Returns: list of {TableName, table_info-record}
+%%----------------------------------------------------------------------
+extract_table_infos([]) -> [];
+extract_table_infos([#me{entrytype = table,
+ assocList = AL,
+ aliasname = Name} | T]) ->
+ {value, VI} = snmpc_misc:assq(table_info, AL),
+ [{Name, VI} | extract_table_infos(T)];
+extract_table_infos([_ME | T]) ->
+ extract_table_infos(T).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Section for misc useful functions
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% m(M) -> {?MODULE, M}.
+
+set_dir(File, NewDir) ->
+ case string:chr(File, $/) of
+ 0 -> lists:append(NewDir, File);
+ N -> set_dir(lists:nthtail(N,File), NewDir)
+ end.
+
+%% Look up a key in a list, and if found returns the value
+%% or if not found returns the default value
+key1search(Key, List) ->
+ key1search(Key, List, undefined).
+
+key1search(Key, List, Default) ->
+ case lists:keysearch(Key, 1, List) of
+ {value, {Key, Val}} -> Val;
+ _ -> Default
+ end.
+
+
+%% print the compiled mib
+look_at(FileName) ->
+ case file:read_file(FileName) of
+ {ok,Bin} ->
+ binary_to_term(Bin);
+ {error,Reason} ->
+ {error,Reason}
+ end.
+
+
+%% Data is appended to compiler information
+add_cdata(OffsetInRecord, ListOfData) ->
+ CDATA = get(cdata),
+ OldData = element(OffsetInRecord, CDATA),
+ put(cdata, setelement(OffsetInRecord, CDATA, lists:append(ListOfData,
+ OldData))),
+ undefined.
+
+check_sub_ids([H | _T], Name, Line) when H < 0 ->
+ error("OBJECT IDENTIFIER must have all sub "
+ "indexes > 0. Name: '~w'. Illegal sub index: ~w.",
+ [Name, H], Line);
+check_sub_ids([H | _T], Name, Line) when H > 4294967295 ->
+ error("OBJECT IDENTIFIER must have all sub "
+ "indexes < 4294967295. Name: '~w'. Illegal sub index: ~w.",
+ [Name, H], Line);
+check_sub_ids([_H | T], Name, Line) ->
+ check_sub_ids(T, Name, Line);
+check_sub_ids([], _Name, _Line) ->
+ ok.
+
+
+%%-----------------------------------------------------------------
+%% Handle forward references:
+%% This code handles OIDs that are defined in terms of a
+%% parent OID that is defined later in the file. Ex:
+%% x OBJECT IDENTIFIER ::= {y 1}
+%% y OBJECT IDENTIFIER ::= {enterprises 1}
+%% The following alg is used to handle this:
+%% Datastructure:
+%% An ets table, with one entry for each object in the mib:
+%% {Name, FatherName, Line, SubIndex, Children}
+%% Name : aliasname
+%% FatherName : aliasname of parent object
+%% SubIndex : list of subindexes from parent object
+%% Children : list of aliasnames for all objects registered
+%% under this one
+%% FatherName == 'root' => top-level object
+%% 1) When an OID is found in the mib, it is registered using
+%% register_oid/4. This function updates the parent entry,
+%% by adding the new name to its Children list. It also
+%% updates the entry for the object defined.
+%% 2) When all objects are registered, the ets table contains
+%% a directed graph of all objects.
+%% 3) resolve_oids/1 is called. This function traverses the
+%% graph, starting at 'root', and changes each entry to
+%% {Name, Line, Oid}, where Oid is a list of integers.
+%% 4) The list of MibEntries is traversed. Each object is
+%% looked up in the ets table, and the correspsonding oid
+%% is updated. The functions for this is update_me_oids/2
+%% and update_trap_oids/2.
+%%-----------------------------------------------------------------
+register_oid(Line, Name, ParentName, SubIndex) when Name =/= '$no_name$' ->
+ ?vtrace2("register_oid -> entry with"
+ "~n Name: ~p"
+ "~n ParentName: ~p"
+ "~n SubIndex: ~p", [Name, ParentName, SubIndex], Line),
+ check_sub_ids(SubIndex, Name, Line),
+ OidEts = (get(cdata))#cdata.oid_ets,
+ %% Lookup Parent - if it doesn't already exist, create it
+ {_ParentName, ItsParentName, ItsLine, ItsSubIndex, Children} =
+ case ets:lookup(OidEts, ParentName) of
+ [Found] ->
+ ?vtrace("register_oid -> parent found: "
+ "~n ~p", [Found]),
+ Found;
+ [] ->
+ ?vtrace("register_oid -> father not found: "
+ "~n ~p", [ets:tab2list(OidEts)]),
+ {ParentName, undef, undef, [], []}
+ end,
+ %% Update Father with a pointer to us
+ NChildren = case lists:member(Name, Children) of
+ true -> Children;
+ false -> [Name | Children]
+ end,
+ NParent = {ParentName, ItsParentName, ItsLine, ItsSubIndex, NChildren},
+ ?vtrace("register_oid -> NParent: ~n~p", [NParent]),
+ ets:insert(OidEts, NParent),
+ %% Lookup ourselves - if we don't exist, create us
+ MyChildren =
+ case ets:lookup(OidEts, Name) of
+ [Found2] ->
+ ?vtrace("register_oid -> children found: "
+ "~n ~p", [Found2]),
+ element(5, Found2);
+ [] ->
+ ?vtrace("register_oid -> no children found", []),
+ []
+ end,
+ %% Update ourselves
+ NSelf = {Name, ParentName, Line, SubIndex, MyChildren},
+ ?vtrace("register_oid -> NSelf: "
+ "~n ~p", [NSelf]),
+ ets:insert(OidEts, NSelf);
+register_oid(_Line, _Name, _ParentName, _SubIndex) ->
+ ok.
+
+
+resolve_oids(OidEts) ->
+ case ets:lookup(OidEts, root) of
+ [{_, _, _, _, RootChildren}] ->
+ resolve_oids(RootChildren, [], OidEts);
+ [] ->
+ ok
+ end.
+
+resolve_oids([Name | T], FatherOid, OidEts) ->
+ {MyOid, MyChildren, MyLine} =
+ case ets:lookup(OidEts, Name) of
+ [{Name, Oid, Line}] ->
+ print_error("Circular OBJECT IDENTIFIER definitions "
+ "involving ~w\n", [Name], Line),
+ {Oid, [], Line};
+ [{Name, _Father, Line, SubIndex, Children}] ->
+ {FatherOid ++ SubIndex, Children, Line}
+ end,
+ ets:insert(OidEts, {Name, MyOid, MyLine}),
+ resolve_oids(T, FatherOid, OidEts),
+ resolve_oids(MyChildren, MyOid, OidEts);
+resolve_oids([], _, _) ->
+ ok.
+
+
+
+update_me_oids([], _OidEts, Acc) ->
+ lists:reverse(Acc);
+update_me_oids([#me{aliasname = '$no_name$'} | Mes], OidEts, Acc) ->
+ update_me_oids(Mes, OidEts, Acc);
+update_me_oids([Me | Mes], OidEts, Acc) ->
+ ?vtrace("update_me_oids -> entry with"
+ "~n Me: ~p", [Me]),
+ Oid = tr_oid(Me#me.aliasname, OidEts),
+ NMe = resolve_oid_defval(Me, OidEts),
+ update_me_oids(Mes, OidEts, [NMe#me{oid = Oid} | Acc]).
+
+update_trap_oids([], _OidEts, Acc) ->
+ lists:reverse(Acc);
+update_trap_oids([#trap{enterpriseoid = EOid,
+ oidobjects = OidObjs} = Trap | Traps],
+ OidEts, Acc) ->
+ ?vtrace("update_trap_oids -> entry with"
+ "~n EOid: ~p", [EOid]),
+ NEnter = tr_oid(EOid, OidEts),
+ NOidObjs = tr_oid_objs(OidObjs, OidEts),
+ NTrap = Trap#trap{enterpriseoid = NEnter,
+ oidobjects = NOidObjs},
+ update_trap_oids(Traps, OidEts, [NTrap|Acc]);
+update_trap_oids([#notification{trapname = Name,
+ oidobjects = OidObjs} = Notif | Traps],
+ OidEts, Acc) ->
+ ?vtrace("update_trap_oids -> entry with"
+ "~n Name: ~p", [Name]),
+ Oid = tr_oid(Name, OidEts),
+ NOidObjs = tr_oid_objs(OidObjs, OidEts),
+ NNotif = Notif#notification{oid = Oid, oidobjects = NOidObjs},
+ update_trap_oids(Traps, OidEts, [NNotif|Acc]).
+
+tr_oid(Name, OidEts) ->
+ ?vtrace("tr_oid -> entry with"
+ "~n Name: ~p", [Name]),
+ case ets:lookup(OidEts, Name) of
+ [{Name, MyOid, _MyLine}] ->
+ MyOid;
+ [{_Natrap, Parent, Line, SubIndex, _Children}] ->
+ print_error("OBJECT IDENTIFIER [~w] defined in terms "
+ "of undefined parent object. Parent: '~w'."
+ "(Sub-indexes: ~w.)",
+ [Name, Parent, SubIndex], Line),
+ ?vtrace("tr_oid -> ets:tab2list(~w): "
+ "~n ~p", [OidEts, ets:tab2list(OidEts)]),
+ rnd_oid()
+ end.
+
+tr_oid_objs([{{variable, Name}, Type} | T], OidEts) ->
+ ?vtrace("tr_oid_objs(variable) -> entry with"
+ "~n Name: ~p", [Name]),
+ Oid = tr_oid(Name, OidEts) ++ [0],
+ [{Oid, Type} | tr_oid_objs(T, OidEts)];
+tr_oid_objs([{{column, Name}, Type} | T], OidEts) ->
+ ?vtrace("tr_oid_objs(column) -> entry with"
+ "~n Name: ~p", [Name]),
+ Oid = tr_oid(Name, OidEts),
+ [{Oid, Type} | tr_oid_objs(T, OidEts)];
+tr_oid_objs([], _OidEts) ->
+ [].
+
+
+resolve_oid_defval(ME, OidEts)
+ when (ME#me.asn1_type)#asn1_type.bertype == 'OBJECT IDENTIFIER' ->
+ #me{aliasname = MEName, assocList = AssocList} = ME,
+ case snmpc_misc:assq(defval, AssocList) of
+ {value, DefVal} when is_atom(DefVal) ->
+ case ets:lookup(OidEts, DefVal) of
+ [{_, Oid, _}] ->
+ ME#me{assocList = lists:keyreplace(defval, 1, AssocList,
+ {defval, Oid})};
+ _ ->
+ print_error("Can not find OBJECT-TYPE definition for '~w' "
+ "Used in DEFVAL for '~w'.", [DefVal, MEName]),
+ ME
+ end;
+ _ ->
+ ME
+ end;
+resolve_oid_defval(ME, _OidEts) ->
+ ME.
+
+rnd_oid() ->
+ [99,99]. %% '99' means "stop computer" in Y2Kish...
+
+error(FormatStr, Data) when is_list(FormatStr) ->
+ print_error(FormatStr,Data),
+ exit(error).
+
+error(FormatStr, Data, Line) when is_list(FormatStr) ->
+ print_error(FormatStr,Data,Line),
+ exit(error).
+
+print_error(FormatStr, Data) when is_list(FormatStr) ->
+ ok = io:format("~s: Error: " ++ FormatStr,[get(filename)|Data]),
+ put(errors,yes),
+ io:format("~n").
+
+print_error(FormatStr, Data,Line) when is_list(FormatStr) ->
+ ok = io:format("~s: ~w: Error: " ++ FormatStr,[get(filename), Line |Data]),
+ put(errors,yes),
+ io:format("~n").
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Section for debug functions
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+vprint(Severity, Mod, Line, MibLine, F, A) ->
+ case printable(Severity) of
+ standard when is_integer(MibLine) ->
+ io:format("[~s:~w][~s]: " ++ F ++ "~n",
+ [get(filename), MibLine, image_of_severity(Severity)|A]);
+ standard ->
+ io:format("[~s][~s]: " ++ F ++ "~n",
+ [get(filename), image_of_severity(Severity)|A]);
+ extended when is_integer(MibLine) ->
+ io:format("[~s:~w][~w:~w][~s]: " ++ F ++ "~n",
+ [get(filename), MibLine, Mod, Line,
+ image_of_severity(Severity)|A]);
+ extended ->
+ io:format("[~s][~w:~w][~s]: " ++ F ++ "~n",
+ [get(filename), Mod, Line,
+ image_of_severity(Severity)|A]);
+ _ ->
+ ok
+ end.
+
+printable(Severity) ->
+ printable(get(verbosity), Severity).
+
+printable(silence, _) -> none;
+printable(warning, warning) -> standard;
+printable(info, info) -> standard;
+printable(info, warning) -> standard;
+printable(log, warning) -> standard;
+printable(log, info) -> standard;
+printable(log, log) -> standard;
+printable(debug, warning) -> standard;
+printable(debug, info) -> standard;
+printable(debug, log) -> standard;
+printable(debug, debug) -> standard;
+printable(trace, _Sev) -> extended;
+printable(_Ver, _Sev) -> none.
+
+-spec image_of_severity(Sev :: severity()) -> string().
+image_of_severity(warning) -> "WAR";
+image_of_severity(info) -> "INF";
+image_of_severity(log) -> "LOG";
+image_of_severity(debug) -> "DBG";
+image_of_severity(trace) -> "TRC";
+image_of_severity(_) -> " - ".
+
+
+vvalidate(silence) -> ok;
+vvalidate(warning) -> ok;
+vvalidate(info) -> ok;
+vvalidate(log) -> ok;
+vvalidate(debug) -> ok;
+vvalidate(trace) -> ok;
+vvalidate(V) -> exit({invalid_verbosity,V}).
+
+
diff --git a/lib/snmp/src/compile/snmpc_lib.hrl b/lib/snmp/src/compile/snmpc_lib.hrl
new file mode 100644
index 0000000000..000486e728
--- /dev/null
+++ b/lib/snmp/src/compile/snmpc_lib.hrl
@@ -0,0 +1,37 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 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%
+%%
+
+-ifndef(snmpc_lib).
+-define(snmpc_lib, true).
+
+-define(vwarning(F, A), ?verbosity(warning, F, A, ignore)).
+-define(vwarning2(F, A, MibLine), ?verbosity(warning, F, A, MibLine)).
+-define(vinfo(F, A), ?verbosity(info, F, A, ignore)).
+-define(vinfo2(F, A, MibLine), ?verbosity(info, F, A, MibLine)).
+-define(vlog(F, A), ?verbosity(log, F, A, ignore)).
+-define(vlog2(F, A, MibLine), ?verbosity(log, F, A, MibLine)).
+-define(vdebug(F, A), ?verbosity(debug, F, A, ignore)).
+-define(vdebug2(F, A, MibLine), ?verbosity(debug, F, A, MibLine)).
+-define(vtrace(F, A), ?verbosity(trace, F, A, ignore)).
+-define(vtrace2(F, A, MibLine), ?verbosity(trace, F, A, MibLine)).
+
+-define(verbosity(Severity, F, A, MibLine),
+ snmpc_lib:vprint(Severity, ?MODULE, ?LINE, MibLine, F, A)).
+
+-endif. % -ifndef(snmpc_lib).
diff --git a/lib/snmp/src/compile/snmpc_mib_gram.yrl b/lib/snmp/src/compile/snmpc_mib_gram.yrl
new file mode 100644
index 0000000000..1957f52936
--- /dev/null
+++ b/lib/snmp/src/compile/snmpc_mib_gram.yrl
@@ -0,0 +1,973 @@
+%%
+%% %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%
+%%
+
+%%----------------------------------------------------------------------
+%% Number of expected shift/reduce warnings
+%% This is ugly but...
+%%----------------------------------------------------------------------
+
+Expect 2.
+
+
+%% ----------------------------------------------------------------------
+Nonterminals
+%% ----------------------------------------------------------------------
+accessv1
+definition
+defvalpart
+description
+descriptionfield
+displaypart
+entry
+namedbits
+fatherobjectname
+fieldname
+fields
+implies
+import
+import_stuff
+imports
+imports_from_one_mib
+index
+indexpartv1
+indextypev1
+indextypesv1
+parentintegers
+listofdefinitions
+listofimports
+mib
+mibname
+nameassign
+newtype
+newtypename
+objectidentifier
+objectname
+objecttypev1
+range_num
+referpart
+size
+sizedescr
+statusv1
+syntax
+tableentrydefinition
+traptype
+type
+usertype
+variables
+varpart
+
+%v2
+moduleidentity
+revisionpart
+revisions
+listofdefinitionsv2
+mibid
+last_updated
+oranization
+contact_info
+revision
+revision_string
+revision_desc
+v1orv2
+objectidentity
+objecttypev2
+unitspart
+indexpartv2
+indextypesv2
+indextypev2
+statusv2
+accessv2
+notification
+objectspart
+objects
+definitionv2
+textualconvention
+objectgroup
+notificationgroup
+modulecompliance
+modulepart
+modules
+module
+modulenamepart
+mandatorypart
+compliancepart
+compliances
+compliance
+compliancegroup
+object
+syntaxpart
+writesyntaxpart
+accesspart
+fsyntax
+defbitsvalue
+defbitsnames
+.
+%% ----------------------------------------------------------------------
+Terminals
+%% ----------------------------------------------------------------------
+integer variable atom string quote '{' '}' '::=' ':' '=' ',' '.' '(' ')' ';' '|'
+'ACCESS'
+'BEGIN'
+'BIT'
+'Counter'
+'DEFINITIONS'
+'DEFVAL'
+'DESCRIPTION'
+'DISPLAY-HINT'
+'END'
+'ENTERPRISE'
+'FROM'
+'Gauge'
+'IDENTIFIER'
+'IMPORTS'
+'INDEX'
+'INTEGER'
+'IpAddress'
+'NetworkAddress'
+'OBJECT'
+'OBJECT-TYPE'
+'OCTET'
+'OF'
+'Opaque'
+'REFERENCE'
+'SEQUENCE'
+'SIZE'
+'STATUS'
+'STRING'
+'SYNTAX'
+'TRAP-TYPE'
+'TimeTicks'
+'VARIABLES'
+
+%v2
+'LAST-UPDATED'
+'ORGANIZATION'
+'CONTACT-INFO'
+'MODULE-IDENTITY'
+'NOTIFICATION-TYPE'
+'MODULE-COMPLIANCE'
+'OBJECT-GROUP'
+'NOTIFICATION-GROUP'
+'REVISION'
+'OBJECT-IDENTITY'
+'MAX-ACCESS'
+'UNITS'
+'AUGMENTS'
+'IMPLIED'
+'OBJECTS'
+'TEXTUAL-CONVENTION'
+'NOTIFICATIONS'
+'MODULE'
+'MANDATORY-GROUPS'
+'GROUP'
+'WRITE-SYNTAX'
+'MIN-ACCESS'
+'BITS'
+'DisplayString'
+'PhysAddress'
+'MacAddress'
+'TruthValue'
+'TestAndIncr'
+'AutonomousType'
+'InstancePointer'
+'VariablePointer'
+'RowPointer'
+'RowStatus'
+'TimeStamp'
+'TimeInterval'
+'DateAndTime'
+'StorageType'
+'TDomain'
+'TAddress'
+.
+
+
+Rootsymbol mib.
+Endsymbol '$end'.
+
+% **********************************************************************
+
+mib -> mibname 'DEFINITIONS' implies 'BEGIN'
+ import v1orv2 'END'
+ : {Version, Defs} = '$6',
+ #pdata{mib_version = Version,
+ mib_name = '$1',
+ imports = '$5',
+ defs = Defs}.
+
+v1orv2 -> moduleidentity listofdefinitionsv2 :
+ {v2_mib, ['$1'|lists:reverse('$2')]}.
+v1orv2 -> listofdefinitions : {v1_mib, lists:reverse('$1')}.
+
+definition -> objectidentifier : '$1'.
+definition -> objecttypev1 : '$1'.
+definition -> newtype : '$1'.
+definition -> tableentrydefinition : '$1'.
+definition -> traptype : '$1'.
+
+listofdefinitions -> definition : ['$1'] .
+listofdefinitions -> listofdefinitions definition : ['$2' | '$1'].
+
+import -> '$empty' : [].
+import -> 'IMPORTS' imports ';' : '$2'.
+
+imports -> imports_from_one_mib : ['$1'].
+imports -> imports_from_one_mib imports : ['$1' | '$2'].
+
+imports_from_one_mib -> listofimports 'FROM' variable :
+ {{val('$3'), lists:reverse('$1')}, line_of('$2')}.
+
+listofimports -> import_stuff : ['$1'].
+listofimports -> listofimports ',' import_stuff : ['$3' | '$1'].
+
+import_stuff -> 'OBJECT-TYPE' : {builtin, 'OBJECT-TYPE'}.
+import_stuff -> 'TRAP-TYPE' : {builtin, 'TRAP-TYPE'}.
+import_stuff -> 'NetworkAddress' : {builtin, 'NetworkAddress'}.
+import_stuff -> 'TimeTicks' : {builtin, 'TimeTicks'}.
+import_stuff -> 'IpAddress' : {builtin, 'IpAddress'}.
+import_stuff -> 'Counter' : {builtin, 'Counter'}.
+import_stuff -> 'Gauge' : {builtin, 'Gauge'}.
+import_stuff -> 'Opaque' : {builtin, 'Opaque'}.
+import_stuff -> variable : filter_v2imports(get(snmp_version), val('$1')).
+import_stuff -> atom : {node, val('$1')}.
+%%v2
+import_stuff -> 'MODULE-IDENTITY'
+ : ensure_ver(2,'$1'), {builtin, 'MODULE-IDENTITY'}.
+import_stuff -> 'NOTIFICATION-TYPE'
+ : ensure_ver(2,'$1'), {builtin, 'NOTIFICATION-TYPE'}.
+import_stuff -> 'MODULE-COMPLIANCE'
+ : ensure_ver(2,'$1'), {builtin, 'MODULE-COMPLIANCE'}.
+import_stuff -> 'NOTIFICATION-GROUP'
+ : ensure_ver(2,'$1'), {builtin, 'NOTIFICATION-GROUP'}.
+import_stuff -> 'OBJECT-GROUP'
+ : ensure_ver(2,'$1'), {builtin, 'OBJECT-GROUP'}.
+import_stuff -> 'OBJECT-IDENTITY'
+ : ensure_ver(2,'$1'), {builtin, 'OBJECT-IDENTITY'}.
+import_stuff -> 'TEXTUAL-CONVENTION'
+ : ensure_ver(2,'$1'), {builtin, 'TEXTUAL-CONVENTION'}.
+import_stuff -> 'DisplayString'
+ : ensure_ver(2,'$1'), {builtin, 'DisplayString'}.
+import_stuff -> 'PhysAddress'
+ : ensure_ver(2,'$1'), {builtin, 'PhysAddress'}.
+import_stuff -> 'MacAddress'
+ : ensure_ver(2,'$1'), {builtin, 'MacAddress'}.
+import_stuff -> 'TruthValue'
+ : ensure_ver(2,'$1'), {builtin, 'TruthValue'}.
+import_stuff -> 'TestAndIncr'
+ : ensure_ver(2,'$1'), {builtin, 'TestAndIncr'}.
+import_stuff -> 'AutonomousType'
+ : ensure_ver(2,'$1'), {builtin, 'AutonomousType'}.
+import_stuff -> 'InstancePointer'
+ : ensure_ver(2,'$1'), {builtin, 'InstancePointer'}.
+import_stuff -> 'VariablePointer'
+ : ensure_ver(2,'$1'), {builtin, 'VariablePointer'}.
+import_stuff -> 'RowPointer'
+ : ensure_ver(2,'$1'), {builtin, 'RowPointer'}.
+import_stuff -> 'RowStatus'
+ : ensure_ver(2,'$1'), {builtin, 'RowStatus'}.
+import_stuff -> 'TimeStamp'
+ : ensure_ver(2,'$1'), {builtin, 'TimeStamp'}.
+import_stuff -> 'TimeInterval'
+ : ensure_ver(2,'$1'), {builtin, 'TimeInterval'}.
+import_stuff -> 'DateAndTime'
+ : ensure_ver(2,'$1'), {builtin, 'DateAndTime'}.
+import_stuff -> 'StorageType'
+ : ensure_ver(2,'$1'), {builtin, 'StorageType'}.
+import_stuff -> 'TDomain'
+ : ensure_ver(2,'$1'), {builtin, 'TDomain'}.
+import_stuff -> 'TAddress'
+ : ensure_ver(2,'$1'), {builtin, 'TAddress'}.
+
+traptype -> objectname 'TRAP-TYPE' 'ENTERPRISE' objectname varpart
+ description referpart implies integer :
+ Trap = make_trap('$1', '$4', lists:reverse('$5'),
+ '$6', '$7', val('$9')),
+ {Trap, line_of('$2')}.
+
+% defines a name to an internal node.
+objectidentifier -> objectname 'OBJECT' 'IDENTIFIER' nameassign :
+ {Parent, SubIndex} = '$4',
+ Int = make_internal('$1', dummy, Parent, SubIndex),
+ {Int, line_of('$2')}.
+
+% defines name, access and type for a variable.
+objecttypev1 -> objectname 'OBJECT-TYPE'
+ 'SYNTAX' syntax
+ 'ACCESS' accessv1
+ 'STATUS' statusv1
+ 'DESCRIPTION' descriptionfield
+ referpart indexpartv1 defvalpart
+ nameassign :
+ Kind = kind('$13', '$12'),
+ OT = make_object_type('$1', '$4', '$6', '$8', '$10',
+ '$11', Kind, '$14'),
+ {OT, line_of('$2')}.
+
+newtype -> newtypename implies syntax :
+ NT = make_new_type('$1', dummy, '$3'),
+ {NT, line_of('$2')}.
+
+tableentrydefinition -> newtypename implies 'SEQUENCE' '{' fields '}' :
+ Seq = make_sequence('$1', lists:reverse('$5')),
+ {Seq, line_of('$3')}.
+
+% returns: list of {<fieldname>, <asn1_type>}
+fields -> fieldname fsyntax :
+ [{val('$1'), '$2'}].
+
+fields -> fields ',' fieldname fsyntax : [{val('$3'), '$4'} | '$1'].
+
+fsyntax -> 'BITS' : {{bits,[{dummy,0}]},line_of('$1')}.
+fsyntax -> syntax : '$1'.
+
+fieldname -> atom : '$1'.
+
+syntax -> usertype : {{type, val('$1')}, line_of('$1')}.
+syntax -> type : {{type, cat('$1')},line_of('$1')}.
+syntax -> type size : {{type_with_size, cat('$1'), '$2'},line_of('$1')}.
+syntax -> usertype size : {{type_with_size,val('$1'), '$2'},line_of('$1')}.
+syntax -> 'INTEGER' '{' namedbits '}' :
+ {{integer_with_enum, 'INTEGER', '$3'}, line_of('$1')}.
+syntax -> 'BITS' '{' namedbits '}' :
+ ensure_ver(2,'$1'),
+ {{bits, '$3'}, line_of('$1')}.
+syntax -> 'SEQUENCE' 'OF' usertype :
+ {{sequence_of,val('$3')},line_of('$1')}.
+
+size -> '(' sizedescr ')' : make_range('$2').
+size -> '(' 'SIZE' '(' sizedescr ')' ')' : make_range('$4').
+
+%% Returns a list of integers describing a range.
+sizedescr -> range_num '.' '.' range_num : ['$1', '$4'].
+sizedescr -> range_num '.' '.' range_num sizedescr :['$1', '$4' |'$5'].
+sizedescr -> range_num : ['$1'].
+sizedescr -> sizedescr '|' sizedescr : ['$1', '$3'].
+
+range_num -> integer : val('$1') .
+range_num -> quote atom : make_range_integer(val('$1'), val('$2')) .
+range_num -> quote variable : make_range_integer(val('$1'), val('$2')) .
+
+namedbits -> atom '(' integer ')' : [{val('$1'), val('$3')}].
+namedbits -> namedbits ',' atom '(' integer ')' :
+ [{val('$3'), val('$5')} | '$1'].
+
+usertype -> variable : '$1'.
+
+type -> 'OCTET' 'STRING' : {'OCTET STRING', line_of('$1')}.
+type -> 'BIT' 'STRING' : {'BIT STRING', line_of('$1')}.
+type -> 'OBJECT' 'IDENTIFIER' : {'OBJECT IDENTIFIER', line_of('$1')}.
+type -> 'INTEGER' : '$1'.
+type -> 'NetworkAddress' : '$1'.
+type -> 'IpAddress' : '$1'.
+type -> 'Counter' : ensure_ver(1,'$1'),'$1'.
+type -> 'Gauge' : ensure_ver(1,'$1'),'$1'.
+type -> 'TimeTicks' : '$1'.
+type -> 'Opaque' : '$1'.
+type -> 'DisplayString' : ensure_ver(2,'$1'), '$1'.
+type -> 'PhysAddress' : ensure_ver(2,'$1'), '$1'.
+type -> 'MacAddress' : ensure_ver(2,'$1'), '$1'.
+type -> 'TruthValue' : ensure_ver(2,'$1'), '$1'.
+type -> 'TestAndIncr' : ensure_ver(2,'$1'), '$1'.
+type -> 'AutonomousType' : ensure_ver(2,'$1'), '$1'.
+type -> 'InstancePointer' : ensure_ver(2,'$1'), '$1'.
+type -> 'VariablePointer' : ensure_ver(2,'$1'), '$1'.
+type -> 'RowPointer' : ensure_ver(2,'$1'), '$1'.
+type -> 'RowStatus' : ensure_ver(2,'$1'), '$1'.
+type -> 'TimeStamp' : ensure_ver(2,'$1'), '$1'.
+type -> 'TimeInterval' : ensure_ver(2,'$1'), '$1'.
+type -> 'DateAndTime' : ensure_ver(2,'$1'), '$1'.
+type -> 'StorageType' : ensure_ver(2,'$1'), '$1'.
+type -> 'TDomain' : ensure_ver(2,'$1'), '$1'.
+type -> 'TAddress' : ensure_ver(2,'$1'), '$1'.
+
+% Returns: {FatherName, SubIndex} (the parent)
+nameassign -> implies '{' fatherobjectname parentintegers '}' : {'$3', '$4' }.
+nameassign -> implies '{' parentintegers '}' : { root, '$3'}.
+
+
+varpart -> '$empty' : [].
+varpart -> 'VARIABLES' '{' variables '}' : '$3'.
+variables -> objectname : ['$1'].
+variables -> variables ',' objectname : ['$3' | '$1'].
+
+implies -> '::=' : '$1'.
+implies -> ':' ':' '=' : w("Sloppy asignment on line ~p", [line_of('$1')]), '$1'.
+descriptionfield -> string : lists:reverse(val('$1')).
+descriptionfield -> '$empty' : undefined.
+description -> 'DESCRIPTION' string : lists:reverse(val('$2')).
+description -> '$empty' : undefined.
+
+displaypart -> 'DISPLAY-HINT' string : display_hint('$2') .
+displaypart -> '$empty' : undefined .
+
+% returns: {indexes, undefined}
+% | {indexes, IndexList} where IndexList is a list of aliasnames.
+indexpartv1 -> 'INDEX' '{' indextypesv1 '}' : {indexes, lists:reverse('$3')}.
+indexpartv1 -> '$empty' : {indexes, undefined}.
+
+indextypesv1 -> indextypev1 : ['$1'].
+indextypesv1 -> indextypesv1 ',' indextypev1 : ['$3' | '$1'].
+
+indextypev1 -> index : '$1'.
+
+index -> objectname : '$1'.
+
+parentintegers -> integer : [val('$1')].
+parentintegers -> atom '(' integer ')' : [val('$3')].
+parentintegers -> integer parentintegers : [val('$1') | '$2'].
+parentintegers -> atom '(' integer ')' parentintegers : [val('$3') | '$5'].
+
+defvalpart -> 'DEFVAL' '{' integer '}' : {defval, val('$3')}.
+defvalpart -> 'DEFVAL' '{' atom '}' : {defval, val('$3')}.
+defvalpart -> 'DEFVAL' '{' '{' defbitsvalue '}' '}' : {defval, '$4'}.
+defvalpart -> 'DEFVAL' '{' quote atom '}'
+ : {defval, make_defval_for_string(line_of('$1'), lists:reverse(val('$3')),
+ val('$4'))}.
+defvalpart -> 'DEFVAL' '{' quote variable '}'
+ : {defval, make_defval_for_string(line_of('$1'), lists:reverse(val('$3')),
+ val('$4'))}.
+defvalpart -> 'DEFVAL' '{' string '}'
+ : {defval, lists:reverse(val('$3'))}.
+defvalpart -> '$empty' : undefined.
+
+defbitsvalue -> defbitsnames : '$1'.
+defbitsvalue -> '$empty' : [].
+
+defbitsnames -> atom : [val('$1')].
+defbitsnames -> defbitsnames ',' atom : [val('$3') | '$1'].
+
+objectname -> atom : val('$1').
+mibname -> variable : val('$1').
+fatherobjectname -> objectname : '$1'.
+newtypename -> variable : val('$1').
+
+accessv1 -> atom: accessv1('$1').
+
+statusv1 -> atom : statusv1('$1').
+
+referpart -> 'REFERENCE' string : lists:reverse(val('$2')).
+referpart -> '$empty' : undefined.
+
+
+%%----------------------------------------------------------------------
+%% SNMPv2 grammatics
+%%v2
+%%----------------------------------------------------------------------
+moduleidentity -> mibid 'MODULE-IDENTITY'
+ 'LAST-UPDATED' last_updated
+ 'ORGANIZATION' oranization
+ 'CONTACT-INFO' contact_info
+ 'DESCRIPTION' descriptionfield
+ revisionpart nameassign :
+ MI = make_module_identity('$1', '$4', '$6', '$8',
+ '$10', '$11', '$12'),
+ {MI, line_of('$2')}.
+
+mibid -> atom : val('$1').
+last_updated -> string : lists:reverse(val('$1')) .
+oranization -> string : lists:reverse(val('$1')) .
+contact_info -> string : lists:reverse(val('$1')) .
+
+revisionpart -> '$empty' : [] .
+revisionpart -> revisions : lists:reverse('$1') .
+
+revisions -> revision : ['$1'] .
+revisions -> revisions revision : ['$2' | '$1'] .
+revision -> 'REVISION' revision_string 'DESCRIPTION' revision_desc :
+ make_revision('$2', '$4') .
+
+revision_string -> string : lists:reverse(val('$1')) .
+revision_desc -> string : lists:reverse(val('$1')) .
+
+definitionv2 -> objectidentifier : '$1'.
+definitionv2 -> objecttypev2 : '$1'.
+definitionv2 -> textualconvention : '$1'.
+definitionv2 -> objectidentity : '$1'.
+definitionv2 -> newtype : '$1'.
+definitionv2 -> tableentrydefinition : '$1'.
+definitionv2 -> notification : '$1'.
+definitionv2 -> objectgroup : '$1'.
+definitionv2 -> notificationgroup : '$1'.
+definitionv2 -> modulecompliance : '$1'.
+
+listofdefinitionsv2 -> '$empty' : [] .
+listofdefinitionsv2 -> listofdefinitionsv2 definitionv2 : ['$2' | '$1'].
+
+textualconvention -> newtypename implies 'TEXTUAL-CONVENTION' displaypart
+ 'STATUS' statusv2 description referpart 'SYNTAX' syntax :
+ NT = make_new_type('$1', 'TEXTUAL-CONVENTION', '$4',
+ '$6', '$7', '$8', '$10'),
+ {NT, line_of('$3')}.
+
+objectidentity -> objectname 'OBJECT-IDENTITY' 'STATUS' statusv2
+ 'DESCRIPTION' string referpart nameassign :
+ {Parent, SubIndex} = '$8',
+ Int = make_internal('$1', 'OBJECT-IDENTITY',
+ Parent, SubIndex),
+ {Int, line_of('$2')}.
+
+objectgroup -> objectname 'OBJECT-GROUP' objectspart
+ 'STATUS' statusv2 description referpart nameassign :
+ OG = make_object_group('$1', '$3', '$5', '$6', '$7', '$8'),
+ {OG, line_of('$2')}.
+
+notificationgroup -> objectname 'NOTIFICATION-GROUP' 'NOTIFICATIONS' '{'
+ objects '}' 'STATUS' statusv2 description referpart
+ nameassign :
+ NG = make_notification_group('$1', '$5', '$8', '$9',
+ '$10', '$11'),
+ {NG, line_of('$2')}.
+
+modulecompliance -> objectname 'MODULE-COMPLIANCE' 'STATUS' statusv2
+ description referpart modulepart nameassign :
+ MC = make_module_compliance('$1', '$4', '$5', '$6',
+ '$7', '$8'),
+ {MC, line_of('$2')}.
+
+modulepart -> '$empty'.
+modulepart -> modules.
+
+modules -> module.
+modules -> modules module.
+
+module -> 'MODULE' modulenamepart mandatorypart compliancepart.
+
+modulenamepart -> mibname.
+modulenamepart -> '$empty'.
+
+mandatorypart -> 'MANDATORY-GROUPS' '{' objects '}'.
+mandatorypart -> '$empty'.
+
+compliancepart -> compliances.
+compliancepart -> '$empty'.
+
+compliances -> compliance.
+compliances -> compliances compliance.
+
+compliance -> compliancegroup.
+compliance -> object.
+
+compliancegroup -> 'GROUP' objectname description.
+
+object -> 'OBJECT' objectname syntaxpart writesyntaxpart accesspart description.
+
+syntaxpart -> 'SYNTAX' syntax.
+syntaxpart -> '$empty'.
+
+writesyntaxpart -> 'WRITE-SYNTAX' syntax.
+writesyntaxpart -> '$empty'.
+
+accesspart -> 'MIN-ACCESS' accessv2.
+accesspart -> '$empty'.
+
+objecttypev2 -> objectname 'OBJECT-TYPE'
+ 'SYNTAX' syntax
+ unitspart
+ 'MAX-ACCESS' accessv2
+ 'STATUS' statusv2
+ 'DESCRIPTION' descriptionfield
+ referpart indexpartv2 defvalpart
+ nameassign :
+ Kind = kind('$14', '$13'),
+ OT = make_object_type('$1', '$4', '$5', '$7', '$9',
+ '$11', '$12', Kind, '$15'),
+ {OT, line_of('$2')}.
+
+indexpartv2 -> 'INDEX' '{' indextypesv2 '}' : {indexes, lists:reverse('$3')}.
+indexpartv2 -> 'AUGMENTS' '{' entry '}' : {augments, '$3'}.
+indexpartv2 -> '$empty' : {indexes, undefined}.
+
+indextypesv2 -> indextypev2 : ['$1'].
+indextypesv2 -> indextypesv2 ',' indextypev2 : ['$3' | '$1'].
+
+indextypev2 -> 'IMPLIED' index : {implied,'$2'}.
+indextypev2 -> index : '$1'.
+
+entry -> objectname : '$1'.
+
+unitspart -> '$empty' : undefined.
+unitspart -> 'UNITS' string : units('$2') .
+
+statusv2 -> atom : statusv2('$1').
+
+accessv2 -> atom: accessv2('$1').
+
+notification -> objectname 'NOTIFICATION-TYPE' objectspart
+ 'STATUS' statusv2 'DESCRIPTION' descriptionfield referpart
+ nameassign :
+ Not = make_notification('$1','$3','$5', '$7', '$8', '$9'),
+ {Not, line_of('$2')}.
+
+objectspart -> 'OBJECTS' '{' objects '}' : lists:reverse('$3').
+objectspart -> '$empty' : [].
+
+objects -> objectname : ['$1'].
+objects -> objects ',' objectname : ['$3'|'$1'].
+
+%%----------------------------------------------------------------------
+Erlang code.
+%%----------------------------------------------------------------------
+
+-include("snmp_types.hrl").
+-include("snmpc_lib.hrl").
+-include("snmpc.hrl").
+
+% value
+val(Token) -> element(3, Token).
+
+line_of(Token) -> element(2, Token).
+
+%% category
+cat(Token) -> element(1, Token).
+
+statusv1(Tok) ->
+ case val(Tok) of
+ mandatory -> mandatory;
+ optional -> optional;
+ obsolete -> obsolete;
+ deprecated -> deprecated;
+ Else -> return_error(line_of(Tok),
+ "syntax error before: " ++ atom_to_list(Else))
+ end.
+
+statusv2(Tok) ->
+ case val(Tok) of
+ current -> current;
+ deprecated -> deprecated;
+ obsolete -> obsolete;
+ Else -> return_error(line_of(Tok),
+ "syntax error before: " ++ atom_to_list(Else))
+ end.
+
+accessv1(Tok) ->
+ case val(Tok) of
+ 'read-only' -> 'read-only';
+ 'read-write' -> 'read-write';
+ 'write-only' -> 'write-only';
+ 'not-accessible' -> 'not-accessible';
+ Else -> return_error(line_of(Tok),
+ "syntax error before: " ++ atom_to_list(Else))
+ end.
+
+accessv2(Tok) ->
+ case val(Tok) of
+ 'not-accessible' -> 'not-accessible';
+ 'accessible-for-notify' -> 'accessible-for-notify';
+ 'read-only' -> 'read-only';
+ 'read-write' -> 'read-write';
+ 'read-create' -> 'read-create';
+ Else -> return_error(line_of(Tok),
+ "syntax error before: " ++ atom_to_list(Else))
+ end.
+
+%% ---------------------------------------------------------------------
+%% Various basic record build functions
+%% ---------------------------------------------------------------------
+
+make_module_identity(Name, LU, Org, CI, Desc, Revs, NA) ->
+ #mc_module_identity{name = Name,
+ last_updated = LU,
+ organization = Org,
+ contact_info = CI,
+ description = Desc,
+ revisions = Revs,
+ name_assign = NA}.
+
+make_revision(Rev, Desc) ->
+ #mc_revision{revision = Rev,
+ description = Desc}.
+
+make_object_type(Name, Syntax, MaxAcc, Status, Desc, Ref, Kind, NA) ->
+ #mc_object_type{name = Name,
+ syntax = Syntax,
+ max_access = MaxAcc,
+ status = Status,
+ description = Desc,
+ reference = Ref,
+ kind = Kind,
+ name_assign = NA}.
+
+make_object_type(Name, Syntax, Units, MaxAcc, Status, Desc, Ref, Kind, NA) ->
+ #mc_object_type{name = Name,
+ syntax = Syntax,
+ units = Units,
+ max_access = MaxAcc,
+ status = Status,
+ description = Desc,
+ reference = Ref,
+ kind = Kind,
+ name_assign = NA}.
+
+make_new_type(Name, Macro, Syntax) ->
+ #mc_new_type{name = Name,
+ macro = Macro,
+ syntax = Syntax}.
+
+make_new_type(Name, Macro, DisplayHint, Status, Desc, Ref, Syntax) ->
+ #mc_new_type{name = Name,
+ macro = Macro,
+ status = Status,
+ description = Desc,
+ reference = Ref,
+ display_hint = DisplayHint,
+ syntax = Syntax}.
+
+make_trap(Name, Ent, Vars, Desc, Ref, Num) ->
+ #mc_trap{name = Name,
+ enterprise = Ent,
+ vars = Vars,
+ description = Desc,
+ reference = Ref,
+ num = Num}.
+
+make_notification(Name, Vars, Status, Desc, Ref, NA) ->
+ #mc_notification{name = Name,
+ vars = Vars,
+ status = Status,
+ description = Desc,
+ reference = Ref,
+ name_assign = NA}.
+
+make_module_compliance(Name, Status, Desc, Ref, Mod, NA) ->
+ #mc_module_compliance{name = Name,
+ status = Status,
+ description = Desc,
+ reference = Ref,
+ module = Mod,
+ name_assign = NA}.
+
+make_object_group(Name, Objs, Status, Desc, Ref, NA) ->
+ #mc_object_group{name = Name,
+ objects = Objs,
+ status = Status,
+ description = Desc,
+ reference = Ref,
+ name_assign = NA}.
+
+make_notification_group(Name, Objs, Status, Desc, Ref, NA) ->
+ #mc_notification_group{name = Name,
+ objects = Objs,
+ status = Status,
+ description = Desc,
+ reference = Ref,
+ name_assign = NA}.
+
+make_sequence(Name, Fields) ->
+ #mc_sequence{name = Name,
+ fields = Fields}.
+
+make_internal(Name, Macro, Parent, SubIdx) ->
+ #mc_internal{name = Name,
+ macro = Macro,
+ parent = Parent,
+ sub_index = SubIdx}.
+
+
+
+%% ---------------------------------------------------------------------
+
+
+%%----------------------------------------------------------------------
+%% Purpose: Find how much room needs to be allocated for the data type
+%% (when sending it in a PDU (the maximum difference will be
+%% the size allocated)).
+%% This is applicable for OCTET STRINGs and OBJECT IDENTIFIERs.
+%%
+%% Or : Find the range of integers in the integer list.
+%% This is applicable for INTEGERs
+%%
+%% Arg: A list of integers.
+%%----------------------------------------------------------------------
+
+make_range_integer(RevHexStr, h) ->
+ erlang:list_to_integer(lists:reverse(RevHexStr), 16);
+make_range_integer(RevHexStr, 'H') ->
+ erlang:list_to_integer(lists:reverse(RevHexStr), 16);
+make_range_integer(RevBitStr, b) ->
+ erlang:list_to_integer(lists:reverse(RevBitStr), 2);
+make_range_integer(RevBitStr, 'B') ->
+ erlang:list_to_integer(lists:reverse(RevBitStr), 2);
+make_range_integer(RevStr, Base) ->
+ throw({error, {invalid_base, Base, lists:reverse(RevStr)}}).
+
+make_range(XIntList) ->
+ IntList = lists:flatten(XIntList),
+ {range, lists:min(IntList), lists:max(IntList)}.
+
+make_defval_for_string(Line, Str, Atom) ->
+ case lists:member(Atom, [h, 'H', b, 'B']) of
+ true ->
+ case catch make_defval_for_string2(Str, Atom) of
+ Defval when is_list(Defval) ->
+ Defval;
+ {error, ErrStr} ->
+ snmpc_lib:print_error("Bad DEFVAL ~w string ~p - ~s",
+ [Atom, Str, ErrStr],
+ Line),
+ "";
+ _Else ->
+ snmpc_lib:print_error("Bad DEFVAL ~w string ~p",
+ [Atom, Str],
+ Line),
+ ""
+ end;
+ false ->
+ snmpc_lib:print_error("Bad DEFVAL string type ~w for ~p",
+ [Atom, Str],
+ Line),
+ ""
+ end.
+
+
+make_defval_for_string2([], h) -> [];
+make_defval_for_string2([X16,X|HexString], h) ->
+ lists:append(hex_to_bytes(snmpc_misc:to_upper([X16,X])),
+ make_defval_for_string2(HexString, h));
+make_defval_for_string2([_Odd], h) ->
+ throw({error, "odd number of bytes in hex string"});
+make_defval_for_string2(HexString, 'H') ->
+ make_defval_for_string2(HexString,h);
+
+make_defval_for_string2(BitString, 'B') ->
+ bits_to_bytes(BitString);
+make_defval_for_string2(BitString, b) ->
+ make_defval_for_string2(BitString, 'B').
+
+bits_to_bytes(BitStr) ->
+ lists:reverse(bits_to_bytes(lists:reverse(BitStr), 1, 0)).
+
+bits_to_bytes([], 1, _Byte) -> % empty bitstring
+ [];
+bits_to_bytes([], 256, _Byte) -> % correct; multiple of 8
+ [];
+% If we are to support arbitrary length of bitstrings. This migth
+% be needed in the new SMI.
+%bits_to_bytes([], N, Byte) ->
+% [Byte];
+bits_to_bytes([], _N, _Byte) ->
+ throw({error, "not a multiple of eight bits in bitstring"});
+bits_to_bytes(Rest, 256, Byte) ->
+ [Byte | bits_to_bytes(Rest, 1, 0)];
+bits_to_bytes([$1 | T], N, Byte) ->
+ bits_to_bytes(T, N*2, N + Byte);
+bits_to_bytes([$0 | T], N, Byte) ->
+ bits_to_bytes(T, N*2, Byte);
+bits_to_bytes([_BadChar | _T], _N, _Byte) ->
+ throw({error, "bad character in bit string"}).
+
+%%----------------------------------------------------------------------
+%% These HEX conversion routines are stolen from module asn1_bits by
+%% I didn't want to ship the entire asn1-compiler so I used cut-and-paste.
+%%----------------------------------------------------------------------
+
+%% hex_to_bytes(HexNumber) when is_atom(HexNumber) ->
+%% hex_to_bytes(atom_to_list(HexNumber));
+
+hex_to_bytes(HexNumber) ->
+ case length(HexNumber) rem 2 of
+ 1 -> %% Odd
+ hex_to_bytes(lists:append(HexNumber,[$0]),[]);
+ 0 -> %% even
+ hex_to_bytes(HexNumber,[])
+ end.
+
+hex_to_bytes([],R) ->
+ lists:reverse(R);
+hex_to_bytes([Hi,Lo|Rest],Res) ->
+ hex_to_bytes(Rest,[hex_to_byte(Hi,Lo)|Res]).
+
+hex_to_four_bits(Hex) ->
+ if
+ Hex == $0 -> 0;
+ Hex == $1 -> 1;
+ Hex == $2 -> 2;
+ Hex == $3 -> 3;
+ Hex == $4 -> 4;
+ Hex == $5 -> 5;
+ Hex == $6 -> 6;
+ Hex == $7 -> 7;
+ Hex == $8 -> 8;
+ Hex == $9 -> 9;
+ Hex == $A -> 10;
+ Hex == $B -> 11;
+ Hex == $C -> 12;
+ Hex == $D -> 13;
+ Hex == $E -> 14;
+ Hex == $F -> 15;
+ true -> throw({error, "bad hex character"})
+ end.
+
+hex_to_byte(Hi,Lo) ->
+ (hex_to_four_bits(Hi) bsl 4) bor hex_to_four_bits(Lo).
+
+kind(DefValPart,IndexPart) ->
+ case DefValPart of
+ undefined ->
+ case IndexPart of
+ {indexes, undefined} -> {variable, []};
+ {indexes, Indexes} ->
+ {table_entry, {indexes, Indexes}};
+ {augments,Table} ->
+ {table_entry,{augments,Table}}
+ end;
+ {defval, DefVal} -> {variable, [{defval, DefVal}]}
+ end.
+
+display_hint(Val) ->
+ case val(Val) of
+ Str when is_list(Str) ->
+ lists:reverse(Str);
+ _ ->
+ throw({error, {invalid_display_hint, Val}})
+ end.
+
+units(Val) ->
+ case val(Val) of
+ Str when is_list(Str) ->
+ lists:reverse(Str);
+ _ ->
+ throw({error, {invalid_units, Val}})
+ end.
+
+ensure_ver(Ver, Line, What) ->
+ case get(snmp_version) of
+ Ver -> ok;
+ _Other ->
+ snmpc_lib:print_error(
+ "~s is only allowed in SNMPv~p.",[What,Ver],Line)
+ end.
+
+
+ensure_ver(Ver,Token) ->
+ ensure_ver(Ver,line_of(Token), atom_to_list(cat(Token))).
+
+filter_v2imports(2,'Integer32') -> {builtin, 'Integer32'};
+filter_v2imports(2,'Counter32') -> {builtin, 'Counter32'};
+filter_v2imports(2,'Gauge32') -> {builtin, 'Gauge32'};
+filter_v2imports(2,'Unsigned32') -> {builtin, 'Unsigned32'};
+filter_v2imports(2,'Counter64') -> {builtin, 'Counter64'};
+filter_v2imports(_,Type) -> {type, Type}.
+
+w(F, A) ->
+ ?vwarning(F, A).
+
+%i(F, A) ->
+% io:format("~w:" ++ F ++ "~n", [?MODULE|A]).
+
diff --git a/lib/snmp/src/compile/snmpc_mib_to_hrl.erl b/lib/snmp/src/compile/snmpc_mib_to_hrl.erl
new file mode 100644
index 0000000000..07bd29231b
--- /dev/null
+++ b/lib/snmp/src/compile/snmpc_mib_to_hrl.erl
@@ -0,0 +1,391 @@
+%%
+%% %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%
+%%
+
+-module(snmpc_mib_to_hrl).
+
+-include_lib("stdlib/include/erl_compile.hrl").
+-include("snmp_types.hrl").
+-include("snmpc_lib.hrl").
+
+%% External exports
+-export([convert/1, compile/3]).
+
+%%-----------------------------------------------------------------
+%% Func: convert/1
+%% Args: MibName = string() without extension.
+%% Purpose: Produce a .hrl file with oid for tables and variables,
+%% column numbers for columns and values for enums.
+%% Writes only the first occurence of a name. Prints a
+%% warning if a duplicate name is found.
+%% Returns: ok | {error, Reason}
+%% Note: The Mib must be compiled.
+%%-----------------------------------------------------------------
+convert(MibName) ->
+ MibFile = MibName ++ ".bin",
+ HrlFile = MibName ++ ".hrl",
+ put(verbosity, trace),
+ convert(MibFile, HrlFile, MibName).
+
+convert(MibFile, HrlFile, MibName) ->
+ ?vtrace("convert -> entry with"
+ "~n MibFile: ~s"
+ "~n HrlFile: ~s"
+ "~n MibName: ~s", [MibFile, HrlFile, MibName]),
+ case snmpc_misc:read_mib(MibFile) of
+ {ok, #mib{asn1_types = Types, mes = MEs, traps = Traps}} ->
+ ?vdebug("mib successfully read", []),
+ resolve(Types, MEs, Traps, HrlFile,
+ filename:basename(MibName)),
+ ok;
+ {error, Reason} ->
+ ?vinfo("failed reading mib: "
+ "~n Reason: ~p", [Reason]),
+ {error, Reason}
+ end.
+
+resolve(Types, MEs, Traps, HrlFile, MibName) ->
+ ?vtrace("resolve -> entry", []),
+ case file:open(HrlFile, [write]) of
+ {ok, Fd} ->
+ insert_header(Fd),
+ insert_begin(Fd, MibName),
+ insert_notifs(Traps, Fd),
+ insert_oids(MEs, Fd),
+ insert_range(MEs, Fd),
+ insert_enums(Types, MEs, Fd),
+ insert_defvals(MEs, Fd),
+ insert_end(Fd),
+ file:close(Fd),
+ ?vlog("~s written", [HrlFile]);
+ {error, Reason} ->
+ ?vinfo("failed opening output file: "
+ "~n Reason: ~p", [Reason]),
+ {error, Reason}
+ end.
+
+insert_header(Fd) ->
+ ?vdebug("insert file header", []),
+ io:format(Fd, "%%% This file was automatically generated by "
+ "snmpc_mib_to_hrl version ~s~n", [?version]),
+ {Y,Mo,D} = date(),
+ {H,Mi,S} = time(),
+ io:format(Fd, "%%% Date: ~2.2.0w-~s-~w::~2.2.0w:~2.2.0w:~2.2.0w~n",
+ [D,month(Mo),Y,H,Mi,S]).
+
+insert_begin(Fd, MibName) ->
+ ?vdebug("insert file begin", []),
+ io:format(Fd,
+ "-ifndef('~s').~n"
+ "-define('~s', true).~n", [MibName, MibName]).
+
+insert_end(Fd) ->
+ ?vdebug("insert file end", []),
+ io:format(Fd, "-endif.~n", []).
+
+insert_oids(MEs, Fd) ->
+ ?vdebug("insert oids", []),
+ io:format(Fd, "~n%% Oids~n", []),
+ insert_oids2(MEs, Fd),
+ io:format(Fd, "~n", []).
+
+insert_oids2([#me{imported = true} | T], Fd) ->
+ insert_oids2(T, Fd);
+insert_oids2([#me{entrytype = table_column, oid = Oid, aliasname = Name} | T],
+ Fd) ->
+ ?vtrace("insert oid [table column]: ~p - ~w", [Name, Oid]),
+ io:format(Fd, "-define(~w, ~w).~n", [Name, lists:last(Oid)]),
+ insert_oids2(T, Fd);
+insert_oids2([#me{entrytype = variable, oid = Oid, aliasname = Name} | T],
+ Fd) ->
+ ?vtrace("insert oid [variable]: ~p - ~w", [Name, Oid]),
+ io:format(Fd, "-define(~w, ~w).~n", [Name, Oid]),
+ io:format(Fd, "-define(~w, ~w).~n", [merge_atoms(Name, instance),
+ Oid ++ [0]]),
+ insert_oids2(T, Fd);
+insert_oids2([#me{oid = Oid, aliasname = Name} | T], Fd) ->
+ ?vtrace("insert oid: ~p - ~w", [Name, Oid]),
+ io:format(Fd, "~n-define(~w, ~w).~n", [Name, Oid]),
+ insert_oids2(T, Fd);
+insert_oids2([], _Fd) ->
+ ok.
+
+
+insert_notifs(Traps, Fd) ->
+ ?vdebug("insert notifications", []),
+ Notifs = [Notif || Notif <- Traps, is_record(Notif, notification)],
+ case Notifs of
+ [] ->
+ ok;
+ _ ->
+ io:format(Fd, "~n%% Notifications~n", []),
+ insert_notifs2(Notifs, Fd)
+ end.
+
+insert_notifs2([], _Fd) ->
+ ok;
+insert_notifs2([#notification{trapname = Name, oid = Oid}|T], Fd) ->
+ ?vtrace("insert notification ~p - ~w", [Name, Oid]),
+ io:format(Fd, "-define(~w, ~w).~n", [Name, Oid]),
+ insert_notifs2(T, Fd).
+
+
+%%-----------------------------------------------------------------
+%% There's nothing strange with this function! Enums can be
+%% defined in types and in mibentries; therefore, we first call
+%% ins_types and then ins_mes to insert enums from different places.
+%%-----------------------------------------------------------------
+insert_enums(Types, MEs, Fd) ->
+ ?vdebug("insert enums", []),
+ T = ins_types(Types, Fd, []),
+ ins_mes(MEs, T, Fd).
+
+%% Insert all types, but not the imported. Ret the names of inserted
+%% types.
+ins_types([#asn1_type{aliasname = Name,
+ assocList = Alist,
+ imported = false} | T],
+ Fd, Res)
+ when is_list(Alist) ->
+ case lists:keysearch(enums, 1, Alist) of
+ {value, {enums, Enums}} when Enums =/= [] ->
+ case Enums of
+ [] -> ins_types(T, Fd, Res);
+ NewEnums ->
+ io:format(Fd, "~n%% Definitions from ~w~n", [Name]),
+ ins_enums(NewEnums, Name, Fd),
+ ins_types(T, Fd, [Name | Res])
+ end;
+ _ -> ins_types(T, Fd, Res)
+ end;
+ins_types([_ | T], Fd, Res) ->
+ ins_types(T, Fd, Res);
+ins_types([], _Fd, Res) -> Res.
+
+ins_mes([#me{entrytype = internal} | T], Types, Fd) ->
+ ins_mes(T, Types, Fd);
+ins_mes([#me{entrytype = table} | T], Types, Fd) ->
+ ins_mes(T, Types, Fd);
+ins_mes([#me{aliasname = Name,
+ asn1_type = #asn1_type{assocList = Alist,
+ aliasname = Aname},
+ imported = false} | T],
+ Types, Fd)
+ when is_list(Alist) ->
+ case lists:keysearch(enums, 1, Alist) of
+ {value, {enums, Enums}} when Enums =/= [] ->
+ case Enums of
+ [] -> ins_mes(T, Types, Fd);
+ NewEnums ->
+ %% Now, check if the type is already inserted
+ %% (by ins_types).
+ case lists:member(Aname, Types) of
+ false ->
+ io:format(Fd, "~n%% Enum definitions from ~w~n",
+ [Name]),
+ ins_enums(NewEnums, Name, Fd),
+ ins_mes(T, Types, Fd);
+ _ -> ins_mes(T, Types, Fd)
+ end
+ end;
+ _ -> ins_mes(T, Types, Fd)
+ end;
+ins_mes([_ | T], Types, Fd) ->
+ ins_mes(T, Types, Fd);
+ins_mes([], _Types, _Fd) -> ok.
+
+ins_enums([{Name, Val} | T], Origin, Fd) ->
+ EnumName = merge_atoms(Origin, Name),
+ io:format(Fd, "-define(~w, ~w).~n", [EnumName, Val]),
+ ins_enums(T, Origin, Fd);
+ins_enums([], _Origin, _Fd) ->
+ ok.
+
+%%----------------------------------------------------------------------
+%% Solves the problem with placing '' around some atoms.
+%% You can't write two atoms using ~w_~w.
+%%----------------------------------------------------------------------
+merge_atoms(TypeOrigin, Name) ->
+ list_to_atom(lists:append([atom_to_list(TypeOrigin), "_",
+ atom_to_list(Name)])).
+
+insert_defvals(Mes, Fd) ->
+ ?vdebug("insert default values", []),
+ io:format(Fd, "~n%% Default values~n", []),
+ insert_defvals2(Mes, Fd),
+ io:format(Fd, "~n", []).
+
+insert_defvals2([#me{imported = true} | T], Fd) ->
+ insert_defvals2(T, Fd);
+insert_defvals2([#me{entrytype = table_column, assocList = Alist,
+ aliasname = Name} | T],
+ Fd) ->
+ case snmpc_misc:assq(defval, Alist) of
+ {value, Val} ->
+ Atom = merge_atoms('default', Name),
+ io:format(Fd, "-define(~w, ~w).~n", [Atom, Val]);
+ _ -> ok
+ end,
+ insert_defvals2(T, Fd);
+insert_defvals2([#me{entrytype = variable, assocList = Alist, aliasname = Name}
+ | T],
+ Fd) ->
+ case snmpc_misc:assq(variable_info, Alist) of
+ {value, VarInfo} ->
+ case VarInfo#variable_info.defval of
+ undefined -> ok;
+ Val ->
+ Atom = merge_atoms('default', Name),
+ io:format(Fd, "-define(~w, ~w).~n", [Atom, Val])
+ end;
+ _ -> ok
+ end,
+ insert_defvals2(T, Fd);
+insert_defvals2([_ | T], Fd) ->
+ insert_defvals2(T, Fd);
+insert_defvals2([], _Fd) -> ok.
+
+insert_range(Mes, Fd) ->
+ ?vdebug("insert range", []),
+ io:format(Fd, "~n%% Range values~n", []),
+ insert_range2(Mes, Fd),
+ io:format(Fd, "~n", []).
+
+insert_range2([#me{imported = true} | T], Fd)->
+ insert_range2(T,Fd);
+insert_range2([#me{asn1_type=#asn1_type{bertype='OCTET STRING',lo=Low,hi=High},aliasname=Name}|T],Fd)->
+ case Low =:= undefined of
+ true->
+ insert_range2(T,Fd);
+ false->
+ AtomLow = merge_atoms('low', Name),
+ AtomHigh = merge_atoms('high', Name),
+ io:format(Fd,"-define(~w, ~w).~n",[AtomLow,Low]),
+ io:format(Fd,"-define(~w, ~w).~n",[AtomHigh,High]),
+ insert_range2(T,Fd)
+ end;
+insert_range2([#me{asn1_type=#asn1_type{bertype='Unsigned32',lo=Low,hi=High},aliasname=Name}|T],Fd)->
+ AtomLow = merge_atoms('low', Name),
+ AtomHigh = merge_atoms('high', Name),
+ io:format(Fd,"-define(~w, ~w).~n",[AtomLow,Low]),
+ io:format(Fd,"-define(~w, ~w).~n",[AtomHigh,High]),
+ insert_range2(T,Fd);
+insert_range2([#me{asn1_type=#asn1_type{bertype='Counter32',lo=Low,hi=High},aliasname=Name}|T],Fd)->
+ AtomLow = merge_atoms('low', Name),
+ AtomHigh = merge_atoms('high', Name),
+ io:format(Fd,"-define(~w, ~w).~n",[AtomLow,Low]),
+ io:format(Fd,"-define(~w, ~w).~n",[AtomHigh,High]),
+ insert_range2(T,Fd);
+insert_range2([#me{asn1_type=#asn1_type{bertype='INTEGER',lo=Low,hi=High},aliasname=Name}|T],Fd)->
+ case Low =:= undefined of
+ true->
+ insert_range2(T,Fd);
+ false->
+ AtomLow = merge_atoms('low', Name),
+ AtomHigh = merge_atoms('high', Name),
+ io:format(Fd,"-define(~w, ~w).~n",[AtomLow,Low]),
+ io:format(Fd,"-define(~w, ~w).~n",[AtomHigh,High]),
+ insert_range2(T,Fd)
+ end;
+insert_range2([_|T],Fd) ->
+ insert_range2(T,Fd);
+insert_range2([],_Fd) ->
+ ok.
+
+month(1) -> "Jan";
+month(2) -> "Feb";
+month(3) -> "Mar";
+month(4) -> "Apr";
+month(5) -> "May";
+month(6) -> "Jun";
+month(7) -> "Jul";
+month(8) -> "Aug";
+month(9) -> "Sep";
+month(10) -> "Oct";
+month(11) -> "Nov";
+month(12) -> "Dec".
+
+%%%-----------------------------------------------------------------
+%%% Interface for erl_compile.
+%%%-----------------------------------------------------------------
+
+%% Opts#options.specific
+compile(Input, Output, Opts) ->
+ set_verbosity(Opts),
+ set_filename(Input),
+ ?vtrace("compile -> entry with"
+ "~n Input: ~s"
+ "~n Output: ~s"
+ "~n Opts: ~p", [Input, Output, Opts]),
+ case convert(Input++".bin", Output++".hrl", Input) of
+ ok ->
+ ok;
+ {error, Reason} ->
+ io:format("~p", [Reason]),
+ error
+ end.
+
+set_verbosity(#options{verbose = Verbose, specific = Spec}) ->
+ set_verbosity(Verbose, Spec).
+
+set_verbosity(Verbose, Spec) ->
+ Verbosity =
+ case lists:keysearch(verbosity, 1, Spec) of
+ {value, {verbosity, V}} ->
+ case (catch snmpc_lib:vvalidate(V)) of
+ ok ->
+ case Verbose of
+ true ->
+ case V of
+ silence ->
+ log;
+ info ->
+ log;
+ _ ->
+ V
+ end;
+ _ ->
+ V
+ end;
+ _ ->
+ case Verbose of
+ true ->
+ log;
+ false ->
+ silence
+ end
+ end;
+ false ->
+ case Verbose of
+ true ->
+ log;
+ false ->
+ silence
+ end
+ end,
+ put(verbosity, Verbosity).
+
+
+set_filename(Filename) ->
+ Rootname = filename:rootname(Filename),
+ Basename = filename:basename(Rootname ++ ".mib"),
+ put(filename, Basename).
+
+
+
+
diff --git a/lib/snmp/src/compile/snmpc_misc.erl b/lib/snmp/src/compile/snmpc_misc.erl
new file mode 100644
index 0000000000..557f3e0f6b
--- /dev/null
+++ b/lib/snmp/src/compile/snmpc_misc.erl
@@ -0,0 +1,173 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2003-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%
+%%
+
+-module(snmpc_misc).
+
+%% need definition of mib record
+-include("snmp_types.hrl").
+-include("snmpc_misc.hrl").
+
+
+-export([assq/2,
+ bits_to_int/2,
+ ensure_trailing_dir_delimiter/1,
+ foreach/3,
+ is_string/1,
+ read_mib/1,
+ read_noexit/2,
+ strip_extension_from_filename/2,
+ to_upper/1]).
+
+
+%%--------------------------------------------------
+%% Not a real assq, but what the heck, it's useful.
+%%--------------------------------------------------
+assq(Key, List) ->
+ case lists:keysearch(Key, 1, List) of
+ {value, {Key, Val}} -> {value, Val};
+ _ -> false
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Converts a list of named bits to the integer value.
+%% Returns: integer()|error
+%%----------------------------------------------------------------------
+bits_to_int(Val,Kibbles) ->
+ bits_to_int(Val,Kibbles,0).
+
+bits_to_int([],_Kibbles,Res) -> Res;
+bits_to_int([Kibble|Ks],Kibbles,Res) ->
+ case snmp_misc:assq(Kibble,Kibbles) of
+ {value,V} ->
+ bits_to_int(Ks,Kibbles,Res + round(math:pow(2,V)));
+ _ ->
+ error
+ end.
+
+
+ensure_trailing_dir_delimiter([]) -> "/";
+ensure_trailing_dir_delimiter(DirSuggestion) ->
+ case lists:last(DirSuggestion) of
+ $/ -> DirSuggestion;
+ _ -> lists:append(DirSuggestion,"/")
+ end.
+
+
+strip_extension_from_filename(FileName, Ext) when is_atom(FileName) ->
+ strip_extension_from_filename(atom_to_list(FileName), Ext);
+
+strip_extension_from_filename(FileName, Ext) when is_list(FileName) ->
+ case lists:suffix(Ext, FileName) of
+ true -> lists:sublist(FileName, 1, length(FileName) - length(Ext));
+ false -> FileName
+ end.
+
+
+to_upper([C|Cs]) when (C >= $a) andalso (C =< $z) -> [C-($a-$A)|to_upper(Cs)];
+to_upper([C|Cs]) -> [C|to_upper(Cs)];
+to_upper([]) -> [].
+
+
+is_string([]) -> true;
+is_string([Tkn | Str])
+ when is_integer(Tkn) andalso (Tkn >= 0) andalso (Tkn =< 255) ->
+ is_string(Str);
+is_string(_) -> false.
+
+
+foreach(Function, ExtraArgs, [H | T]) ->
+ apply(Function, [H | ExtraArgs]),
+ foreach(Function, ExtraArgs, T);
+foreach(_Function, _ExtraArgs, []) ->
+ true.
+
+
+
+%%----------------------------------------------------------------------
+%% Returns: {ok, Mib}|{error, Reason}
+%% The reason for having the function if this module is:
+%% The compiler package and the agent package are separated, this is
+%% the only common module.
+%%----------------------------------------------------------------------
+read_mib(FileName) ->
+ (catch do_read_mib(FileName)).
+
+do_read_mib(FileName) ->
+ ?read_mib(FileName).
+
+
+%% Ret. {ok, Res} | {error, Line, Error} | {error, open_file}
+read_noexit(File, CheckFunc) ->
+ case file:open(File, [read]) of
+ {ok, Fd} ->
+ case loop(Fd, [], CheckFunc, 1, File) of
+ {error, Line, R} ->
+ file:close(Fd),
+ {error, Line, R};
+ Res ->
+ file:close(Fd),
+ {ok, Res}
+ end;
+ _Error ->
+ {error, open_file}
+ end.
+
+
+%%-----------------------------------------------------------------
+%% Ret: {error, Line, Reason} | Row
+%%-----------------------------------------------------------------
+loop(Fd, Res, Func, StartLine, File) ->
+ case read(Fd, "", StartLine) of
+ {ok, Row, EndLine} ->
+ case (catch apply(Func, [Row])) of
+ {ok, NewRow} ->
+ loop(Fd, [NewRow | Res], Func, EndLine, File);
+ true ->
+ loop(Fd, [Row | Res], Func, EndLine, File);
+ Error ->
+ {error, EndLine, Error}
+ end;
+ {error, EndLine, Error} ->
+ {error, EndLine, Error};
+ eof ->
+ Res
+ end.
+
+
+%%-----------------------------------------------------------------
+%% io:read modified to give us line numbers.
+%%-----------------------------------------------------------------
+read(Io, Prompt, StartLine) ->
+ case io:request(Io, {get_until, Prompt, erl_scan, tokens, [StartLine]}) of
+ {ok, Toks, EndLine} ->
+ case erl_parse:parse_term(Toks) of
+ {ok, Term} ->
+ {ok, Term, EndLine};
+ {error, {Line, erl_parse, Error}} ->
+ {error, Line, {parse_error, Error}}
+ end;
+ {error, E, EndLine} ->
+ {error, EndLine, E};
+ {eof, _EndLine} ->
+ eof;
+ Other ->
+ Other
+ end.
+
diff --git a/lib/snmp/src/compile/snmpc_misc.hrl b/lib/snmp/src/compile/snmpc_misc.hrl
new file mode 100644
index 0000000000..c29f2eb9e5
--- /dev/null
+++ b/lib/snmp/src/compile/snmpc_misc.hrl
@@ -0,0 +1,74 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2004-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%
+%%
+
+-define(verify_format_version(VFV_Ver1,VFV_Ver2),
+ fun(VFV_V,VFV_V) ->
+ ok;
+ (VFV_V1,VFV_V2) when is_list(VFV_V1) andalso is_list(VFV_V2) ->
+ Toks1 = string:tokens(VFV_V1, [$.]),
+ [Major1|_] = case (catch [list_to_integer(I) || I <- Toks1]) of
+ Nums when is_list(Nums) ->
+ Nums;
+ _ ->
+ {error, {invalid_version_format, VFV_V1}}
+ end,
+ Toks2 = string:tokens(VFV_V2, [$.]),
+ case (catch [list_to_integer(I) || I <- Toks2]) of
+ [Major1|_] ->
+ ok;
+ [_Major2|_] ->
+ {error, wrong_version};
+ _ ->
+ {error, {invalid_version_format, VFV_V2}}
+ end;
+ (VFV_V1,VFV_V2) ->
+ {error, {invalid_format, VFV_V1, VFV_V2}}
+ end(VFV_Ver1,VFV_Ver2)).
+
+-define(read_mib(RM_FN),
+ RM_Bin = case file:read_file(RM_FN) of
+ {ok, RM_B} ->
+ RM_B;
+ RM_Error ->
+ throw(RM_Error)
+ end,
+ RM_Mib = case (catch binary_to_term(RM_Bin)) of
+ RM_M when is_record(RM_M, mib) ->
+ RM_M;
+ _ ->
+ throw({error, bad_mib_format})
+ end,
+ #mib{mib_format_version = RM_V1} = #mib{},
+ case RM_Mib of
+ #mib{mib_format_version = RM_V2,
+ misc = RM_X} when is_integer(RM_X) ->
+ case (catch ?verify_format_version(RM_V1, RM_V2)) of
+ ok ->
+ {ok, RM_Mib#mib{misc = []}};
+ _ ->
+ throw({error, {wrong_mib_format_version_tag, RM_V2}})
+ end;
+ #mib{mib_format_version = RM_V2} ->
+ case (catch ?verify_format_version(RM_V1, RM_V2)) of
+ ok ->
+ {ok, RM_Mib#mib{misc = []}};
+ _ ->
+ throw({error, {wrong_mib_format_version_tag, RM_V2}})
+ end
+ end).
diff --git a/lib/snmp/src/compile/snmpc_tok.erl b/lib/snmp/src/compile/snmpc_tok.erl
new file mode 100644
index 0000000000..6b99e7ae43
--- /dev/null
+++ b/lib/snmp/src/compile/snmpc_tok.erl
@@ -0,0 +1,357 @@
+%%
+%% %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%
+%%
+
+-module(snmpc_tok).
+
+%% c(snmpc_tok).
+
+%%----------------------------------------------------------------------
+%% Generic (?) Tokenizer.
+%%----------------------------------------------------------------------
+%% Token: {Category, Line, Value}|{Category, Line}
+%% (Category == <KeyWord> ==> 2-tuple (otherwise 3-tuple)
+%% Category: integer | quote | string
+%% | variable | atom | <keyword> | <single_char>
+%%----------------------------------------------------------------------
+
+%% API
+-export([start_link/2, stop/1, get_token/1, get_all_tokens/1, tokenize/2]).
+
+%% Internal exports
+-export([null_get_line/0, format_error/1, terminate/2, handle_call/3, init/1,
+ test/0]).
+
+
+%%----------------------------------------------------------------------
+%% Reserved_words: list of KeyWords. Example: ['IF', 'BEGIN', ..., 'GOTO']
+%% Options: list of Option
+%% Option: {file, <filename>},
+%% or: {get_line_function, {Mod, Func, Arg} (default io, get_line, [Fid])},
+%% get_line_function shall behave as io:get_line.
+%% {print_lineno, L}
+%% Returns: {ok, Pid} | {error, Reason}
+%%----------------------------------------------------------------------
+start_link(Reserved_words, Options) ->
+ case lists:keysearch(file, 1, Options) of
+ {value, {file, Filename}} ->
+ case file:open(Filename, [read]) of
+ {ok, Fid} ->
+ gen_server:start_link(?MODULE,
+ {Reserved_words, Options,
+ {io, get_line, [Fid, prompt]}}, []);
+ Error ->
+ Str = format_error({"Cannot open file '~s' (~800p).~n",
+ [Filename, Error]}),
+ {error,Str}
+ end;
+ false ->
+ MFA = case lists:keysearch(get_line_function, 1, Options) of
+ {value, {get_line_function, {M, F, A}}} ->
+ {M,F,A};
+ false -> {?MODULE, null_get_line, []}
+ end,
+ gen_server:start_link(?MODULE,{Reserved_words,Options,MFA}, [])
+ end.
+
+%%--------------------------------------------------
+%% Returns:
+%% {ok, [Token], LineNo} | {eof, LineNo} | {error, Error_description, Endline}
+%% For more information, see manual page for yecc (and its requirements on a
+%% tokenizer).
+%%--------------------------------------------------
+get_token(TokPid) ->
+ V = gen_server:call(TokPid, get_token, infinity),
+ %% io:format("tok:~w~n", [V]),
+ V.
+
+get_all_tokens(TokPid) ->
+ V = gen_server:call(TokPid, get_all_tokens, infinity),
+ %% io:format("tok:~w~n", [V]),
+ V.
+
+
+
+%%--------------------------------------------------
+%% Returns: {ok, Tokens, EndLine} | {error, Error_description, Endline}
+%% Comment: Tokeniser must be started since all options reside in
+%% the process dictionary of the tokeniser process.
+%%--------------------------------------------------
+tokenize(TokPid, String) ->
+ gen_server:call(TokPid, {tokenize, String}, infinity).
+
+stop(TokPid) ->
+ gen_server:call(TokPid,stop, infinity).
+
+%%----------------------------------------------------------------------
+%% Implementation
+%%----------------------------------------------------------------------
+insert_keywords_into_ets(_DB, []) -> done;
+insert_keywords_into_ets(DB, [Word | T]) ->
+ ets:insert(DB, {Word, reserved_word}),
+ insert_keywords_into_ets(DB, T).
+
+reserved_word(X) ->
+ case ets:lookup(get(db), X) of
+ [{X, reserved_word}] ->
+ true;
+ _ ->
+ false
+ end.
+
+%% If you only need to tokenize strings
+null_get_line() -> eof.
+
+format_error({Format, Data}) ->
+ io_lib:format(lists:append("Tokeniser error: ", Format), Data).
+
+test() ->
+ start_link(['AUGMENTS','BEGIN','CONTACT-INFO','DEFINITIONS','DEFVAL',
+ 'DESCRIPTION','DISPLAY-HINT','END','IDENTIFIER','IMPLIED',
+ 'INDEX','INTEGER','LAST-UPDATED','MAX-ACCESS','MODULE-IDENTITY',
+ 'NOTIFICATION-TYPE','OBJECT','OBJECT-IDENTITY','OBJECT-TYPE',
+ 'OBJECTS','ORGANIZATION','REFERENCE','REVISION',
+ 'SIZE','STATUS','SYNTAX','TEXTUAL-CONVENTION','UNITS',
+ 'current','deprecated','not-accessible','obsolete',
+ 'read-create','read-only','read-write', 'IMPORTS', 'FROM',
+ 'MODULE-COMPLIANCE',
+ 'DisplayString',
+ 'PhysAddress',
+ 'MacAddress',
+ 'TruthValue',
+ 'TestAndIncr',
+ 'AutonomousType',
+ 'InstancePointer',
+ 'VariablePointer',
+ 'RowPointer',
+ 'RowStatus',
+ 'TimeStamp',
+ 'TimeInterval',
+ 'DateAndTime',
+ 'StorageType',
+ 'TDomain',
+ 'TAddress'],
+ [{file, "modemmib.mib"}]).
+
+init({Reserved_words, Options, GetLineMFA}) ->
+ put(get_line_function,GetLineMFA),
+ put(print_lineno,
+ case lists:keysearch(print_lineno, 1, Options) of
+ {value, {print_lineno, L}} -> L;
+ false -> undefined
+ end),
+ DB = ets:new(reserved_words, [set, private]),
+ insert_keywords_into_ets(DB, Reserved_words),
+ put(db, DB),
+ put(line, 0),
+ {ok, ""}.
+
+getLine() ->
+ OldLine = put(line, 1 + get(line)),
+ {M,F,A} = get(get_line_function),
+ case get(print_lineno) of
+ undefined -> true;
+ X -> case OldLine rem X of
+ 0 -> io:format('~w..',[OldLine]);
+ _ -> true
+ end
+ end,
+ apply(M,F,A).
+
+%% You can only do this when no file is open.
+handle_call({tokenizeString, String}, _From, "") ->
+ {reply, safe_tokenize_whole_string(String), ""};
+
+handle_call(get_token, _From, String) ->
+ {ReplyToken, RestChars} = safe_tokenise(String),
+ {reply, ReplyToken, RestChars};
+
+handle_call(get_all_tokens, _From, String) ->
+ Toks = get_all_tokens(String,[]),
+ {reply, Toks, []};
+
+
+handle_call(stop, _From, String) ->
+ {stop, normal, ok, String}.
+
+terminate(_Reason, _State) ->
+ ok.
+
+%% ErrorInfo = {ErrorLine, Module, ErrorDescriptor}
+%% will be used as
+%% apply(Module, format_error, [ErrorDescriptor]). shall return a string.
+
+%% Returns a reply
+tokenize_whole_string(eof) -> [];
+tokenize_whole_string(String) ->
+ {Token, RestChars} = tokenise(String),
+ [Token | tokenize_whole_string(RestChars)].
+
+safe_tokenize_whole_string(String) ->
+ case catch tokenize_whole_string(String) of
+ {error, ErrorInfo} -> {error, ErrorInfo, get(line)};
+ Tokens -> {ok, Tokens, get(line)}
+ end.
+
+%% throw({error, {get(line), ?MODULE, "Unexpected eof~n"}}).
+
+%% Returns: {ReplyToken, NewState}
+safe_tokenise(eof) -> {{eof, get(line)}, eof};
+safe_tokenise(Chars) when is_list(Chars) ->
+ case catch tokenise(Chars) of
+ {error, ErrorInfo} -> {{error, ErrorInfo, get(line)}, {[], eof}};
+ {Token, RestChars} when is_tuple(Token) ->
+ {{ok, [Token], get(line)}, RestChars}
+ end.
+
+get_all_tokens(eof,Toks) ->
+ lists:reverse(Toks);
+get_all_tokens(Str,Toks) ->
+ case catch tokenise(Str) of
+ {error, ErrorInfo} -> {error, ErrorInfo};
+ {Token, RestChars} when is_tuple(Token) ->
+ get_all_tokens(RestChars, [Token|Toks])
+ end.
+
+
+
+%%--------------------------------------------------
+%% Returns: {Token, Rest}
+%%--------------------------------------------------
+tokenise([H|T]) when ($a =< H) andalso (H =< $z) ->
+ get_name(atom, [H], T);
+
+tokenise([H|T]) when ($A =< H) andalso (H =< $Z) ->
+ get_name(variable, [H], T);
+
+tokenise([$:,$:,$=|T]) ->
+ {{'::=', get(line)}, T};
+
+tokenise([$-,$-|T]) ->
+ tokenise(skip_comment(T));
+
+tokenise([$-,H|T]) when ($0 =< H ) andalso (H =< $9) ->
+ {Val, Rest} = get_integer(T, [H]),
+ {{integer, get(line), -1 * Val}, Rest};
+
+tokenise([H|T]) when ($0 =< H) andalso (H =< $9) ->
+ {Val, Rest} = get_integer(T, [H]),
+ {{integer, get(line), Val}, Rest};
+
+tokenise([$"|T]) ->
+ collect_string($", T, []);
+
+tokenise([$'|T]) ->
+ collect_string($', T, []);
+
+%% Read away white spaces
+tokenise([9| T]) -> tokenise(T);
+tokenise([10| T]) -> tokenise(T);
+tokenise([13| T]) -> tokenise(T);
+tokenise([32| T]) -> tokenise(T);
+
+%% Handle singe characters like { } [ ] + = ...
+tokenise([Ch | T]) ->
+ Atm = list_to_atom([Ch]),
+ {{Atm, get(line)}, T};
+
+tokenise([]) ->
+ tokenise(getLine());
+
+tokenise(eof) ->
+ {{'$end', get(line)}, eof}.
+
+collect_string($", [$"|T],BackwardsStr) ->
+ {{string, get(line), BackwardsStr}, T};
+
+collect_string($', [$'|T],BackwardsStr) ->
+ {{quote, get(line), BackwardsStr}, T};
+
+collect_string(StopChar, [Ch|T], Str) ->
+ collect_string(StopChar,T,[Ch|Str]);
+
+collect_string(StopChar, [],Str) ->
+ collect_string(StopChar, getLine(), Str);
+
+collect_string(StopChar, eof, Str) ->
+ throw({error, {get(line), ?MODULE,
+ {"Missing ~s in string:~n \"~s\"~n",
+ [[StopChar], lists:reverse(Str)]}}}).
+
+get_name(Category, Name, [Char|T]) ->
+ case isInName(Char) of
+ true ->
+ get_name(Category, [Char|Name], T);
+ false ->
+ makeNameRespons(Category, Name, [Char | T])
+ end;
+get_name(Category, Name, []) ->
+ makeNameRespons(Category, Name, []).
+
+makeNameRespons(Category, Name, RestChars) ->
+ Atm = list_to_atom(lists:reverse(Name)),
+ case reserved_word(Atm) of
+ true -> {{Atm, get(line)}, RestChars};
+ false -> {{Category, get(line), Atm}, RestChars}
+ end.
+
+isInName($-) -> true;
+isInName(Ch) -> isalnum(Ch).
+
+isalnum(H) when ($A =< H) andalso (H =< $Z) ->
+ true;
+isalnum(H) when ($a =< H) andalso (H =< $z) ->
+ true;
+isalnum(H) when ($0 =< H) andalso (H =< $9) ->
+ true;
+isalnum(_) ->
+ false.
+
+isdigit(H) when ($0 =< H) andalso (H =< $9) ->
+ true;
+isdigit(_) ->
+ false.
+
+get_integer([H|T], "0") ->
+ case isdigit(H) of
+ true ->
+ throw({error, {get(line), ?MODULE,
+ {"Unexpected ~w~n",
+ [list_to_atom([H])]}}});
+ false ->
+ {0, [H|T]}
+ end;
+get_integer([H|T], L) ->
+ case isdigit(H) of
+ true ->
+ get_integer(T, [H|L]);
+ false ->
+ {list_to_integer(lists:reverse(L)), [H|T]}
+ end;
+get_integer([], L) ->
+ {list_to_integer(lists:reverse(L)), []}.
+
+%%--------------------------------------------------
+%% ASN.1 type of comments. "--" is comment to eoln or next "--"
+%%--------------------------------------------------
+skip_comment([]) ->
+ [];
+skip_comment([$-,$-|T]) ->
+ T;
+skip_comment([_|T]) ->
+ skip_comment(T).
diff --git a/lib/snmp/src/manager/Makefile b/lib/snmp/src/manager/Makefile
new file mode 100644
index 0000000000..c1d5703300
--- /dev/null
+++ b/lib/snmp/src/manager/Makefile
@@ -0,0 +1,124 @@
+#-*-makefile-*- ; force emacs to enter makefile-mode
+
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2004-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%
+
+include $(ERL_TOP)/make/target.mk
+
+EBIN = ../../ebin
+
+include $(ERL_TOP)/make/$(TARGET)/otp.mk
+
+# ----------------------------------------------------
+# Application version
+# ----------------------------------------------------
+include ../../vsn.mk
+
+VSN = $(SNMP_VSN)
+
+# ----------------------------------------------------
+# Release directory specification
+# ----------------------------------------------------
+RELSYSDIR = $(RELEASE_PATH)/lib/snmp-$(VSN)
+
+
+# ----------------------------------------------------
+# Target Specs
+# ----------------------------------------------------
+
+include modules.mk
+
+ERL_FILES = $(MODULES:%=%.erl)
+
+HRL_FILES = $(INTERNAL_HRL_FILES:%=%.hrl)
+
+TARGET_FILES = $(MODULES:%=$(EBIN)/%.$(EMULATOR))
+
+
+# ----------------------------------------------------
+# SNMP FLAGS
+# ----------------------------------------------------
+ifeq ($(SNMP_DEFAULT_VERBOSITY),)
+ SNMP_FLAGS = -Ddefault_verbosity=silence
+else
+ SNMP_FLAGS = -Ddefault_verbosity=$(SNMP_DEFAULT_VERBOSITY)
+endif
+
+ifeq ($(SNMP_DEBUG),d)
+ SNMP_FLAGS += -Dsnmp_debug
+endif
+
+
+# ----------------------------------------------------
+# FLAGS
+# ----------------------------------------------------
+
+ERL_COMPILE_FLAGS += -pa $(ERL_TOP)/lib/snmp/ebin
+
+ifeq ($(WARN_UNUSED_VARS),true)
+ERL_COMPILE_FLAGS += +warn_unused_vars
+endif
+
+ERL_COMPILE_FLAGS += -I../../include \
+ -I../misc \
+ -Dversion=\"$(VSN)$(PRE_VSN)\" \
+ +'{parse_transform,sys_pre_attributes}' \
+ +'{attribute,insert,app_vsn,$(APP_VSN)}' \
+ -I$(ERL_TOP)/lib/stdlib \
+ $(SNMP_FLAGS)
+
+
+# ----------------------------------------------------
+# Targets
+# ----------------------------------------------------
+
+debug:
+ @$(MAKE) TYPE=debug opt
+
+opt: $(TARGET_FILES)
+
+
+clean:
+ rm -f $(TARGET_FILES)
+ rm -f core *~
+
+docs:
+
+info:
+ @echo "ERL_FILES: $(ERL_FILES)"
+ @echo "HRL_FILES: $(HRL_FILES)"
+ @echo "TARGET_FILES: $(TARGET_FILES)"
+ @echo ""
+
+
+# ----------------------------------------------------
+# Release Target
+# ----------------------------------------------------
+include $(ERL_TOP)/make/otp_release_targets.mk
+
+release_spec: opt
+ $(INSTALL_DIR) $(RELSYSDIR)/src
+ $(INSTALL_DIR) $(RELSYSDIR)/src/manager
+ $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) $(RELSYSDIR)/src/manager
+ $(INSTALL_DIR) $(RELSYSDIR)/ebin
+ $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin
+# $(INSTALL_DIR) $(RELSYSDIR)/include
+# $(INSTALL_DATA) $(EXT_HRL_FILES) $(RELSYSDIR)/include
+
+release_docs_spec:
+
+include depend.mk
diff --git a/lib/snmp/src/manager/depend.mk b/lib/snmp/src/manager/depend.mk
new file mode 100644
index 0000000000..0e7e9e3df7
--- /dev/null
+++ b/lib/snmp/src/manager/depend.mk
@@ -0,0 +1,75 @@
+#-*-makefile-*- ; force emacs to enter makefile-mode
+
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2004-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%
+
+$(EBIN)/snmpm_user.$(EMULATOR): \
+ snmpm_user.erl
+
+$(EBIN)/snmpm_network_interface.$(EMULATOR): \
+ snmpm_network_interface.erl
+
+$(EBIN)/snmpm.$(EMULATOR): \
+ snmpm.erl
+
+$(EBIN)/snmpm_config.$(EMULATOR): \
+ snmpm_config.erl \
+ ../../include/snmp_types.hrl \
+ ../misc/snmp_verbosity.hrl
+
+$(EBIN)/snmpm_mpd.$(EMULATOR): \
+ snmpm_mpd.erl \
+ ../../include/snmp_types.hrl \
+ ../../include/SNMP-MPD-MIB.hrl \
+ ../../include/SNMPv2-TM.hrl \
+ ../misc/snmp_verbosity.hrl
+
+$(EBIN)/snmpm_misc_sup.$(EMULATOR): \
+ snmpm_misc_sup.erl \
+ ../misc/snmp_debug.hrl
+
+$(EBIN)/snmpm_net_if.$(EMULATOR): \
+ ../../include/snmp_types.hrl \
+ ../misc/snmp_debug.hrl \
+ ../misc/snmp_verbosity.hrl \
+ snmpm_net_if.erl \
+ snmpm_network_interface.erl
+
+$(EBIN)/snmpm_server.$(EMULATOR): \
+ ../../include/snmp_types.hrl \
+ ../../include/STANDARD-MIB.hrl \
+ ../misc/snmp_verbosity.hrl \
+ snmpm_server.erl
+
+$(EBIN)/snmpm_server_sup.$(EMULATOR): \
+ snmpm_server_sup.erl
+
+$(EBIN)/snmpm_supervisor.$(EMULATOR): \
+ snmpm_supervisor.erl
+
+$(EBIN)/snmpm_user_default.$(EMULATOR): \
+ snmpm_user_default.erl \
+ snmpm_user.erl
+
+$(EBIN)/snmpm_usm.$(EMULATOR): \
+ snmpm_usm.erl \
+ snmpm_usm.hrl \
+ ../../include/snmp_types.hrl \
+ ../../include/SNMP-USER-BASED-SM-MIB.hrl \
+ ../misc/snmp_verbosity.hrl
+
+
diff --git a/lib/snmp/src/manager/modules.mk b/lib/snmp/src/manager/modules.mk
new file mode 100644
index 0000000000..79f3dd65d9
--- /dev/null
+++ b/lib/snmp/src/manager/modules.mk
@@ -0,0 +1,45 @@
+#-*-makefile-*- ; force emacs to enter makefile-mode
+
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2004-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%
+
+BEHAVIOUR_MODULES = \
+ snmpm_user \
+ snmpm_user_old \
+ snmpm_network_interface \
+ snmpm_network_interface_filter
+
+MODULES = \
+ $(BEHAVIOUR_MODULES) \
+ snmpm \
+ snmpm_conf \
+ snmpm_config \
+ snmpm_mpd \
+ snmpm_misc_sup \
+ snmpm_net_if \
+ snmpm_net_if_filter \
+ snmpm_server \
+ snmpm_server_sup \
+ snmpm_supervisor \
+ snmpm_user_default \
+ snmpm_usm
+
+INTERNAL_HRL_FILES = \
+ snmpm_usm \
+ snmpm_atl \
+ snmpm_internal
+
diff --git a/lib/snmp/src/manager/snmpm.erl b/lib/snmp/src/manager/snmpm.erl
new file mode 100644
index 0000000000..141addf440
--- /dev/null
+++ b/lib/snmp/src/manager/snmpm.erl
@@ -0,0 +1,1528 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2004-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%
+%%
+
+-module(snmpm).
+
+%%----------------------------------------------------------------------
+%% This module implements a simple SNMP manager for Erlang.
+%%----------------------------------------------------------------------
+
+%% User interface
+-export([
+ %%
+ %% Management API
+ start/0, start/1,
+ start_link/0, start_link/1,
+ stop/0,
+
+ monitor/0, demonitor/1,
+ notify_started/1, cancel_notify_started/1,
+
+ backup/1,
+
+ load_mib/1, unload_mib/1,
+ which_mibs/0,
+ name_to_oid/1, oid_to_name/1, oid_to_type/1,
+
+ register_user/3, register_user/4,
+ register_user_monitor/3, register_user_monitor/4,
+ unregister_user/1,
+ which_users/0,
+
+ register_agent/2, register_agent/3, register_agent/4,
+ unregister_agent/2, unregister_agent/3,
+ which_agents/0, which_agents/1,
+ agent_info/2, update_agent_info/4,
+
+ register_usm_user/3, unregister_usm_user/2,
+ which_usm_users/0, which_usm_users/1,
+ usm_user_info/3, update_usm_user_info/4,
+
+ %%
+ %% Basic SNMP API
+ sync_get/3, sync_get/4, sync_get/5, sync_get/6,
+ async_get/3, async_get/4, async_get/5, async_get/6,
+ sync_get_next/3, sync_get_next/4, sync_get_next/5, sync_get_next/6,
+ async_get_next/3, async_get_next/4, async_get_next/5, async_get_next/6,
+ sync_set/3, sync_set/4, sync_set/5, sync_set/6,
+ async_set/3, async_set/4, async_set/5, async_set/6,
+ sync_get_bulk/5, sync_get_bulk/6, sync_get_bulk/7, sync_get_bulk/8,
+ async_get_bulk/5, async_get_bulk/6, async_get_bulk/7, async_get_bulk/8,
+ cancel_async_request/2,
+
+ %%
+ %% Extended SNMP API
+ %% discovery/2, discovery/3, discovery/4, discovery/5, discovery/6,
+
+ %%
+ %% Logging
+ log_to_txt/2, log_to_txt/3, log_to_txt/4,
+ log_to_txt/5, log_to_txt/6, log_to_txt/7,
+ change_log_size/1,
+ get_log_type/0,
+ set_log_type/1,
+
+ reconfigure/0,
+
+ system_start_time/0,
+ sys_up_time/0,
+
+ info/0,
+ verbosity/2
+ ]).
+
+-export([format_reason/1, format_reason/2]).
+
+%% Backward compatibillity exports
+-export([
+ agent_info/3, update_agent_info/5,
+ g/3, g/4, g/5, g/6, g/7,
+ ag/3, ag/4, ag/5, ag/6, ag/7,
+ gn/3, gn/4, gn/5, gn/6, gn/7,
+ agn/3, agn/4, agn/5, agn/6, agn/7,
+ gb/5, gb/6, gb/7, gb/8, gb/9,
+ agb/5, agb/6, agb/7, agb/8, agb/9,
+ s/3, s/4, s/5, s/6, s/7,
+ as/3, as/4, as/5, as/6, as/7
+ ]).
+
+%% Application internal export
+-export([start_link/3, snmpm_start_verify/2, snmpm_start_verify/3]).
+
+
+-include("snmp_debug.hrl").
+-include("snmpm_atl.hrl").
+-include("snmp_types.hrl").
+
+-define(DEFAULT_AGENT_PORT, 161).
+-define(DEFAULT_CONTEXT, "").
+
+
+%% This function is called when the snmp application
+%% starts.
+start_link(Opts, normal, []) ->
+ start_link(Opts).
+
+
+simple_conf() ->
+ Vsns = [v1, v2, v3],
+ {ok, Cwd} = file:get_cwd(),
+ %% Check if the manager config file exist, if not create it
+ MgrConf = filename:join(Cwd, "manager.conf"),
+ case file:read_file_info(MgrConf) of
+ {ok, _} ->
+ ok;
+ _ ->
+ ok = snmp_config:write_manager_config(Cwd, "",
+ [{port, 5000},
+ {engine_id, "mgrEngine"},
+ {max_message_size, 484}])
+ end,
+ Conf = [{dir, Cwd}, {db_dir, Cwd}],
+ [{versions, Vsns}, {config, Conf}].
+
+%% Simple start. Start a manager with default values.
+start_link() ->
+ start_link(simple_conf()).
+
+%% This function is normally not used. Instead the manager is
+%% started as a consequence of a call to application:start(snmp)
+%% when {snmp, [{manager, Options}]} is present in the
+%% node config file.
+start_link(Opts) ->
+ %% This start the manager top supervisor, which in turn
+ %% starts the other processes.
+ {ok, _} = snmpm_supervisor:start_link(normal, Opts),
+ ok.
+
+%% Simple start. Start a manager with default values.
+start() ->
+ start(simple_conf()).
+
+start(Opts) ->
+ %% This start the manager top supervisor, which in turn
+ %% starts the other processes.
+ {ok, Pid} = snmpm_supervisor:start_link(normal, Opts),
+ unlink(Pid),
+ ok.
+
+stop() ->
+ snmpm_supervisor:stop().
+
+
+monitor() ->
+ erlang:monitor(process, snmpm_supervisor).
+
+demonitor(Ref) ->
+ erlang:demonitor(Ref).
+
+
+-define(NOTIFY_START_TICK_TIME, 500).
+
+notify_started(To) when is_integer(To) andalso (To > 0) ->
+ spawn_link(?MODULE, snmpm_start_verify, [self(), To]).
+
+cancel_notify_started(Pid) ->
+ Pid ! {cancel, self()},
+ ok.
+
+snmpm_start_verify(Parent, To) ->
+ ?d("starting", []),
+ snmpm_start_verify(Parent, monitor(), To).
+
+snmpm_start_verify(Parent, _Ref, To) when (To =< 0) ->
+ ?d("timeout", []),
+ unlink(Parent),
+ Parent ! {snmpm_start_timeout, self()};
+snmpm_start_verify(Parent, Ref, To) ->
+ T0 = t(),
+ receive
+ {cancel, Parent} ->
+ ?d("cancel", []),
+ demonitor(Ref),
+ unlink(Parent),
+ exit(normal);
+ {'EXIT', Parent, _} ->
+ exit(normal);
+ {'DOWN', Ref, process, _Object, _Info} ->
+ ?d("down", []),
+ sleep(?NOTIFY_START_TICK_TIME),
+ ?MODULE:snmpm_start_verify(Parent, monitor(), t(T0, To))
+ after ?NOTIFY_START_TICK_TIME ->
+ ?d("down timeout", []),
+ demonitor(Ref),
+ case snmpm_server:is_started() of
+ true ->
+ unlink(Parent),
+ Parent ! {snmpm_started, self()};
+ _ ->
+ ?MODULE:snmpm_start_verify(Parent, monitor(), t(T0, To))
+ end
+ end.
+
+t(T0, T) -> T - (t() - T0).
+t() -> snmp_misc:now(ms).
+sleep(To) -> snmp_misc:sleep(To).
+
+
+%% -- Misc --
+
+backup(BackupDir) ->
+ snmpm_config:backup(BackupDir).
+
+
+%% -- Mibs --
+
+%% Load a mib into the manager
+load_mib(MibFile) ->
+ snmpm_server:load_mib(MibFile).
+
+%% Unload a mib from the manager
+unload_mib(Mib) ->
+ snmpm_server:unload_mib(Mib).
+
+%% Which mib's are loaded
+which_mibs() ->
+ snmpm_config:which_mibs().
+
+%% Get all the possible oid's for the aliasname
+name_to_oid(Name) ->
+ snmpm_config:name_to_oid(Name).
+
+%% Get the aliasname for an oid
+oid_to_name(Oid) ->
+ snmpm_config:oid_to_name(Oid).
+
+%% Get the type for an oid
+oid_to_type(Oid) ->
+ snmpm_config:oid_to_type(Oid).
+
+
+%% -- Info --
+
+info() ->
+ snmpm_server:info().
+
+
+%% -- Verbosity --
+
+%% Change the verbosity of a process in the manager
+verbosity(config, V) ->
+ snmpm_config:verbosity(V);
+verbosity(server, V) ->
+ snmpm_server:verbosity(V);
+verbosity(net_if, V) ->
+ snmpm_server:verbosity(net_if, V);
+verbosity(note_store, V) ->
+ snmpm_server:verbosity(note_store, V);
+verbosity(all, V) ->
+ snmpm_config:verbosity(V),
+ snmpm_server:verbosity(V),
+ snmpm_server:verbosity(net_if, V),
+ snmpm_server:verbosity(note_store, V).
+
+
+%% -- Users --
+
+%% Register the 'user'.
+%% The manager entity responsible for a specific agent.
+%% Module is the callback module (snmpm_user behaviour) which
+%% will be called whenever something happens (detected
+%% agent, incomming reply or incomming trap/notification).
+%% Note that this could have already been done as a
+%% consequence of the node config.
+register_user(Id, Module, Data) ->
+ register_user(Id, Module, Data, []).
+
+%% Default config for agents registered by this user
+register_user(Id, Module, Data, DefaultAgentConfig) ->
+ snmpm_server:register_user(Id, Module, Data, DefaultAgentConfig).
+
+register_user_monitor(Id, Module, Data) ->
+ register_user_monitor(Id, Module, Data, []).
+
+register_user_monitor(Id, Module, Data, DefaultAgentConfig) ->
+ snmpm_server:register_user_monitor(Id, Module, Data, DefaultAgentConfig).
+
+unregister_user(Id) ->
+ snmpm_server:unregister_user(Id).
+
+which_users() ->
+ snmpm_config:which_users().
+
+
+%% -- Agents --
+
+%% Explicitly instruct the manager to handle this agent.
+%% Called to instruct the manager that this agent
+%% shall be handled. These functions is used when
+%% the user know's in advance which agents the
+%% manager shall handle.
+%% Note that there is an alternate way to do the same thing:
+%% Add the agent to the manager config files.
+%%
+%% UserId -> Id of the user responsible for this agent: term()
+%% TargetName -> Unique name for the agent: (string())
+%% Config -> Agent configuration: [config()]
+
+do_register_agent(UserId, TargetName, Config) ->
+ snmpm_config:register_agent(UserId, TargetName, Config).
+
+register_agent(UserId, TargetName, Config)
+ when (is_list(TargetName) andalso
+ (length(TargetName) > 0) andalso
+ is_list(Config)) ->
+ do_register_agent(UserId, TargetName, [{reg_type, target_name} | Config]);
+
+%% Backward compatibillity
+%% Note that the agent engine id is a mandatory config option,
+%% so this function *will* fail!
+register_agent(UserId, Addr, Port) when is_integer(Port) ->
+ register_agent(UserId, Addr, Port, []);
+
+%% Backward compatibillity
+register_agent(UserId, Addr, Config) when is_list(Config) ->
+ register_agent(UserId, Addr, ?DEFAULT_AGENT_PORT, Config).
+
+%% Backward compatibillity
+%% Note that the agent engine id is a mandatory config option,
+%% so this function *will* fail!
+register_agent(UserId, Addr) ->
+ register_agent(UserId, Addr, ?DEFAULT_AGENT_PORT, []).
+
+%% Backward compatibillity
+register_agent(UserId, Addr, Port, Config0) ->
+ case lists:keymember(target_name, 1, Config0) of
+ false ->
+ TargetName = mk_target_name(Addr, Port, Config0),
+ Config = [{reg_type, addr_port},
+ {address, Addr}, {port, Port} | Config0],
+ do_register_agent(UserId, TargetName, ensure_engine_id(Config));
+ true ->
+ {value, {_, TargetName}} =
+ lists:keysearch(target_name, 1, Config0),
+ Config1 = lists:keydelete(target_name, 1, Config0),
+ Config2 = [{reg_type, addr_port},
+ {address, Addr}, {port, Port} | Config1],
+ register_agent(UserId, TargetName, ensure_engine_id(Config2))
+ end.
+
+unregister_agent(UserId, TargetName) when is_list(TargetName) ->
+ snmpm_config:unregister_agent(UserId, TargetName);
+
+%% Backward compatibillity functions
+unregister_agent(UserId, Addr) ->
+ unregister_agent(UserId, Addr, ?DEFAULT_AGENT_PORT).
+
+unregister_agent(UserId, Addr, Port) ->
+ case target_name(Addr, Port) of
+ {ok, TargetName} ->
+ unregister_agent(UserId, TargetName);
+ Error ->
+ Error
+ end.
+
+agent_info(TargetName, Item) ->
+ snmpm_config:agent_info(TargetName, Item).
+
+%% Backward compatibillity
+agent_info(Addr, Port, Item) ->
+ case target_name(Addr, Port) of
+ {ok, TargetName} ->
+ agent_info(TargetName, Item);
+ Error ->
+ Error
+ end.
+
+update_agent_info(UserId, TargetName, Item, Val) ->
+%% p("update_agent_info -> entry with"
+%% "~n UserId: ~p"
+%% "~n TargetName: ~p"
+%% "~n Item: ~p"
+%% "~n Val: ~p", [UserId, TargetName, Item, Val]),
+ snmpm_config:update_agent_info(UserId, TargetName, Item, Val).
+
+%% Backward compatibillity functions
+update_agent_info(UserId, Addr, Port, Item, Val) ->
+%% p("update_agent_info -> entry with"
+%% "~n UserId: ~p"
+%% "~n Addr: ~p"
+%% "~n Port: ~p"
+%% "~n Item: ~p"
+%% "~n Val: ~p", [UserId, Addr, Port, Item, Val]),
+ case target_name(Addr, Port) of
+ {ok, TargetName} ->
+%% p("update_agent_info -> TargetName: ~p", [TargetName]),
+ update_agent_info(UserId, TargetName, Item, Val);
+ Error ->
+ Error
+ end.
+
+which_agents() ->
+ snmpm_config:which_agents().
+
+which_agents(UserId) ->
+ snmpm_config:which_agents(UserId).
+
+
+%% -- USM users --
+
+register_usm_user(EngineID, UserName, Conf)
+ when is_list(EngineID) andalso is_list(UserName) andalso is_list(Conf) ->
+ snmpm_config:register_usm_user(EngineID, UserName, Conf).
+
+unregister_usm_user(EngineID, UserName)
+ when is_list(EngineID) andalso is_list(UserName) ->
+ snmpm_config:unregister_usm_user(EngineID, UserName).
+
+usm_user_info(EngineID, UserName, Item)
+ when is_list(EngineID) andalso is_list(UserName) andalso is_atom(Item) ->
+ snmpm_config:usm_user_info(EngineID, UserName, Item).
+
+update_usm_user_info(EngineID, UserName, Item, Val)
+ when is_list(EngineID) andalso is_list(UserName) andalso is_atom(Item) ->
+ snmpm_config:update_usm_user_info(EngineID, UserName, Item, Val).
+
+which_usm_users() ->
+ snmpm_config:which_usm_users().
+
+which_usm_users(EngineID) when is_list(EngineID) ->
+ snmpm_config:which_usm_users(EngineID).
+
+
+%% -- Discovery --
+
+%% Start a discovery process
+%% discovery(UserId, BAddr) ->
+%% snmpm_server:discovery(UserId, BAddr).
+
+%% discovery(UserId, BAddr, ExpireOrConfig) ->
+%% snmpm_server:discovery(UserId, BAddr, ExpireOrConfig).
+
+%% discovery(UserId, BAddr, Config, Expire) ->
+%% snmpm_server:discovery(UserId, BAddr, Config, Expire).
+
+%% discovery(UserId, BAddr, Port, Config, Expire) ->
+%% snmpm_server:discovery(UserId, BAddr, Port, Config, Expire).
+
+%% discovery(UserId, BAddr, Port, Config, Expire, ExtraInfo) ->
+%% snmpm_server:discovery(UserId, BAddr, Port, Config, Expire, ExtraInfo).
+
+
+%% -- Requests --
+
+%% --- synchroneous get-request ---
+%%
+
+sync_get(UserId, TargetName, Oids) ->
+%% p("sync_get -> entry with"
+%% "~n UserId: ~p"
+%% "~n TargetName: ~p"
+%% "~n Oids: ~p", [UserId, TargetName, Oids]),
+ sync_get(UserId, TargetName, ?DEFAULT_CONTEXT, Oids).
+
+sync_get(UserId, TargetName, Context, Oids) when is_list(Oids) ->
+%% p("sync_get -> entry with"
+%% "~n UserId: ~p"
+%% "~n TargetName: ~p"
+%% "~n Context: ~p"
+%% "~n Oids: ~p", [UserId, TargetName, Context, Oids]),
+ snmpm_server:sync_get(UserId, TargetName, Context, Oids);
+
+sync_get(UserId, TargetName, Oids, Timeout) when is_integer(Timeout) ->
+%% p("sync_get -> entry with"
+%% "~n UserId: ~p"
+%% "~n TargetName: ~p"
+%% "~n Oids: ~p"
+%% "~n Timeout: ~p", [UserId, TargetName, Oids, Timeout]),
+ sync_get(UserId, TargetName, ?DEFAULT_CONTEXT, Oids, Timeout).
+
+sync_get(UserId, TargetName, Context, Oids, Timeout) ->
+%% p("sync_get -> entry with"
+%% "~n UserId: ~p"
+%% "~n TargetName: ~p"
+%% "~n Context: ~p"
+%% "~n Oids: ~p"
+%% "~n Timeout: ~p", [UserId, TargetName, Context, Oids, Timeout]),
+ snmpm_server:sync_get(UserId, TargetName, Context, Oids, Timeout).
+
+sync_get(UserId, TargetName, Context, Oids, Timeout, ExtraInfo) ->
+%% p("sync_get -> entry with"
+%% "~n UserId: ~p"
+%% "~n TargetName: ~p"
+%% "~n Context: ~p"
+%% "~n Oids: ~p"
+%% "~n Timeout: ~p"
+%% "~n ExtraInfo: ~p",
+%% [UserId, TargetName, Context, Oids, Timeout, ExtraInfo]),
+ snmpm_server:sync_get(UserId, TargetName, Context, Oids, Timeout,
+ ExtraInfo).
+
+
+g(UserId, Addr, Oids) ->
+%% p("g -> entry with"
+%% "~n UserId: ~p"
+%% "~n Addr: ~p"
+%% "~n Oids: ~p", [UserId, Addr, Oids]),
+ g(UserId, Addr, ?DEFAULT_AGENT_PORT, Oids).
+
+g(UserId, Addr, CtxName, Oids) when is_list(CtxName) andalso is_list(Oids) ->
+%% p("g -> entry with"
+%% "~n UserId: ~p"
+%% "~n Addr: ~p"
+%% "~n CtxName: ~p"
+%% "~n Oids: ~p", [UserId, Addr, CtxName, Oids]),
+ g(UserId, Addr, ?DEFAULT_AGENT_PORT, CtxName, Oids);
+
+g(UserId, Addr, Port, Oids) when is_integer(Port) andalso is_list(Oids) ->
+%% p("g -> entry with"
+%% "~n UserId: ~p"
+%% "~n Addr: ~p"
+%% "~n Port: ~p"
+%% "~n Oids: ~p", [UserId, Addr, Port, Oids]),
+ g(UserId, Addr, Port, ?DEFAULT_CONTEXT, Oids);
+
+g(UserId, Addr, Oids, Timeout)
+ when is_list(Oids) andalso is_integer(Timeout) ->
+%% p("g -> entry with"
+%% "~n UserId: ~p"
+%% "~n Addr: ~p"
+%% "~n Oids: ~p"
+%% "~n Timeout: ~p", [UserId, Addr, Oids, Timeout]),
+ g(UserId, Addr, ?DEFAULT_AGENT_PORT, Oids, Timeout).
+
+g(UserId, Addr, Port, CtxName, Oids)
+ when is_integer(Port) andalso is_list(CtxName) andalso is_list(Oids) ->
+%% p("g -> entry with"
+%% "~n UserId: ~p"
+%% "~n Addr: ~p"
+%% "~n Port: ~p"
+%% "~n Context: ~p"
+%% "~n Oids: ~p", [UserId, Addr, Port, CtxName, Oids]),
+ case target_name(Addr, Port) of
+ {ok, TargetName} ->
+%% p("g -> TargetName: ~p", [TargetName]),
+ sync_get(UserId, TargetName, CtxName, Oids);
+ Error ->
+ Error
+ end;
+
+g(UserId, Addr, Port, Oids, Timeout)
+ when is_integer(Port) andalso is_list(Oids) andalso is_integer(Timeout) ->
+%% p("g -> entry with"
+%% "~n UserId: ~p"
+%% "~n Addr: ~p"
+%% "~n Oids: ~p"
+%% "~n Timeout: ~p",
+%% [UserId, Addr, Oids, Timeout]),
+ g(UserId, Addr, Port, ?DEFAULT_CONTEXT, Oids, Timeout);
+
+g(UserId, Addr, CtxName, Oids, Timeout)
+ when is_list(CtxName) andalso is_list(Oids) andalso is_integer(Timeout) ->
+%% p("g -> entry with"
+%% "~n UserId: ~p"
+%% "~n Addr: ~p"
+%% "~n CtxName: ~p"
+%% "~n Oids: ~p"
+%% "~n Timeout: ~p",
+%% [UserId, Addr, CtxName, Oids, Timeout]),
+ g(UserId, Addr, ?DEFAULT_AGENT_PORT, CtxName, Oids, Timeout).
+
+g(UserId, Addr, Port, CtxName, Oids, Timeout) ->
+%% p("g -> entry with"
+%% "~n UserId: ~p"
+%% "~n Addr: ~p"
+%% "~n Port: ~p"
+%% "~n CtxName: ~p"
+%% "~n Oids: ~p"
+%% "~n Timeout: ~p",
+%% [UserId, Addr, Port, CtxName, Oids, Timeout]),
+ case target_name(Addr, Port) of
+ {ok, TargetName} ->
+%% p("g -> TargetName: ~p", [TargetName]),
+ sync_get(UserId, TargetName, CtxName, Oids, Timeout);
+ Error ->
+ Error
+ end.
+
+g(UserId, Addr, Port, CtxName, Oids, Timeout, ExtraInfo) ->
+%% p("g -> entry with"
+%% "~n UserId: ~p"
+%% "~n Addr: ~p"
+%% "~n Port: ~p"
+%% "~n CtxName: ~p"
+%% "~n Oids: ~p"
+%% "~n Timeout: ~p"
+%% "~n ExtraInfo: ~p",
+%% [UserId, Addr, Port, CtxName, Oids, Timeout, ExtraInfo]),
+ case target_name(Addr, Port) of
+ {ok, TargetName} ->
+%% p("g -> TargetName: ~p", [TargetName]),
+ sync_get(UserId, TargetName, CtxName, Oids, Timeout, ExtraInfo);
+ Error ->
+ Error
+ end.
+
+
+
+%% --- asynchroneous get-request ---
+%%
+%% The reply will be delivered to the user
+%% through a call to handle_pdu/5
+%%
+
+async_get(UserId, TargetName, Oids) ->
+ async_get(UserId, TargetName, ?DEFAULT_CONTEXT, Oids).
+
+async_get(UserId, TargetName, Context, Oids) when is_list(Oids) ->
+ snmpm_server:async_get(UserId, TargetName, Context, Oids);
+
+async_get(UserId, TargetName, Oids, Expire) when is_integer(Expire) ->
+ async_get(UserId, TargetName, ?DEFAULT_CONTEXT, Oids, Expire).
+
+async_get(UserId, TargetName, Context, Oids, Expire) ->
+ snmpm_server:async_get(UserId, TargetName, Context, Oids, Expire).
+
+async_get(UserId, TargetName, Context, Oids, Expire, ExtraInfo) ->
+ snmpm_server:async_get(UserId, TargetName, Context, Oids, Expire,
+ ExtraInfo).
+
+
+ag(UserId, Addr, Oids) ->
+ ag(UserId, Addr, ?DEFAULT_AGENT_PORT, Oids).
+
+ag(UserId, Addr, Port, Oids) when is_integer(Port) andalso is_list(Oids) ->
+ ag(UserId, Addr, Port, ?DEFAULT_CONTEXT, Oids);
+
+ag(UserId, Addr, CtxName, Oids) when is_list(CtxName) andalso is_list(Oids) ->
+ ag(UserId, Addr, ?DEFAULT_AGENT_PORT, CtxName, Oids);
+
+ag(UserId, Addr, Oids, Expire) when is_list(Oids) andalso is_integer(Expire) ->
+ ag(UserId, Addr, ?DEFAULT_AGENT_PORT, ?DEFAULT_CONTEXT, Oids, Expire).
+
+ag(UserId, Addr, Port, CtxName, Oids)
+ when is_integer(Port) andalso is_list(CtxName) andalso is_list(Oids) ->
+ case target_name(Addr, Port) of
+ {ok, TargetName} ->
+ async_get(UserId, TargetName, CtxName, Oids);
+ Error ->
+ Error
+ end;
+
+ag(UserId, Addr, Port, Oids, Expire)
+ when is_integer(Port) andalso is_list(Oids) andalso is_integer(Expire) ->
+ ag(UserId, Addr, Port, ?DEFAULT_CONTEXT, Oids, Expire);
+
+ag(UserId, Addr, CtxName, Oids, Expire)
+ when is_list(CtxName) andalso is_list(Oids) andalso is_integer(Expire) ->
+ ag(UserId, Addr, ?DEFAULT_AGENT_PORT, CtxName, Oids, Expire).
+
+ag(UserId, Addr, Port, CtxName, Oids, Expire) ->
+ case target_name(Addr, Port) of
+ {ok, TargetName} ->
+ async_get(UserId, TargetName, CtxName, Oids, Expire);
+ Error ->
+ Error
+ end.
+
+ag(UserId, Addr, Port, CtxName, Oids, Expire, ExtraInfo) ->
+ case target_name(Addr, Port) of
+ {ok, TargetName} ->
+ async_get(UserId, TargetName, CtxName, Oids, Expire, ExtraInfo);
+ Error ->
+ Error
+ end.
+
+
+
+%% --- synchroneous get_next-request ---
+%%
+
+sync_get_next(UserId, TargetName, Oids) ->
+ sync_get_next(UserId, TargetName, ?DEFAULT_CONTEXT, Oids).
+
+sync_get_next(UserId, TargetName, Context, Oids)
+ when is_list(Context) andalso is_list(Oids) ->
+ snmpm_server:sync_get_next(UserId, TargetName, Context, Oids);
+
+sync_get_next(UserId, TargetName, Oids, Timeout)
+ when is_list(Oids) andalso is_integer(Timeout) ->
+ sync_get_next(UserId, TargetName, ?DEFAULT_CONTEXT, Oids, Timeout).
+
+sync_get_next(UserId, TargetName, Context, Oids, Timeout) ->
+ snmpm_server:sync_get_next(UserId, TargetName, Context, Oids, Timeout).
+
+sync_get_next(UserId, TargetName, Context, Oids, Timeout, ExtraInfo) ->
+ snmpm_server:sync_get_next(UserId, TargetName, Context, Oids, Timeout,
+ ExtraInfo).
+
+
+gn(UserId, Addr, Oids) ->
+ gn(UserId, Addr, ?DEFAULT_AGENT_PORT, Oids).
+
+gn(UserId, Addr, CtxName, Oids) when is_list(CtxName) andalso is_list(Oids) ->
+ gn(UserId, Addr, ?DEFAULT_AGENT_PORT, CtxName, Oids);
+
+gn(UserId, Addr, Port, Oids) when is_integer(Port) andalso is_list(Oids) ->
+ gn(UserId, Addr, Port, ?DEFAULT_CONTEXT, Oids);
+
+gn(UserId, Addr, Oids, Timeout)
+ when is_list(Oids) andalso is_integer(Timeout) ->
+ gn(UserId, Addr, ?DEFAULT_AGENT_PORT, Oids, Timeout).
+
+gn(UserId, Addr, Port, CtxName, Oids)
+ when is_integer(Port) andalso is_list(CtxName) andalso is_list(Oids) ->
+ case target_name(Addr, Port) of
+ {ok, TargetName} ->
+ sync_get_next(UserId, TargetName, CtxName, Oids);
+ Error ->
+ Error
+ end;
+
+gn(UserId, Addr, Port, Oids, Timeout)
+ when is_integer(Port) andalso is_list(Oids) andalso is_integer(Timeout) ->
+ gn(UserId, Addr, Port, ?DEFAULT_CONTEXT, Oids, Timeout);
+gn(UserId, Addr, CtxName, Oids, Timeout)
+ when is_list(CtxName) andalso is_list(Oids) andalso is_integer(Timeout) ->
+ gn(UserId, Addr, ?DEFAULT_AGENT_PORT, CtxName, Oids, Timeout).
+
+gn(UserId, Addr, Port, CtxName, Oids, Timeout) ->
+ case target_name(Addr, Port) of
+ {ok, TargetName} ->
+ sync_get_next(UserId, TargetName, CtxName, Oids, Timeout);
+ Error ->
+ Error
+ end.
+
+gn(UserId, Addr, Port, CtxName, Oids, Timeout, ExtraInfo) ->
+ case target_name(Addr, Port) of
+ {ok, TargetName} ->
+ sync_get_next(UserId, TargetName, CtxName, Oids, Timeout, ExtraInfo);
+ Error ->
+ Error
+ end.
+
+
+
+%% --- asynchroneous get_next-request ---
+%%
+
+async_get_next(UserId, TargetName, Oids) ->
+ async_get_next(UserId, TargetName, ?DEFAULT_CONTEXT, Oids).
+
+async_get_next(UserId, TargetName, Context, Oids)
+ when is_list(Context) andalso is_list(Oids) ->
+ snmpm_server:async_get_next(UserId, TargetName, Context, Oids);
+
+async_get_next(UserId, TargetName, Oids, Timeout)
+ when is_list(Oids) andalso is_integer(Timeout) ->
+ async_get_next(UserId, TargetName, ?DEFAULT_CONTEXT, Oids, Timeout).
+
+async_get_next(UserId, TargetName, Context, Oids, Timeout) ->
+ snmpm_server:async_get_next(UserId, TargetName, Context, Oids, Timeout).
+
+async_get_next(UserId, TargetName, Context, Oids, Timeout, ExtraInfo) ->
+ snmpm_server:async_get_next(UserId, TargetName, Context, Oids, Timeout,
+ ExtraInfo).
+
+agn(UserId, Addr, Oids) ->
+ agn(UserId, Addr, ?DEFAULT_AGENT_PORT, Oids).
+
+agn(UserId, Addr, CtxName, Oids) when is_list(CtxName) andalso is_list(Oids) ->
+ agn(UserId, Addr, ?DEFAULT_AGENT_PORT, CtxName, Oids);
+
+agn(UserId, Addr, Port, Oids) when is_integer(Port) andalso is_list(Oids) ->
+ agn(UserId, Addr, Port, ?DEFAULT_CONTEXT, Oids);
+
+agn(UserId, Addr, Oids, Expire)
+ when is_list(Oids) andalso is_integer(Expire) ->
+ agn(UserId, Addr, ?DEFAULT_AGENT_PORT, Oids, Expire).
+
+agn(UserId, Addr, Port, CtxName, Oids)
+ when is_integer(Port) andalso is_list(CtxName) andalso is_list(Oids) ->
+ case target_name(Addr, Port) of
+ {ok, TargetName} ->
+ async_get_next(UserId, TargetName, CtxName, Oids);
+ Error ->
+ Error
+ end;
+
+agn(UserId, Addr, Port, Oids, Expire)
+ when is_integer(Port) andalso is_list(Oids) andalso is_integer(Expire) ->
+ agn(UserId, Addr, Port, ?DEFAULT_CONTEXT, Oids, Expire);
+agn(UserId, Addr, CtxName, Oids, Expire)
+ when is_list(CtxName) andalso is_list(CtxName) andalso is_integer(Expire) ->
+ agn(UserId, Addr, ?DEFAULT_AGENT_PORT, CtxName, Oids, Expire).
+
+agn(UserId, Addr, Port, CtxName, Oids, Expire) ->
+ case target_name(Addr, Port) of
+ {ok, TargetName} ->
+ async_get_next(UserId, TargetName, CtxName, Oids, Expire);
+ Error ->
+ Error
+ end.
+
+agn(UserId, Addr, Port, CtxName, Oids, Expire, ExtraInfo) ->
+ case target_name(Addr, Port) of
+ {ok, TargetName} ->
+ async_get_next(UserId, TargetName, CtxName, Oids, Expire,
+ ExtraInfo);
+ Error ->
+ Error
+ end.
+
+
+
+%% --- synchroneous set-request ---
+%%
+
+sync_set(UserId, TargetName, VarsAndVals) ->
+ sync_set(UserId, TargetName, ?DEFAULT_CONTEXT, VarsAndVals).
+
+sync_set(UserId, TargetName, Context, VarsAndVals)
+ when is_list(Context) andalso is_list(VarsAndVals) ->
+ snmpm_server:sync_set(UserId, TargetName, Context, VarsAndVals);
+
+sync_set(UserId, TargetName, VarsAndVals, Timeout)
+ when is_list(VarsAndVals) andalso is_integer(Timeout) ->
+ sync_set(UserId, TargetName, ?DEFAULT_CONTEXT, VarsAndVals, Timeout).
+
+sync_set(UserId, TargetName, Context, VarsAndVals, Timeout) ->
+ snmpm_server:sync_set(UserId, TargetName, Context, VarsAndVals, Timeout).
+
+sync_set(UserId, TargetName, Context, VarsAndVals, Timeout, ExtraInfo) ->
+ snmpm_server:sync_set(UserId, TargetName, Context, VarsAndVals, Timeout,
+ ExtraInfo).
+
+
+s(UserId, Addr, VarsAndVals) ->
+ s(UserId, Addr, ?DEFAULT_AGENT_PORT, VarsAndVals).
+
+s(UserId, Addr, Port, VarsAndVals)
+ when is_integer(Port) andalso is_list(VarsAndVals) ->
+ s(UserId, Addr, Port, ?DEFAULT_CONTEXT, VarsAndVals);
+
+s(UserId, Addr, CtxName, VarsAndVals)
+ when is_list(CtxName) andalso is_list(VarsAndVals) ->
+ s(UserId, Addr, ?DEFAULT_AGENT_PORT, CtxName, VarsAndVals);
+
+s(UserId, Addr, VarsAndVals, Timeout)
+ when is_list(VarsAndVals) andalso is_integer(Timeout) ->
+ s(UserId, Addr, ?DEFAULT_AGENT_PORT, VarsAndVals, Timeout).
+
+s(UserId, Addr, Port, CtxName, VarsAndVals)
+ when is_integer(Port) andalso
+ is_list(CtxName) andalso
+ is_list(VarsAndVals) ->
+ case target_name(Addr, Port) of
+ {ok, TargetName} ->
+ sync_set(UserId, TargetName, CtxName, VarsAndVals);
+ Error ->
+ Error
+ end;
+
+s(UserId, Addr, Port, VarsAndVals, Timeout)
+ when is_integer(Port) andalso
+ is_list(VarsAndVals) andalso
+ is_integer(Timeout) ->
+ s(UserId, Addr, Port, ?DEFAULT_CONTEXT, VarsAndVals, Timeout);
+
+s(UserId, Addr, CtxName, VarsAndVals, Timeout)
+ when is_list(CtxName) andalso
+ is_list(VarsAndVals) andalso
+ is_integer(Timeout) ->
+ s(UserId, Addr, ?DEFAULT_AGENT_PORT, CtxName, VarsAndVals, Timeout).
+
+s(UserId, Addr, Port, CtxName, VarsAndVals, Timeout) ->
+ case target_name(Addr, Port) of
+ {ok, TargetName} ->
+ sync_set(UserId, TargetName, CtxName, VarsAndVals, Timeout);
+ Error ->
+ Error
+ end.
+
+s(UserId, Addr, Port, CtxName, VarsAndVals, Timeout, ExtraInfo) ->
+ case target_name(Addr, Port) of
+ {ok, TargetName} ->
+ sync_set(UserId, TargetName, CtxName, VarsAndVals, Timeout, ExtraInfo);
+ Error ->
+ Error
+ end.
+
+
+
+%% --- asynchroneous set-request ---
+%%
+
+async_set(UserId, TargetName, VarsAndVals) ->
+ async_set(UserId, TargetName, ?DEFAULT_CONTEXT, VarsAndVals).
+
+async_set(UserId, TargetName, Context, VarsAndVals)
+ when is_list(Context) andalso is_list(VarsAndVals) ->
+ snmpm_server:async_set(UserId, TargetName, Context, VarsAndVals);
+
+async_set(UserId, TargetName, VarsAndVals, Expire)
+ when is_list(VarsAndVals) andalso is_integer(Expire) ->
+ async_set(UserId, TargetName, ?DEFAULT_CONTEXT, VarsAndVals, Expire).
+
+async_set(UserId, TargetName, Context, VarsAndVals, Expire) ->
+ snmpm_server:async_set(UserId, TargetName, Context, VarsAndVals, Expire).
+
+async_set(UserId, TargetName, Context, VarsAndVals, Expire, ExtraInfo) ->
+ snmpm_server:async_set(UserId, TargetName, Context, VarsAndVals, Expire,
+ ExtraInfo).
+
+
+as(UserId, Addr, VarsAndVals) ->
+ as(UserId, Addr, ?DEFAULT_AGENT_PORT, VarsAndVals).
+
+as(UserId, Addr, Port, VarsAndVals)
+ when is_integer(Port) andalso is_list(VarsAndVals) ->
+ as(UserId, Addr, Port, ?DEFAULT_CONTEXT, VarsAndVals);
+
+as(UserId, Addr, CtxName, VarsAndVals)
+ when is_list(CtxName) andalso is_list(VarsAndVals) ->
+ as(UserId, Addr, ?DEFAULT_AGENT_PORT, CtxName, VarsAndVals);
+
+as(UserId, Addr, VarsAndVals, Expire)
+ when is_list(VarsAndVals) andalso is_integer(Expire) ->
+ as(UserId, Addr, ?DEFAULT_AGENT_PORT, VarsAndVals, Expire).
+
+as(UserId, Addr, Port, CtxName, VarsAndVals)
+ when is_integer(Port) andalso
+ is_list(CtxName) andalso
+ is_list(VarsAndVals) ->
+ case target_name(Addr, Port) of
+ {ok, TargetName} ->
+ async_set(UserId, TargetName, CtxName, VarsAndVals);
+ Error ->
+ Error
+ end;
+
+as(UserId, Addr, Port, VarsAndVals, Expire)
+ when is_integer(Port) andalso
+ is_list(VarsAndVals) andalso
+ is_integer(Expire) ->
+ as(UserId, Addr, Port, ?DEFAULT_CONTEXT, VarsAndVals, Expire);
+
+as(UserId, Addr, CtxName, VarsAndVals, Expire)
+ when is_list(CtxName) andalso
+ is_list(VarsAndVals) andalso
+ is_integer(Expire) ->
+ as(UserId, Addr, ?DEFAULT_AGENT_PORT, CtxName, VarsAndVals, Expire).
+
+as(UserId, Addr, Port, CtxName, VarsAndVals, Expire) ->
+ case target_name(Addr, Port) of
+ {ok, TargetName} ->
+ async_set(UserId, TargetName, CtxName, VarsAndVals, Expire);
+ Error ->
+ Error
+ end.
+
+as(UserId, Addr, Port, CtxName, VarsAndVals, Expire, ExtraInfo) ->
+ case target_name(Addr, Port) of
+ {ok, TargetName} ->
+ async_set(UserId, TargetName, CtxName, VarsAndVals, Expire, ExtraInfo);
+ Error ->
+ Error
+ end.
+
+
+
+
+%% --- synchroneous get-bulk ---
+%%
+
+sync_get_bulk(UserId, TargetName, NonRep, MaxRep, Oids) ->
+ sync_get_bulk(UserId, TargetName, NonRep, MaxRep, ?DEFAULT_CONTEXT, Oids).
+
+sync_get_bulk(UserId, TargetName, NonRep, MaxRep, Context, Oids)
+ when is_integer(NonRep) andalso
+ is_integer(MaxRep) andalso
+ is_list(Context) andalso
+ is_list(Oids) ->
+ snmpm_server:sync_get_bulk(UserId, TargetName,
+ NonRep, MaxRep,
+ Context, Oids);
+
+sync_get_bulk(UserId, TargetName, NonRep, MaxRep, Oids, Timeout)
+ when is_integer(NonRep) andalso
+ is_integer(MaxRep) andalso
+ is_list(Oids) andalso
+ is_integer(Timeout) ->
+ sync_get_bulk(UserId, TargetName, NonRep, MaxRep,
+ ?DEFAULT_CONTEXT, Oids, Timeout).
+
+sync_get_bulk(UserId, TargetName, NonRep, MaxRep, Context, Oids, Timeout) ->
+ snmpm_server:sync_get_bulk(UserId, TargetName, NonRep, MaxRep,
+ Context, Oids, Timeout).
+
+sync_get_bulk(UserId, TargetName, NonRep, MaxRep, Context, Oids, Timeout,
+ ExtraInfo) ->
+ snmpm_server:sync_get_bulk(UserId, TargetName, NonRep, MaxRep,
+ Context, Oids, Timeout, ExtraInfo).
+
+
+gb(UserId, Addr, NonRep, MaxRep, Oids) ->
+ gb(UserId, Addr, ?DEFAULT_AGENT_PORT, NonRep, MaxRep, Oids).
+
+gb(UserId, Addr, Port, NonRep, MaxRep, Oids)
+ when is_integer(Port) andalso
+ is_integer(NonRep) andalso
+ is_integer(MaxRep) andalso
+ is_list(Oids) ->
+ gb(UserId, Addr, Port, NonRep, MaxRep, ?DEFAULT_CONTEXT, Oids);
+
+gb(UserId, Addr, NonRep, MaxRep, CtxName, Oids)
+ when is_integer(NonRep) andalso
+ is_integer(MaxRep) andalso
+ is_list(CtxName) andalso
+ is_list(Oids) ->
+ gb(UserId, Addr, ?DEFAULT_AGENT_PORT, NonRep, MaxRep, CtxName, Oids);
+
+gb(UserId, Addr, NonRep, MaxRep, Oids, Timeout)
+ when is_integer(NonRep) andalso
+ is_integer(MaxRep) andalso
+ is_list(Oids) andalso
+ is_integer(Timeout) ->
+ gb(UserId, Addr, ?DEFAULT_AGENT_PORT, NonRep, MaxRep, Oids, Timeout).
+
+gb(UserId, Addr, Port, NonRep, MaxRep, CtxName, Oids)
+ when is_integer(Port) andalso
+ is_integer(NonRep) andalso
+ is_integer(MaxRep) andalso
+ is_list(CtxName) andalso
+ is_list(Oids) ->
+ case target_name(Addr, Port) of
+ {ok, TargetName} ->
+ sync_get_bulk(UserId, TargetName, NonRep, MaxRep, CtxName, Oids);
+ Error ->
+ Error
+ end;
+
+gb(UserId, Addr, Port, NonRep, MaxRep, Oids, Timeout)
+ when is_integer(Port) andalso
+ is_integer(NonRep) andalso
+ is_integer(MaxRep) andalso
+ is_list(Oids) andalso
+ is_integer(Timeout) ->
+ gb(UserId, Addr, Port, NonRep, MaxRep, ?DEFAULT_CONTEXT, Oids, Timeout);
+
+gb(UserId, Addr, NonRep, MaxRep, CtxName, Oids, Timeout)
+ when is_integer(NonRep) andalso
+ is_integer(MaxRep) andalso
+ is_list(CtxName) andalso
+ is_list(Oids) andalso
+ is_integer(Timeout) ->
+ gb(UserId, Addr, ?DEFAULT_AGENT_PORT, NonRep, MaxRep, CtxName, Oids,
+ Timeout).
+
+gb(UserId, Addr, Port, NonRep, MaxRep, CtxName, Oids, Timeout) ->
+ case target_name(Addr, Port) of
+ {ok, TargetName} ->
+ sync_get_bulk(UserId, TargetName,
+ NonRep, MaxRep, CtxName, Oids, Timeout);
+ Error ->
+ Error
+ end.
+
+gb(UserId, Addr, Port, NonRep, MaxRep, CtxName, Oids, Timeout, ExtraInfo) ->
+ case target_name(Addr, Port) of
+ {ok, TargetName} ->
+ sync_get_bulk(UserId, TargetName,
+ NonRep, MaxRep, CtxName, Oids, Timeout, ExtraInfo);
+ Error ->
+ Error
+ end.
+
+
+
+%% --- asynchroneous get-bulk ---
+%%
+
+async_get_bulk(UserId, TargetName, NonRep, MaxRep, Oids) ->
+ async_get_bulk(UserId, TargetName, NonRep, MaxRep, ?DEFAULT_CONTEXT, Oids).
+
+async_get_bulk(UserId, TargetName, NonRep, MaxRep, Context, Oids)
+ when is_integer(NonRep) andalso
+ is_integer(MaxRep) andalso
+ is_list(Context) andalso
+ is_list(Oids) ->
+ snmpm_server:async_get_bulk(UserId, TargetName,
+ NonRep, MaxRep, Context, Oids);
+
+async_get_bulk(UserId, TargetName, NonRep, MaxRep, Oids, Expire)
+ when is_integer(NonRep) andalso
+ is_integer(MaxRep) andalso
+ is_list(Oids) andalso
+ is_integer(Expire) ->
+ async_get_bulk(UserId, TargetName,
+ NonRep, MaxRep, ?DEFAULT_CONTEXT, Oids, Expire).
+
+async_get_bulk(UserId, TargetName, NonRep, MaxRep, Context, Oids, Expire) ->
+ snmpm_server:async_get_bulk(UserId, TargetName,
+ NonRep, MaxRep, Context, Oids, Expire).
+
+async_get_bulk(UserId, TargetName, NonRep, MaxRep, Context, Oids, Expire,
+ ExtraInfo) ->
+ snmpm_server:async_get_bulk(UserId, TargetName,
+ NonRep, MaxRep,
+ Context, Oids, Expire, ExtraInfo).
+
+
+agb(UserId, Addr, NonRep, MaxRep, Oids) ->
+ agb(UserId, Addr, ?DEFAULT_AGENT_PORT, NonRep, MaxRep, Oids).
+
+agb(UserId, Addr, Port, NonRep, MaxRep, Oids)
+ when is_integer(Port) andalso
+ is_integer(NonRep) andalso
+ is_integer(MaxRep) andalso
+ is_list(Oids) ->
+ agb(UserId, Addr, Port, NonRep, MaxRep, ?DEFAULT_CONTEXT, Oids);
+
+agb(UserId, Addr, NonRep, MaxRep, CtxName, Oids)
+ when is_integer(NonRep) andalso
+ is_integer(MaxRep) andalso
+ is_list(CtxName) andalso
+ is_list(Oids) ->
+ agb(UserId, Addr, ?DEFAULT_AGENT_PORT, NonRep, MaxRep, CtxName, Oids);
+
+agb(UserId, Addr, NonRep, MaxRep, Oids, Expire)
+ when is_integer(NonRep) andalso
+ is_integer(MaxRep) andalso
+ is_list(Oids) andalso
+ is_integer(Expire) ->
+ agb(UserId, Addr, ?DEFAULT_AGENT_PORT, NonRep, MaxRep, Oids, Expire).
+
+agb(UserId, Addr, Port, NonRep, MaxRep, CtxName, Oids)
+ when is_integer(Port) andalso
+ is_integer(NonRep) andalso
+ is_integer(MaxRep),
+ is_list(CtxName) andalso
+ is_list(Oids) ->
+ case target_name(Addr, Port) of
+ {ok, TargetName} ->
+ async_get_bulk(UserId, TargetName,
+ NonRep, MaxRep, CtxName, Oids);
+ Error ->
+ Error
+ end;
+
+agb(UserId, Addr, Port, NonRep, MaxRep, Oids, Expire)
+ when is_integer(Port) andalso
+ is_integer(NonRep) andalso
+ is_integer(MaxRep) andalso
+ is_list(Oids) andalso
+ is_integer(Expire) ->
+ agb(UserId, Addr, Port, NonRep, MaxRep, ?DEFAULT_CONTEXT, Oids, Expire);
+
+agb(UserId, Addr, NonRep, MaxRep, CtxName, Oids, Expire)
+ when is_integer(NonRep) andalso
+ is_integer(MaxRep) andalso
+ is_list(CtxName) andalso
+ is_list(Oids) andalso
+ is_integer(Expire) ->
+ agb(UserId, Addr, ?DEFAULT_AGENT_PORT, NonRep, MaxRep, CtxName, Oids).
+
+agb(UserId, Addr, Port, NonRep, MaxRep, CtxName, Oids, Expire) ->
+ case target_name(Addr, Port) of
+ {ok, TargetName} ->
+ async_get_bulk(UserId, TargetName,
+ NonRep, MaxRep, CtxName, Oids, Expire);
+ Error ->
+ Error
+ end.
+
+agb(UserId, Addr, Port, NonRep, MaxRep, CtxName, Oids, Expire, ExtraInfo) ->
+ case target_name(Addr, Port) of
+ {ok, TargetName} ->
+ async_get_bulk(UserId, TargetName,
+ NonRep, MaxRep, CtxName, Oids, Expire,
+ ExtraInfo);
+ Error ->
+ Error
+ end.
+
+
+cancel_async_request(UserId, ReqId) ->
+ snmpm_server:cancel_async_request(UserId, ReqId).
+
+
+%%%-----------------------------------------------------------------
+%%% Audit Trail Log functions (for backward compatibillity)
+%%%-----------------------------------------------------------------
+log_to_txt(LogDir, Mibs) ->
+ OutFile = "snmpm_log.txt",
+ LogName = ?audit_trail_log_name,
+ LogFile = ?audit_trail_log_file,
+ snmp:log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile).
+log_to_txt(LogDir, Mibs, OutFile) ->
+ LogName = ?audit_trail_log_name,
+ LogFile = ?audit_trail_log_file,
+ snmp:log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile).
+log_to_txt(LogDir, Mibs, OutFile, LogName) ->
+ LogFile = ?audit_trail_log_file,
+ snmp:log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile).
+log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile) ->
+ snmp:log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile).
+log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Start) ->
+ snmp:log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Start).
+log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Start, Stop) ->
+ snmp:log_to_txt(LogDir, Mibs, OutFile, LogName, LogFile, Start, Stop).
+
+
+change_log_size(NewSize) ->
+ LogName = ?audit_trail_log_name,
+ snmp:change_log_size(LogName, NewSize).
+
+
+get_log_type() ->
+ snmpm_server:get_log_type().
+
+%% NewType -> atl_type()
+set_log_type(NewType) ->
+ snmpm_server:set_log_type(NewType).
+
+
+reconfigure() ->
+ snmpm_server:reconfigure().
+
+
+%%%-----------------------------------------------------------------
+
+system_start_time() ->
+ {ok, Time} = snmpm_config:system_start_time(),
+ Time.
+
+sys_up_time() ->
+ % time in 0.01 seconds.
+ StartTime = system_start_time(),
+ (snmp_misc:now(cs) - StartTime) rem (2 bsl 31).
+
+
+%%%-----------------------------------------------------------------
+%%% This is just some simple utility functions to create a pretty-
+%%% printable string of the error reason received from either:
+%%%
+%%% * If any of the sync/async get/get-next/set/get-bulk
+%%% returnes {error, Reason}
+%%% * The Reason parameter in the handle_error user callback
+%%% function
+%%%
+%%%-----------------------------------------------------------------
+
+format_reason(Reason) ->
+ format_reason("", Reason).
+
+format_reason(Prefix, Reason) when is_integer(Prefix) and (Prefix >= 0) ->
+ format_reason(lists:duplicate(Prefix, $ ), Reason);
+format_reason(Prefix, Reason) when is_list(Prefix) ->
+ case (catch do_format_reason(Prefix, Reason)) of
+ FL when is_list(FL) ->
+ FL;
+ _ ->
+ %% Crap, try it without any fancy formatting
+ case (catch io_lib:format("~sInternal manager error: ~n"
+ "~s ~p~n",
+ [Prefix, Prefix, Reason])) of
+ L1 when is_list(L1) ->
+ lists:flatten(L1);
+ _ ->
+ %% Really crap, try it without the prefix
+ case (catch io_lib:format("Internal manager error: ~n"
+ " ~p~n",
+ [Reason])) of
+ L2 when is_list(L2) ->
+ lists:flatten(L2);
+ _ ->
+ %% Ok, I give up
+ "Illegal input. Unable to format error reason"
+ end
+ end
+ end.
+
+
+do_format_reason(Prefix, {failed_generating_response, {RePdu, Reason}}) ->
+ FmtPdu = format_pdu(Prefix ++ " ", RePdu),
+ lists:flatten(io_lib:format("~sFailed generating response: ~n"
+ "~s"
+ "~s ~p~n",
+ [Prefix, FmtPdu, Prefix, Reason]));
+do_format_reason(Prefix, {failed_processing_message, Reason}) ->
+ lists:flatten(io_lib:format("~sFailed processing message: ~n"
+ "~s ~p~n",
+ [Prefix, Prefix, Reason]));
+do_format_reason(Prefix, {unexpected_pdu, SnmpInfo}) ->
+ FmtSnmpInfo = format_snmp_info(Prefix ++ " ", SnmpInfo),
+ lists:flatten(io_lib:format("~sUnexpected PDU: ~n~s",
+ [Prefix, FmtSnmpInfo]));
+do_format_reason(Prefix, {send_failed, ReqId, Reason}) ->
+ lists:flatten(io_lib:format("~sSend failed: ~n"
+ "~s Request id: ~w~n"
+ "~s Reason: ~p~n",
+ [Prefix, Prefix, ReqId, Prefix, Reason]));
+do_format_reason(Prefix, {invalid_sec_info, SecInfo, SnmpInfo}) ->
+ FmtSecInfo = format_sec_info(Prefix ++ " ", SecInfo),
+ FmtSnmpInfo = format_snmp_info(Prefix ++ " ", SnmpInfo),
+ lists:flatten(io_lib:format("~sInvalid security info: ~n"
+ "~s"
+ "~s",
+ [Prefix, FmtSecInfo, FmtSnmpInfo]));
+do_format_reason(Prefix, Reason) ->
+ lists:flatten(io_lib:format("~sInternal manager error: ~n"
+ "~s ~p~n", [Prefix, Prefix, Reason])).
+
+format_pdu(Prefix, #pdu{type = Type,
+ request_id = ReqId,
+ error_status = ES,
+ error_index = EI,
+ varbinds = VBs}) ->
+ FmtPdyType = format_pdu_type(Type),
+ FmtErrStatus = format_error_status(ES),
+ FmtErrIdx = format_error_index(EI),
+ FmtVBs = format_varbinds(Prefix ++ " ", VBs),
+ lists:flatten(io_lib:format("~s~s: ~n"
+ "~s Request-id: ~w~n"
+ "~s Error-status: ~s~n"
+ "~s Error-index: ~s~n"
+ "~s",
+ [Prefix, FmtPdyType,
+ Prefix, ReqId,
+ Prefix, FmtErrStatus,
+ Prefix, FmtErrIdx,
+ FmtVBs]));
+format_pdu(Prefix, #trappdu{enterprise = E,
+ agent_addr = AA,
+ generic_trap = GT,
+ specific_trap = ST,
+ time_stamp = TS,
+ varbinds = VBs}) ->
+ FmtVBs = format_varbinds(Prefix ++ " ", VBs),
+ lists:flatten(io_lib:format("~sTrap PDU: ~n"
+ "~s Enterprise: ~p~n"
+ "~s Agent address: ~p~n"
+ "~s Generic trap: ~p~n"
+ "~s Specific trap: ~p~n"
+ "~s Time stamp: ~p~n"
+ "~s",
+ [Prefix,
+ Prefix, E,
+ Prefix, AA,
+ Prefix, GT,
+ Prefix, ST,
+ Prefix, TS,
+ FmtVBs]));
+format_pdu(Prefix, PDU) ->
+ lists:flatten(io_lib:format("~s~p~n", [Prefix, PDU])).
+
+format_pdu_type('get-request') ->
+ "GetRequest-PDU";
+format_pdu_type('get-next-request') ->
+ "GetNextRequest-PDU";
+format_pdu_type('get-response') ->
+ "Response-PDU";
+format_pdu_type('set-request') ->
+ "SetRequest-PDU";
+format_pdu_type('get-bulk-request') ->
+ "GetBulkRequest-PDU";
+format_pdu_type('inform-request') ->
+ "InformRequest-PDU";
+format_pdu_type('snmpv2-trap') ->
+ "SNMPv2-Trap-PDU";
+format_pdu_type(report) ->
+ "Report-PDU";
+format_pdu_type(T) ->
+ lists:flatten(io_lib:format("~p", [T])).
+
+format_snmp_info(Prefix, {ES, EI, VBs}) ->
+ lists:flatten(io_lib:format("~sSNMP info: ~n"
+ "~s Error-status: ~s~n"
+ "~s Error-index: ~s~n"
+ "~s",
+ [Prefix,
+ Prefix, format_error_status(ES),
+ Prefix, format_error_index(EI),
+ format_varbinds(Prefix ++ " ", VBs)]));
+format_snmp_info(Prefix, JunkSnmpInfo) ->
+ lists:flatten(io_lib:format("~sJunk SNMP info: ~n"
+ "~s ~p~n",
+ [Prefix, Prefix, JunkSnmpInfo])).
+
+format_error_status(ES) ->
+ lists:flatten(io_lib:format("~p", [ES])).
+
+format_error_index(EI) ->
+ lists:flatten(io_lib:format("~p", [EI])).
+
+format_sec_info(Prefix, Info) ->
+ FmtSecInfo = do_format_sec_info(Prefix ++ " ", Info),
+ lists:flatten(io_lib:format("~sSecurity info: ~n~s",
+ [Prefix, FmtSecInfo])).
+
+do_format_sec_info(_Prefix, []) ->
+ "";
+do_format_sec_info(Prefix, [{Tag, ExpVal, Val}|T]) ->
+ format_sec_info(Prefix, Tag, ExpVal, Val) ++
+ do_format_sec_info(Prefix, T).
+
+
+format_sec_info(_Prefix, _Tag, Val, Val) ->
+ "";
+format_sec_info(Prefix, Tag, ExpVal, Val) ->
+ lists:flatten(io_lib:format("~s~s:~n"
+ "~s Expected value: ~p~n"
+ "~s Actual value: ~p~n",
+ [Prefix, format_sec_info_tag(Tag),
+ Prefix, ExpVal,
+ Prefix, Val])).
+
+format_sec_info_tag(sec_engine_id) ->
+ "Sec engine id";
+format_sec_info_tag(msg_sec_model) ->
+ "Msg sec model";
+format_sec_info_tag(sec_name) ->
+ "Sec name";
+format_sec_info_tag(sec_level) ->
+ "Sec level";
+format_sec_info_tag(ctx_engine_id) ->
+ "Context engine id";
+format_sec_info_tag(ctx_name) ->
+ "Context name";
+format_sec_info_tag(request_id) ->
+ "Request id";
+format_sec_info_tag(T) ->
+ lists:flatten(io_lib:format("~p", [T])).
+
+format_varbinds(Prefix, []) ->
+ lists:flatten(io_lib:format("~sVarbinds: []~n", [Prefix]));
+format_varbinds(Prefix, VBs) when is_list(VBs) ->
+ lists:flatten(io_lib:format("~sVarbinds: ~n~s",
+ [Prefix, format_vbs(Prefix ++ " ", VBs)]));
+format_varbinds(Prefix, VBs) ->
+ lists:flatten(io_lib:format("~sInvalid varbinds: ~n"
+ "~s ~p~n",
+ [Prefix, Prefix, VBs])).
+
+format_vbs(_Prefix, []) ->
+ "";
+format_vbs(Prefix, [VB|VBs]) ->
+ format_vb(Prefix, VB) ++ format_vbs(Prefix, VBs).
+
+format_vb(Prefix, #varbind{oid = Oid0,
+ variabletype = Type,
+ value = Val,
+ org_index = Idx}) ->
+ Oid =
+ case snmpm:oid_to_name(Oid0) of
+ {ok, O} ->
+ O;
+ _ ->
+ Oid0
+ end,
+ FmtVT = format_vb_variabletype(Prefix ++ " ", Type),
+ FmtVal = format_vb_value(Prefix ++ " ", Type, Val),
+ lists:flatten(io_lib:format("~s~w:~n"
+ "~s"
+ "~s"
+ "~s Org-index: ~p~n",
+ [Prefix, Oid,
+ FmtVT,
+ FmtVal,
+ Prefix, Idx]));
+format_vb(Prefix, JunkVB) ->
+ lists:flatten(io_lib:format("~sJunk varbind:~n"
+ "~s ~p~n", [Prefix, Prefix, JunkVB])).
+
+format_vb_variabletype(Prefix, Type) when is_atom(Type) ->
+ lists:flatten(io_lib:format("~sVariable-type: ~s~n",
+ [Prefix, atom_to_list(Type)]));
+format_vb_variabletype(Prefix, Type) ->
+ lists:flatten(io_lib:format("~sVariable-type: ~p~n", [Prefix, Type])).
+
+format_vb_value(Prefix, _Type, Val) ->
+ lists:flatten(io_lib:format("~sValue: ~p~n", [Prefix, Val])).
+
+
+%% ---------------------------------------------------------------------------
+%%
+%% --- Internal utility functions ---
+%%
+
+target_name(Addr, Port) ->
+ snmpm_config:agent_info(Addr, Port, target_name).
+
+mk_target_name(Addr, Port, Config) ->
+ snmpm_config:mk_target_name(Addr, Port, Config).
+
+ensure_engine_id(Config) ->
+ case lists:keymember(engine_id, 1, Config) of
+ true ->
+ Config;
+ false ->
+ DefaultEngineId = "agentEngine-default",
+ [{engine_id, DefaultEngineId} | Config]
+ end.
+
+
+
+%% p(F) ->
+%% p(F, []).
+
+%% p(F, A) ->
+%% io:format("~w:" ++ F ++ "~n", [?MODULE | A]).
diff --git a/lib/snmp/src/manager/snmpm_atl.hrl b/lib/snmp/src/manager/snmpm_atl.hrl
new file mode 100644
index 0000000000..d99ee05ae6
--- /dev/null
+++ b/lib/snmp/src/manager/snmpm_atl.hrl
@@ -0,0 +1,21 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2004-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%
+%%
+
+-define(audit_trail_log_name, "snmpm_log").
+-define(audit_trail_log_file, "snmpm.log").
diff --git a/lib/snmp/src/manager/snmpm_conf.erl b/lib/snmp/src/manager/snmpm_conf.erl
new file mode 100644
index 0000000000..75f9c09477
--- /dev/null
+++ b/lib/snmp/src/manager/snmpm_conf.erl
@@ -0,0 +1,396 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2006-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%
+%%
+
+-module(snmpm_conf).
+
+-include_lib("kernel/include/file.hrl").
+
+-export([
+ %% manager.conf
+ manager_entry/2,
+ write_manager_config/2, write_manager_config/3,
+ append_manager_config/2,
+ read_manager_config/1,
+
+ %% users.conf
+ users_entry/1, users_entry/2, users_entry/3,
+ write_users_config/2, write_users_config/3,
+ append_users_config/2,
+ read_users_config/1,
+
+ %% agents.conf
+ agents_entry/12,
+ write_agents_config/2, write_agents_config/3,
+ append_agents_config/2,
+ read_agents_config/1,
+
+ %% usm.conf
+ usm_entry/6, usm_entry/7,
+ write_usm_config/2, write_usm_config/3,
+ append_usm_config/2,
+ read_usm_config/1
+ ]).
+
+
+
+-define(MANAGER_CONF_FILE, "manager.conf").
+-define(USERS_CONF_FILE, "users.conf").
+-define(AGENTS_CONF_FILE, "agents.conf").
+-define(USM_USERS_CONF_FILE, "usm.conf").
+
+%%
+%% ------ manager.conf ------
+%%
+
+manager_entry(Tag, Val) ->
+ {Tag, Val}.
+
+
+write_manager_config(Dir, Conf) ->
+ Comment =
+"%% This file defines the Manager local configuration info\n"
+"%% Each row is a 2-tuple:\n"
+"%% {Variable, Value}.\n"
+"%% For example\n"
+"%% {port, 5000}.\n"
+"%% {address, [127,42,17,5]}.\n"
+"%% {engine_id, \"managerEngine\"}.\n"
+"%% {max_message_size, 484}.\n"
+"%%\n\n",
+ Hdr = header() ++ Comment,
+ write_manager_config(Dir, Hdr, Conf).
+
+write_manager_config(Dir, Hdr, Conf)
+ when is_list(Dir) andalso is_list(Hdr) andalso is_list(Conf) ->
+ Verify = fun() -> verify_manager_conf(Conf) end,
+ Write = fun(Fid) -> write_manager_conf(Fid, Hdr, Conf) end,
+ write_config_file(Dir, ?MANAGER_CONF_FILE, Verify, Write).
+
+
+append_manager_config(Dir, Conf)
+ when is_list(Dir) andalso is_list(Conf) ->
+ Verify = fun() -> verify_manager_conf(Conf) end,
+ Write = fun(Fid) -> write_manager_conf(Fid, Conf) end,
+ append_config_file(Dir, ?MANAGER_CONF_FILE, Verify, Write).
+
+
+read_manager_config(Dir) ->
+ Verify = fun(Entry) -> verify_manager_conf_entry(Entry) end,
+ read_config_file(Dir, ?MANAGER_CONF_FILE, Verify).
+
+
+verify_manager_conf([]) ->
+ ok;
+verify_manager_conf([H|T]) ->
+ verify_manager_conf_entry(H),
+ verify_manager_conf(T);
+verify_manager_conf(X) ->
+ error({bad_manager_config, X}).
+
+verify_manager_conf_entry(Entry) ->
+ case snmpm_config:check_manager_config(Entry) of
+ ok ->
+ ok;
+%% {ok, _} ->
+%% ok;
+ Error ->
+ throw(Error)
+ end.
+
+write_manager_conf(Fd, "", Conf) ->
+ write_manager_conf(Fd, Conf);
+write_manager_conf(Fd, Hdr, Conf) ->
+ io:format(Fd, "~s~n", [Hdr]),
+ write_manager_conf(Fd, Conf).
+
+write_manager_conf(_Fd, []) ->
+ ok;
+write_manager_conf(Fd, [H|T]) ->
+ do_write_manager_conf(Fd, H),
+ write_manager_conf(Fd, T).
+
+do_write_manager_conf(Fd, {address = Tag, Val}) ->
+ io:format(Fd, "{~w, ~w}.~n", [Tag, Val]);
+do_write_manager_conf(Fd, {port = Tag, Val} ) ->
+ io:format(Fd, "{~w, ~w}.~n", [Tag, Val]);
+do_write_manager_conf(Fd, {engine_id = Tag, Val} ) ->
+ io:format(Fd, "{~w, \"~s\"}.~n", [Tag, Val]);
+do_write_manager_conf(Fd, {max_message_size = Tag, Val} ) ->
+ io:format(Fd, "{~w, ~w}.~n", [Tag, Val]);
+do_write_manager_conf(_Fd, Crap) ->
+ error({bad_manager_config, Crap}).
+
+
+%%
+%% ------ users.conf ------
+%%
+
+users_entry(UserId) ->
+ users_entry(UserId, snmpm_user_default).
+
+users_entry(UserId, UserMod) ->
+ users_entry(UserId, UserMod, undefined).
+
+users_entry(UserId, UserMod, UserData) ->
+ users_entry(UserId, UserMod, UserData, []).
+
+users_entry(UserId, UserMod, UserData, DefaultAgentConfig) ->
+ {UserId, UserMod, UserData, DefaultAgentConfig}.
+
+
+write_users_config(Dir, Conf) ->
+ Comment =
+"%% This file defines the users the manager handles\n"
+"%% Each row is a 4-tuple:\n"
+"%% {UserId, UserMod, UserData, DefaultAgentConfig}.\n"
+"%% For example\n"
+"%% {kalle, kalle_callback_user_mod, \"dummy\", []}.\n"
+"%%\n\n",
+ Hdr = header() ++ Comment,
+ write_users_config(Dir, Hdr, Conf).
+
+write_users_config(Dir, Hdr, Conf)
+ when is_list(Dir) andalso is_list(Hdr) andalso is_list(Conf) ->
+ Verify = fun() -> verify_users_conf(Conf) end,
+ Write = fun(Fd) -> write_users_conf(Fd, Hdr, Conf) end,
+ write_config_file(Dir, ?USERS_CONF_FILE, Verify, Write).
+
+
+append_users_config(Dir, Conf)
+ when is_list(Dir) andalso is_list(Conf) ->
+ Verify = fun() -> verify_users_conf(Conf) end,
+ Write = fun(Fd) -> write_users_conf(Fd, Conf) end,
+ append_config_file(Dir, ?USERS_CONF_FILE, Verify, Write).
+
+
+read_users_config(Dir) when is_list(Dir) ->
+ Verify = fun(Entry) -> verify_users_conf_entry(Entry) end,
+ read_config_file(Dir, ?USERS_CONF_FILE, Verify).
+
+
+verify_users_conf([]) ->
+ ok;
+verify_users_conf([H|T]) ->
+ verify_users_conf_entry(H),
+ verify_users_conf(T);
+verify_users_conf(X) ->
+ error({bad_users_conf, X}).
+
+verify_users_conf_entry(Entry) ->
+ {ok, _} = snmpm_config:check_user_config(Entry),
+ ok.
+
+write_users_conf(Fd, "", Conf) ->
+ write_users_conf(Fd, Conf);
+write_users_conf(Fd, Hdr, Conf) ->
+ io:format(Fd, "~s~n", [Hdr]),
+ write_users_conf(Fd, Conf).
+
+write_users_conf(_Fd, []) ->
+ ok;
+write_users_conf(Fd, [H|T]) ->
+ do_write_users_conf(Fd, H),
+ write_users_conf(Fd, T).
+
+do_write_users_conf(Fd, {Id, Mod, Data}) ->
+ do_write_users_conf(Fd, {Id, Mod, Data, []});
+do_write_users_conf(Fd, {Id, Mod, Data, DefaultAgentConfig}) ->
+ io:format(Fd, "{~w, ~w, ~w, ~w}.~n", [Id, Mod, Data, DefaultAgentConfig]);
+do_write_users_conf(_Fd, Crap) ->
+ error({bad_users_config, Crap}).
+
+
+%%
+%% ------ agents.conf ------
+%%
+
+agents_entry(UserId, TargetName, Comm, Ip, Port, EngineID, Timeout,
+ MaxMessageSize, Version, SecModel, SecName, SecLevel) ->
+ {UserId, TargetName, Comm, Ip, Port, EngineID, Timeout,
+ MaxMessageSize, Version, SecModel, SecName, SecLevel}.
+
+
+write_agents_config(Dir, Conf) ->
+ Comment =
+"%% This file defines the agents the manager handles\n"
+"%% Each row is a 12-tuple:\n"
+"%% {UserId, \n"
+"%% TargetName, Comm, Ip, Port, EngineID, Timeout, \n"
+"%% MaxMessageSize, Version, SecModel, SecName, SecLevel}\n"
+"%%\n\n",
+ Hdr = header() ++ Comment,
+ write_agents_config(Dir, Hdr, Conf).
+
+write_agents_config(Dir, Hdr, Conf)
+ when is_list(Dir) andalso is_list(Hdr) andalso is_list(Conf) ->
+ Verify = fun() -> verify_agents_conf(Conf) end,
+ Write = fun(Fd) -> write_agents_conf(Fd, Hdr, Conf) end,
+ write_config_file(Dir, ?AGENTS_CONF_FILE, Verify, Write).
+
+
+append_agents_config(Dir, Conf)
+ when is_list(Dir) andalso is_list(Conf) ->
+ Verify = fun() -> verify_agents_conf(Conf) end,
+ Write = fun(Fd) -> write_agents_conf(Fd, Conf) end,
+ append_config_file(Dir, ?AGENTS_CONF_FILE, Verify, Write).
+
+
+read_agents_config(Dir) ->
+ Verify = fun(Entry) -> verify_agents_conf_entry(Entry) end,
+ read_config_file(Dir, ?AGENTS_CONF_FILE, Verify).
+
+
+verify_agents_conf([]) ->
+ ok;
+verify_agents_conf([H|T]) ->
+ verify_agents_conf_entry(H),
+ verify_agents_conf(T);
+verify_agents_conf(X) ->
+ error({bad_agents_config, X}).
+
+verify_agents_conf_entry(Entry) ->
+ {ok, _} = snmpm_config:check_agent_config(Entry),
+ ok.
+
+write_agents_conf(Fd, "", Conf) ->
+ write_agents_conf(Fd, Conf);
+write_agents_conf(Fd, Hdr, Conf) ->
+ io:format(Fd, "~s~n", [Hdr]),
+ write_agents_conf(Fd, Conf).
+
+write_agents_conf(_Fd, []) ->
+ ok;
+write_agents_conf(Fd, [H|T]) ->
+ do_write_agents_conf(Fd, H),
+ write_agents_conf(Fd, T).
+
+do_write_agents_conf(Fd,
+ {UserId,
+ TargetName, Comm, Ip, Port, EngineID,
+ Timeout, MaxMessageSize, Version,
+ SecModel, SecName, SecLevel} = _A) ->
+ io:format(Fd,
+ "{~w, \"~s\", \"~s\", ~w, ~w, \"~s\", ~w, ~w, ~w, ~w, \"~s\", ~w}.~n", [UserId, TargetName, Comm, Ip, Port, EngineID, Timeout, MaxMessageSize, Version, SecModel, SecName, SecLevel]);
+do_write_agents_conf(_Fd, Crap) ->
+ error({bad_agents_config, Crap}).
+
+
+%%
+%% ------ usm.conf -----
+%%
+
+usm_entry(EngineID, UserName, AuthP, AuthKey, PrivP, PrivKey) ->
+ {EngineID, UserName, AuthP, AuthKey, PrivP, PrivKey}.
+
+usm_entry(EngineID, UserName, SecName, AuthP, AuthKey, PrivP, PrivKey) ->
+ {EngineID, UserName, SecName, AuthP, AuthKey, PrivP, PrivKey}.
+
+
+write_usm_config(Dir, Conf) ->
+ Comment =
+"%% This file defines the usm users the manager handles\n"
+"%% Each row is a 6 or 7-tuple:\n"
+"%% {EngineID, UserName, AuthP, AuthKey, PrivP, PrivKey}\n"
+"%% {EngineID, UserName, SecName, AuthP, AuthKey, PrivP, PrivKey}\n"
+"%%\n\n",
+ Hdr = header() ++ Comment,
+ write_usm_config(Dir, Hdr, Conf).
+
+write_usm_config(Dir, Hdr, Conf)
+ when is_list(Dir) andalso is_list(Hdr) andalso is_list(Conf) ->
+ Verify = fun() -> verify_usm_conf(Conf) end,
+ Write = fun(Fd) -> write_usm_conf(Fd, Hdr, Conf) end,
+ write_config_file(Dir, ?USM_USERS_CONF_FILE, Verify, Write).
+
+
+append_usm_config(Dir, Conf)
+ when is_list(Dir) andalso is_list(Conf) ->
+ Verify = fun() -> verify_usm_conf(Conf) end,
+ Write = fun(Fd) -> write_usm_conf(Fd, Conf) end,
+ append_config_file(Dir, ?USM_USERS_CONF_FILE, Verify, Write).
+
+
+read_usm_config(Dir)
+ when is_list(Dir) ->
+ Verify = fun(Entry) -> verify_usm_conf_entry(Entry) end,
+ read_config_file(Dir, ?USM_USERS_CONF_FILE, Verify).
+
+
+verify_usm_conf([]) ->
+ ok;
+verify_usm_conf([H|T]) ->
+ verify_usm_conf_entry(H),
+ verify_usm_conf(T);
+verify_usm_conf(X) ->
+ error({bad_usm_conf, X}).
+
+verify_usm_conf_entry(Entry) ->
+ {ok, _} = snmpm_config:check_usm_user_config(Entry),
+ ok.
+
+write_usm_conf(Fd, "", Conf) ->
+ write_usm_conf(Fd, Conf);
+write_usm_conf(Fd, Hdr, Conf) ->
+ io:format(Fd, "~s~n", [Hdr]),
+ write_usm_conf(Fd, Conf).
+
+write_usm_conf(_Fd, []) ->
+ ok;
+write_usm_conf(Fd, [H|T]) ->
+ do_write_usm_conf(Fd, H),
+ write_usm_conf(Fd, T).
+
+do_write_usm_conf(Fd,
+ {EngineID, UserName, AuthP, AuthKey, PrivP, PrivKey}) ->
+ io:format(Fd, "{\"~s\", \"~s\", ~w, ~w, ~w, ~w}.~n",
+ [EngineID, UserName, AuthP, AuthKey, PrivP, PrivKey]);
+do_write_usm_conf(Fd,
+ {EngineID, UserName, SecName,
+ AuthP, AuthKey, PrivP, PrivKey}) ->
+ io:format(Fd, "{\"~s\", \"~s\", \"~s\", �~w, ~w, ~w, ~w}.~n",
+ [EngineID, UserName, SecName, AuthP, AuthKey, PrivP, PrivKey]);
+do_write_usm_conf(_Fd, Crap) ->
+ error({bad_usm_conf, Crap}).
+
+
+%% ---- config file wrapper functions ----
+
+write_config_file(Dir, File, Verify, Write) ->
+ snmp_config:write_config_file(Dir, File, Verify, Write).
+
+append_config_file(Dir, File, Verify, Write) ->
+ snmp_config:append_config_file(Dir, File, Verify, Write).
+
+read_config_file(Dir, File, Verify) ->
+ snmp_config:read_config_file(Dir, File, Verify).
+
+
+%% ---- config file utility functions ----
+
+header() ->
+ {Y,Mo,D} = date(),
+ {H,Mi,S} = time(),
+ io_lib:format("%% This file was generated by "
+ "~w (version-~s) ~w-~2.2.0w-~2.2.0w "
+ "~2.2.0w:~2.2.0w:~2.2.0w\n",
+ [?MODULE, ?version, Y, Mo, D, H, Mi, S]).
+
+
+error(R) ->
+ throw({error, R}).
diff --git a/lib/snmp/src/manager/snmpm_config.erl b/lib/snmp/src/manager/snmpm_config.erl
new file mode 100644
index 0000000000..1a5400bf8e
--- /dev/null
+++ b/lib/snmp/src/manager/snmpm_config.erl
@@ -0,0 +1,3116 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2004-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%
+%%
+%% -------------------------------------------------------------------------
+%%
+%% Some of the stuff stored here should really be persistent!!
+%% (e.g. snmp-engine-boot)
+%%
+%% -------------------------------------------------------------------------
+
+-module(snmpm_config).
+
+-behaviour(gen_server).
+
+%% External exports
+-export([start_link/1, stop/0, is_started/0]).
+-export([register_user/4, unregister_user/1,
+ which_users/0,
+ user_info/0, user_info/1, user_info/2,
+
+ register_agent/3, unregister_agent/2,
+ agent_info/0, agent_info/2, agent_info/3, update_agent_info/4,
+ which_agents/0, which_agents/1,
+
+ is_known_engine_id/2,
+ get_agent_engine_id/1,
+ get_agent_engine_max_message_size/1,
+ get_agent_version/1,
+ get_agent_mp_model/1,
+ get_agent_user_id/1, get_agent_user_id/2,
+ get_agent_user_info/2,
+
+ system_info/0, system_info/1,
+ %% update_system_info/2,
+ get_engine_id/0, get_engine_max_message_size/0,
+
+ register_usm_user/3, unregister_usm_user/2,
+ which_usm_users/0, which_usm_users/1,
+ usm_user_info/3, update_usm_user_info/4,
+ get_usm_user/2, get_usm_user_from_sec_name/2,
+ is_usm_engine_id_known/1,
+ get_engine_boots/0, get_engine_time/0,
+ set_engine_boots/1, set_engine_time/1,
+ get_usm_eboots/1, get_usm_etime/1, get_usm_eltime/1,
+ set_usm_eboots/2, set_usm_etime/2, set_usm_eltime/2,
+ reset_usm_cache/1,
+
+
+ cre_counter/2,
+ incr_counter/2,
+
+ cre_stats_counter/2,
+ maybe_cre_stats_counter/2,
+ incr_stats_counter/2,
+ reset_stats_counter/1,
+ get_stats_counters/0, get_stats_counter/1,
+
+ load_mib/1, unload_mib/1, which_mibs/0,
+ make_mini_mib/0,
+ name_to_oid/1, oid_to_name/1, oid_to_type/1,
+
+ system_start_time/0,
+
+ info/0,
+ verbosity/1,
+
+ backup/1,
+
+ mk_target_name/3
+
+ ]).
+
+%% Backward compatibillity exports
+-export([
+ register_user/3,
+ unregister_agent/3,
+ update_agent_info/5,
+ is_known_engine_id/3,
+ get_agent_engine_id/2,
+ get_agent_engine_max_message_size/2,
+ get_agent_version/2,
+ get_agent_mp_model/2
+ ]).
+
+-export([check_manager_config/1,
+ check_user_config/1,
+ check_agent_config/1,
+ check_usm_user_config/1]).
+
+
+%% gen_server callbacks
+-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
+ code_change/3, terminate/2]).
+
+
+%% Includes:
+-include_lib("kernel/include/file.hrl").
+-include("snmp_types.hrl").
+-include("snmpm_internal.hrl").
+-include("snmpm_usm.hrl").
+-include("snmp_debug.hrl").
+-include("snmp_verbosity.hrl").
+
+
+%% Types:
+-record(user, {id, mod, data, default_agent_config}).
+
+-record(state, {backup}).
+
+
+%% Macros and Constants:
+-define(SERVER, ?MODULE).
+-define(BACKUP_DB, snmpm_config_backup).
+-define(CONFIG_DB, snmpm_config_db).
+
+-define(DEFAULT_USER, default_user).
+
+-define(DEFAULT_AGENT_PORT, 161).
+
+-define(IRB_DEFAULT, auto).
+%% -define(IRB_DEFAULT, {user, timer:seconds(15)}).
+
+-define(USER_MOD_DEFAULT, snmpm_user_default).
+-define(USER_DATA_DEFAULT, undefined).
+
+%% -define(DEF_ADDR_TAG, default_addr_tag).
+-define(DEFAULT_TARGETNAME, default_agent).
+-define(DEF_PORT_TAG, default_port_tag).
+
+-ifdef(snmp_debug).
+-define(GS_START_LINK(Opts),
+ gen_server:start_link({local, ?SERVER}, ?MODULE, [Opts],
+ [{debug,[trace]}])).
+-else.
+-define(GS_START_LINK(Opts),
+ gen_server:start_link({local, ?SERVER}, ?MODULE, [Opts], [])).
+-endif.
+
+
+
+%%%-------------------------------------------------------------------
+%%% API
+%%%-------------------------------------------------------------------
+start_link(Opts) ->
+ ?d("start_link -> entry with"
+ "~n Opts: ~p", [Opts]),
+ ?GS_START_LINK(Opts).
+
+stop() ->
+ call(stop).
+
+is_started() ->
+ call(is_started, 1000).
+
+backup(BackupDir) when is_list(BackupDir) ->
+ call({backup, BackupDir}).
+
+%% Backward compatibillity
+register_user(UserId, UserMod, UserData) ->
+ register_user(UserId, UserMod, UserData, []).
+
+register_user(UserId, UserMod, UserData, DefaultAgentConfig)
+ when (UserId =/= ?DEFAULT_USER) andalso is_list(DefaultAgentConfig) ->
+ case (catch verify_user_behaviour(UserMod)) of
+ ok ->
+ Config = default_agent_config(DefaultAgentConfig),
+ call({register_user, UserId, UserMod, UserData, Config});
+ Error ->
+ Error
+ end;
+register_user(UserId, _UserMod, _UserData, DefaultAgentConfig)
+ when (UserId =/= ?DEFAULT_USER) ->
+ {error, {bad_default_agent_config, DefaultAgentConfig}};
+register_user(UserId, _, _, _) ->
+ {error, {bad_user_id, UserId}}.
+
+default_agent_config(DefaultAgentConfig) ->
+ {ok, SystemDefaultAgentConfig} = agent_info(),
+ default_agent_config(SystemDefaultAgentConfig, DefaultAgentConfig).
+
+default_agent_config([], DefaultAgentConfig) ->
+ DefaultAgentConfig;
+default_agent_config([{Key, _} = Entry|T], DefaultAgentConfig) ->
+ case lists:keysearch(Key, 1, DefaultAgentConfig) of
+ {value, _} ->
+ default_agent_config(T, DefaultAgentConfig);
+ false ->
+ default_agent_config(T, [Entry|DefaultAgentConfig])
+ end.
+
+
+verify_user_behaviour(UserMod) ->
+ case snmp_misc:verify_behaviour(snmpm_user, UserMod) of
+ ok ->
+ ok;
+ Error ->
+ %% This user may implement the old behaviour, check it
+ case snmp_misc:verify_behaviour(snmpm_user_old, UserMod) of
+ ok ->
+ ok;
+ _ ->
+ throw(Error)
+ end
+ end.
+
+
+unregister_user(UserId) when UserId =/= ?DEFAULT_USER ->
+ call({unregister_user, UserId});
+unregister_user(BadUserId) ->
+ {error, {bad_user_id, BadUserId}}.
+
+
+which_users() ->
+ Pattern = #user{id = '$1', _ = '_'},
+ Match = ets:match(snmpm_user_table, Pattern),
+ [UserId || [UserId] <- Match, UserId =/= ?DEFAULT_USER].
+
+
+user_info() ->
+ UserId = ?DEFAULT_USER,
+ case user_info(UserId) of
+ {ok, Mod, Data} ->
+ {ok, UserId, Mod, Data};
+ Error ->
+ Error
+ end.
+
+user_info(UserId) ->
+ case ets:lookup(snmpm_user_table, UserId) of
+ [#user{mod = UserMod, data = UserData}] ->
+ {ok, UserMod, UserData};
+ _ ->
+ {error, not_found}
+ end.
+
+user_info(UserId, Item) ->
+ case (catch do_user_info(UserId, Item)) of
+ {'EXIT', _} ->
+ {error, {not_found, Item}};
+ Val ->
+ {ok, Val}
+ end.
+
+do_user_info(UserId, module) ->
+ ets:lookup_element(snmpm_user_table, UserId, #user.mod);
+do_user_info(UserId, data) ->
+ ets:lookup_element(snmpm_user_table, UserId, #user.data);
+do_user_info(UserId, default_agent_config) ->
+ ets:lookup_element(snmpm_user_table, UserId, #user.default_agent_config);
+do_user_info(_UserId, BadItem) ->
+ error({not_found, BadItem}).
+
+
+%% A target-name constructed in this way is a string with the following
+%% <IP-address>:<Port>-<Version>
+%%
+mk_target_name(Addr0, Port, Config) when is_list(Config) ->
+ Version =
+ case lists:keysearch(version, 1, Config) of
+ {value, {_, V}} ->
+ V;
+ false ->
+ select_lowest_supported_version()
+ end,
+%% p("mk_target_name -> Version: ~p", [Version]),
+ case normalize_address(Addr0) of
+ {A, B, C, D} ->
+ lists:flatten(
+ io_lib:format("~w.~w.~w.~w:~w-~w", [A, B, C, D, Port, Version]));
+ [A, B, C, D] ->
+ lists:flatten(
+ io_lib:format("~w.~w.~w.~w:~w-~w", [A, B, C, D, Port, Version]));
+ _ ->
+ lists:flatten(
+ io_lib:format("~p:~w-~w", [Addr0, Port, Version]))
+ end.
+
+select_lowest_supported_version() ->
+ {ok, Versions} = system_info(versions),
+ select_lowest_supported_version([v1, v2, v3], Versions).
+
+select_lowest_supported_version([], Versions) ->
+ error({bad_versions, Versions});
+select_lowest_supported_version([H|T], Versions) ->
+ case lists:member(H, Versions) of
+ true ->
+ H;
+ false ->
+ select_lowest_supported_version(T, Versions)
+ end.
+
+
+register_agent(UserId, _TargetName, _Config) when (UserId =:= user_id) ->
+ {error, {bad_user_id, UserId}};
+register_agent(UserId, TargetName, Config)
+ when (is_list(TargetName) andalso
+ (length(TargetName) > 0) andalso
+ is_list(Config)) ->
+
+%% p("register_agent -> entry with"
+%% "~n UserId: ~p"
+%% "~n TargetName: ~p"
+%% "~n Config: ~p", [UserId, TargetName, Config]),
+
+ %% Check:
+ %% 1) That the mandatory configs are present
+ %% 2) That the illegal config user_id (used internally) is
+ %% not present
+ %% 3) Check that there are no invalid or erroneous configs
+ %% 4) Chack that the manager is capable to use the selected version
+ case verify_agent_config(Config) of
+ ok ->
+ call({register_agent, UserId, TargetName, Config});
+ Error ->
+ Error
+ end.
+
+
+verify_agent_config(Conf) ->
+ ok = verify_mandatory(Conf, [engine_id, address, reg_type]),
+ case verify_invalid(Conf, [user_id]) of
+ ok ->
+ case verify_agent_config2(Conf) of
+ ok ->
+ {ok, Vsns} = system_info(versions),
+ Vsn =
+ case lists:keysearch(version, 1, Conf) of
+ {value, {version, V}} ->
+ V;
+ false ->
+ v1
+ end,
+ case lists:member(Vsn, Vsns) of
+ true ->
+ ok;
+ false ->
+ {error, {version_not_supported_by_manager, Vsn, Vsns}}
+ end
+ end;
+ Error ->
+ Error
+ end.
+
+verify_agent_config2(Conf) ->
+ verify_agent2(Conf).
+
+
+unregister_agent(UserId, TargetName) ->
+ call({unregister_agent, UserId, TargetName}).
+
+unregister_agent(UserId, Addr0, Port) ->
+ Addr = normalize_address(Addr0),
+ case do_agent_info(Addr, Port, target_name) of
+ {ok, TargetName} ->
+ unregister_agent(UserId, TargetName);
+ Error ->
+ Error
+ end.
+
+agent_info() ->
+ agent_info(?DEFAULT_TARGETNAME, all).
+
+agent_info(TargetName, all) ->
+ case ets:match_object(snmpm_agent_table, {{TargetName, '_'}, '_'}) of
+ [] ->
+ {error, not_found};
+ All ->
+ {ok, [{Item, Val} || {{_, Item}, Val} <- All]}
+ end;
+agent_info(TargetName, Item) ->
+ case ets:lookup(snmpm_agent_table, {TargetName, Item}) of
+ [{_, Val}] ->
+ {ok, Val};
+ [] ->
+ {error, not_found}
+ end.
+
+agent_info(Addr0, Port, Item) ->
+ Addr = normalize_address(Addr0),
+ do_agent_info(Addr, Port, Item).
+
+do_agent_info(Addr, Port, target_name = Item) ->
+ case ets:lookup(snmpm_agent_table, {Addr, Port, Item}) of
+ [{_, Val}] ->
+ {ok, Val};
+ [] ->
+ {error, not_found}
+ end;
+do_agent_info(Addr, Port, Item) ->
+ case do_agent_info(Addr, Port, target_name) of
+ {ok, TargetName} ->
+ agent_info(TargetName, Item);
+ Error ->
+ Error
+ end.
+
+
+which_agents() ->
+ which_agents('_').
+
+which_agents(UserId) ->
+ Pat = {{'$1', user_id}, UserId},
+ Agents = ets:match(snmpm_agent_table, Pat),
+ [TargetName || [TargetName] <- Agents].
+
+
+update_agent_info(UserId, TargetName, Item, Val0)
+ when (Item =/= user_id) ->
+ case (catch verify_val(Item, Val0)) of
+ {ok, Val} ->
+ call({update_agent_info, UserId, TargetName, Item, Val});
+ Error ->
+ Error
+ end.
+
+%% Backward compatibillity
+update_agent_info(UserId, Addr, Port, Item, Val) ->
+ case agent_info(Addr, Port, target_name) of
+ {ok, TargetName} ->
+ update_agent_info(UserId, TargetName, Item, Val);
+ Error ->
+ Error
+ end.
+
+is_known_engine_id(EngineID, TargetName) ->
+ case agent_info(TargetName, engine_id) of
+ {ok, EngineID} ->
+ true;
+ {ok, _OtherEngineID} ->
+ false;
+ _ ->
+ false
+ end.
+
+%% Backward compatibillity
+is_known_engine_id(EngineID, Addr, Port) ->
+ case agent_info(Addr, Port, target_name) of
+ {ok, TargetName} ->
+ is_known_engine_id(EngineID, TargetName);
+ _ ->
+ false
+ end.
+
+get_agent_engine_id(TargetName) ->
+ agent_info(TargetName, engine_id).
+
+%% Backward compatibillity
+get_agent_engine_id(Addr, Port) ->
+ agent_info(Addr, Port, engine_id).
+
+get_agent_engine_max_message_size(TargetName) ->
+ agent_info(TargetName, max_message_size).
+
+%% Backward compatibillity
+get_agent_engine_max_message_size(Addr, Port) ->
+ agent_info(Addr, Port, max_message_size).
+
+get_agent_version(TargetName) ->
+ agent_info(TargetName, version).
+
+%% Backward compatibillity
+get_agent_version(Addr, Port) ->
+ agent_info(Addr, Port, version).
+
+get_agent_mp_model(TargetName) ->
+ case agent_info(TargetName, version) of
+ {ok, v2} ->
+ {ok, v2c};
+ {ok, V} ->
+ {ok, V};
+ Err ->
+ Err
+ end.
+
+%% Backward compatibillity
+get_agent_mp_model(Addr, Port) ->
+ case agent_info(Addr, Port, target_name) of
+ {ok, TargetName} ->
+ get_agent_mp_model(TargetName);
+ Error ->
+ Error
+ end.
+
+get_agent_user_id(TargetName) ->
+ agent_info(TargetName, user_id).
+
+get_agent_user_id(Addr, Port) ->
+ agent_info(Addr, Port, user_id).
+
+get_agent_user_info(Addr, Port) ->
+ case agent_info(Addr, Port, target_name) of
+ {ok, Target} ->
+ case agent_info(Target, reg_type) of
+ {ok, RegType} ->
+ case agent_info(Target, user_id) of
+ {ok, UserId} ->
+ {ok, UserId, Target, RegType};
+ {error, not_found} ->
+ {error, {user_id_not_found, Target}}
+ end;
+ {error, not_found} ->
+ {error, {reg_type_not_found, Target}}
+ end;
+ {error, not_found} ->
+ {error, {target_name_not_found, Addr, Port}}
+ end.
+
+
+
+system_info() ->
+ system_info(all).
+
+system_info(all) ->
+ lists:sort(ets:tab2list(snmpm_config_table));
+system_info(Key) when is_atom(Key) ->
+ case ets:lookup(snmpm_config_table, Key) of
+ [{_, Val}] ->
+ {ok, Val};
+ _ ->
+ {error, not_found}
+ end.
+
+%% update_system_info(Key, Val) ->
+%% call({update_system_info, Key, Val}).
+
+system_start_time() ->
+ system_info(system_start_time).
+
+get_engine_id() ->
+ system_info(engine_id).
+
+get_engine_max_message_size() ->
+ system_info(max_message_size).
+
+get_engine_boots() ->
+ case dets:lookup(?CONFIG_DB, snmp_engine_boots) of
+ [{_, Boots}] ->
+ {ok, Boots};
+ _ ->
+ {error, not_found}
+ end.
+
+set_engine_boots(Boots) ->
+ case (whereis(?SERVER) =:= self()) of
+ false ->
+ call({set_engine_boots, Boots});
+ true ->
+ dets:insert(?CONFIG_DB, {snmp_engine_boots, Boots}),
+ ok
+ end.
+
+
+get_engine_time() ->
+ case system_info(snmp_engine_base) of
+ {ok, EngineBase} ->
+ {ok, snmp_misc:now(sec) - EngineBase};
+ Error ->
+ Error
+ end.
+
+get_usm_eboots(SnmpEngineID) ->
+ Key = {eboots, SnmpEngineID},
+ case get_usm_cache(Key) of
+ {ok, Boots} ->
+ {ok, Boots};
+ _ ->
+ {ok, 0}
+ end.
+
+get_usm_etime(SnmpEngineID) ->
+ Key = {etime, SnmpEngineID},
+ case get_usm_cache(Key) of
+ {ok, Diff} ->
+ {ok, snmp_misc:now(sec) - Diff};
+ _ ->
+ {ok, 0}
+ end.
+
+get_usm_eltime(SnmpEngineID) ->
+ Key = {eltime, SnmpEngineID},
+ case get_usm_cache(Key) of
+ {ok, Time} ->
+ {ok, Time};
+ _ ->
+ {ok, 0}
+ end.
+
+get_usm_cache(Key) ->
+ case ets:lookup(snmpm_usm_table, {usm_cache, Key}) of
+ [{_, Val}] ->
+ {ok, Val};
+ _ ->
+ {error, not_found}
+ end.
+
+set_usm_eboots(SnmpEngineID, EngineBoots) ->
+ set_usm_cache({eboots, SnmpEngineID}, EngineBoots).
+
+set_usm_etime(SnmpEngineID, Diff) ->
+ set_usm_cache({etime, SnmpEngineID}, Diff).
+
+set_usm_eltime(SnmpEngineID, Time) ->
+ set_usm_cache({eltime, SnmpEngineID}, Time).
+
+set_usm_cache(Key, Val) ->
+ call({set_usm_cache, Key, Val}).
+
+reset_usm_cache(SnmpEngineID) ->
+ case (whereis(?SERVER) =:= self()) of
+ false ->
+ call({reset_usm_cache, SnmpEngineID});
+ true ->
+ Pat = {{usm_cache, {'_', SnmpEngineID}}, '_'},
+ ets:match_delete(snmpm_usm_table, Pat),
+ ok
+ end.
+
+set_engine_time(Time) ->
+ call({set_engine_time, Time}).
+
+register_usm_user(EngineID, Name, Config)
+ when is_list(EngineID) andalso is_list(Name) ->
+ case verify_usm_user_config(EngineID, Name, Config) of
+ {ok, User} ->
+ call({register_usm_user, User});
+ Error ->
+ Error
+ end.
+
+unregister_usm_user(EngineID, Name)
+ when is_list(EngineID) andalso is_list(Name) ->
+ call({unregister_usm_user, EngineID, Name}).
+
+verify_usm_user_config(EngineID, Name, Config) ->
+ %% case verify_mandatory(Config, []) of
+ %% ok ->
+ %% case verify_invalid(Config, [engine_id, name]) of
+ %% ok ->
+ %% verify_usm_user_config2(EngineID, Name, Config);
+ %% Error ->
+ %% Error
+ %% end;
+ %% Error ->
+ %% Error
+ %% end.
+ ok = verify_mandatory(Config, []),
+ case verify_invalid(Config, [engine_id, name]) of
+ ok ->
+ verify_usm_user_config2(EngineID, Name, Config);
+ Error ->
+ Error
+ end.
+
+verify_usm_user_config2(EngineID, Name, Config) ->
+ SecName = verify_usm_user_get(sec_name, Name, Config),
+ Auth = verify_usm_user_get(auth, usmNoAuthProtocol, Config),
+ AuthKey = verify_usm_user_get(auth_key, [], Config),
+ Priv = verify_usm_user_get(priv, usmNoPrivProtocol, Config),
+ PrivKey = verify_usm_user_get(priv_key, [], Config),
+ User = {EngineID, Name, SecName, Auth, AuthKey, Priv, PrivKey},
+ verify_usm_user(User).
+
+verify_usm_user_get(Item, Default, Config) ->
+ case lists:keysearch(Item, 1, Config) of
+ {value, {_, Val}} ->
+ Val;
+ false ->
+ Default
+ end.
+
+which_usm_users() ->
+ Pattern = {usm_key('$1', '$2'), '_'},
+ Match = ets:match(snmpm_usm_table, Pattern),
+ [{EngineID, UserName} || [EngineID, UserName] <- Match].
+
+which_usm_users(EngineID) ->
+ Pattern = {usm_key(EngineID, '$1'), '_'},
+ Match = ets:match(snmpm_usm_table, Pattern),
+ [UserName || [UserName] <- Match].
+
+usm_user_info(EngineID, UserName, Item) ->
+ case ets:lookup(snmpm_usm_table, usm_key(EngineID, UserName)) of
+ [] ->
+ {error, not_found};
+ [{_Key, UsmUser}] ->
+ do_usm_user_info(UsmUser, Item)
+ end.
+
+do_usm_user_info(#usm_user{sec_name = SecName}, sec_name) ->
+ {ok, SecName};
+do_usm_user_info(#usm_user{auth = AuthP}, auth) ->
+ {ok, AuthP};
+do_usm_user_info(#usm_user{auth_key = AuthKey}, auth_key) ->
+ {ok, AuthKey};
+do_usm_user_info(#usm_user{priv = PrivP}, priv) ->
+ {ok, PrivP};
+do_usm_user_info(#usm_user{priv_key = PrivKey}, priv_key) ->
+ {ok, PrivKey};
+do_usm_user_info(#usm_user{engine_id = EngineID}, engine_id) ->
+ {ok, EngineID};
+do_usm_user_info(#usm_user{name = Name}, name) ->
+ {ok, Name};
+do_usm_user_info(_, Item) ->
+ {error, {bad_iten, Item}}.
+
+update_usm_user_info(EngineID, UserName, Item, Val)
+ when (Item =/= engine_id) andalso (Item =/= name) ->
+ call({update_usm_user_info, EngineID, UserName, Item, Val}).
+
+get_usm_user(EngineID, UserName) ->
+ Key = usm_key(EngineID, UserName),
+ case ets:lookup(snmpm_usm_table, Key) of
+ [{_, User}] ->
+ {ok, User};
+ _ ->
+ {error, not_found}
+ end.
+
+is_usm_engine_id_known(EngineID) ->
+ Pattern = {usm_key(EngineID, '$1'), '_'},
+ case ets:match(snmpm_usm_table, Pattern) of
+ [] ->
+ false;
+ _ ->
+ true
+ end.
+
+get_usm_user_from_sec_name(EngineID, SecName) ->
+ %% Since the normal mapping between UserName and SecName is the
+ %% identity-function, we first try to use the SecName as UserName,
+ %% and check the resulting row. If it doesn't match, we'll have to
+ %% loop through the entire table.
+ Key = usm_key(EngineID, SecName),
+ case ets:lookup(snmpm_usm_table, Key) of
+ [{Key, #usm_user{sec_name = SecName} = User}] ->
+ {ok, User};
+ _ ->
+ %% That did not work, so we have to search
+ Pattern = {usm_key(EngineID, '_'),
+ #usm_user{sec_name = SecName, _ = '_'}},
+ case ets:match_object(snmpm_usm_table, Pattern) of
+ [{_, User}|_] ->
+ {ok, User};
+ _ ->
+ {error, not_found}
+ end
+ end.
+
+
+%% Wrap-counters (wrapping at 2147483647 or 4294967295)
+cre_counter(Counter, Initial) ->
+ case (whereis(?SERVER) =:= self()) of
+ false ->
+ call({cre_counter, Counter, Initial});
+ true ->
+ ets:insert(snmpm_counter_table, {Counter, Initial}),
+ Initial
+ end.
+
+incr_counter(usm_salt, Incr) -> % Backward compatibillity (upgrade)
+ incr_counter(usm_des_salt, Incr); % Backward compatibillity (upgrade)
+incr_counter(usm_des_salt, Incr) ->
+ incr_counter(usm_des_salt, Incr, 4294967295);
+incr_counter(usm_aes_salt, Incr) ->
+ incr_counter(usm_aes_salt, Incr, 36893488147419103231);
+incr_counter(Counter, Incr) ->
+ incr_counter(Counter, Incr, 2147483647).
+
+incr_counter(Counter, Incr, Wrap) ->
+ case (catch ets:update_counter(snmpm_counter_table, Counter, Incr)) of
+ {'EXIT', _} ->
+ cre_counter(Counter, Incr);
+ NewVal when NewVal =< Wrap ->
+ NewVal;
+ N ->
+ cre_counter(Counter, N - Wrap)
+ end.
+
+
+maybe_cre_stats_counter(Counter, Initial) ->
+ case ets:lookup(snmpm_stats_table, Counter) of
+ [_] ->
+ ok;
+ _ ->
+ cre_stats_counter(Counter, Initial)
+ end.
+
+cre_stats_counter(Counter, Initial) ->
+ case (whereis(?SERVER) =:= self()) of
+ false ->
+ call({cre_stats_counter, Counter, Initial});
+ true ->
+ ets:insert(snmpm_stats_table, {Counter, Initial}),
+ Initial
+ end.
+
+incr_stats_counter(Counter, Incr) ->
+ case (catch ets:update_counter(snmpm_stats_table, Counter, Incr)) of
+ {'EXIT', _} ->
+ cre_counter(Counter, Incr);
+ NewVal ->
+ NewVal
+ end.
+
+reset_stats_counter(Counter) ->
+ case (whereis(?SERVER) =:= self()) of
+ false ->
+ call({reset_stats_counter, Counter});
+ true ->
+ ets:insert(snmpm_stats_table, {Counter, 0})
+ end,
+ ok.
+
+get_stats_counter(Counter) ->
+ case ets:lookup(snmpm_stats_table, Counter) of
+ [{Counter, Value}] ->
+ {ok, Value};
+ _ ->
+ {error, not_found}
+ end.
+
+get_stats_counters() ->
+ ets:tab2list(snmpm_stats_table).
+
+load_mib(Mib) when is_list(Mib) ->
+ call({load_mib, Mib}).
+
+unload_mib(Mib) when is_list(Mib) ->
+ call({unload_mib, Mib}).
+
+which_mibs() ->
+ Pattern = {{mib, '_'}, '$1', '$2'},
+ Mibs = ets:match(snmpm_mib_table, Pattern),
+ [list_to_tuple(X) || X <- Mibs].
+
+name_to_oid(Name) ->
+ Pat = {{mini_mib, '$1'}, Name, '_', '_'},
+ case ets:match(snmpm_mib_table, Pat) of
+ [] ->
+ {error, not_found};
+ X ->
+ Oids = [Oid || [Oid] <- X],
+ {ok, Oids}
+ end.
+
+oid_to_name(Oid) ->
+ case ets:lookup(snmpm_mib_table, {mini_mib, Oid}) of
+ [{_, Name, _, _}] ->
+ {ok, Name};
+ [] ->
+ {error, not_found}
+ end.
+
+oid_to_type(Oid) ->
+ case ets:lookup(snmpm_mib_table, {mini_mib, Oid}) of
+ [{_, _, Type, _}] ->
+ {ok, Type};
+ [] ->
+ {error, not_found}
+ end.
+
+make_mini_mib() ->
+ Pat = {{mini_mib, '$1'}, '$2', '$3', '_'},
+ MiniElems = ets:match(snmpm_mib_table, Pat),
+ lists:keysort(1, [list_to_tuple(MiniElem) || MiniElem <- MiniElems]).
+
+
+info() ->
+ call(info).
+
+verbosity(Verbosity) ->
+ case ?vvalidate(Verbosity) of
+ Verbosity ->
+ call({verbosity, Verbosity});
+ _ ->
+ {error, {invalid_verbosity, Verbosity}}
+ end.
+
+
+%%%-------------------------------------------------------------------
+%%% Callback functions from gen_server
+%%%-------------------------------------------------------------------
+
+%%--------------------------------------------------------------------
+%% Func: init/1
+%% Returns: {ok, State} |
+%% {ok, State, Timeout} |
+%% ignore |
+%% {stop, Reason}
+%%--------------------------------------------------------------------
+init([Opts]) ->
+% put(sname, mconf),
+% put(verbosity, trace),
+ ?d("init -> entry with"
+ "~n Opts: ~p", [Opts]),
+ case (catch do_init(Opts)) of
+ ok ->
+ {ok, #state{}};
+ {error, Reason} ->
+ error_msg("init error: ~p", [Reason]),
+ {stop, Reason};
+ {'EXIT', Reason} ->
+ error_msg("init exit: ~p", [Reason]),
+ {stop, Reason};
+ Error ->
+ error_msg("init failed: ~p", [Error]),
+ {stop, Error}
+ end.
+
+do_init(Opts) ->
+ process_flag(trap_exit, true),
+ %% Mandatory = [versions, {config, [dir]}],
+ Mandatory = [{config, [dir, db_dir]}],
+ verify_options(Opts, Mandatory),
+
+ ets:new(snmpm_counter_table, [set, public, named_table, {keypos, 1}]),
+ ets:new(snmpm_stats_table, [set, public, named_table, {keypos, 1}]),
+ ets:new(snmpm_mib_table, [set, protected, named_table, {keypos, 1}]),
+ ets:new(snmpm_config_table, [set, protected, named_table, {keypos, 1}]),
+ ets:new(snmpm_agent_table, [set, protected, named_table, {keypos, 1}]),
+ ets:new(snmpm_user_table, [set, protected, named_table, {keypos, 2}]),
+ ets:new(snmpm_usm_table, [set, protected, named_table, {keypos, 1}]),
+
+ %% -- System start time --
+ ets:insert(snmpm_config_table, {system_start_time, snmp_misc:now(cs)}),
+
+ %% --- Own options (dir and db_dir mandatory) ---
+ ConfOpts = get_opt(config, Opts, []),
+ ConfVerb = get_opt(verbosity, ConfOpts, silence),
+ ConfDir = get_opt(dir, ConfOpts),
+ ConfDbDir = get_opt(db_dir, ConfOpts),
+ ConfDbInitErr = get_opt(db_init_error, ConfOpts, terminate),
+ ConfRep = get_opt(repair, ConfOpts, true),
+ ConfAs = get_opt(auto_save, ConfOpts, 5000),
+ ets:insert(snmpm_config_table, {config_verbosity, ConfVerb}),
+ ets:insert(snmpm_config_table, {config_dir, ConfDir}),
+ ets:insert(snmpm_config_table, {config_db_dir, ConfDbDir}),
+ ets:insert(snmpm_config_table, {config_db_init_error, ConfDbInitErr}),
+ ets:insert(snmpm_config_table, {config_repair, ConfRep}),
+ ets:insert(snmpm_config_table, {config_auto_save, ConfAs}),
+ put(sname, mconf),
+ put(verbosity, ConfVerb),
+ ?vlog("starting", []),
+
+ %% -- Create dets file used for storing persistent data --
+ dets_open(ConfDbDir, ConfDbInitErr, ConfRep, ConfAs),
+
+ %% -- Prio (optional) --
+ Prio = get_opt(priority, Opts, normal),
+ ets:insert(snmpm_config_table, {prio, Prio}),
+ process_flag(priority, Prio),
+
+ %% -- Server (optional) --
+ ServerOpts = get_opt(server, Opts, []),
+ ServerVerb = get_opt(verbosity, ServerOpts, silence),
+ ServerGct = get_opt(timeout, ServerOpts, 30000),
+ ServerMt = get_opt(multi_threaded, ServerOpts, true),
+ ets:insert(snmpm_config_table, {server_verbosity, ServerVerb}),
+ ets:insert(snmpm_config_table, {server_timeout, ServerGct}),
+ ets:insert(snmpm_config_table, {server_multi_threaded, ServerMt}),
+
+ %% -- Mibs (optional) --
+ ?vdebug("initiate mini mib", []),
+ Mibs = get_opt(mibs, Opts, []),
+ ets:insert(snmpm_config_table, {mibs, Mibs}),
+ init_mini_mib(Mibs),
+
+ %% -- Net-if (optional) --
+ ?vdebug("net_if options", []),
+ NetIfIrb =
+ case get_opt(inform_request_behaviour, Opts, ?IRB_DEFAULT) of
+ user ->
+ {user, timer:seconds(15)};
+ Irb ->
+ Irb
+ end,
+ NetIfOpts = get_opt(net_if, Opts, []),
+ NetIfMod = get_opt(module, NetIfOpts, snmpm_net_if),
+ NetIfVerb = get_opt(verbosity, NetIfOpts, silence),
+ NetIfOptions = get_opt(options, NetIfOpts, []),
+ ets:insert(snmpm_config_table, {net_if_module, NetIfMod}),
+ ets:insert(snmpm_config_table, {net_if_verbosity, NetIfVerb}),
+ ets:insert(snmpm_config_table, {net_if_irb, NetIfIrb}),
+ ets:insert(snmpm_config_table, {net_if_options, NetIfOptions}),
+
+ %% -- Versions (optional) --
+ %% -- Versions (mandatory) ???????????? --
+ ?vdebug("versions", []),
+ Vsns = get_opt(versions, Opts, [v1, v2, v3]),
+ ets:insert(snmpm_config_table, {versions, Vsns}),
+
+ %% -- Audit trail log (optional) --
+ ?vdebug("audit trail log", []),
+ case get_opt(audit_trail_log, Opts, []) of
+ [] ->
+ ?vtrace("no ATL", []),
+ ets:insert(snmpm_config_table, {audit_trail_log, false});
+ AuditTrailLogOpts ->
+ ?vtrace("ATL options: ~p", [AuditTrailLogOpts]),
+ ets:insert(snmpm_config_table, {audit_trail_log, true}),
+ LogDir = get_atl_dir(AuditTrailLogOpts),
+ LogType = get_atl_type(AuditTrailLogOpts),
+ LogSize = get_atl_size(AuditTrailLogOpts),
+ LogRep = get_atl_repair(AuditTrailLogOpts),
+ ets:insert(snmpm_config_table, {audit_trail_log_dir, LogDir}),
+ ets:insert(snmpm_config_table, {audit_trail_log_type, LogType}),
+ ets:insert(snmpm_config_table, {audit_trail_log_size, LogSize}),
+ ets:insert(snmpm_config_table, {audit_trail_log_repair, LogRep})
+ end,
+
+ %% -- System default agent config --
+ ?vdebug("system default agent config", []),
+ init_agent_default(),
+
+ %% -- User (optional) --
+ ?vdebug("default user", []),
+ DefUserMod = get_opt(def_user_mod, Opts, ?USER_MOD_DEFAULT),
+ DefUserData = get_opt(def_user_data, Opts, ?USER_DATA_DEFAULT),
+ ets:insert(snmpm_config_table, {def_user_mod, DefUserMod}),
+ ets:insert(snmpm_config_table, {def_user_data, DefUserData}),
+
+ {ok, SystemDefaultAgentConfig} = agent_info(),
+ DefUser = #user{id = ?DEFAULT_USER,
+ mod = DefUserMod,
+ data = DefUserData,
+ default_agent_config = SystemDefaultAgentConfig},
+ ok = handle_register_user(DefUser),
+
+ %% -- Note store --
+ ?vdebug("note store", []),
+ NoteStoreOpts = get_opt(note_store, Opts, []),
+ NoteStoreVerb = get_opt(verbosity, NoteStoreOpts, silence),
+ NoteStoreTimeout = get_opt(timeout, NoteStoreOpts, 30000),
+ ets:insert(snmpm_config_table, {note_store_verbosity, NoteStoreVerb}),
+ ets:insert(snmpm_config_table, {note_store_timeout, NoteStoreTimeout}),
+
+ %% -- Manager SNMP config --
+ ?vdebug("manager snmp config", []),
+ MgrConf = read_manager_config_file(ConfDir),
+ init_manager_config(MgrConf),
+
+ %% -- User config --
+ ?vdebug("users config", []),
+ Users = read_users_config_file(ConfDir),
+ init_users_config(Users),
+
+ %% -- Agents config --
+ ?vdebug("agents config", []),
+ Agents = read_agents_config_file(ConfDir),
+ init_agents_config(Agents),
+
+ %% -- USM config --
+ UsmUsers = read_usm_config_file(ConfDir),
+ init_usm_users_config(UsmUsers),
+
+ %% -- snmp engine init --
+ init_engine(),
+
+ ?vlog("started", []),
+ ok.
+
+
+dets_open(Dir, DbInitError, Repair, AutoSave) ->
+ Name = ?CONFIG_DB,
+ Filename = dets_filename(Name, Dir),
+ case file:read_file_info(Filename) of
+ {ok, _} ->
+ %% File exists
+ case do_dets_open(Name, Filename, Repair, AutoSave) of
+ {ok, _Dets} ->
+ ok;
+ {error, Reason1} ->
+ info_msg("Corrupt local database: ~p", [Filename]),
+ case DbInitError of
+ terminate ->
+ error({failed_reopen_dets, Filename, Reason1});
+ _ ->
+ Saved = Filename ++ ".saved",
+ file:rename(Filename, Saved),
+ case do_dets_open(Name, Filename,
+ Repair, AutoSave) of
+ {ok, _Dets} ->
+ ok;
+ {error, Reason2} ->
+ error({failed_open_dets, Filename,
+ Reason1, Reason2})
+ end
+ end
+ end;
+ _ ->
+ case do_dets_open(Name, Filename, Repair, AutoSave) of
+ {ok, _Dets} ->
+ ok;
+ {error, Reason} ->
+ error({failed_open_dets, Filename, Reason})
+ end
+ end.
+
+do_dets_open(Name, Filename, Repair, AutoSave) ->
+ Opts = [{repair, Repair},
+ {auto_save, AutoSave},
+ {file, Filename}],
+ dets:open_file(Name, Opts).
+
+
+dets_filename(Name, Dir) when is_atom(Name) ->
+ dets_filename(atom_to_list(Name), Dir);
+dets_filename(Name, Dir) ->
+ filename:join(dets_filename1(Dir), Name).
+
+dets_filename1([]) -> ".";
+dets_filename1(Dir) -> Dir.
+
+
+%% ------------------------------------------------------------------------
+
+init_engine() ->
+ case get_engine_boots() of
+ {ok, Val} when Val < 2147483647 ->
+ set_engine_boots(Val + 1);
+ {ok, _} ->
+ ok;
+ _ ->
+ set_engine_boots(1)
+ end,
+ reset_engine_base().
+
+reset_engine_base() ->
+ ets:insert(snmpm_config_table, {snmp_engine_base, snmp_misc:now(sec)}).
+
+
+%% ------------------------------------------------------------------------
+
+verify_options(Opts, Mandatory) ->
+ ?d("verify_options -> entry with"
+ "~n Opts: ~p"
+ "~n Mandatory: ~p", [Opts, Mandatory]),
+ verify_mandatory_options(Opts, Mandatory),
+ verify_options(Opts).
+
+%% mandatory() -> [mand()]
+%% mand() -> atom() | {atom, [atom()]}
+verify_mandatory_options(_Opts, []) ->
+ ok;
+verify_mandatory_options(Opts, [Mand|Mands]) ->
+ verify_mandatory_option(Opts, Mand),
+ verify_mandatory_options(Opts, Mands).
+
+verify_mandatory_option(Opts, {Mand, MandSubOpts}) ->
+ ?d("verify_mandatory_option -> entry with"
+ "~n Mand: ~p"
+ "~n MandSubObjs: ~p", [Mand, MandSubOpts]),
+ case lists:keysearch(Mand, 1, Opts) of
+ {value, {Mand, SubOpts}} ->
+ verify_mandatory_options(SubOpts, MandSubOpts);
+ false ->
+ ?d("missing mandatory option: ~w [~p]", [Mand, MandSubOpts]),
+ error({missing_mandatory, Mand, MandSubOpts})
+ end;
+verify_mandatory_option(Opts, Mand) ->
+ ?d("verify_mandatory_option -> entry with"
+ "~n Mand: ~p", [Mand]),
+ case lists:keymember(Mand, 1, Opts) of
+ true ->
+ ok;
+ false ->
+ ?d("missing mandatory option: ~w", [Mand]),
+ error({missing_mandatory, Mand})
+ end.
+
+verify_options([]) ->
+ ?d("verify_options -> done", []),
+ ok;
+verify_options([Opt|Opts]) ->
+ ?d("verify_options -> entry with"
+ "~n Opt: ~p", [Opt]),
+ verify_option(Opt),
+ verify_options(Opts).
+
+verify_option({prio, Prio}) ->
+ verify_prio(Prio);
+verify_option({mibs, Mibs}) ->
+ verify_mibs(Mibs);
+verify_option({inform_request_behaviour, IRB}) ->
+ verify_irb(IRB);
+verify_option({net_if, NetIfOpts}) ->
+ verify_net_if_opts(NetIfOpts);
+verify_option({server, ServerOpts}) ->
+ verify_server_opts(ServerOpts);
+verify_option({note_store, NoteStoreOpts}) ->
+ verify_note_store_opts(NoteStoreOpts);
+verify_option({config, ConfOpts}) ->
+ verify_config_opts(ConfOpts);
+verify_option({versions, Vsns}) ->
+ verify_versions(Vsns);
+verify_option({audit_trail_log, LogOpts}) ->
+ Mandatory = [dir, size],
+ case (catch verify_mandatory_options(LogOpts, Mandatory)) of
+ ok ->
+ verify_audit_trail_log_opts(LogOpts);
+ {error, {missing_mandatory, LogOpt}} ->
+ error({missing_mandatory, audit_trail_log, LogOpt})
+ end;
+verify_option({def_user_mod, Mod}) ->
+ verify_module(def_user_mod, Mod);
+verify_option({def_user_data, _Data}) ->
+ ok;
+verify_option(Opt) ->
+ {error, {invalid_option, Opt}}.
+
+verify_prio(Prio) when is_atom(Prio) ->
+ ok;
+verify_prio(Prio) ->
+ error({invalid_prio, Prio}).
+
+verify_irb(auto) ->
+ ok;
+verify_irb(user) ->
+ ok;
+verify_irb({user, To}) when is_integer(To) andalso (To > 0) ->
+ ok;
+verify_irb(IRB) ->
+ error({invalid_irb, IRB}).
+
+verify_mibs([]) ->
+ ok;
+verify_mibs([Mib|Mibs]) when is_list(Mib) ->
+ verify_mibs(Mibs);
+verify_mibs(Mibs) ->
+ error({invalid_mibs, Mibs}).
+
+verify_config_opts([]) ->
+ ok;
+verify_config_opts([{verbosity, Verbosity}|Opts]) ->
+ verify_verbosity(Verbosity),
+ verify_config_opts(Opts);
+verify_config_opts([{dir, Dir}|Opts]) ->
+ verify_conf_dir(Dir),
+ verify_config_opts(Opts);
+verify_config_opts([{db_dir, Dir}|Opts]) ->
+ verify_conf_db_dir(Dir),
+ verify_config_opts(Opts);
+verify_config_opts([{db_init_error, DbInitErr}|Opts]) ->
+ verify_conf_db_init_error(DbInitErr),
+ verify_config_opts(Opts);
+verify_config_opts([{repair, Repair}|Opts]) ->
+ verify_conf_repair(Repair),
+ verify_config_opts(Opts);
+verify_config_opts([{auto_save, AutoSave}|Opts]) ->
+ verify_conf_auto_save(AutoSave),
+ verify_config_opts(Opts);
+verify_config_opts([Opt|_]) ->
+ error({invalid_config_option, Opt}).
+
+verify_server_opts([]) ->
+ ok;
+verify_server_opts([{verbosity, Verbosity}|Opts]) ->
+ verify_verbosity(Verbosity),
+ verify_server_opts(Opts);
+verify_server_opts([{timeout, Timeout}|Opts]) ->
+ verify_server_timeout(Timeout),
+ verify_server_opts(Opts);
+verify_server_opts([Opt|_]) ->
+ error({invalid_server_option, Opt}).
+
+verify_server_timeout(T) when is_integer(T) andalso (T > 0) ->
+ ok;
+verify_server_timeout(T) ->
+ error({invalid_server_timeout, T}).
+
+verify_net_if_opts([]) ->
+ ok;
+verify_net_if_opts([{module, Mod}|Opts]) ->
+ verify_network_interface_behaviour(Mod),
+ verify_net_if_opts(Opts);
+verify_net_if_opts([{verbosity, Verbosity}|Opts]) ->
+ verify_verbosity(Verbosity),
+ verify_net_if_opts(Opts);
+verify_net_if_opts([{options, Options}|Opts]) when is_list(Options) ->
+ verify_net_if_opts(Opts);
+verify_net_if_opts([Opt|_]) ->
+ error({invalid_net_if_option, Opt}).
+
+verify_network_interface_behaviour(Mod) ->
+ case snmp_misc:verify_behaviour(snmpm_network_interface, Mod) of
+ ok ->
+ ok;
+ Error ->
+ throw(Error)
+ end.
+
+
+verify_note_store_opts([]) ->
+ ok;
+verify_note_store_opts([{verbosity, Verbosity}|Opts]) ->
+ verify_verbosity(Verbosity),
+ verify_note_store_opts(Opts);
+verify_note_store_opts([{timeout, Timeout}|Opts]) ->
+ verify_note_store_timeout(Timeout),
+ verify_note_store_opts(Opts);
+verify_note_store_opts([Opt|_]) ->
+ error({invalid_note_store_option, Opt}).
+
+verify_note_store_timeout(T) when is_integer(T) andalso (T > 0) ->
+ ok;
+verify_note_store_timeout(T) ->
+ error({invalid_note_store_timeout, T}).
+
+verify_conf_dir(Dir) ->
+ case (catch verify_dir(Dir)) of
+ ok ->
+ ok;
+ {error, Reason} ->
+ error({invalid_conf_dir, Dir, Reason});
+ _ ->
+ error({invalid_conf_dir, Dir})
+ end.
+
+verify_conf_db_dir(Dir) ->
+ case (catch verify_dir(Dir)) of
+ ok ->
+ ok;
+ {error, Reason} ->
+ error({invalid_conf_db_dir, Dir, Reason});
+ _ ->
+ error({invalid_conf_db_dir, Dir})
+ end.
+
+
+verify_conf_db_init_error(terminate) ->
+ ok;
+verify_conf_db_init_error(create) ->
+ ok;
+verify_conf_db_init_error(InvalidDbInitError) ->
+ error({invalid_conf_db_init_error, InvalidDbInitError}).
+
+
+verify_conf_repair(true) ->
+ ok;
+verify_conf_repair(false) ->
+ ok;
+verify_conf_repair(force) ->
+ ok;
+verify_conf_repair(InvalidRepair) ->
+ error({invalid_conf_db_repair, InvalidRepair}).
+
+
+verify_conf_auto_save(infinity) ->
+ ok;
+verify_conf_auto_save(AutoSave)
+ when is_integer(AutoSave) andalso (AutoSave > 0) ->
+ ok;
+verify_conf_auto_save(InvalidAutoSave) ->
+ error({invalid_conf_db_auto_save, InvalidAutoSave}).
+
+
+verify_versions([]) ->
+ ok;
+verify_versions([Vsn|Vsns]) ->
+ verify_version(Vsn),
+ verify_versions(Vsns).
+
+verify_version(v1) ->
+ ok;
+verify_version(v2) ->
+ ok;
+verify_version(v3) ->
+ ok;
+verify_version(Vsn) ->
+ error({invalid_version, Vsn}).
+
+verify_audit_trail_log_opts([]) ->
+ ok;
+verify_audit_trail_log_opts([{dir, Dir}|Opts]) ->
+ verify_log_dir(Dir),
+ verify_audit_trail_log_opts(Opts);
+verify_audit_trail_log_opts([{type, Type}|Opts]) ->
+ verify_log_type(Type),
+ verify_audit_trail_log_opts(Opts);
+verify_audit_trail_log_opts([{size, Size}|Opts]) ->
+ verify_log_size(Size),
+ verify_audit_trail_log_opts(Opts);
+verify_audit_trail_log_opts([{repair, Repair}|Opts]) ->
+ verify_log_repair(Repair),
+ verify_audit_trail_log_opts(Opts);
+verify_audit_trail_log_opts([Opt|_Opts]) ->
+ error({invalid_audit_trail_log_option, Opt}).
+
+verify_log_type(read) ->
+ ok;
+verify_log_type(write) ->
+ ok;
+verify_log_type(read_write) ->
+ ok;
+verify_log_type(Type) ->
+ error({invalid_audit_trail_log_type, Type}).
+
+verify_log_dir(Dir) ->
+ case (catch verify_dir(Dir)) of
+ ok ->
+ ok;
+ {error, Reason} ->
+ error({invalid_audit_trail_log_dir, Dir, Reason});
+ _ ->
+ error({invalid_audit_trail_log_dir, Dir})
+ end.
+
+verify_log_size(Sz) when is_integer(Sz) andalso (Sz > 0) ->
+ ok;
+verify_log_size(infinity) ->
+ ok;
+verify_log_size({MaxNoBytes, MaxNoFiles})
+ when (is_integer(MaxNoBytes) andalso
+ (MaxNoBytes > 0) andalso
+ is_integer(MaxNoFiles) andalso
+ (MaxNoFiles > 0) andalso
+ (MaxNoFiles < 65000)) ->
+ ok;
+verify_log_size(Sz) ->
+ error({invalid_audit_trail_log_size, Sz}).
+
+verify_log_repair(true) -> ok;
+verify_log_repair(false) -> ok;
+verify_log_repair(truncate) -> ok;
+verify_log_repair(Repair) ->
+ error({invalid_audit_trail_log_repair, Repair}).
+
+
+verify_module(_, Mod) when is_atom(Mod) ->
+ ok;
+verify_module(ReasonTag, Mod) ->
+ error({invalid_module, ReasonTag, Mod}).
+
+% verify_bool(_, true) ->
+% ok;
+% verify_bool(_, false) ->
+% ok;
+% verify_bool(ReasonTag, Bool) ->
+% error({invalid_bool, ReasonTag, Bool}).
+
+verify_dir(Dir) when is_list(Dir) ->
+ case file:read_file_info(Dir) of
+ {ok, #file_info{type = directory}} ->
+ ok;
+ {ok, _} ->
+ {error, not_directory};
+ {error, _Reason} ->
+ {error, not_found}
+ end;
+verify_dir(Dir) ->
+ {error, {invalid_log_dir, Dir}}.
+
+
+verify_verbosity(Verbosity) ->
+ case snmp_verbosity:validate(Verbosity) of
+ Verbosity ->
+ ok;
+ _ ->
+ error({invalid_verbosity, Verbosity})
+ end.
+
+%% ------------------------------------------------------------------------
+
+init_manager_config([]) ->
+ ok;
+init_manager_config([{Key, Val}|Confs]) ->
+ ets:insert(snmpm_config_table, {Key, Val}),
+ init_manager_config(Confs).
+
+
+
+init_agent_default() ->
+ %% The purpose of the default_agent is only to have a place
+ %% to store system wide default values related to agents.
+ %%
+
+ %% Port
+ init_agent_default(port, ?DEFAULT_AGENT_PORT),
+
+ %% Timeout
+ init_agent_default(timeout, 10000),
+
+ %% Max message (packet) size
+ init_agent_default(max_message_size, 484),
+
+ %% MPModel
+ init_agent_default(version, v2),
+
+ %% SecModel
+ init_agent_default(sec_model, v2c),
+
+ %% SecName
+ init_agent_default(sec_name, "initial"),
+
+ %% SecLevel
+ init_agent_default(sec_level, noAuthNoPriv),
+
+ %% Community
+ init_agent_default(community, "all-rights"),
+ ok.
+
+
+init_agent_default(Item, Val) when Item =/= user_id ->
+ case do_update_agent_info(default_agent, Item, Val) of
+ ok ->
+ ok;
+ {error, Reason} ->
+ error(Reason)
+ end.
+
+
+read_agents_config_file(Dir) ->
+ Check = fun(C) -> check_agent_config2(C) end,
+ case read_file(Dir, "agents.conf", Check, []) of
+ {ok, Conf} ->
+ Conf;
+ Error ->
+ ?vlog("agent config error: ~p", [Error]),
+ throw(Error)
+ end.
+
+check_agent_config2(Agent) ->
+ case (catch check_agent_config(Agent)) of
+ {ok, {UserId, TargetName, Conf, Version}} ->
+ {ok, Vsns} = system_info(versions),
+ case lists:member(Version, Vsns) of
+ true ->
+ {ok, {UserId, TargetName, Conf}};
+ false ->
+ error({version_not_supported_by_manager,
+ Version, Vsns})
+ end;
+ Err ->
+ throw(Err)
+ end.
+
+check_agent_config({UserId,
+ TargetName,
+ Community,
+ Ip, Port,
+ EngineId,
+ Timeout, MaxMessageSize,
+ Version, SecModel, SecName, SecLevel}) ->
+ ?vtrace("check_agent_config -> entry with"
+ "~n UserId: ~p"
+ "~n TargetName: ~p"
+ "~n Community: ~p"
+ "~n Ip: ~p"
+ "~n Port: ~p"
+ "~n EngineId: ~p"
+ "~n Timeout: ~p"
+ "~n MaxMessageSize: ~p"
+ "~n Version: ~p"
+ "~n SecModel: ~p"
+ "~n SecName: ~p"
+ "~n SecLevel: ~p",
+ [UserId, TargetName, Community, Ip, Port,
+ EngineId, Timeout, MaxMessageSize,
+ Version, SecModel, SecName, SecLevel]),
+ Addr = normalize_address(Ip),
+ ?vtrace("check_agent_config -> Addr: ~p", [Addr]),
+ Agent = {UserId,
+ TargetName,
+ Community,
+ Addr, Port,
+ EngineId,
+ Timeout, MaxMessageSize,
+ Version, SecModel, SecName, SecLevel},
+ {ok, verify_agent(Agent)};
+check_agent_config(Agent) ->
+ error({bad_agent_config, Agent}).
+
+
+init_agents_config([]) ->
+ ok;
+init_agents_config([Agent|Agents]) ->
+ init_agent_config(Agent),
+ init_agents_config(Agents).
+
+init_agent_config({_UserId, ?DEFAULT_TARGETNAME = TargetName, _Config}) ->
+ throw({error, {invalid_target_name, TargetName}});
+init_agent_config({UserId, TargetName, Config}) ->
+ case handle_register_agent(UserId, TargetName, Config) of
+ ok ->
+ ok;
+ Error ->
+ throw(Error)
+ end.
+
+
+verify_agent({UserId,
+ TargetName,
+ Comm,
+ Ip, Port,
+ EngineId,
+ Timeout, MMS,
+ Version, SecModel, SecName, SecLevel}) ->
+ ?vtrace("verify_agent -> entry with"
+ "~n UserId: ~p"
+ "~n TargetName: ~p", [UserId, TargetName]),
+ snmp_conf:check_string(TargetName, {gt, 0}),
+ case verify_val(address, Ip) of
+ {ok, Addr} ->
+ snmp_conf:check_integer(Port, {gt, 0}),
+ Conf =
+ [{address, Addr},
+ {port, Port},
+ {community, Comm},
+ {engine_id, EngineId},
+ {timeout, Timeout},
+ {max_message_size, MMS},
+ {version, Version},
+ {sec_model, SecModel},
+ {sec_name, SecName},
+ {sec_level, SecLevel}
+ ],
+ case verify_agent2(Conf) of
+ ok ->
+ {UserId, TargetName, Conf, Version};
+ Err ->
+ throw(Err)
+ end;
+
+ Error ->
+ ?vlog("verify_agent -> failed: ~n ~p", [Error]),
+ throw(Error)
+ end.
+
+verify_agent2([]) ->
+ ok;
+verify_agent2([{Item, Val}|Items]) ->
+ case verify_val(Item, Val) of
+ {ok, _Val} ->
+ verify_agent2(Items);
+ Err ->
+ Err
+ end;
+verify_agent2([Bad|_]) ->
+ {error, {bad_agent_config, Bad}}.
+
+
+read_users_config_file(Dir) ->
+ Check = fun(C) -> check_user_config(C) end,
+ case read_file(Dir, "users.conf", Check, []) of
+ {ok, Conf} ->
+ Conf;
+ Error ->
+ ?vlog("failure reading users config file: ~n ~p", [Error]),
+ throw(Error)
+ end.
+
+
+check_user_config({Id, Mod, Data}) ->
+ check_user_config({Id, Mod, Data, []});
+check_user_config({Id, Mod, _Data, DefaultAgentConfig} = User)
+ when (Id =/= ?DEFAULT_USER) andalso is_list(DefaultAgentConfig) ->
+ case (catch verify_user_behaviour(Mod)) of
+ ok ->
+ case verify_user_agent_config(DefaultAgentConfig) of
+ ok ->
+ {ok, User};
+ {error, Reason} ->
+ error({bad_default_agent_config, Reason})
+ end;
+ Error ->
+ throw(Error)
+ end;
+check_user_config({Id, _Mod, _Data, DefaultAgentConfig})
+ when (Id =/= ?DEFAULT_USER) ->
+ {error, {bad_default_agent_config, DefaultAgentConfig}};
+check_user_config({Id, _Mod, _Data, _DefaultAgentConfig}) ->
+ error({bad_user_id, Id});
+check_user_config(User) ->
+ error({bad_user_config, User}).
+
+init_users_config([]) ->
+ ok;
+init_users_config([User|Users]) ->
+ init_user_config(User),
+ init_users_config(Users).
+
+init_user_config(User) ->
+ case (catch verify_user(User)) of
+ {ok, UserRec} ->
+ case handle_register_user(UserRec) of
+ ok ->
+ ok;
+ {error, Reason} ->
+ error_msg("failed register user: "
+ "~n~w~n~w", [User, Reason])
+ end;
+ {error, Reason} ->
+ error_msg("user config check failed: "
+ "~n~w~n~w", [User, Reason])
+ end.
+
+verify_user({Id, UserMod, UserData}) ->
+ verify_user({Id, UserMod, UserData, []});
+verify_user({Id, UserMod, UserData, DefaultAgentConfig})
+ when (Id =/= ?DEFAULT_USER) andalso is_list(DefaultAgentConfig) ->
+ ?d("verify_user -> entry with"
+ "~n Id: ~p"
+ "~n UserMod: ~p"
+ "~n UserData: ~p"
+ "~n DefaultAgentConfig: ~p",
+ [Id, UserMod, UserData, DefaultAgentConfig]),
+ case (catch verify_user_behaviour(UserMod)) of
+ ok ->
+ case verify_user_agent_config(DefaultAgentConfig) of
+ ok ->
+ Config = default_agent_config(DefaultAgentConfig),
+ {ok, #user{id = Id,
+ mod = UserMod,
+ data = UserData,
+ default_agent_config = Config}};
+ {error, Reason} ->
+ error({bad_default_agent_config, Reason})
+ end;
+ Error ->
+ throw(Error)
+ end;
+verify_user({Id, _UserMod, _UserData, DefaultAgentConfig})
+ when (Id =/= ?DEFAULT_USER) ->
+ {error, {bad_default_agent_config, DefaultAgentConfig}};
+verify_user({Id, _, _, _}) ->
+ {error, {bad_user_id, Id}}.
+
+verify_user_agent_config(Conf) ->
+ case verify_invalid(Conf, [user_id, engine_id, address]) of
+ ok ->
+ verify_agent_config2(Conf);
+ Error ->
+ Error
+ end.
+
+read_usm_config_file(Dir) ->
+ Check = fun(C) -> check_usm_user_config(C) end,
+ case read_file(Dir, "usm.conf", Check, []) of
+ {ok, Conf} ->
+ Conf;
+ Error ->
+ throw(Error)
+ end.
+
+%% Identity-function
+check_usm_user_config({EngineId, Name,
+ AuthP, AuthKey,
+ PrivP, PrivKey}) ->
+ User = {EngineId, Name, Name, AuthP, AuthKey, PrivP, PrivKey},
+ verify_usm_user(User);
+check_usm_user_config({_EngineId, _Name, _SecName,
+ _AuthP, _AuthKey,
+ _PrivP, _PrivKey} = User) ->
+ verify_usm_user(User);
+check_usm_user_config(User) ->
+ error({bad_usm_config, User}).
+
+init_usm_users_config([]) ->
+ ok;
+init_usm_users_config([User|Users]) ->
+ init_usm_user_config(User),
+ init_usm_users_config(Users).
+
+init_usm_user_config(User) when is_record(User, usm_user) ->
+ case handle_register_usm_user(User) of
+ ok ->
+ ok;
+ Error ->
+ throw(Error)
+ end;
+init_usm_user_config(BadUser) ->
+ error({bad_usm_user, BadUser}).
+
+
+verify_usm_user({EngineID, Name, SecName, AuthP, AuthKey, PrivP, PrivKey}) ->
+ ?d("verify_usm_user -> entry with"
+ "~n EngineID: ~p"
+ "~n Name: ~p"
+ "~n SecName: ~p"
+ "~n AuthP: ~p"
+ "~n AuthKey: ~p"
+ "~n PrivP: ~p"
+ "~n PrivKey: ~p",
+ [EngineID, Name, SecName, AuthP, AuthKey, PrivP, PrivKey]),
+ verify_usm_user_engine_id(EngineID),
+ verify_usm_user_name(Name),
+ verify_usm_user_sec_name(SecName),
+ verify_usm_user(AuthP, AuthKey, PrivP, PrivKey),
+ User = #usm_user{engine_id = EngineID,
+ name = Name,
+ sec_name = SecName,
+ auth = AuthP,
+ auth_key = AuthKey,
+ priv = PrivP,
+ priv_key = PrivKey},
+ {ok, User}.
+
+verify_usm_user_engine_id(EngineID) ->
+ case (catch snmp_conf:check_string(EngineID, {gt, 0})) of
+ ok ->
+ ok;
+ _ ->
+ error({bad_usm_engine_id, EngineID})
+ end.
+
+verify_usm_user_name(Name) ->
+ case (catch snmp_conf:check_string(Name, {gt, 0})) of
+ ok ->
+ ok;
+ _ ->
+ error({bad_usm_user_name, Name})
+ end.
+
+verify_usm_user_sec_name(Name) ->
+ case (catch snmp_conf:check_string(Name, {gt, 0})) of
+ ok ->
+ ok;
+ _ ->
+ error({bad_usm_sec_name, Name})
+ end.
+
+verify_usm_user(AuthP, AuthKey, PrivP, PrivKey) ->
+ verify_usm_user_auth(AuthP, AuthKey),
+ verify_usm_user_priv(PrivP, PrivKey),
+ ok.
+
+verify_usm_user_auth(usmNoAuthProtocol, AuthKey) ->
+ case (catch snmp_conf:check_string(AuthKey, any)) of
+ ok ->
+ ok;
+ _ ->
+ error({invalid_auth_key, usmNoAuthProtocol})
+ end;
+verify_usm_user_auth(usmHMACMD5AuthProtocol, AuthKey)
+ when is_list(AuthKey) andalso (length(AuthKey) =:= 16) ->
+ case is_crypto_supported(md5_mac_96) of
+ true ->
+ case snmp_conf:all_integer(AuthKey) of
+ true ->
+ ok;
+ _ ->
+ error({invalid_auth_key, usmHMACMD5AuthProtocol})
+ end;
+ false ->
+ error({unsupported_crypto, md5_mac_96})
+ end;
+verify_usm_user_auth(usmHMACMD5AuthProtocol, AuthKey) when is_list(AuthKey) ->
+ Len = length(AuthKey),
+ error({invalid_auth_key, usmHMACMD5AuthProtocol, Len});
+verify_usm_user_auth(usmHMACMD5AuthProtocol, _AuthKey) ->
+ error({invalid_auth_key, usmHMACMD5AuthProtocol});
+verify_usm_user_auth(usmHMACSHAAuthProtocol, AuthKey)
+ when is_list(AuthKey) andalso (length(AuthKey) =:= 20) ->
+ case is_crypto_supported(sha_mac_96) of
+ true ->
+ case snmp_conf:all_integer(AuthKey) of
+ true ->
+ ok;
+ _ ->
+ error({invalid_auth_key, usmHMACSHAAuthProtocol})
+ end;
+ false ->
+ error({unsupported_crypto, sha_mac_96})
+ end;
+verify_usm_user_auth(usmHMACSHAAuthProtocol, AuthKey) when is_list(AuthKey) ->
+ Len = length(AuthKey),
+ error({invalid_auth_key, usmHMACSHAAuthProtocol, Len});
+verify_usm_user_auth(usmHMACSHAAuthProtocol, _AuthKey) ->
+ error({invalid_auth_key, usmHMACSHAAuthProtocol});
+verify_usm_user_auth(AuthP, _AuthKey) ->
+ error({invalid_auth_protocol, AuthP}).
+
+verify_usm_user_priv(usmNoPrivProtocol, PrivKey) ->
+ case (catch snmp_conf:check_string(PrivKey, any)) of
+ ok ->
+ ok;
+ _ ->
+ error({invalid_priv_key, usmNoPrivProtocol})
+ end;
+verify_usm_user_priv(usmDESPrivProtocol, PrivKey)
+ when (length(PrivKey) =:= 16) ->
+ case is_crypto_supported(des_cbc_decrypt) of
+ true ->
+ case snmp_conf:all_integer(PrivKey) of
+ true ->
+ ok;
+ _ ->
+ error({invalid_priv_key, usmDESPrivProtocol})
+ end;
+ false ->
+ error({unsupported_crypto, des_cbc_decrypt})
+ end;
+verify_usm_user_priv(usmDESPrivProtocol, PrivKey) when is_list(PrivKey) ->
+ Len = length(PrivKey),
+ error({invalid_priv_key, usmDESPrivProtocol, Len});
+verify_usm_user_priv(usmDESPrivProtocol, _PrivKey) ->
+ error({invalid_priv_key, usmDESPrivProtocol});
+verify_usm_user_priv(usmAesCfb128Protocol, PrivKey)
+ when (length(PrivKey) =:= 16) ->
+ case is_crypto_supported(aes_cfb_128_decrypt) of
+ true ->
+ case snmp_conf:all_integer(PrivKey) of
+ true ->
+ ok;
+ _ ->
+ error({invalid_priv_key, usmAesCfb128Protocol})
+ end;
+ false ->
+ error({unsupported_crypto, aes_cfb_128_decrypt})
+ end;
+verify_usm_user_priv(usmAesCfb128Protocol, PrivKey) when is_list(PrivKey) ->
+ Len = length(PrivKey),
+ error({invalid_priv_key, usmAesCfb128Protocol, Len});
+verify_usm_user_priv(usmAesCfb128Protocol, _PrivKey) ->
+ error({invalid_priv_key, usmAesCfb128Protocol});
+verify_usm_user_priv(PrivP, _PrivKey) ->
+ error({invalid_priv_protocol, PrivP}).
+
+is_crypto_supported(Func) ->
+ %% The 'catch' handles the case when 'crypto' is
+ %% not present in the system (or not started).
+ case (catch lists:member(Func, crypto:info())) of
+ true -> true;
+ _ -> false
+ end.
+
+
+read_manager_config_file(Dir) ->
+ Check = fun(Conf) -> check_manager_config(Conf) end,
+ case read_file(Dir, "manager.conf", Check) of
+ {ok, Conf} ->
+ ?d("read_manager_config_file -> ok: "
+ "~n Conf: ~p", [Conf]),
+ %% If the address is not specified, then we assume
+ %% it should be the local host.
+ %% If the address is not possible to determine
+ %% that way, then we give up...
+ check_mandatory_manager_config(Conf),
+ ensure_manager_config(Conf);
+ Error ->
+ throw(Error)
+ end.
+
+default_manager_config() ->
+ {ok, HostName} = inet:gethostname(),
+ case inet:getaddr(HostName, inet) of
+ {ok, A} ->
+ [{address, tuple_to_list(A)}];
+ {error, _Reason} ->
+ ?d("default_manager_config -> failed getting address: "
+ "~n _Reason: ~p", [_Reason]),
+ []
+ end.
+
+check_manager_config({address, Addr}) ->
+ snmp_conf:check_ip(Addr);
+check_manager_config({port, Port}) ->
+ snmp_conf:check_integer(Port, {gt, 0});
+check_manager_config({engine_id, EngineID}) ->
+ snmp_conf:check_string(EngineID);
+check_manager_config({max_message_size, Max}) ->
+ snmp_conf:check_integer(Max, {gte, 484});
+check_manager_config(Conf) ->
+ {error, {unknown_config, Conf}}.
+
+
+check_mandatory_manager_config(Conf) ->
+ Mand = [port, engine_id, max_message_size],
+ check_mandatory_manager_config(Mand, Conf).
+
+check_mandatory_manager_config([], _Conf) ->
+ ok;
+check_mandatory_manager_config([Item|Mand], Conf) ->
+ case lists:keysearch(Item, 1, Conf) of
+ false ->
+ error({missing_mandatory_manager_config, Item});
+ _ ->
+ check_mandatory_manager_config(Mand, Conf)
+ end.
+
+
+ensure_manager_config(Confs) ->
+ ensure_manager_config(Confs, default_manager_config()).
+
+ensure_manager_config(Confs, []) ->
+ Confs;
+ensure_manager_config(Confs, [{Key,_} = DefKeyVal|Defs]) ->
+ case lists:keysearch(Key, 1, Confs) of
+ false ->
+ ensure_manager_config([DefKeyVal|Confs], Defs);
+ {value, _Conf} ->
+ ensure_manager_config(Confs, Defs)
+ end.
+
+% ensure_manager_config([], Defs, Confs) ->
+% Confs ++ Defs;
+% ensure_manager_config(Confs0, [{Key, DefVal}|Defs], Acc) ->
+% case lists:keysearch(Key, 1, Confs0) of
+% false ->
+% ensure_manager_config(Confs0, Defs, [{Key, DefVal}|Acc]);
+% {value, Conf} ->
+% Confs = lists:keydelete(Key, 1, Confs0),
+% ensure_manager_config(Confs, Defs, [Conf|Acc])
+% end.
+
+
+
+read_file(Dir, FileName, Check, Default) ->
+ File = filename:join(Dir, FileName),
+ case file:read_file_info(File) of
+ {ok, _} ->
+ case (catch do_read(File, Check)) of
+ {ok, Conf} ->
+ {ok, Conf};
+ Error ->
+ ?vtrace("read_file -> read failed:"
+ "~n Error: ~p", [Error]),
+ Error
+ end;
+ {error, Reason} ->
+ ?vlog("failed reading config from ~s: ~p", [FileName, Reason]),
+ {ok, Default}
+ end.
+
+read_file(Dir, FileName, Check) ->
+ File = filename:join(Dir, FileName),
+ case file:read_file_info(File) of
+ {ok, _} ->
+ case (catch do_read(File, Check)) of
+ {ok, Conf} ->
+ ?vtrace("read_file -> read ok"
+ "~n Conf: ~p", [Conf]),
+ {ok, Conf};
+ Error ->
+ ?vtrace("read_file -> read failed:"
+ "~n Error: ~p", [Error]),
+ Error
+ end;
+ {error, Reason} ->
+ error_msg("failed reading config from ~s: ~p", [FileName, Reason]),
+ {error, {failed_reading, FileName, Reason}}
+ end.
+
+do_read(File, Check) ->
+ {ok, snmp_conf:read(File, Check)}.
+
+
+%%--------------------------------------------------------------------
+%% Func: handle_call/3
+%% Returns: {reply, Reply, State} |
+%% {reply, Reply, State, Timeout} |
+%% {noreply, State} |
+%% {noreply, State, Timeout} |
+%% {stop, Reason, Reply, State} | (terminate/2 is called)
+%% {stop, Reason, State} (terminate/2 is called)
+%%--------------------------------------------------------------------
+handle_call({register_user, UserId, UserMod, UserData, DefaultAgentConfig},
+ _From, State) ->
+ ?vlog("received register_user request: "
+ "~n UserId: ~p"
+ "~n UserMod: ~p"
+ "~n UserData: ~p"
+ "~n DefaultAgentConfig: ~p",
+ [UserId, UserMod, UserData, DefaultAgentConfig]),
+ User = #user{id = UserId,
+ mod = UserMod,
+ data = UserData,
+ default_agent_config = DefaultAgentConfig},
+ Reply = handle_register_user(User),
+ {reply, Reply, State};
+
+handle_call({unregister_user, UserId}, _From, State) ->
+ ?vlog("received unregister_user request: "
+ "~n UserId: ~p", [UserId]),
+ Reply = handle_unregister_user(UserId),
+ {reply, Reply, State};
+
+handle_call({register_agent, UserId, TargetName, Config}, _From, State) ->
+ ?vlog("received register_agent request: "
+ "~n UserId: ~p"
+ "~n TargetName: ~p"
+ "~n Config: ~p", [UserId, TargetName, Config]),
+ Reply = handle_register_agent(UserId, TargetName, Config),
+ {reply, Reply, State};
+
+handle_call({unregister_agent, UserId, TargetName}, _From, State) ->
+ ?vlog("received unregister_agent request: "
+ "~n UserId: ~p"
+ "~n TargetName: ~p", [UserId, TargetName]),
+ Reply = handle_unregister_agent(UserId, TargetName),
+ {reply, Reply, State};
+
+handle_call({update_agent_info, UserId, TargetName, Item, Val},
+ _From, State) ->
+ ?vlog("received update_agent_info request: "
+ "~n UserId: ~p"
+ "~n TargetName: ~p"
+ "~n Item: ~p"
+ "~n Val: ~p", [UserId, TargetName, Item, Val]),
+ Reply = handle_update_agent_info(UserId, TargetName, Item, Val),
+ {reply, Reply, State};
+
+handle_call({register_usm_user, User}, _From, State) ->
+ ?vlog("received register_usm_user request: "
+ "~n User: ~p", [User]),
+ Reply = handle_register_usm_user(User),
+ {reply, Reply, State};
+
+handle_call({unregister_usm_user, EngineID, Name}, _From, State) ->
+ ?vlog("received register_usm_user request: "
+ "~n EngineID: ~p"
+ "~n Name: ~p", [EngineID, Name]),
+ Reply = handle_unregister_usm_user(EngineID, Name),
+ {reply, Reply, State};
+
+handle_call({update_usm_user_info, EngineID, UserName, Item, Val},
+ _From, State) ->
+ ?vlog("received update_usm_user_info request: "
+ "~n EngineID: ~p"
+ "~n UserName: ~p"
+ "~n Item: ~p"
+ "~n Val: ~p", [EngineID, UserName, Item, Val]),
+ Reply = handle_update_usm_user_info(EngineID, UserName, Item, Val),
+ {reply, Reply, State};
+
+handle_call({cre_counter, Counter, Initial}, _From, State) ->
+ ?vlog("received cre_counter ~p -> ~w", [Counter, Initial]),
+ Reply = cre_counter(Counter, Initial),
+ {reply, Reply, State};
+
+handle_call({cre_stats_counter, Counter, Initial}, _From, State) ->
+ ?vlog("received cre_stats_counter ~p -> ~w", [Counter, Initial]),
+ Reply = cre_stats_counter(Counter, Initial),
+ {reply, Reply, State};
+
+handle_call({reset_stats_counter, Counter}, _From, State) ->
+ ?vlog("received reset_stats_counter ~p", [Counter]),
+ Reply = reset_stats_counter(Counter),
+ {reply, Reply, State};
+
+handle_call({load_mib, Mib}, _From, State) ->
+ ?vlog("received load_mib ~p", [Mib]),
+ case handle_load_mib(Mib) of
+ ok ->
+ {reply, ok, State};
+ Error ->
+ {reply, Error, State}
+ end;
+
+
+handle_call({unload_mib, Mib}, _From, State) ->
+ ?vlog("received unload_mib ~p", [Mib]),
+ case handle_unload_mib(Mib) of
+ ok ->
+ {reply, ok, State};
+ Error ->
+ {reply, Error, State}
+ end;
+
+
+handle_call({set_engine_boots, Boots}, _From, State) ->
+ ?vlog("received set_engine_boots ~p", [Boots]),
+ set_engine_boots(Boots),
+ {reply, ok, State};
+
+handle_call({set_engine_time, Time}, _From, State) ->
+ ?vlog("received set_engine_time ~p", [Time]),
+ Base = snmp_misc:now(sec) - Time,
+ ets:insert(snmpm_config_table, {snmp_engine_base, Base}),
+ {reply, ok, State};
+
+handle_call({set_usm_cache, Key, Val}, _From, State) ->
+ ?vlog("received set_usm_cache: ~w -> ~p", [Key, Val]),
+ ets:insert(snmpm_usm_table, {{usm_cache, Key}, Val}),
+ {reply, ok, State};
+
+handle_call({reset_usm_cache, EngineID}, _From, State) ->
+ ?vlog("received reset_usm_cache: ~p", [EngineID]),
+ reset_usm_cache(EngineID),
+ {reply, ok, State};
+
+handle_call({verbosity, Verbosity}, _From, State) ->
+ ?vlog("received verbosity request", []),
+ put(verbosity, Verbosity),
+ {reply, ok, State};
+
+handle_call(info, _From, State) ->
+ ?vlog("received info request", []),
+ Reply = get_info(),
+ {reply, Reply, State};
+
+handle_call({backup, BackupDir}, From, State) ->
+ ?vlog("backup to ~p", [BackupDir]),
+ Pid = self(),
+ V = get(verbosity),
+ case file:read_file_info(BackupDir) of
+ {ok, #file_info{type = directory}} ->
+ BackupServer =
+ erlang:spawn_link(
+ fun() ->
+ put(sname, mcbs),
+ put(verbosity, V),
+ Dir = filename:join([BackupDir]),
+ Reply = handle_backup(?CONFIG_DB, Dir),
+ Pid ! {backup_done, Reply},
+ unlink(Pid)
+ end),
+ ?vtrace("backup server: ~p", [BackupServer]),
+ {noreply, State#state{backup = {BackupServer, From}}};
+ {ok, _} ->
+ {reply, {error, not_a_directory}, State};
+ Error ->
+ {reply, Error, State}
+ end;
+
+
+%% handle_call({update_system_info, Key, Val}, _From, State) ->
+%% ?vlog("received update_system_info: ~p -> ~p", [Key, Val]),
+%% Reply = handle_update_system_info(Key, Val),
+%% {reply, Reply, State};
+
+
+handle_call(is_started, _From, State) ->
+ ?vlog("received is_started request", []),
+ {reply, true, State};
+
+
+handle_call(stop, _From, State) ->
+ {stop, normal, ok, State};
+
+
+handle_call(Req, _From, State) ->
+ warning_msg("received unknown request: ~n~p", [Req]),
+ {reply, {error, unknown_request}, State}.
+
+
+%%--------------------------------------------------------------------
+%% Func: handle_cast/2
+%% Returns: {noreply, State} |
+%% {noreply, State, Timeout} |
+%% {stop, Reason, State} (terminate/2 is called)
+%%--------------------------------------------------------------------
+handle_cast(Msg, State) ->
+ warning_msg("received unknown message: ~n~p", [Msg]),
+ {noreply, State}.
+
+
+%%--------------------------------------------------------------------
+%% Func: handle_info/2
+%% Returns: {noreply, State} |
+%% {noreply, State, Timeout} |
+%% {stop, Reason, State} (terminate/2 is called)
+%%--------------------------------------------------------------------
+handle_info({'EXIT', Pid, Reason}, #state{backup = {Pid, From}} = S) ->
+ ?vlog("backup server (~p) exited for reason ~n~p", [Pid, Reason]),
+ gen_server:reply(From, {error, Reason}),
+ {noreply, S#state{backup = undefined}};
+
+handle_info({'EXIT', Pid, Reason}, S) ->
+ %% The only other processes we should be linked to are
+ %% either the server or our supervisor, so die...
+ {stop, {received_exit, Pid, Reason}, S};
+
+handle_info({backup_done, Reply}, #state{backup = {_, From}} = S) ->
+ ?vlog("backup done:"
+ "~n Reply: ~p", [Reply]),
+ gen_server:reply(From, Reply),
+ {noreply, S#state{backup = undefined}};
+
+handle_info(Info, State) ->
+ warning_msg("received unknown info: ~n~p", [Info]),
+ {noreply, State}.
+
+
+%%--------------------------------------------------------------------
+%% Func: terminate/2
+%% Purpose: Shutdown the server
+%% Returns: any (ignored by gen_server)
+%%--------------------------------------------------------------------
+terminate(Reason, _State) ->
+ ?vdebug("terminate: ~p",[Reason]),
+ ok.
+
+%%----------------------------------------------------------------------
+%% Func: code_change/3
+%% Purpose: Convert process state when code is changed
+%% Returns: {ok, NewState}
+%%----------------------------------------------------------------------
+
+%% downgrade
+%%
+code_change({down, _Vsn}, S1, downgrade_to_pre_4_7) ->
+ #state{backup = B} = S1,
+ stop_backup_server(B),
+ S2 = {state},
+ {ok, S2};
+
+%% upgrade
+%%
+code_change(_Vsn, _S1, upgrade_from_pre_4_7) ->
+ %% {state} = S1,
+ S2 = #state{},
+ {ok, S2};
+
+code_change(_Vsn, State, _Extra) ->
+ {ok, State}.
+
+
+stop_backup_server(undefined) ->
+ ok;
+stop_backup_server({Pid, _}) when is_pid(Pid) ->
+ exit(Pid, kill).
+
+
+
+%%----------------------------------------------------------
+%% Update system info
+%%----------------------------------------------------------
+
+%% handle_update_system_info(audit_trail_log_type = Key, Val) ->
+%% case snmpm_config:system_info(audit_trail_log) of
+%% {ok, true} ->
+%% Value =
+%% case Val of
+%% read ->
+%% {ok, [read]};
+%% write ->
+%% {ok, [write]};
+%% read_write ->
+%% {ok, [read,write]};
+%% _ ->
+%% {error, {bad_value, Key, Val}}
+%% end,
+%% case Value of
+%% {ok, NewValue} ->
+%% ets:insert(snmpm_config_table, {Key, NewValue}),
+%% ok;
+%% false ->
+%% Value
+%% end;
+%% _ ->
+%% {error, audit_trail_log_not_enabled}
+%% end;
+%% handle_update_system_info(BadKey, Val) ->
+%% {error, {unsupported_update, BadKey, Val}}.
+
+
+%%----------------------------------------------------------
+%% Backup
+%%----------------------------------------------------------
+
+handle_backup(D, BackupDir) ->
+ %% First check that we do not wrote to the corrent db-dir...
+ ?vtrace("handle_backup -> entry with"
+ "~n D: ~p"
+ "~n BackupDir: ~p", [D, BackupDir]),
+ case dets:info(D, filename) of
+ undefined ->
+ ?vinfo("handle_backup -> no file to backup", []),
+ {error, no_file};
+ Filename ->
+ ?vinfo("handle_backup -> file to backup: ~n ~p", [Filename]),
+ case filename:dirname(Filename) of
+ BackupDir ->
+ ?vinfo("handle_backup -> backup dir and db dir the same",
+ []),
+ {error, db_dir};
+ _ ->
+ case file:read_file_info(BackupDir) of
+ {ok, #file_info{type = directory}} ->
+ ?vdebug("handle_backup -> backup dir ok", []),
+ %% All well so far...
+ Type = dets:info(D, type),
+ KP = dets:info(D, keypos),
+ dets_backup(D,
+ filename:basename(Filename),
+ BackupDir, Type, KP);
+ {ok, _} ->
+ ?vinfo("handle_backup -> backup dir not a dir",
+ []),
+ {error, not_a_directory};
+ Error ->
+ ?vinfo("handle_backup -> Error: ~p", [Error]),
+ Error
+ end
+ end
+ end.
+
+dets_backup(D, Filename, BackupDir, Type, KP) ->
+ ?vtrace("dets_backup -> entry with"
+ "~n D: ~p"
+ "~n Filename: ~p"
+ "~n BackupDir: ~p", [D, Filename, BackupDir]),
+ BackupFile = filename:join(BackupDir, Filename),
+ ?vtrace("dets_backup -> "
+ "~n BackupFile: ~p", [BackupFile]),
+ Opts = [{file, BackupFile}, {type, Type}, {keypos, KP}],
+ case dets:open_file(?BACKUP_DB, Opts) of
+ {ok, B} ->
+ ?vtrace("dets_backup -> create fun", []),
+ F = fun(Arg) ->
+ dets_backup(Arg, start, D, B)
+ end,
+ dets:safe_fixtable(D, true),
+ Res = dets:init_table(?BACKUP_DB, F, [{format, bchunk}]),
+ dets:safe_fixtable(D, false),
+ ?vtrace("dets_backup -> Res: ~p", [Res]),
+ Res;
+ Error ->
+ ?vinfo("dets_backup -> open_file failed: "
+ "~n ~p", [Error]),
+ Error
+ end.
+
+
+dets_backup(close, _Cont, _D, B) ->
+ dets:close(B),
+ ok;
+dets_backup(read, Cont1, D, B) ->
+ case dets:bchunk(D, Cont1) of
+ {Cont2, Data} ->
+ F = fun(Arg) ->
+ dets_backup(Arg, Cont2, D, B)
+ end,
+ {Data, F};
+ '$end_of_table' ->
+ dets:close(B),
+ end_of_input;
+ Error ->
+ Error
+ end.
+
+
+%%%-------------------------------------------------------------------
+%%% Internal functions
+%%%-------------------------------------------------------------------
+
+handle_register_user(#user{id = Id} = User) ->
+ ?vdebug("handle_register_user -> entry with"
+ "~n User: ~p", [User]),
+ case ets:lookup(snmpm_user_table, Id) of
+ [] ->
+ ets:insert(snmpm_user_table, User),
+ ok;
+ _ ->
+ {error, {already_registered, User}}
+ end.
+
+handle_unregister_user(UserId) ->
+ ?vdebug("handle_unregister_user -> entry with"
+ "~n UserId: ~p", [UserId]),
+ ets:delete(snmpm_user_table, UserId),
+ ok.
+
+
+handle_register_agent(UserId, TargetName, Config) ->
+ ?vdebug("handle_register_agent -> entry with"
+ "~n UserId: ~p"
+ "~n TargetName: ~p"
+ "~n Config: ~p", [UserId, TargetName, Config]),
+ case (catch agent_info(TargetName, user_id)) of
+ {error, _} ->
+ case ets:lookup(snmpm_user_table, UserId) of
+ [#user{default_agent_config = DefConfig}] ->
+ do_handle_register_agent(TargetName, DefConfig),
+ do_handle_register_agent(TargetName,
+ [{user_id, UserId}|Config]),
+ %% <DIRTY-BACKWARD-COMPATIBILLITY>
+ %% And now for some (backward compatibillity)
+ %% dirty crossref stuff
+ {ok, Addr} = agent_info(TargetName, address),
+ {ok, Port} = agent_info(TargetName, port),
+ ets:insert(snmpm_agent_table,
+ {{Addr, Port, target_name}, TargetName}),
+ %% </DIRTY-BACKWARD-COMPATIBILLITY>
+ ok;
+ _ ->
+ {error, {not_found, UserId}}
+ end;
+ {ok, UserId} ->
+ ?vinfo("[~w] Agent (~p) already registered"
+ "~nwhen"
+ "~n Agents: ~p",
+ [UserId, TargetName, which_agents()]),
+ {error, {already_registered, TargetName}};
+ {ok, OtherUserId} ->
+ ?vinfo("[~w] Agent (~p) already registered to ~p"
+ "~nwhen"
+ "~n Agents: ~p",
+ [UserId, TargetName, OtherUserId, which_agents()]),
+ {error, {already_registered, TargetName, OtherUserId}}
+ end.
+
+do_handle_register_agent(_TargetName, []) ->
+ ok;
+do_handle_register_agent(TargetName, [{Item, Val}|Rest]) ->
+ case (catch do_update_agent_info(TargetName, Item, Val)) of
+ ok ->
+ do_handle_register_agent(TargetName, Rest);
+ {error, Reason} ->
+ ets:match_delete(snmpm_agent_table, {TargetName, '_'}),
+ {error, Reason}
+ end;
+do_handle_register_agent(TargetName, BadConfig) ->
+ error_msg("error during agent registration - bad config: ~n~p",
+ [BadConfig]),
+ ets:match_delete(snmpm_agent_table, {TargetName, '_'}),
+ {error, {bad_agent_config, TargetName, BadConfig}}.
+
+
+handle_unregister_agent(UserId, TargetName) ->
+ ?vdebug("handle_unregister_agent -> entry with"
+ "~n UserId: ~p"
+ "~n TargetName: ~p", [UserId, TargetName]),
+ case (catch agent_info(TargetName, user_id)) of
+ {ok, UserId} ->
+ {ok, EngineID} = agent_info(TargetName, engine_id),
+ reset_usm_cache(EngineID),
+ %% <DIRTY-BACKWARD-COMPATIBILLITY>
+ %% And now for some (backward compatibillity)
+ %% dirty crossref stuff
+ {ok, Addr} = agent_info(TargetName, address),
+ {ok, Port} = agent_info(TargetName, port),
+ ets:delete(snmpm_agent_table, {Addr, Port, target_name}),
+ %% </DIRTY-BACKWARD-COMPATIBILLITY>
+ ets:match_delete(snmpm_agent_table, {{TargetName, '_'}, '_'}),
+ ok;
+ {ok, OtherUserId} ->
+ {error, {not_owner, OtherUserId}};
+ Error ->
+ Error
+ end.
+
+
+handle_update_agent_info(UserId, TargetName, Item, Val) ->
+ ?vdebug("handle_update_agent_info -> entry with"
+ "~n UserId: ~p"
+ "~n TargetName: ~p"
+ "~n Item: ~p"
+ "~n Val: ~p", [UserId, TargetName, Item, Val]),
+ case (catch agent_info(TargetName, user_id)) of
+ {ok, UserId} ->
+ do_update_agent_info(TargetName, Item, Val);
+ {ok, OtherUserId} ->
+ {error, {not_owner, OtherUserId}};
+ Error ->
+ Error
+ end.
+
+do_update_agent_info(TargetName, Item, Val0) ->
+%% p("do_update_agent_info -> entry with"
+%% "~n TargetName: ~p"
+%% "~n Item: ~p"
+%% "~n Val0: ~p", [TargetName, Item, Val0]),
+ case verify_val(Item, Val0) of
+ {ok, Val} ->
+%% p("do_update_agent_info -> verified value"
+%% "~n Val: ~p", [Val]),
+ ets:insert(snmpm_agent_table, {{TargetName, Item}, Val}),
+ ok;
+ Error ->
+ ?vlog("do_update_agent_info -> verify value failed: "
+ "~n TargetName: ~p"
+ "~n Item: ~p"
+ "~n Val0: ~p"
+ "~n Error: ~p", [TargetName, Item, Val0, Error]),
+ {error, {bad_agent_val, TargetName, Item, Val0}}
+ end.
+
+
+handle_register_usm_user(#usm_user{engine_id = EngineID,
+ name = Name} = User) ->
+ ?vdebug("handle_register_usm_user -> entry with"
+ "~n User: ~p", [User]),
+ Key = usm_key(EngineID, Name),
+ case ets:lookup(snmpm_usm_table, Key) of
+ [] ->
+ do_update_usm_user_info(Key, User);
+ _ ->
+ {error, {already_registered, EngineID, Name}}
+ end;
+handle_register_usm_user(BadUsmUser) ->
+ {error, {bad_usm_user, BadUsmUser}}.
+
+handle_unregister_usm_user(EngineID, Name) ->
+ ?vdebug("handle_unregister_usm_user -> entry with"
+ "~n EngineID: ~p"
+ "~n Name: ~p", [EngineID, Name]),
+ Key = usm_key(EngineID, Name),
+ ets:delete(snmpm_usm_table, Key),
+ ok.
+
+
+handle_update_usm_user_info(EngineID, Name, Item, Val) ->
+ ?vdebug("handle_update_usm_user_info -> entry with"
+ "~n EngineID: ~p"
+ "~n Name: ~p"
+ "~n Item: ~p"
+ "~n Val: ~p", [EngineID, Name, Item, Val]),
+ Key = usm_key(EngineID, Name),
+ case ets:lookup(snmpm_usm_table, Key) of
+ [] ->
+ {error, not_found};
+ [{_Key, User}] ->
+ do_update_usm_user_info(Key, User, Item, Val)
+ end.
+
+do_update_usm_user_info(Key, User, sec_name, Val) ->
+ %% case verify_usm_user_sec_name(Val) of
+ %% ok ->
+ %% do_update_usm_user_info(Key, User#usm_user{sec_name = Val});
+ %% _ ->
+ %% {error, {invalid_usm_sec_name, Val}}
+ %% end;
+ ok = verify_usm_user_sec_name(Val),
+ do_update_usm_user_info(Key, User#usm_user{sec_name = Val});
+do_update_usm_user_info(Key, User, auth, Val)
+ when (Val =:= usmNoAuthProtocol) orelse
+ (Val =:= usmHMACMD5AuthProtocol) orelse
+ (Val =:= usmHMACSHAAuthProtocol) ->
+ do_update_usm_user_info(Key, User#usm_user{auth = Val});
+do_update_usm_user_info(_Key, _User, auth, Val) ->
+ {error, {invalid_auth_protocol, Val}};
+do_update_usm_user_info(Key,
+ #usm_user{auth = usmNoAuthProtocol} = User,
+ auth_key, Val) ->
+ case (catch snmp_conf:check_string(Val, any)) of
+ ok ->
+ do_update_usm_user_info(Key, User#usm_user{auth_key = Val});
+ _ ->
+ {error, {invalid_auth_key, Val}}
+ end;
+do_update_usm_user_info(Key,
+ #usm_user{auth = usmHMACMD5AuthProtocol} = User,
+ auth_key, Val)
+ when length(Val) =:= 16 ->
+ case is_crypto_supported(md5_mac_96) of
+ true ->
+ do_update_usm_user_info(Key, User#usm_user{auth_key = Val});
+ false ->
+ {error, {unsupported_crypto, md5_mac_96}}
+ end;
+do_update_usm_user_info(_Key,
+ #usm_user{auth = usmHMACMD5AuthProtocol},
+ auth_key, Val) when is_list(Val) ->
+ Len = length(Val),
+ {error, {invalid_auth_key_length, usmHMACMD5AuthProtocol, Len}};
+do_update_usm_user_info(_Key,
+ #usm_user{auth = usmHMACMD5AuthProtocol},
+ auth_key, Val) ->
+ {error, {invalid_auth_key, usmHMACMD5AuthProtocol, Val}};
+do_update_usm_user_info(Key,
+ #usm_user{auth = usmHMACSHAAuthProtocol} = User,
+ auth_key, Val)
+ when length(Val) =:= 20 ->
+ case is_crypto_supported(sha_mac_96) of
+ true ->
+ do_update_usm_user_info(Key, User#usm_user{auth_key = Val});
+ false ->
+ {error, {unsupported_crypto, sha_mac_96}}
+ end;
+do_update_usm_user_info(_Key,
+ #usm_user{auth = usmHMACSHAAuthProtocol},
+ auth_key, Val) when is_list(Val) ->
+ Len = length(Val),
+ {error, {invalid_auth_key_length, usmHMACSHAAuthProtocol, Len}};
+do_update_usm_user_info(_Key,
+ #usm_user{auth = usmHMACSHAAuthProtocol},
+ auth_key, Val) ->
+ {error, {invalid_auth_key, usmHMACSHAAuthProtocol, Val}};
+do_update_usm_user_info(Key, User, priv, Val)
+ when (Val =:= usmNoPrivProtocol) orelse
+ (Val =:= usmDESPrivProtocol) orelse
+ (Val =:= usmAesCfb128Protocol) ->
+ do_update_usm_user_info(Key, User#usm_user{priv = Val});
+do_update_usm_user_info(_Key, _User, priv, Val) ->
+ {error, {invalid_priv_protocol, Val}};
+do_update_usm_user_info(Key,
+ #usm_user{priv = usmNoPrivProtocol} = User,
+ priv_key, Val) ->
+ case (catch snmp_conf:check_string(Val, any)) of
+ ok ->
+ do_update_usm_user_info(Key, User#usm_user{priv_key = Val});
+ _ ->
+ {error, {invalid_priv_key, Val}}
+ end;
+do_update_usm_user_info(Key,
+ #usm_user{priv = usmDESPrivProtocol} = User,
+ priv_key, Val)
+ when length(Val) =:= 16 ->
+ case is_crypto_supported(des_cbc_decrypt) of
+ true ->
+ do_update_usm_user_info(Key, User#usm_user{priv_key = Val});
+ false ->
+ {error, {unsupported_crypto, des_cbc_decrypt}}
+ end;
+do_update_usm_user_info(Key,
+ #usm_user{priv = usmAesCfb128Protocoll} = User,
+ priv_key, Val)
+ when length(Val) =:= 16 ->
+ case is_crypto_supported(aes_cfb_128_decrypt) of
+ true ->
+ do_update_usm_user_info(Key, User#usm_user{priv_key = Val});
+ false ->
+ {error, {unsupported_crypto, aes_cfb_128_decrypt}}
+ end;
+do_update_usm_user_info(_Key,
+ #usm_user{auth = usmHMACSHAAuthProtocol},
+ priv_key, Val) when is_list(Val) ->
+ Len = length(Val),
+ {error, {invalid_priv_key_length, usmHMACSHAAuthProtocol, Len}};
+do_update_usm_user_info(_Key,
+ #usm_user{auth = usmHMACSHAAuthProtocol},
+ priv_key, Val) ->
+ {error, {invalid_priv_key, usmHMACSHAAuthProtocol, Val}};
+do_update_usm_user_info(_Key, _User, Item, Val) ->
+ {error, {bad_item, Item, Val}}.
+
+do_update_usm_user_info(Key, User) ->
+ ets:insert(snmpm_usm_table, {Key, User}),
+ ok.
+
+
+usm_key(EngineId, Name) ->
+ {usmUserTable, EngineId, Name}.
+
+
+%% ---------------------------------------------------------------------
+
+verify_mandatory(_, []) ->
+ ok;
+verify_mandatory(Conf, [Mand|Mands]) ->
+ case lists:keymember(Mand, 1, Conf) of
+ true ->
+ verify_mandatory(Conf, Mands);
+ false ->
+ {error, {missing_mandatory_config, Mand}}
+ end.
+
+verify_invalid(_, []) ->
+ ok;
+verify_invalid(Conf, [Inv|Invs]) ->
+ case lists:member(Inv, Conf) of
+ false ->
+ verify_invalid(Conf, Invs);
+ true ->
+ {error, {illegal_config, Inv}}
+ end.
+
+
+verify_val(user_id, UserId) ->
+ {ok, UserId};
+verify_val(reg_type, RegType)
+ when (RegType =:= addr_port) orelse (RegType =:= target_name) ->
+ {ok, RegType};
+verify_val(address, Addr0) ->
+ case normalize_address(Addr0) of
+ {_A1, _A2, _A3, _A4} = Addr ->
+ {ok, Addr};
+ _ when is_list(Addr0) ->
+ case (catch snmp_conf:check_ip(Addr0)) of
+ ok ->
+ {ok, list_to_tuple(Addr0)};
+ Err ->
+ Err
+ end;
+ _ ->
+ error({bad_address, Addr0})
+ end;
+verify_val(port, Port) ->
+ case (catch snmp_conf:check_integer(Port, {gt, 0})) of
+ ok ->
+ {ok, Port};
+ Err ->
+ Err
+ end;
+verify_val(community, Comm) ->
+ case (catch snmp_conf:check_string(Comm)) of
+ ok ->
+ {ok, Comm};
+ Err ->
+ Err
+ end;
+verify_val(engine_id, discovery = EngineId) ->
+ {ok, EngineId};
+verify_val(engine_id, EngineId) ->
+ case (catch snmp_conf:check_string(EngineId)) of
+ ok ->
+ {ok, EngineId};
+ Err ->
+ Err
+ end;
+verify_val(timeout, Timeout) ->
+ (catch snmp_conf:check_timer(Timeout));
+verify_val(max_message_size, MMS) ->
+ case (catch snmp_conf:check_packet_size(MMS)) of
+ ok ->
+ {ok, MMS};
+ Err ->
+ Err
+ end;
+verify_val(version, V)
+ when (V =:= v1) orelse (V =:= v2) orelse (V =:= v3) ->
+ {ok, V};
+verify_val(version, BadVersion) ->
+ error({bad_version, BadVersion});
+verify_val(sec_model, Model) ->
+ (catch snmp_conf:check_sec_model(Model));
+verify_val(sec_name, Name) when is_list(Name) ->
+ case (catch snmp_conf:check_string(Name)) of
+ ok ->
+ {ok, Name};
+ Err ->
+ Err
+ end;
+verify_val(sec_name, BadName) ->
+ error({bad_sec_name, BadName});
+verify_val(sec_level, Level) ->
+ (catch snmp_conf:check_sec_level(Level));
+verify_val(Item, _) ->
+ {error, {no_such_item, Item}}.
+
+
+%%%-------------------------------------------------------------------
+%%%
+%%% Mini MIB stuff
+%%%
+%%%-------------------------------------------------------------------
+
+init_mini_mib(MibFiles) ->
+ MiniMibs = lists:flatten([do_load_mib(MibFile) || MibFile <- MibFiles]),
+ MiniMIB = remove_duplicates(lists:keysort(1, MiniMibs), []),
+ init_mini_mib2(MiniMIB).
+
+remove_duplicates([], Res) ->
+ Res;
+remove_duplicates([X,X|T], Res) ->
+ remove_duplicates([X|T], Res);
+remove_duplicates([{Oid, Name, Type, _} = X, {Oid, Name, Type, _}|T], Res) ->
+ remove_duplicates([X|T], Res);
+remove_duplicates([X|T], Res) ->
+ remove_duplicates(T, [X|Res]).
+
+init_mini_mib2([]) ->
+ ok;
+init_mini_mib2([{Oid, Name, Type, MibName}|MiniMib]) ->
+ ?vtrace("init mini mib -> ~w: ~w [~w] from ~s",
+ [Name, Oid, Type,MibName ]),
+ ets:insert(snmpm_mib_table, {{mini_mib, Oid}, Name, Type, MibName}),
+ init_mini_mib2(MiniMib).
+
+
+handle_load_mib(Mib) ->
+ [{mibs, Mibs0}] = ets:lookup(snmpm_config_table, mibs),
+ case lists:member(Mib, Mibs0) of
+ true ->
+ {error, already_loaded};
+ false ->
+ Mibs = [Mib|Mibs0],
+ case (catch do_load_mib(Mib)) of
+ MiniElems when is_list(MiniElems) ->
+ ets:insert(snmpm_config_table, {mibs, Mibs}),
+ update_mini_mib(MiniElems),
+ ok;
+ Error ->
+ Error
+ end
+ end.
+
+update_mini_mib([]) ->
+ ok;
+update_mini_mib([{Oid, Name, Type, MibName}|Elems]) ->
+ Key = {mini_mib, Oid},
+ case ets:lookup(snmpm_mib_table, Key) of
+ [{Key, _Name, _Type, _AnotherMibName}] ->
+ %% Already loaded from another mib
+ update_mini_mib(Elems);
+ [] ->
+ %% Not yet loaded
+ ?vtrace("update mini mib -> ~w: ~w [~w] from ~s",
+ [Name, Oid, Type, MibName]),
+ ets:insert(snmpm_mib_table, {Key, Name, Type, MibName}),
+ update_mini_mib(Elems)
+ end.
+
+
+handle_unload_mib(Mib) ->
+ Key = {mib, Mib},
+ case ets:lookup(snmpm_mib_table, Key) of
+ [{Key, MibName, _MibFile}] ->
+ do_unload_mib(MibName),
+ [{mibs, Mibs0}] = ets:lookup(snmpm_config_table, mibs),
+ Mibs = lists:delete(Mib, Mibs0),
+ ets:insert(snmpm_config_table, {mibs, Mibs}),
+ ets:delete(snmpm_mib_table, Key),
+ ok;
+ _ ->
+ {error, not_loaded}
+ end.
+
+do_unload_mib(MibName) ->
+ Pat = {{mini_mib, '$1'}, '_', '_', MibName},
+ Oids = ets:match(snmpm_mib_table, Pat),
+ F = fun([Oid]) -> ets:delete(snmpm_mib_table, {mini_mib, Oid}) end,
+ lists:foreach(F, Oids).
+
+
+do_load_mib(MibFile) ->
+ ?vtrace("load mib ~s", [MibFile]),
+ F1 = snmp_misc:strip_extension_from_filename(MibFile, ".bin"),
+ ActualFileName = lists:append(F1, ".bin"),
+ case snmp_misc:read_mib(ActualFileName) of
+ {ok, #mib{name = Name, mes = MEs, traps = Traps}} ->
+ %% Check that the mib was not loaded or loaded
+ %% with a different filename:
+ %% e.g. /tmp/MYMIB.bin and /tmp/mibs/MYMIB.bin
+ Name1 = mib_name(Name),
+ Pattern = {{mib, '_'}, Name1, '$1'},
+ case ets:match(snmpm_mib_table, Pattern) of
+ [] ->
+
+ Rec = {{mib, MibFile}, Name1, ActualFileName},
+ ets:insert(snmpm_mib_table, Rec),
+ init_mini_mib_elems(Name1, MEs++Traps, []);
+
+ %% This means that the mib has already been loaded
+ [[ActualFileName]] ->
+ [];
+
+ %% This means that the mib was loaded before,
+ %% but under another filename
+ [[OtherMibFile]] ->
+ error({already_loaded, MibFile, OtherMibFile})
+ end;
+
+ {error, Reason} ->
+ error({failed_reading_mib, MibFile, Reason})
+ end.
+
+mib_name(N) when is_list(N) ->
+ list_to_atom(N);
+mib_name(N) ->
+ N.
+
+init_mini_mib_elems(_, [], Res) ->
+ Res;
+init_mini_mib_elems(MibName,
+ [#me{aliasname = N,
+ oid = Oid,
+ entrytype = variable,
+ asn1_type = #asn1_type{bertype = Type}} | T], Res) ->
+ init_mini_mib_elems(MibName, T, [{Oid, N, Type, MibName}|Res]);
+
+init_mini_mib_elems(MibName,
+ [#me{aliasname = N,
+ oid = Oid,
+ entrytype = table_column,
+ asn1_type = #asn1_type{bertype = Type}}|T], Res) ->
+ init_mini_mib_elems(MibName, T, [{Oid, N, Type, MibName}|Res]);
+
+init_mini_mib_elems(MibName,
+ [#me{aliasname = N,
+ oid = Oid,
+ asn1_type = undefined}|T], Res) ->
+ init_mini_mib_elems(MibName, T, [{Oid, N, undefined, MibName}|Res]);
+
+init_mini_mib_elems(MibName,
+ [#notification{trapname = N,
+ oid = Oid}|T], Res) ->
+ init_mini_mib_elems(MibName, T, [{Oid, N, undefined, MibName}|Res]);
+
+init_mini_mib_elems(MibName, [_|T], Res) ->
+ init_mini_mib_elems(MibName, T, Res).
+
+
+
+%%----------------------------------------------------------------------
+
+normalize_address(Addr) ->
+ case inet:getaddr(Addr, inet) of
+ {ok, Addr2} ->
+ Addr2;
+ _ when is_list(Addr) ->
+ case (catch snmp_conf:check_ip(Addr)) of
+ ok ->
+ list_to_tuple(Addr);
+ _ ->
+ Addr
+ end;
+ _ ->
+ Addr
+ end.
+
+
+%%----------------------------------------------------------------------
+
+call(Req) ->
+ call(Req, infinity).
+
+call(Req, To) ->
+ gen_server:call(?SERVER, Req, To).
+
+% cast(Msg) ->
+% gen_server:cast(snmpm_server, Msg).
+
+
+%%-------------------------------------------------------------------
+
+get_atl_dir(Opts) ->
+ get_opt(dir, Opts).
+
+get_atl_type(Opts) ->
+ case get_opt(type, Opts, read_write) of
+ read_write ->
+ [read,write];
+ read ->
+ [read];
+ write ->
+ [write]
+ end.
+
+get_atl_size(Opts) ->
+ get_opt(size, Opts).
+
+get_atl_repair(Opts) ->
+ get_opt(repair, Opts, truncate).
+
+
+%%----------------------------------------------------------------------
+
+get_opt(Key, Opts) ->
+ ?d("get option ~w from ~p", [Key, Opts]),
+ snmp_misc:get_option(Key, Opts).
+
+get_opt(Key, Opts, Def) ->
+ ?d("get option ~w with default ~p from ~p", [Key, Def, Opts]),
+ snmp_misc:get_option(Key, Opts, Def).
+
+
+%%----------------------------------------------------------------------
+
+get_info() ->
+ ProcSize = proc_mem(self()),
+ CntSz = tab_size(snmpm_counter_table),
+ StatsSz = tab_size(snmpm_stats_table),
+ MibSz = tab_size(snmpm_mib_table),
+ ConfSz = tab_size(snmpm_config_table),
+ AgentSz = tab_size(snmpm_agent_table),
+ UserSz = tab_size(snmpm_user_table),
+ UsmSz = tab_size(snmpm_usm_table),
+ [{process_memory, ProcSize},
+ {db_memory, [{counter, CntSz},
+ {stats, StatsSz},
+ {mib, MibSz},
+ {config, ConfSz},
+ {agent, AgentSz},
+ {user, UserSz},
+ {usm, UsmSz}]}].
+
+proc_mem(P) when is_pid(P) ->
+ case (catch erlang:process_info(P, memory)) of
+ {memory, Sz} when is_integer(Sz) ->
+ Sz;
+ _ ->
+ undefined
+ end.
+%% proc_mem(_) ->
+%% undefined.
+
+tab_size(T) ->
+ case (catch ets:info(T, memory)) of
+ Sz when is_integer(Sz) ->
+ Sz;
+ _ ->
+ undefined
+ end.
+
+
+%%----------------------------------------------------------------------
+
+error(Reason) ->
+ throw({error, Reason}).
+
+
+%%----------------------------------------------------------------------
+
+info_msg(F, A) ->
+ ?snmpm_info("Config server: " ++ F, A).
+
+warning_msg(F, A) ->
+ ?snmpm_warning("Config server: " ++ F, A).
+
+error_msg(F, A) ->
+ ?snmpm_error("Config server: " ++ F, A).
+
+%% p(F) ->
+%% p(F, []).
+
+%% p(F, A) ->
+%% io:format("~w:" ++ F ++ "~n", [?MODULE | A]).
+
diff --git a/lib/snmp/src/manager/snmpm_internal.hrl b/lib/snmp/src/manager/snmpm_internal.hrl
new file mode 100644
index 0000000000..5d9b32e3f6
--- /dev/null
+++ b/lib/snmp/src/manager/snmpm_internal.hrl
@@ -0,0 +1,32 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2006-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%
+%%
+
+-ifndef(snmpm_internal).
+-define(snmpm_internal, true).
+
+-include_lib("snmp/src/app/snmp_internal.hrl").
+
+-define(snmpm_info(F, A), ?snmp_info("manager", F, A)).
+-define(snmpm_warning(F, A), ?snmp_warning("manager", F, A)).
+-define(snmpm_error(F, A), ?snmp_error("manager", F, A)).
+
+-endif. % -ifdef(snmpm_internal).
+
+
+
diff --git a/lib/snmp/src/manager/snmpm_misc_sup.erl b/lib/snmp/src/manager/snmpm_misc_sup.erl
new file mode 100644
index 0000000000..1a5d7676df
--- /dev/null
+++ b/lib/snmp/src/manager/snmpm_misc_sup.erl
@@ -0,0 +1,112 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2004-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%
+%%
+
+-module(snmpm_misc_sup).
+
+-include("snmp_debug.hrl").
+
+-behaviour(supervisor).
+
+%% External exports
+-export([
+ start_link/0,
+ start_net_if/2, stop_net_if/0,
+ start_note_store/2, stop_note_store/0
+ ]).
+
+%% Internal exports
+-export([init/1]).
+
+-define(SUP, ?MODULE).
+
+
+%%%-----------------------------------------------------------------
+%%% This is a supervisor for the mib and net_ifprocesses.
+%%% Each agent has one mib process.
+%%%-----------------------------------------------------------------
+
+start_link() ->
+ ?d("start_link -> entry", []),
+ SupName = {local,?SUP},
+ supervisor:start_link(SupName, ?MODULE, []).
+
+
+start_net_if(Mod, NoteStore) ->
+ ?d("start_net_if -> entry with"
+ "~n Mod: ~p"
+ "~n NoteStore: ~p", [Mod, NoteStore]),
+ SupName = ?SUP,
+ Name = net_if,
+ Args = [self(), NoteStore],
+ start_sup_child(SupName, Name, Mod, Args).
+
+stop_net_if() ->
+ stop_sup_child(?SUP, net_if).
+
+
+%% The note store is a common code component, so we must
+%% pass all the arguments in a way that works both for
+%% the agent and the manager entities. I.e. as arguments
+%% to the start_link function.
+start_note_store(Prio, Opts) ->
+ ?d("start_note_store -> entry with"
+ "~n Prio: ~p"
+ "~n Opts: ~p", [Prio, Opts]),
+ SupName = ?MODULE,
+ Name = note_store,
+ Mod = snmp_note_store,
+ Args = [Prio, snmpm, Opts],
+ start_sup_child(SupName, Name, Mod, Args).
+
+stop_note_store() ->
+ stop_sup_child(?SUP, note_store).
+
+
+%% ---------------------------------------------------------------
+
+start_sup_child(SupName, Name, Mod, Args) ->
+ %% make sure we start from scratch...
+ Children = supervisor:which_children(SupName),
+ case lists:keysearch(Name, 1, Children) of
+ {value, {_, _Pid, _, _}} ->
+ stop_sup_child(SupName, Name);
+ _ ->
+ ok
+ end,
+ Spec = {Name,
+ {Mod, start_link, Args},
+ temporary, 2000, worker, [Mod]},
+ supervisor:start_child(SupName, Spec).
+
+stop_sup_child(SupName, Name) ->
+ case whereis(SupName) of
+ undefined ->
+ ok;
+ _ ->
+ supervisor:terminate_child(SupName, Name),
+ supervisor:delete_child(SupName, Name)
+ end.
+
+
+
+init([]) ->
+ ?d("init -> entry", []),
+ SupFlags = {one_for_all, 0, 3600},
+ {ok, {SupFlags, []}}.
+
diff --git a/lib/snmp/src/manager/snmpm_mpd.erl b/lib/snmp/src/manager/snmpm_mpd.erl
new file mode 100644
index 0000000000..d76ad20051
--- /dev/null
+++ b/lib/snmp/src/manager/snmpm_mpd.erl
@@ -0,0 +1,1024 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2004-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%
+%%
+
+-module(snmpm_mpd).
+
+-export([init/1,
+
+ process_msg/7,
+ generate_msg/5, generate_response_msg/4,
+
+ next_msg_id/0,
+ next_req_id/0,
+
+ reset/1,
+ inc/1]).
+
+-define(SNMP_USE_V3, true).
+-include("snmp_types.hrl").
+-include("snmpm_internal.hrl").
+-include("SNMP-MPD-MIB.hrl").
+-include("SNMPv2-TM.hrl").
+
+-define(VMODULE,"MPD").
+-include("snmp_verbosity.hrl").
+
+-define(empty_msg_size, 24).
+
+-record(state, {v1 = false, v2c = false, v3 = false}).
+
+
+%%%-----------------------------------------------------------------
+%%% This module implemets the Message Processing and Dispatch part of
+%%% the multi-lingual SNMP agent.
+%%%
+%%% The MPD is responsible for:
+%%% *) call the security module (auth/priv).
+%%% *) decoding the message into a PDU.
+%%% *) decide a suitable Access Control Model, and provide it with
+%%% the data it needs.
+%%% *) maintaining SNMP counters.
+%%%
+%%% In order to take care of the different versions of counters, it
+%%% implements and maintains the union of all SNMP counters (i.e. from
+%%% rfc1213 and from rfc1907). It is up to the administrator of the
+%%% agent to load the correct MIB. Note that this module implements
+%%% the counters only, it does not provide instrumentation functions
+%%% for the counters.
+%%%
+%%% With the terms defined in rfc2271, this module implememts part
+%%% of the Dispatcher and the Message Processing functionality.
+%%%-----------------------------------------------------------------
+init(Vsns) ->
+ ?vdebug("init -> entry with ~p", [Vsns]),
+ {A,B,C} = erlang:now(),
+ random:seed(A,B,C),
+ snmpm_config:cre_counter(msg_id, random:uniform(2147483647)),
+ snmpm_config:cre_counter(req_id, random:uniform(2147483647)),
+ init_counters(),
+ State = init_versions(Vsns, #state{}),
+ init_usm(State#state.v3),
+ ?vtrace("init -> done when ~p", [State]),
+ State.
+
+reset(#state{v3 = V3}) ->
+ reset_counters(),
+ reset_usm(V3).
+
+
+%%-----------------------------------------------------------------
+%% Func: process_msg(Packet, TDomain, TAddress, State) ->
+%% {ok, SnmpVsn, Pdu, PduMS, ACMData} | {discarded, Reason}
+%% Types: Packet = binary()
+%% TDomain = snmpUDPDomain | atom()
+%% TAddress = {Ip, Udp}
+%% State = #state
+%% Purpose: This is the main Message Dispatching function. (see
+%% section 4.2.1 in rfc2272)
+%%-----------------------------------------------------------------
+process_msg(Msg, TDomain, Addr, Port, State, NoteStore, Logger) ->
+
+ inc(snmpInPkts),
+
+ case (catch snmp_pdus:dec_message_only(binary_to_list(Msg))) of
+
+ %% Version 1
+ #message{version = 'version-1', vsn_hdr = Community, data = Data}
+ when State#state.v1 =:= true ->
+ HS = ?empty_msg_size + length(Community),
+ process_v1_v2c_msg('version-1', NoteStore, Msg, TDomain,
+ Addr, Port,
+ Community, Data, HS, Logger);
+
+ %% Version 2
+ #message{version = 'version-2', vsn_hdr = Community, data = Data}
+ when State#state.v2c =:= true ->
+ HS = ?empty_msg_size + length(Community),
+ process_v1_v2c_msg('version-2', NoteStore, Msg, TDomain,
+ Addr, Port,
+ Community, Data, HS, Logger);
+
+ %% Version 3
+ #message{version = 'version-3', vsn_hdr = H, data = Data}
+ when State#state.v3 =:= true ->
+ ?vlog("v3:"
+ "~n msgID: ~p"
+ "~n msgFlags: ~p"
+ "~n msgSecModel: ~p",
+ [H#v3_hdr.msgID,H#v3_hdr.msgFlags,H#v3_hdr.msgSecurityModel]),
+ process_v3_msg(NoteStore, Msg, H, Data, Addr, Port, Logger);
+
+ %% Crap
+ {'EXIT', {bad_version, Vsn}} ->
+ ?vinfo("exit: bad version: ~p",[Vsn]),
+ inc(snmpInBadVersions),
+ {discarded, snmpInBadVersions};
+
+ %% More crap
+ {'EXIT', Reason} ->
+ ?vinfo("exit: ~p",[Reason]),
+ inc(snmpInASNParseErrs),
+ {discarded, Reason};
+
+ %% Really crap
+ Crap ->
+ ?vinfo("unknown message: "
+ "~n ~p",[Crap]),
+ inc(snmpInBadVersions),
+ {discarded, snmpInBadVersions}
+ end.
+
+
+%%-----------------------------------------------------------------
+%% Handles a Community based message (v1 or v2c).
+%%-----------------------------------------------------------------
+process_v1_v2c_msg(Vsn, _NoteStore, Msg, snmpUDPDomain,
+ Addr, Port,
+ Community, Data, HS, Log) ->
+
+ ?vdebug("process_v1_v2c_msg -> entry with"
+ "~n Vsn: ~p"
+ "~n Addr: ~p"
+ "~n Port: ~p"
+ "~n Community: ~p"
+ "~n HS: ~p", [Vsn, Addr, Port, Community, HS]),
+
+ Max = get_max_message_size(),
+ AgentMax = get_agent_max_message_size(Addr, Port),
+ PduMS = pdu_ms(Max, AgentMax, HS),
+
+ ?vtrace("process_v1_v2c_msg -> PduMS: ~p", [PduMS]),
+
+ case (catch snmp_pdus:dec_pdu(Data)) of
+ Pdu when is_record(Pdu, pdu) ->
+ ?vtrace("process_v1_v2c_msg -> was a pdu", []),
+ Log(Msg),
+ inc_snmp_in(Pdu),
+ MsgData = {Community, sec_model(Vsn)},
+ {ok, Vsn, Pdu, PduMS, MsgData};
+
+ Trap when is_record(Trap, trappdu) ->
+ ?vtrace("process_v1_v2c_msg -> was a trap", []),
+ Log(Msg),
+ inc_snmp_in(Trap),
+ MsgData = {Community, sec_model(Vsn)},
+ {ok, Vsn, Trap, PduMS, MsgData};
+
+ {'EXIT', Reason} ->
+ ?vlog("process_v1_v2c_msg -> failed decoding PDU: "
+ "~n Reason: ~p", [Reason]),
+ inc(snmpInASNParseErrs),
+ {discarded, Reason}
+ end;
+process_v1_v2c_msg(_Vsn, _NoteStore, _Msg, TDomain,
+ _Addr, _Port,
+ _Comm, _HS, _Data, _Log) ->
+ {discarded, {badarg, TDomain}}.
+
+pdu_ms(MgrMMS, AgentMMS, HS) when AgentMMS < MgrMMS ->
+ AgentMMS - HS;
+pdu_ms(MgrMMS, _AgentMMS, HS) ->
+ MgrMMS - HS.
+
+sec_model('version-1') -> ?SEC_V1;
+sec_model('version-2') -> ?SEC_V2C.
+
+
+%%-----------------------------------------------------------------
+%% Handles a SNMPv3 Message, following the procedures in rfc2272,
+%% section 4.2 and 7.2
+%%-----------------------------------------------------------------
+process_v3_msg(NoteStore, Msg, Hdr, Data, Addr, Port, Log) ->
+
+ ?vdebug("process_v3_msg -> entry with"
+ "~n Hdr: ~p"
+ "~n Addr: ~p"
+ "~n Port: ~p", [Hdr, Addr, Port]),
+
+ %% 7.2.3
+ #v3_hdr{msgID = MsgID,
+ msgMaxSize = MMS,
+ msgFlags = MsgFlags,
+ msgSecurityModel = MsgSecModel,
+ msgSecurityParameters = SecParams,
+ hdr_size = HdrSize} = Hdr,
+
+ %% 7.2.4
+ SecModule = get_security_module(MsgSecModel),
+ ?vtrace("process_v3_msg -> 7.2.4: "
+ "~n SecModule: ~p", [SecModule]),
+
+ %% 7.2.5
+ SecLevel = check_sec_level(MsgFlags),
+ IsReportable = is_reportable(MsgFlags),
+ ?vtrace("process_v3_msg -> 7.2.5: "
+ "~n SecLevel: ~p"
+ "~n IsReportable: ~p", [SecLevel, IsReportable]),
+
+ %% 7.2.6
+ SecRes = (catch SecModule:process_incoming_msg(Msg, Data,
+ SecParams, SecLevel)),
+ ?vtrace("process_v3_msg -> 7.2.6 - message processing result: "
+ "~n ~p",[SecRes]),
+ {SecEngineID, SecName, ScopedPDUBytes, SecData} =
+ check_sec_module_result(SecRes, Hdr, Data, IsReportable, Log),
+ ?vtrace("process_v3_msg -> 7.2.6 - checked module result: "
+ "~n SecEngineID: ~p"
+ "~n SecName: ~p",[SecEngineID, SecName]),
+
+ %% 7.2.7
+ #scopedPdu{contextEngineID = CtxEngineID,
+ contextName = CtxName,
+ data = PDU} =
+ case (catch snmp_pdus:dec_scoped_pdu(ScopedPDUBytes)) of
+ ScopedPDU when is_record(ScopedPDU, scopedPdu) ->
+ ScopedPDU;
+ {'EXIT', Reason} ->
+ ?vlog("failed decoding scoped pdu: "
+ "~n ~p",[Reason]),
+ inc(snmpInASNParseErrs),
+ discard(Reason)
+ end,
+
+ ?vlog("7.2.7"
+ "~n ContextEngineID: \"~s\" "
+ "~n context: \"~s\" ",
+ [CtxEngineID, CtxName]),
+ if
+ SecLevel == 3 -> % encrypted message - log decrypted pdu
+ Log({Hdr, ScopedPDUBytes});
+ true -> % otherwise, log binary
+ Log(Msg)
+ end,
+
+ %% Make sure a get_bulk doesn't get too big.
+ MgrMMS = get_max_message_size(),
+ %% PduMMS is supposed to be the maximum total length of the response
+ %% PDU we can send. From the MMS, we need to subtract everything before
+ %% the PDU, i.e. Message and ScopedPDU.
+ %% Message: [48, TotalLen, Vsn, [Tag, LH, Hdr], [Tag, LM, MsgSec], Data]
+ %% 1 3 <----------- HdrSize ----------->
+ %% HdrSize = everything up to and including msgSecurityParameters.
+ %% ScopedPduData follows. This is
+ %% [Tag, Len, [Tag, L1, CtxName], [Tag, L2, CtxEID]]
+ %% i.e. 6 + length(CtxName) + length(CtxEID)
+ %%
+ %% Total: 1 + TotalLenOctets + 3 + ScopedPduDataLen
+ TotMMS = tot_mms(MgrMMS, MMS),
+ TotalLenOctets = snmp_pdus:get_encoded_length(TotMMS - 1),
+ PduMMS = TotMMS - TotalLenOctets - 10 - HdrSize -
+ length(CtxName) - length(CtxEngineID),
+ ?vtrace("process_v3_msg -> PduMMS = ~p", [PduMMS]),
+ Type = PDU#pdu.type,
+ ?vdebug("process_v3_msg -> PDU type: ~p",[Type]),
+ case Type of
+ report ->
+ %% 7.2.10 & 11
+ %% BMK BMK BMK: discovery?
+ Note = snmp_note_store:get_note(NoteStore, MsgID),
+ case Note of
+ {SecEngineID, MsgSecModel, SecName, SecLevel,
+ CtxEngineID, CtxName, _ReqId} ->
+ ?vtrace("process_v3_msg -> 7.2.11b: ok", []),
+ %% BMK BMK: Should we discard the cached info
+ %% BMK BMK: or do we let the gc deal with it?
+ {ok, 'version-3', PDU, PduMMS, ok};
+ _ when is_tuple(Note) ->
+ ?vlog("process_v3_msg -> 7.2.11b: error"
+ "~n Note: ~p", [Note]),
+ Recv = {SecEngineID, MsgSecModel, SecName, SecLevel,
+ CtxEngineID, CtxName, PDU#pdu.request_id},
+ Err = sec_error(Note, Recv),
+ ACM = {invalid_sec_info, Err},
+ ReqId = element(size(Note), Note),
+ {ok, 'version-3', PDU, PduMMS, {error, ReqId, ACM}};
+ _NoFound ->
+ ?vtrace("process_v3_msg -> _NoFound: "
+ "~p", [_NoFound]),
+ inc(snmpUnknownPDUHandlers),
+ discard({no_outstanding_req, MsgID})
+ end;
+
+ 'get-response' ->
+ %% 7.2.10 & 12
+ case snmp_note_store:get_note(NoteStore, MsgID) of
+ {SecEngineID, MsgSecModel, SecName, SecLevel,
+ CtxEngineID, CtxName, _} ->
+ %% 7.2.12.d
+ {ok, 'version-3', PDU, PduMMS, undefined};
+ _ ->
+ %% 7.2.12.b
+ %% BMK BMK: Should we not discard the cached info??
+ inc(snmpUnknownPDUHandlers),
+ discard({no_outstanding_req, MsgID})
+ end;
+
+ 'snmpv2-trap' ->
+ %% 7.2.14
+ {ok, 'version-3', PDU, PduMMS, undefined};
+
+ 'inform-request' ->
+ %% 7.2.13
+ SnmpEngineID = get_engine_id(),
+ case SecEngineID of
+ SnmpEngineID -> % 7.2.13.b
+ ?vtrace("valid securityEngineID: ~p", [SecEngineID]),
+ %% 4.2.2.1.1 - we don't handle proxys yet => we only
+ %% handle CtxEngineID to ourselves
+ %% Check that we actually know of an agent with this
+ %% CtxEngineID and Addr/Port
+ case is_known_engine_id(CtxEngineID, Addr, Port) of
+ true ->
+ ?vtrace("and the agent EngineID (~p) "
+ "is know to us", [CtxEngineID]),
+ %% Uses ACMData that snmpm_acm knows of.
+ %% BUGBUG BUGBUG
+ ACMData =
+ {MsgID, MsgSecModel, SecName, SecLevel,
+ CtxEngineID, CtxName, SecData},
+ {ok, 'version-3', PDU, PduMMS, ACMData};
+ _ ->
+ %% 4.2.2.1.2
+ NIsReportable = snmp_misc:is_reportable_pdu(Type),
+ Val = inc(snmpUnknownPDUHandlers),
+ ErrorInfo =
+ {#varbind{oid = ?snmpUnknownPDUHandlers,
+ variabletype = 'Counter32',
+ value = Val},
+ SecName,
+ [{securityLevel, SecLevel},
+ {contextEngineID, CtxEngineID},
+ {contextName, CtxName}]},
+ case generate_v3_report_msg(MsgID,
+ MsgSecModel,
+ Data,
+ ErrorInfo,
+ Log) of
+ {ok, Report} when NIsReportable =:= true ->
+ discard(snmpUnknownPDUHandlers, Report);
+ _ ->
+ discard(snmpUnknownPDUHandlers)
+ end
+ end;
+ _ -> % 7.2.13.a
+ ?vinfo("invalid securityEngineID: ~p",[SecEngineID]),
+ discard({badSecurityEngineID, SecEngineID})
+ end;
+
+ _ ->
+ %% 7.2.13 - This would be the requests which we should not
+ %% receive since we are a manager, barring possible
+ %% proxy...
+ discard(Type)
+ end.
+
+
+sec_error(T1, T2)
+ when is_tuple(T1) andalso is_tuple(T2) andalso (size(T1) =:= size(T2)) ->
+ Tags = {sec_engine_id, msg_sec_model, sec_name, sec_level,
+ ctx_engine_id, ctx_name, request_id},
+ sec_error(size(T1), T1, T2, Tags, []);
+sec_error(T1, T2) ->
+ [{internal_error, T1, T2}].
+
+sec_error(0, _T1, _T2, _Tags, Acc) ->
+ Acc;
+sec_error(Idx, T1, T2, Tags, Acc) ->
+ case element(Idx, T1) =:= element(Idx, T2) of
+ true ->
+ sec_error(Idx - 1, T1, T2, Tags, Acc);
+ false ->
+ Elem = {element(Idx, Tags), element(Idx, T1), element(Idx, T2)},
+ sec_error(Idx - 1, T1, T2, Tags, [Elem|Acc])
+ end.
+
+tot_mms(MgrMMS, AgentMMS) when MgrMMS > AgentMMS -> AgentMMS;
+tot_mms(MgrMMS, _AgentMMS) -> MgrMMS.
+
+get_security_module(?SEC_USM) ->
+ snmpm_usm;
+get_security_module(_) ->
+ inc(snmpUnknownSecurityModels),
+ discard(snmpUnknownSecurityModels).
+
+check_sec_level([MsgFlag]) ->
+ SecLevel = MsgFlag band 3,
+ if
+ SecLevel == 2 ->
+ inc(snmpInvalidMsgs),
+ discard(snmpInvalidMsgs);
+ true ->
+ SecLevel
+ end;
+check_sec_level(_Unknown) ->
+ inc(snmpInvalidMsgs),
+ discard(snmpInvalidMsgs).
+
+is_reportable([MsgFlag]) ->
+ 4 == (MsgFlag band 4).
+
+
+check_sec_module_result({ok, X}, _, _, _, _) ->
+ X;
+check_sec_module_result({error, Reason, Info}, _, _, _, _)
+ when is_list(Info) ->
+ %% case 7.2.6 b
+ discard({securityError, Reason, Info});
+check_sec_module_result({error, Reason, ErrorInfo}, V3Hdr, Data, true, Log) ->
+ %% case 7.2.6 a
+ ?vtrace("security module result:"
+ "~n Reason: ~p"
+ "~n ErrorInfo: ~p", [Reason, ErrorInfo]),
+ #v3_hdr{msgID = MsgID, msgSecurityModel = MsgSecModel} = V3Hdr,
+ Pdu = get_scoped_pdu(Data),
+ case generate_v3_report_msg(MsgID, MsgSecModel, Pdu, ErrorInfo, Log) of
+ {ok, Report} ->
+ discard({securityError, Reason}, Report);
+ {discarded, _SomeOtherReason} ->
+ discard({securityError, Reason})
+ end;
+check_sec_module_result({error, Reason, _ErrorInfo}, _, _, _, _) ->
+ ?vtrace("security module result:"
+ "~n Reason: ~p"
+ "~n _ErrorInfo: ~p", [Reason, _ErrorInfo]),
+ discard({securityError, Reason});
+check_sec_module_result(Res, _, _, _, _) ->
+ ?vtrace("security module result:"
+ "~n Res: ~p", [Res]),
+ discard({securityError, Res}).
+
+get_scoped_pdu(D) when is_list(D) ->
+ (catch snmp_pdus:dec_scoped_pdu(D));
+get_scoped_pdu(D) ->
+ D.
+
+
+%%-----------------------------------------------------------------
+%% Generate a message
+%%-----------------------------------------------------------------
+generate_msg('version-3', NoteStore, Pdu,
+ {SecModel, SecName, SecLevel, CtxEngineID, CtxName,
+ TargetName}, Log) ->
+ generate_v3_msg(NoteStore, Pdu,
+ SecModel, SecName, SecLevel, CtxEngineID, CtxName,
+ TargetName, Log);
+generate_msg(Vsn, _NoteStore, Pdu, {Community, _SecModel}, Log) ->
+ generate_v1_v2c_msg(Vsn, Pdu, Community, Log).
+
+
+generate_v3_msg(NoteStore, Pdu,
+ SecModel, SecName, SecLevel, CtxEngineID, CtxName,
+ TargetName, Log) ->
+ %% rfc2272: 7.1.6
+ ?vdebug("generate_v3_msg -> 7.1.6", []),
+ ScopedPDU = #scopedPdu{contextEngineID = CtxEngineID,
+ contextName = CtxName,
+ data = Pdu},
+ case (catch snmp_pdus:enc_scoped_pdu(ScopedPDU)) of
+ {'EXIT', Reason} ->
+ user_err("failed encoding scoped pdu "
+ "~n pdu: ~w"
+ "~n contextName: ~w"
+ "~n reason: ~w", [Pdu, CtxName, Reason]),
+ {discarded, Reason};
+ ScopedPDUBytes ->
+ {ok, generate_v3_msg(NoteStore, Pdu, ScopedPDUBytes,
+ SecModel, SecName, SecLevel,
+ CtxEngineID, CtxName, TargetName, Log)}
+ end.
+
+generate_v3_msg(NoteStore,
+ #pdu{type = Type} = Pdu, ScopedPduBytes,
+ SecModel, SecName, SecLevel, CtxEngineID, CtxName,
+ TargetName, Log) ->
+ %% 7.1.7
+ ?vdebug("generate_v3_msg -> 7.1.7", []),
+ MsgID = next_msg_id(),
+ MsgFlags = snmp_misc:mk_msg_flags(Type, SecLevel),
+ V3Hdr = #v3_hdr{msgID = MsgID,
+ msgMaxSize = get_max_message_size(),
+ msgFlags = MsgFlags,
+ msgSecurityModel = SecModel},
+ Message = #message{version = 'version-3',
+ vsn_hdr = V3Hdr,
+ data = ScopedPduBytes},
+ SecModule = sec_module(SecModel),
+
+ %% 7.1.9a
+ ?vdebug("generate_v3_msg -> 7.1.9a", []),
+ SecEngineID = sec_engine_id(TargetName),
+ ?vtrace("SecEngineID: ~p", [SecEngineID]),
+ %% 7.1.9b
+ ?vdebug("generate_v3_msg -> 7.1.9b", []),
+ case generate_v3_outgoing_msg(Message, SecModule, SecEngineID,
+ SecName, [], SecLevel) of
+ {ok, Packet} ->
+ %% 7.1.9c
+ %% Store in cache for 150 sec.
+ ?vdebug("generate_v3_msg -> 7.1.9c", []),
+ %% The request id is just in the case when we receive a
+ %% report with incorrect securityModel and/or securityLevel
+ CacheVal = {SecEngineID, SecModel, SecName, SecLevel,
+ CtxEngineID, CtxName, Pdu#pdu.request_id},
+ snmp_note_store:set_note(NoteStore, 1500, MsgID, CacheVal),
+ Log(Packet),
+ inc_snmp_out(Pdu),
+ ?vdebug("generate_v3_msg -> done", []),
+ Packet;
+
+ Error ->
+ throw(Error)
+ end.
+
+
+sec_module(?SEC_USM) ->
+ snmpm_usm.
+
+%% 9) If the PDU is a GetRequest-PDU, GetNextRequest-PDU,
+%% GetBulkRequest-PDU, SetRequest-PDU, InformRequest-PDU, or or
+%% SNMPv2-Trap-PDU, then
+%%
+%% a) If the PDU is an SNMPv2-Trap-PDU, then securityEngineID is set
+%% to the value of this entity's snmpEngineID.
+%%
+%% Otherwise, the snmpEngineID of the target entity is determined,
+%% in an implementation-dependent manner, possibly using
+%% transportDomain and transportAddress. The value of
+%% securityEngineID is set to the value of the target entity's
+%% snmpEngineID.
+%%
+%% As we never send traps, the SecEngineID is allways the
+%% snmpEngineID of the target entity!
+sec_engine_id(TargetName) ->
+ case get_agent_engine_id(TargetName) of
+ {ok, EngineId} ->
+ EngineId;
+ _ ->
+ config_err("Can't find engineID for "
+ "snmpTargetAddrName ~p", [TargetName]),
+ %% this will trigger error in secmodule
+ ""
+ end.
+
+
+%% BMK BMK BMK
+%% Denna verkar v�ldigt lik generate_v1_v2c_response_msg!
+%% Gemensam? Borde det finnas olikheter?
+%%
+generate_v1_v2c_msg(Vsn, Pdu, Community, Log) ->
+ ?vdebug("generate_v1_v2c_msg -> encode pdu", []),
+ case (catch snmp_pdus:enc_pdu(Pdu)) of
+ {'EXIT', Reason} ->
+ user_err("failed encoding pdu: "
+ "(pdu: ~w, community: ~w): ~n~w",
+ [Pdu, Community, Reason]),
+ {discarded, Reason};
+ PduBytes ->
+ MMS = get_max_message_size(),
+ Message = #message{version = Vsn,
+ vsn_hdr = Community,
+ data = PduBytes},
+ case generate_v1_v2c_outgoing_msg(Message) of
+ {error, Reason} ->
+ user_err("failed encoding message "
+ "(pdu: ~w, community: ~w): ~n~w",
+ [Pdu, Community, Reason]),
+ {discarded, Reason};
+ {ok, Packet} when size(Packet) =< MMS ->
+ Log(Packet),
+ inc_snmp_out(Pdu),
+ {ok, Packet};
+ {ok, Packet} ->
+ ?vlog("packet max size exceeded: "
+ "~n MMS: ~p"
+ "~n Len: ~p",
+ [MMS, size(Packet)]),
+ {discarded, tooBig}
+ end
+ end.
+
+
+
+%% -----------------------------------------------------------------------
+
+generate_response_msg('version-3', Pdu,
+ {MsgID, SecModel, SecName, SecLevel,
+ CtxEngineID, CtxName, SecData}, Log) ->
+ generate_v3_response_msg(Pdu, MsgID, SecModel, SecName, SecLevel,
+ CtxEngineID, CtxName, SecData, Log);
+generate_response_msg(Vsn, Pdu, {Comm, _SecModel}, Log) ->
+ generate_v1_v2c_response_msg(Vsn, Pdu, Comm, Log).
+
+
+generate_v3_response_msg(#pdu{type = Type} = Pdu, MsgID,
+ SecModel, SecName, SecLevel,
+ CtxEngineID, CtxName, SecData, Log) ->
+ %% rfc2272: 7.1 steps 6-8
+ ScopedPdu = #scopedPdu{contextEngineID = CtxEngineID,
+ contextName = CtxName,
+ data = Pdu},
+ case (catch snmp_pdus:enc_scoped_pdu(ScopedPdu)) of
+ {'EXIT', Reason} ->
+ user_err("failed encoded scoped pdu "
+ "(pdu: ~w, contextName: ~w): ~n~w",
+ [Pdu, CtxName, Reason]),
+ {discarded, Reason};
+ ScopedPduBytes ->
+ MMS = get_max_message_size(),
+ MsgFlags = snmp_misc:mk_msg_flags(Type, SecLevel),
+ V3Hdr = #v3_hdr{msgID = MsgID,
+ msgMaxSize = MMS,
+ msgFlags = MsgFlags,
+ msgSecurityModel = SecModel},
+ Message = #message{version = 'version-3',
+ vsn_hdr = V3Hdr,
+ data = ScopedPduBytes},
+ %% We know that the security model is valid when we
+ %% generate a response.
+ SecModule = sec_module(SecModel),
+ SecEngineID = get_engine_id(),
+ case generate_v3_outgoing_msg(Message, SecModule, SecEngineID,
+ SecName, SecData, SecLevel) of
+ %% Check the packet size. Send the msg even
+ %% if it's larger than the agent can handle -
+ %% it will be dropped. Just check against the
+ %% internal size.
+ {ok, Packet} when size(Packet) =< MMS ->
+ if
+ SecLevel == 3 ->
+ %% encrypted - log decrypted pdu
+ Log({V3Hdr, ScopedPduBytes});
+ true ->
+ %% otherwise log the entire msg
+ Log(Packet)
+ end,
+ inc_snmp_out(Pdu),
+ {ok, Packet};
+
+ {ok, _Packet} when Pdu#pdu.error_status =:= tooBig ->
+ ?vlog("packet max size exceeded (tooBog): "
+ "~n MMS: ~p", [MMS]),
+ inc(snmpSilentDrops),
+ {discarded, tooBig};
+ {ok, _Packet} ->
+ ?vlog("packet max size exceeded: "
+ "~n MMS: ~p", [MMS]),
+ TooBigPdu = Pdu#pdu{error_status = tooBig,
+ error_index = 0,
+ varbinds = []},
+ generate_v3_response_msg(TooBigPdu, MsgID,
+ SecModel, SecName, SecLevel,
+ CtxEngineID,
+ CtxName,
+ SecData, Log);
+ Error ->
+ Error
+ end
+ end.
+
+
+generate_v3_outgoing_msg(Message,
+ SecModule, SecEngineID, SecName, SecData, SecLevel) ->
+ case (catch SecModule:generate_outgoing_msg(Message,
+ SecEngineID,
+ SecName, SecData,
+ SecLevel)) of
+ {'EXIT', Reason} ->
+ config_err("~p (message: ~p)", [Reason, Message]),
+ {discarded, Reason};
+ {error, Reason} ->
+ config_err("~p (message: ~p)", [Reason, Message]),
+ {discarded, Reason};
+ Bin when is_binary(Bin) ->
+ {ok, Bin};
+ OutMsg when is_list(OutMsg) ->
+ case (catch list_to_binary(OutMsg)) of
+ Bin when is_binary(Bin) ->
+ {ok, Bin};
+ {'EXIT', Reason} ->
+ {error, Reason}
+ end
+ end.
+
+
+generate_v1_v2c_response_msg(Vsn, Pdu, Comm, Log) ->
+ case (catch snmp_pdus:enc_pdu(Pdu)) of
+ {'EXIT', Reason} ->
+ user_err("failed encoding pdu: "
+ "(pdu: ~w, community: ~w): ~n~w",
+ [Pdu, Comm, Reason]),
+ {discarded, Reason};
+ PduBytes ->
+ MMS = get_max_message_size(),
+ Message = #message{version = Vsn,
+ vsn_hdr = Comm,
+ data = PduBytes},
+ case generate_v1_v2c_outgoing_msg(Message) of
+ {error, Reason} ->
+ user_err("failed encoding message only "
+ "(pdu: ~w, community: ~w): ~n~w",
+ [Pdu, Comm, Reason]),
+ {discarded, Reason};
+
+ {ok, Packet} when size(Packet) =< MMS ->
+ Log(Packet),
+ inc_snmp_out(Pdu),
+ {ok, Packet};
+
+ {ok, Packet} -> %% Too big
+ too_big(Vsn, Pdu, Comm, MMS, size(Packet), Log)
+ end
+ end.
+
+
+too_big('version-1' = Vsn, #pdu{type = 'get-response'} = Pdu,
+ Comm, _MMS, _Len, Log) ->
+ %% In v1, the varbinds should be identical to the incoming
+ %% request. It isn't identical now! Make acceptable (?)
+ %% approximation.
+ V = set_vb_null(Pdu#pdu.varbinds),
+ TooBigPdu = Pdu#pdu{error_status = tooBig, error_index = 0, varbinds = V},
+ too_big(Vsn, TooBigPdu, Comm, Log);
+too_big('version-2' = Vsn, #pdu{type = 'get-response'} = Pdu,
+ Comm, _MMS, _Len, Log) ->
+ %% In v2, varbinds should be empty (reasonable!)
+ TooBigPdu = Pdu#pdu{error_status = tooBig, error_index = 0, varbinds = []},
+ too_big(Vsn, TooBigPdu, Comm, Log);
+too_big(_Vsn, Pdu, _Comm, _Log, MMS, Len) ->
+ user_err("encoded pdu, ~p bytes, exceeded "
+ "max message size of ~p bytes. Pdu: ~n~w",
+ [Len, MMS, Pdu]),
+ {discarded, tooBig}.
+
+
+too_big(Vsn, Pdu, Comm, Log) ->
+ case (catch snmp_pdus:enc_pdu(Pdu)) of
+ {'EXIT', Reason} ->
+ user_err("failed encoding pdu "
+ "(pdu: ~w, community: ~w): ~n~w",
+ [Pdu, Comm, Reason]),
+ {discarded, Reason};
+ PduBytes ->
+ Message = #message{version = Vsn,
+ vsn_hdr = Comm,
+ data = PduBytes},
+ case generate_v1_v2c_outgoing_msg(Message) of
+ {error, Reason} ->
+ user_err("failed encoding message only"
+ "(pdu: ~w, community: ~w): ~n~w",
+ [Pdu, Comm, Reason]),
+ {discarded, Reason};
+ {ok, Bin} ->
+ Log(Bin),
+ inc_snmp_out(Pdu),
+ {ok, Bin}
+ end
+ end.
+
+set_vb_null(Vbs) ->
+ [Vb#varbind{variabletype = 'NULL', value = 'NULL'} || Vb <- Vbs].
+
+
+generate_v1_v2c_outgoing_msg(Message) ->
+ ?vdebug("generate_v1_v2c_outgoing_msg -> encode message", []),
+ case (catch snmp_pdus:enc_message_only(Message)) of
+ {'EXIT', Reason} ->
+ {error, Reason};
+ Bin when is_binary(Bin) ->
+ {ok, Bin};
+ Packet when is_list(Packet) ->
+ case (catch list_to_binary(Packet)) of
+ Bin when is_binary(Bin) ->
+ {ok, Bin};
+ {'EXIT', Reason} ->
+ {error, Reason}
+ end
+ end.
+
+
+
+generate_v3_report_msg(MsgID, SecModel, ScopedPdu, ErrInfo, Log)
+ when is_record(ScopedPdu, scopedPdu) ->
+ ReqID = (ScopedPdu#scopedPdu.data)#pdu.request_id,
+ generate_v3_report_msg2(MsgID, ReqID, SecModel, ErrInfo, Log);
+generate_v3_report_msg(MsgID, SecModel, _, ErrInfo, Log) ->
+ %% RFC2572, 7.1.3.c.4
+ generate_v3_report_msg2(MsgID, 0, SecModel, ErrInfo, Log).
+
+
+generate_v3_report_msg2(MsgID, ReqID, SecModel, ErrInfo, Log) ->
+ {Varbind, SecName, Opts} = ErrInfo,
+ Pdu = #pdu{type = report,
+ request_id = ReqID,
+ error_status = noError,
+ error_index = 0,
+ varbinds = [Varbind]},
+ SecLevel = snmp_misc:get_option(securityLevel, Opts, 0),
+ CtxEngineID = snmp_misc:get_option(contextEngineID, Opts, get_engine_id()),
+ CtxName = snmp_misc:get_option(contextName, Opts, ""),
+ SecData = snmp_misc:get_option(sec_data, Opts, []),
+ generate_v3_response_msg(Pdu,
+ MsgID, SecModel, SecName, SecLevel,
+ CtxEngineID, CtxName, SecData, Log).
+
+
+%%-----------------------------------------------------------------
+
+%% Get "our" (manager) MMS
+get_max_message_size() ->
+ case snmpm_config:get_engine_max_message_size() of
+ {ok, MMS} ->
+ MMS;
+ E ->
+ user_err("failed retreiving engine max message size: ~w", [E]),
+ 484
+ end.
+
+%% The the MMS of the agent
+get_agent_max_message_size(Addr, Port) ->
+ case snmpm_config:get_agent_engine_max_message_size(Addr, Port) of
+ {ok, MMS} ->
+ MMS;
+ _Error ->
+ ?vlog("unknown agent: ~w:~w", [Addr, Port]),
+ get_max_message_size()
+ end.
+
+%% Get "our" (manager) engine id
+get_engine_id() ->
+ case snmpm_config:get_engine_id() of
+ {ok, Id} ->
+ Id;
+ _Error ->
+ ""
+ end.
+
+%% The engine id of the agent
+get_agent_engine_id(Name) ->
+ snmpm_config:get_agent_engine_id(Name).
+
+is_known_engine_id(EngineID, Addr, Port) ->
+ snmpm_config:is_known_engine_id(EngineID, Addr, Port).
+
+% get_agent_engine_id(Addr, Port) ->
+% case snmpm_config:get_agent_engine_id(Addr, Port) of
+% {ok, Id} ->
+% Id;
+% _Error ->
+% ""
+% end.
+
+
+%%-----------------------------------------------------------------
+%% Sequence number (msg-id & req-id) functions
+%%-----------------------------------------------------------------
+next_msg_id() ->
+ next_id(msg_id).
+
+next_req_id() ->
+ next_id(req_id).
+
+next_id(Id) ->
+ snmpm_config:incr_counter(Id, 1).
+
+
+%%-----------------------------------------------------------------
+%% Version(s) functions
+%%-----------------------------------------------------------------
+init_versions([], S) ->
+ S;
+init_versions([v1|Vsns], S) ->
+ init_versions(Vsns, S#state{v1 = true});
+init_versions([v2|Vsns], S) ->
+ init_versions(Vsns, S#state{v2c = true});
+init_versions([v3|Vsns], S) ->
+ init_versions(Vsns, S#state{v3 = true}).
+
+init_usm(true) ->
+ snmpm_usm:init();
+init_usm(_) ->
+ ok.
+
+
+%%-----------------------------------------------------------------
+%% Counter functions
+%%-----------------------------------------------------------------
+init_counters() ->
+ F = fun(Counter) -> maybe_create_counter(Counter) end,
+ lists:map(F, counters()).
+
+reset_counters() ->
+ F = fun(Counter) -> snmpm_config:reset_stats_counter(Counter) end,
+ lists:map(F, counters()).
+
+reset_usm(true) ->
+ snmpm_usm:reset();
+reset_usm(_) ->
+ ok.
+
+maybe_create_counter(Counter) ->
+ snmpm_config:maybe_cre_stats_counter(Counter, 0).
+
+counters() ->
+ [snmpInPkts,
+ snmpOutPkts,
+ snmpInBadVersions,
+ snmpInBadCommunityNames,
+ snmpInBadCommunityUses,
+ snmpInASNParseErrs,
+ snmpInTooBigs,
+ snmpInNoSuchNames,
+ snmpInBadValues,
+ snmpInReadOnlys,
+ snmpInGenErrs,
+ snmpInTotalReqVars,
+ snmpInTotalSetVars,
+ snmpInGetRequests,
+ snmpInGetNexts,
+ snmpInSetRequests,
+ snmpInGetResponses,
+ snmpInTraps,
+ snmpOutTooBigs,
+ snmpOutNoSuchNames,
+ snmpOutBadValues,
+ snmpOutGenErrs,
+ snmpOutGetRequests,
+ snmpOutGetNexts,
+ snmpOutSetRequests,
+ snmpOutGetResponses,
+ snmpOutTraps,
+ snmpSilentDrops,
+ snmpProxyDrops,
+ %% From SNMP-MPD-MIB
+ snmpUnknownSecurityModels,
+ snmpInvalidMsgs,
+ snmpUnknownPDUHandlers
+ ].
+
+
+%%-----------------------------------------------------------------
+%% inc(VariableName) increments the variable (Counter) in
+%% the local mib. (e.g. snmpInPkts)
+%%-----------------------------------------------------------------
+inc(Name) -> inc(Name, 1).
+inc(Name, N) -> snmpm_config:incr_stats_counter(Name, N).
+
+inc_snmp_in(#pdu{type = Type}) ->
+ inc_in_type(Type);
+inc_snmp_in(TrapPdu) when is_record(TrapPdu, trappdu) ->
+ inc(snmpInPkts),
+ inc(snmpInTraps).
+
+inc_snmp_out(#pdu{type = Type,
+ error_status = ErrorStatus}) ->
+ inc(snmpOutPkts),
+ inc_out_err(ErrorStatus),
+ inc_out_type(Type).
+
+inc_out_type('get-request') -> inc(snmpOutGetRequests);
+inc_out_type('get-next-request') -> inc(snmpOutGetNexts);
+inc_out_type('set-request') -> inc(snmpOutSetRequests);
+inc_out_type(_) -> ok.
+
+inc_out_err(genErr) -> inc(snmpOutGenErrs);
+inc_out_err(tooBig) -> inc(snmpOutTooBigs);
+inc_out_err(noSuchName) -> inc(snmpOutNoSuchNames);
+inc_out_err(badValue) -> inc(snmpOutBadValues);
+inc_out_err(_) -> ok.
+
+inc_in_type('get-response') -> inc(snmpInGetResponses);
+inc_in_type(_) -> ok.
+
+
+%%-----------------------------------------------------------------
+
+discard(Reason) ->
+ throw({discarded, Reason}).
+
+discard(Reason, Report) ->
+ throw({discarded, Reason, Report}).
+
+user_err(F, A) ->
+ error_msg("USER ERROR: " ++ F ++ "~n", A).
+
+config_err(F, A) ->
+ error_msg("CONFIG ERROR: " ++ F ++ "~n", A).
+
+error_msg(F, A) ->
+ ?snmpm_error("MPD: " ++ F, A).
diff --git a/lib/snmp/src/manager/snmpm_net_if.erl b/lib/snmp/src/manager/snmpm_net_if.erl
new file mode 100644
index 0000000000..14d39933dc
--- /dev/null
+++ b/lib/snmp/src/manager/snmpm_net_if.erl
@@ -0,0 +1,1125 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2004-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%
+%%
+
+-module(snmpm_net_if).
+
+-behaviour(gen_server).
+-behaviour(snmpm_network_interface).
+
+
+%% Network Interface callback functions
+-export([
+ start_link/2,
+ stop/1,
+ send_pdu/6, % Backward compatibillity
+ send_pdu/7,
+
+ inform_response/4,
+
+ note_store/2,
+
+ info/1,
+ verbosity/2,
+ %% system_info_updated/2,
+ get_log_type/1, set_log_type/2,
+ filter_reset/1
+ ]).
+
+%% gen_server callbacks
+-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
+ code_change/3, terminate/2]).
+
+-define(SNMP_USE_V3, true).
+-include("snmp_types.hrl").
+-include("snmpm_internal.hrl").
+-include("snmpm_atl.hrl").
+-include("snmp_debug.hrl").
+
+%% -define(VMODULE,"NET_IF").
+-include("snmp_verbosity.hrl").
+
+-record(state,
+ {
+ server,
+ note_store,
+ sock,
+ mpd_state,
+ log,
+ irb = auto, % auto | {user, integer()}
+ irgc,
+ filter
+ }).
+
+
+-define(DEFAULT_FILTER_MODULE, snmpm_net_if_filter).
+-define(DEFAULT_FILTER_OPTS, [{module, ?DEFAULT_FILTER_MODULE}]).
+
+-ifdef(snmp_debug).
+-define(GS_START_LINK(Args),
+ gen_server:start_link(?MODULE, Args, [{debug,[trace]}])).
+-else.
+-define(GS_START_LINK(Args),
+ gen_server:start_link(?MODULE, Args, [])).
+-endif.
+
+
+-define(IRGC_TIMEOUT, timer:minutes(5)).
+
+
+%%%-------------------------------------------------------------------
+%%% API
+%%%-------------------------------------------------------------------
+start_link(Server, NoteStore) ->
+ ?d("start_link -> entry with"
+ "~n Server: ~p"
+ "~n NoteStore: ~p", [Server, NoteStore]),
+ Args = [Server, NoteStore],
+ ?GS_START_LINK(Args).
+
+stop(Pid) ->
+ call(Pid, stop).
+
+send_pdu(Pid, Pdu, Vsn, MsgData, Addr, Port) ->
+ send_pdu(Pid, Pdu, Vsn, MsgData, Addr, Port, undefined).
+
+send_pdu(Pid, Pdu, Vsn, MsgData, Addr, Port, ExtraInfo)
+ when is_record(Pdu, pdu) ->
+ ?d("send_pdu -> entry with"
+ "~n Pid: ~p"
+ "~n Pdu: ~p"
+ "~n Vsn: ~p"
+ "~n MsgData: ~p"
+ "~n Addr: ~p"
+ "~n Port: ~p", [Pid, Pdu, Vsn, MsgData, Addr, Port]),
+ cast(Pid, {send_pdu, Pdu, Vsn, MsgData, Addr, Port, ExtraInfo}).
+
+note_store(Pid, NoteStore) ->
+ call(Pid, {note_store, NoteStore}).
+
+inform_response(Pid, Ref, Addr, Port) ->
+ cast(Pid, {inform_response, Ref, Addr, Port}).
+
+info(Pid) ->
+ call(Pid, info).
+
+verbosity(Pid, V) ->
+ call(Pid, {verbosity, V}).
+
+%% system_info_updated(Pid, What) ->
+%% call(Pid, {system_info_updated, What}).
+
+get_log_type(Pid) ->
+ call(Pid, get_log_type).
+
+set_log_type(Pid, NewType) ->
+ call(Pid, {set_log_type, NewType}).
+
+filter_reset(Pid) ->
+ cast(Pid, filter_reset).
+
+
+%%%-------------------------------------------------------------------
+%%% Callback functions from gen_server
+%%%-------------------------------------------------------------------
+
+%%--------------------------------------------------------------------
+%% Func: init/1
+%% Returns: {ok, State} |
+%% {ok, State, Timeout} |
+%% ignore |
+%% {stop, Reason}
+%%--------------------------------------------------------------------
+init([Server, NoteStore]) ->
+ ?d("init -> entry with"
+ "~n Server: ~p"
+ "~n NoteStore: ~p", [Server, NoteStore]),
+ case (catch do_init(Server, NoteStore)) of
+ {error, Reason} ->
+ {stop, Reason};
+ {ok, State} ->
+ {ok, State}
+ end.
+
+do_init(Server, NoteStore) ->
+ process_flag(trap_exit, true),
+
+ %% -- Prio --
+ {ok, Prio} = snmpm_config:system_info(prio),
+ process_flag(priority, Prio),
+
+ %% -- Create inform request table --
+ ets:new(snmpm_inform_request_table,
+ [set, protected, named_table, {keypos, 1}]),
+
+ %% -- Verbosity --
+ {ok, Verbosity} = snmpm_config:system_info(net_if_verbosity),
+ put(sname,mnif),
+ put(verbosity,Verbosity),
+ ?vlog("starting", []),
+
+ %% -- MPD --
+ {ok, Vsns} = snmpm_config:system_info(versions),
+ MpdState = snmpm_mpd:init(Vsns),
+
+ %% -- Module dependent options --
+ {ok, Opts} = snmpm_config:system_info(net_if_options),
+
+ %% -- Inform response behaviour --
+ {ok, IRB} = snmpm_config:system_info(net_if_irb),
+ IrGcRef = irgc_start(IRB),
+
+ %% -- Socket --
+ SndBuf = get_opt(Opts, sndbuf, default),
+ RecBuf = get_opt(Opts, recbuf, default),
+ BindTo = get_opt(Opts, bind_to, false),
+ NoReuse = get_opt(Opts, no_reuse, false),
+ {ok, Port} = snmpm_config:system_info(port),
+ {ok, Sock} = do_open_port(Port, SndBuf, RecBuf, BindTo, NoReuse),
+
+ %% Flow control --
+ FilterOpts = get_opt(Opts, filter, []),
+ FilterMod = create_filter(FilterOpts),
+ ?vdebug("FilterMod: ~w", [FilterMod]),
+
+ %% -- Audit trail log ---
+ {ok, ATL} = snmpm_config:system_info(audit_trail_log),
+ Log = do_init_log(ATL),
+
+ %% -- Initiate counters ---
+ init_counters(),
+
+ %% -- We are done ---
+ State = #state{server = Server,
+ note_store = NoteStore,
+ mpd_state = MpdState,
+ sock = Sock,
+ log = Log,
+ irb = IRB,
+ irgc = IrGcRef,
+ filter = FilterMod},
+ ?vdebug("started", []),
+ {ok, State}.
+
+
+%% Open port
+do_open_port(Port, SendSz, RecvSz, BindTo, NoReuse) ->
+ ?vtrace("do_open_port -> entry with"
+ "~n Port: ~p"
+ "~n SendSz: ~p"
+ "~n RecvSz: ~p"
+ "~n BindTo: ~p"
+ "~n NoReuse: ~p", [Port, SendSz, RecvSz, BindTo, NoReuse]),
+ IpOpts1 = bind_to(BindTo),
+ IpOpts2 = no_reuse(NoReuse),
+ IpOpts3 = recbuf(RecvSz),
+ IpOpts4 = sndbuf(SendSz),
+ IpOpts = [binary | IpOpts1 ++ IpOpts2 ++ IpOpts3 ++ IpOpts4],
+ OpenRes =
+ case init:get_argument(snmpm_fd) of
+ {ok, [[FdStr]]} ->
+ Fd = list_to_integer(FdStr),
+ gen_udp:open(0, [{fd, Fd}|IpOpts]);
+ error ->
+ gen_udp:open(Port, IpOpts)
+ end,
+ case OpenRes of
+ {error, _} = Error ->
+ throw(Error);
+ OK ->
+ OK
+ end.
+
+bind_to(true) ->
+ case snmpm_config:system_info(address) of
+ {ok, Addr} when is_list(Addr) ->
+ [{ip, list_to_tuple(Addr)}];
+ {ok, Addr} ->
+ [{ip, Addr}];
+ _ ->
+ []
+ end;
+bind_to(_) ->
+ [].
+
+no_reuse(false) ->
+ [{reuseaddr, true}];
+no_reuse(_) ->
+ [].
+
+recbuf(default) ->
+ [];
+recbuf(Sz) ->
+ [{recbuf, Sz}].
+
+sndbuf(default) ->
+ [];
+sndbuf(Sz) ->
+ [{sndbuf, Sz}].
+
+
+create_filter(Opts) when is_list(Opts) ->
+ case get_opt(Opts, module, ?DEFAULT_FILTER_MODULE) of
+ ?DEFAULT_FILTER_MODULE = Mod ->
+ Mod;
+ Module ->
+ snmpm_network_interface_filter:verify(Module),
+ Module
+ end;
+create_filter(BadOpts) ->
+ throw({error, {bad_filter_opts, BadOpts}}).
+
+
+%% Open log
+do_init_log(false) ->
+ ?vtrace("do_init_log(false) -> entry", []),
+ undefined;
+do_init_log(true) ->
+ ?vtrace("do_init_log(true) -> entry", []),
+ {ok, Type} = snmpm_config:system_info(audit_trail_log_type),
+ {ok, Dir} = snmpm_config:system_info(audit_trail_log_dir),
+ {ok, Size} = snmpm_config:system_info(audit_trail_log_size),
+ {ok, Repair} = snmpm_config:system_info(audit_trail_log_repair),
+ Name = ?audit_trail_log_name,
+ File = filename:absname(?audit_trail_log_file, Dir),
+ case snmp_log:create(Name, File, Size, Repair, true) of
+ {ok, Log} ->
+ {Log, Type};
+ {error, Reason} ->
+ throw({error, {failed_create_audit_log, Reason}})
+ end.
+
+
+%%--------------------------------------------------------------------
+%% Func: handle_call/3
+%% Returns: {reply, Reply, State} |
+%% {reply, Reply, State, Timeout} |
+%% {noreply, State} |
+%% {noreply, State, Timeout} |
+%% {stop, Reason, Reply, State} | (terminate/2 is called)
+%% {stop, Reason, State} (terminate/2 is called)
+%%--------------------------------------------------------------------
+handle_call({verbosity, Verbosity}, _From, State) ->
+ ?vlog("received verbosity request", []),
+ put(verbosity, Verbosity),
+ {reply, ok, State};
+
+%% handle_call({system_info_updated, What}, _From, State) ->
+%% ?vlog("received system_info_updated request with What = ~p", [What]),
+%% {NewState, Reply} = handle_system_info_updated(State, What),
+%% {reply, Reply, NewState};
+
+handle_call(get_log_type, _From, State) ->
+ ?vlog("received get-log-type request", []),
+ Reply = (catch handle_get_log_type(State)),
+ {reply, Reply, State};
+
+handle_call({set_log_type, NewType}, _From, State) ->
+ ?vlog("received set-log-type request with NewType = ~p", [NewType]),
+ {NewState, Reply} = (catch handle_set_log_type(State, NewType)),
+ {reply, Reply, NewState};
+
+handle_call({note_store, Pid}, _From, State) ->
+ ?vlog("received new note_store: ~w", [Pid]),
+ {reply, ok, State#state{note_store = Pid}};
+
+handle_call(stop, _From, State) ->
+ ?vlog("received stop request", []),
+ Reply = ok,
+ {stop, normal, Reply, State};
+
+handle_call(info, _From, State) ->
+ ?vlog("received info request", []),
+ Reply = get_info(State),
+ {reply, Reply, State};
+
+handle_call(Req, From, State) ->
+ warning_msg("received unknown request (from ~p): ~n~p", [Req, From]),
+ {reply, {error, {invalid_request, Req}}, State}.
+
+
+%%--------------------------------------------------------------------
+%% Func: handle_cast/2
+%% Returns: {noreply, State} |
+%% {noreply, State, Timeout} |
+%% {stop, Reason, State} (terminate/2 is called)
+%%--------------------------------------------------------------------
+handle_cast({send_pdu, Pdu, Vsn, MsgData, Addr, Port, _ExtraInfo}, State) ->
+ ?vlog("received send_pdu message with"
+ "~n Pdu: ~p"
+ "~n Vsn: ~p"
+ "~n MsgData: ~p"
+ "~n Addr: ~p"
+ "~n Port: ~p", [Pdu, Vsn, MsgData, Addr, Port]),
+ maybe_handle_send_pdu(Pdu, Vsn, MsgData, Addr, Port, State),
+ {noreply, State};
+
+handle_cast({inform_response, Ref, Addr, Port}, State) ->
+ ?vlog("received inform_response message with"
+ "~n Ref: ~p"
+ "~n Addr: ~p"
+ "~n Port: ~p", [Ref, Addr, Port]),
+ handle_inform_response(Ref, Addr, Port, State),
+ {noreply, State};
+
+handle_cast(filter_reset, State) ->
+ ?vlog("received filter_reset message", []),
+ reset_counters(),
+ {noreply, State};
+
+handle_cast(Msg, State) ->
+ warning_msg("received unknown message: ~n~p", [Msg]),
+ {noreply, State}.
+
+
+%%--------------------------------------------------------------------
+%% Func: handle_info/2
+%% Returns: {noreply, State} |
+%% {noreply, State, Timeout} |
+%% {stop, Reason, State} (terminate/2 is called)
+%%--------------------------------------------------------------------
+handle_info({udp, Sock, Ip, Port, Bytes}, #state{sock = Sock} = State) ->
+ ?vlog("received ~w bytes from ~p:~p [~w]", [size(Bytes), Ip, Port, Sock]),
+ maybe_handle_recv_msg(Ip, Port, Bytes, State),
+ {noreply, State};
+
+handle_info(inform_response_gc, State) ->
+ ?vlog("received inform_response_gc message", []),
+ State2 = handle_inform_response_gc(State),
+ {noreply, State2};
+
+handle_info({disk_log, _Node, Log, Info}, State) ->
+ ?vlog("received disk_log message: "
+ "~n Info: ~p", [Info]),
+ State2 = handle_disk_log(Log, Info, State),
+ {noreply, State2};
+
+handle_info(Info, State) ->
+ warning_msg("received unknown info: ~n~p", [Info]),
+ {noreply, State}.
+
+
+%%--------------------------------------------------------------------
+%% Func: terminate/2
+%% Purpose: Shutdown the server
+%% Returns: any (ignored by gen_server)
+%%--------------------------------------------------------------------
+terminate(Reason, #state{log = Log, irgc = IrGcRef}) ->
+ ?vdebug("terminate: ~p",[Reason]),
+ irgc_stop(IrGcRef),
+ %% Close logs
+ do_close_log(Log),
+ ok.
+
+
+do_close_log({Log, _Type}) ->
+ (catch snmp_log:sync(Log)),
+ (catch snmp_log:close(Log)),
+ ok;
+do_close_log(_) ->
+ ok.
+
+
+%%----------------------------------------------------------------------
+%% Func: code_change/3
+%% Purpose: Convert process state when code is changed
+%% Returns: {ok, NewState}
+%%----------------------------------------------------------------------
+
+code_change({down, _Vsn}, OldState, downgrade_to_pre45) ->
+ ?d("code_change(down) -> entry", []),
+ #state{server = Server,
+ note_store = NoteStore,
+ sock = Sock,
+ mpd_state = MpdState,
+ log = Log,
+ irgc = IrGcRef} = OldState,
+ irgc_stop(IrGcRef),
+ (catch ets:delete(snmpm_inform_request_table)),
+ State = {state, Server, NoteStore, Sock, MpdState, Log},
+ {ok, State};
+
+% upgrade
+code_change(_Vsn, OldState, upgrade_from_pre45) ->
+ ?d("code_change(up) -> entry", []),
+ {state, Server, NoteStore, Sock, MpdState, Log} = OldState,
+ State = #state{server = Server,
+ note_store = NoteStore,
+ sock = Sock,
+ mpd_state = MpdState,
+ log = Log,
+ irb = auto,
+ irgc = undefined},
+ ets:new(snmpm_inform_request_table,
+ [set, protected, named_table, {keypos, 1}]),
+ {ok, State};
+
+code_change(_Vsn, State, _Extra) ->
+ {ok, State}.
+
+
+%%%-------------------------------------------------------------------
+%%% Internal functions
+%%%-------------------------------------------------------------------
+
+maybe_handle_recv_msg(Addr, Port, Bytes, #state{filter = FilterMod} = State) ->
+ case (catch FilterMod:accept_recv(Addr, Port)) of
+ false ->
+ %% Drop the received packet
+ inc(netIfMsgInDrops),
+ ok;
+ _ ->
+ handle_recv_msg(Addr, Port, Bytes, State)
+ end.
+
+
+handle_recv_msg(Addr, Port, Bytes, #state{server = Pid})
+ when is_binary(Bytes) andalso (size(Bytes) =:= 0) ->
+ Pid ! {snmp_error, {empty_message, Addr, Port}, Addr, Port},
+ ok;
+
+handle_recv_msg(Addr, Port, Bytes,
+ #state{server = Pid,
+ note_store = NoteStore,
+ mpd_state = MpdState,
+ sock = Sock,
+ log = Log} = State) ->
+ Logger = logger(Log, read, Addr, Port),
+ case (catch snmpm_mpd:process_msg(Bytes, snmpUDPDomain, Addr, Port,
+ MpdState, NoteStore, Logger)) of
+
+ {ok, Vsn, Pdu, MS, ACM} ->
+ maybe_handle_recv_pdu(Addr, Port, Vsn, Pdu, MS, ACM,
+ Logger, State);
+
+ {discarded, Reason, Report} ->
+ ?vdebug("discarded: ~p", [Reason]),
+ ErrorInfo = {failed_processing_message, Reason},
+ Pid ! {snmp_error, ErrorInfo, Addr, Port},
+ maybe_udp_send(State#state.filter, Sock, Addr, Port, Report),
+ ok;
+
+ {discarded, Reason} ->
+ ?vdebug("discarded: ~p", [Reason]),
+ ErrorInfo = {failed_processing_message, Reason},
+ Pid ! {snmp_error, ErrorInfo, Addr, Port},
+ ok;
+
+ Error ->
+ error_msg("processing of received message failed: "
+ "~n ~p", [Error]),
+ ok
+ end.
+
+
+maybe_handle_recv_pdu(Addr, Port,
+ Vsn, #pdu{type = Type} = Pdu, PduMS, ACM,
+ Logger,
+ #state{filter = FilterMod} = State) ->
+ case (catch FilterMod:accept_recv_pdu(Addr, Port, Type)) of
+ false ->
+ inc(netIfPduInDrops),
+ ok;
+ _ ->
+ handle_recv_pdu(Addr, Port, Vsn, Pdu, PduMS, ACM, Logger, State)
+ end;
+maybe_handle_recv_pdu(Addr, Port, Vsn, Trap, PduMS, ACM, Logger,
+ #state{filter = FilterMod} = State)
+ when is_record(Trap, trappdu) ->
+ case (catch FilterMod:accept_recv_pdu(Addr, Port, trappdu)) of
+ false ->
+ inc(netIfPduInDrops),
+ ok;
+ _ ->
+ handle_recv_pdu(Addr, Port, Vsn, Trap, PduMS, ACM, Logger, State)
+ end;
+maybe_handle_recv_pdu(Addr, Port, Vsn, Pdu, PduMS, ACM, Logger, State) ->
+ handle_recv_pdu(Addr, Port, Vsn, Pdu, PduMS, ACM, Logger, State).
+
+
+handle_recv_pdu(Addr, Port,
+ Vsn, #pdu{type = 'inform-request'} = Pdu, _PduMS, ACM,
+ Logger, #state{server = Pid, irb = IRB} = State) ->
+ handle_inform_request(IRB, Pid, Vsn, Pdu, ACM,
+ Addr, Port, Logger, State);
+handle_recv_pdu(Addr, Port,
+ _Vsn, #pdu{type = report} = Pdu, _PduMS, ok,
+ _Logger,
+ #state{server = Pid} = _State) ->
+ ?vtrace("received report - ok", []),
+ Pid ! {snmp_report, {ok, Pdu}, Addr, Port};
+handle_recv_pdu(Addr, Port,
+ _Vsn, #pdu{type = report} = Pdu, _PduMS,
+ {error, ReqId, Reason},
+ _Logger,
+ #state{server = Pid} = _State) ->
+ ?vtrace("received report - error", []),
+ Pid ! {snmp_report, {error, ReqId, Reason, Pdu}, Addr, Port};
+handle_recv_pdu(Addr, Port,
+ _Vsn, #pdu{type = 'snmpv2-trap'} = Pdu, _PduMS, _ACM,
+ _Logger,
+ #state{server = Pid} = _State) ->
+ ?vtrace("received snmpv2-trap", []),
+ Pid ! {snmp_trap, Pdu, Addr, Port};
+handle_recv_pdu(Addr, Port,
+ _Vsn, Trap, _PduMS, _ACM,
+ _Logger,
+ #state{server = Pid} = _State) when is_record(Trap, trappdu) ->
+ ?vtrace("received trappdu", []),
+ Pid ! {snmp_trap, Trap, Addr, Port};
+handle_recv_pdu(Addr, Port,
+ _Vsn, Pdu, _PduMS, _ACM,
+ _Logger,
+ #state{server = Pid} = _State) when is_record(Pdu, pdu) ->
+ ?vtrace("received pdu", []),
+ Pid ! {snmp_pdu, Pdu, Addr, Port};
+handle_recv_pdu(_Addr, _Port, _Vsn, Pdu, _PduMS, ACM, _Logger, _State) ->
+ ?vlog("received unexpected pdu: "
+ "~n Pdu: ~p"
+ "~n ACM: ~p", [Pdu, ACM]).
+
+
+handle_inform_request(auto, Pid, Vsn, Pdu, ACM, Addr, Port, Logger, State) ->
+ ?vtrace("received inform-request (true)", []),
+ Pid ! {snmp_inform, ignore, Pdu, Addr, Port},
+ RePdu = make_response_pdu(Pdu),
+ maybe_send_inform_response(RePdu, Vsn, ACM, Addr, Port, Logger, State);
+handle_inform_request({user, To}, Pid, Vsn, #pdu{request_id = ReqId} = Pdu,
+ ACM, Addr, Port, _Logger, _State) ->
+ ?vtrace("received inform-request (false)", []),
+
+ Pid ! {snmp_inform, ReqId, Pdu, Addr, Port},
+
+ %% Before we go any further, we need to check that we have not
+ %% already received this message (possible resend).
+
+ Key = {ReqId, Addr, Port},
+ case ets:lookup(snmpm_inform_request_table, Key) of
+ [_] ->
+ %% OK, we already know about this. We assume this
+ %% is a resend. Either the agent is really eager or
+ %% the user has not answered yet. Bad user!
+ ok;
+ [] ->
+ RePdu = make_response_pdu(Pdu),
+ Expire = t() + To,
+ Rec = {Key, Expire, {Vsn, ACM, RePdu}},
+ ets:insert(snmpm_inform_request_table, Rec)
+ end.
+
+handle_inform_response(Ref, Addr, Port, State) ->
+ Key = {Ref, Addr, Port},
+ case ets:lookup(snmpm_inform_request_table, Key) of
+ [{Key, _, {Vsn, ACM, RePdu}}] ->
+ Logger = logger(State#state.log, read, Addr, Port),
+ ets:delete(snmpm_inform_request_table, Key),
+ maybe_send_inform_response(RePdu, Vsn, ACM, Addr, Port,
+ Logger, State);
+ [] ->
+ %% Already acknowledged, or the user was to slow to reply...
+ ok
+ end,
+ ok.
+
+maybe_send_inform_response(RePdu, Vsn, ACM, Addr, Port, Logger,
+ #state{server = Pid,
+ sock = Sock,
+ filter = FilterMod}) ->
+ case (catch FilterMod:accept_send_pdu(Addr, Port, pdu_type_of(RePdu))) of
+ false ->
+ inc(netIfPduOutDrops),
+ ok;
+ _ ->
+ case snmpm_mpd:generate_response_msg(Vsn, RePdu, ACM, Logger) of
+ {ok, Msg} ->
+ maybe_udp_send(FilterMod, Sock, Addr, Port, Msg);
+ {discarded, Reason} ->
+ ?vlog("failed generating response message:"
+ "~n Reason: ~p", [Reason]),
+ ReqId = RePdu#pdu.request_id,
+ ErrorInfo = {failed_generating_response, {RePdu, Reason}},
+ Pid ! {snmp_error, ReqId, ErrorInfo, Addr, Port},
+ ok
+ end
+ end.
+
+handle_inform_response_gc(#state{irb = IRB} = State) ->
+ ets:safe_fixtable(snmpm_inform_request_table, true),
+ do_irgc(ets:first(snmpm_inform_request_table), t()),
+ ets:safe_fixtable(snmpm_inform_request_table, false),
+ State#state{irgc = irgc_start(IRB)}.
+
+%% We are deleting at the same time as we are traversing the table!!!
+do_irgc('$end_of_table', _) ->
+ ok;
+do_irgc(Key, Now) ->
+ Next = ets:next(snmpm_inform_request_table, Key),
+ case ets:lookup(snmpm_inform_request_table, Key) of
+ [{Key, BestBefore, _}] when BestBefore < Now ->
+ ets:delete(snmpm_inform_request_table, Key);
+ _ ->
+ ok
+ end,
+ do_irgc(Next, Now).
+
+irgc_start(auto) ->
+ undefined;
+irgc_start(_) ->
+ erlang:send_after(?IRGC_TIMEOUT, self(), inform_response_gc).
+
+irgc_stop(undefined) ->
+ ok;
+irgc_stop(Ref) ->
+ (catch erlang:cancel_timer(Ref)).
+
+
+maybe_handle_send_pdu(Pdu, Vsn, MsgData, Addr, Port,
+ #state{filter = FilterMod} = State) ->
+ case (catch FilterMod:accept_send_pdu(Addr, Port, pdu_type_of(Pdu))) of
+ false ->
+ inc(netIfPduOutDrops),
+ ok;
+ _ ->
+ handle_send_pdu(Pdu, Vsn, MsgData, Addr, Port, State)
+ end.
+
+handle_send_pdu(Pdu, Vsn, MsgData, Addr, Port,
+ #state{server = Pid,
+ note_store = NoteStore,
+ sock = Sock,
+ log = Log,
+ filter = FilterMod}) ->
+ Logger = logger(Log, write, Addr, Port),
+ case (catch snmpm_mpd:generate_msg(Vsn, NoteStore,
+ Pdu, MsgData, Logger)) of
+ {ok, Msg} ->
+ ?vtrace("handle_send_pdu -> message generated", []),
+ maybe_udp_send(FilterMod, Sock, Addr, Port, Msg);
+ {discarded, Reason} ->
+ ?vlog("PDU not sent: "
+ "~n PDU: ~p"
+ "~n Reason: ~p", [Pdu, Reason]),
+ Pid ! {snmp_error, Pdu, Reason},
+ ok
+ end.
+
+
+maybe_udp_send(FilterMod, Sock, Addr, Port, Msg) ->
+ case (catch FilterMod:accept_send(Addr, Port)) of
+ false ->
+ inc(netIfMsgOutDrops),
+ ok;
+ _ ->
+ udp_send(Sock, Addr, Port, Msg)
+ end.
+
+
+udp_send(Sock, Addr, Port, Msg) ->
+ case (catch gen_udp:send(Sock, Addr, Port, Msg)) of
+ ok ->
+ ?vdebug("sent ~w bytes to ~w:~w [~w]",
+ [sz(Msg), Addr, Port, Sock]),
+ ok;
+ {error, Reason} ->
+ error_msg("failed sending message to ~p:~p: "
+ "~n ~p",[Addr, Port, Reason]);
+ Error ->
+ error_msg("failed sending message to ~p:~p: "
+ "~n ~p",[Addr, Port, Error])
+ end.
+
+sz(B) when is_binary(B) ->
+ size(B);
+sz(L) when is_list(L) ->
+ length(L);
+sz(_) ->
+ undefined.
+
+
+handle_disk_log(_Log, {wrap, NoLostItems}, State) ->
+ ?vlog("Audit Trail Log - wrapped: ~w previously logged items where lost",
+ [NoLostItems]),
+ State;
+handle_disk_log(_Log, {truncated, NoLostItems}, State) ->
+ ?vlog("Audit Trail Log - truncated: ~w items where lost when truncating",
+ [NoLostItems]),
+ State;
+handle_disk_log(_Log, full, State) ->
+ error_msg("Failed to write to Audit Trail Log (full)", []),
+ State;
+handle_disk_log(_Log, {error_status, ok}, State) ->
+ State;
+handle_disk_log(_Log, {error_status, {error, Reason}}, State) ->
+ error_msg("Error status received from Audit Trail Log: "
+ "~n~p", [Reason]),
+ State;
+handle_disk_log(_Log, _Info, State) ->
+ State.
+
+
+%% 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("Encoding error. Pdu: ~w. Reason: ~w",[Pdu, Reason]),
+%% error;
+%% L when list(L) ->
+%% {Msg, 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("Encoding error. Pdu: ~w. Reason: ~w",[Pdu, Reason]),
+%% error;
+%% L when list(L) ->
+%% {Msg, L}
+%% end.
+
+
+%% mk_msg('version-3', Pdu, {Context, User, EngineID, CtxEngineId, SecLevel},
+%% MsgData) ->
+%% %% Code copied from snmp_mpd.erl
+%% {MsgId, SecName, SecData} =
+%% if
+%% tuple(MsgData), 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 snmp_usm:generate_outgoing_msg(Message, SecEngineID,
+%% SecName, SecData, SecLevel) of
+%% {'EXIT', Reason} ->
+%% error("Encoding error. Pdu: ~w. Reason: ~w",[Pdu, Reason]),
+%% error;
+%% {error, Reason} ->
+%% error("Encoding error. Pdu: ~w. 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("Encoding error. Pdu: ~w. Reason: ~w",[Pdu, Reason]),
+%% error;
+%% B when list(B) ->
+%% B
+%% end.
+
+
+%% handle_system_info_updated(#state{log = {Log, _OldType}} = State,
+%% audit_trail_log_type = _What) ->
+%% %% Just to make sure, check that ATL is actually enabled
+%% case snmpm_config:system_info(audit_trail_log) of
+%% {ok, true} ->
+%% {ok, Type} = snmpm_config:system_info(audit_trail_log_type),
+%% NewState = State#state{log = {Log, Type}},
+%% {NewState, ok};
+%% _ ->
+%% {State, {error, {adt_not_enabled}}}
+%% end;
+%% handle_system_info_updated(_State, _What) ->
+%% ok.
+
+handle_get_log_type(#state{log = {_Log, Value}} = State) ->
+ %% Just to make sure, check that ATL is actually enabled
+ case snmpm_config:system_info(audit_trail_log) of
+ {ok, true} ->
+ Type =
+ case {lists:member(read, Value), lists:member(write, Value)} of
+ {true, true} ->
+ read_write;
+ {true, false} ->
+ read;
+ {false, true} ->
+ write;
+ {false, false} ->
+ throw({State, {error, {bad_atl_type, Value}}})
+ end,
+ {ok, Type};
+ _ ->
+ {error, not_enabled}
+ end;
+handle_get_log_type(_State) ->
+ {error, not_enabled}.
+
+handle_set_log_type(#state{log = {Log, OldValue}} = State, NewType) ->
+ %% Just to make sure, check that ATL is actually enabled
+ case snmpm_config:system_info(audit_trail_log) of
+ {ok, true} ->
+ NewValue =
+ case NewType of
+ read ->
+ [read];
+ write ->
+ [write];
+ read_write ->
+ [read,write];
+ _ ->
+ throw({State, {error, {bad_atl_type, NewType}}})
+ end,
+ NewState = State#state{log = {Log, NewValue}},
+ OldType =
+ case {lists:member(read, OldValue),
+ lists:member(write, OldValue)} of
+ {true, true} ->
+ read_write;
+ {true, false} ->
+ read;
+ {false, true} ->
+ write;
+ {false, false} ->
+ throw({State, {error, {bad_atl_type, OldValue}}})
+ end,
+ {NewState, {ok, OldType}};
+ _ ->
+ {State, {error, not_enabled}}
+ end;
+handle_set_log_type(State, _NewType) ->
+ {State, {error, not_enabled}}.
+
+
+%% -------------------------------------------------------------------
+
+make_response_pdu(#pdu{request_id = ReqId, varbinds = Vbs}) ->
+ #pdu{type = 'get-response',
+ request_id = ReqId,
+ error_status = noError,
+ error_index = 0,
+ varbinds = Vbs}.
+
+
+%% ----------------------------------------------------------------
+
+pdu_type_of(#pdu{type = Type}) ->
+ Type;
+pdu_type_of(TrapPdu) when is_record(TrapPdu, trappdu) ->
+ trap.
+
+
+%% -------------------------------------------------------------------
+
+t() ->
+ {A,B,C} = erlang:now(),
+ A*1000000000+B*1000+(C div 1000).
+
+
+%% -------------------------------------------------------------------
+
+logger(undefined, _Type, _Addr, _Port) ->
+ fun(_) ->
+ ok
+ end;
+logger({Log, Types}, Type, Addr, Port) ->
+ case lists:member(Type, Types) of
+ true ->
+ fun(Msg) ->
+ snmp_log:log(Log, Msg, Addr, Port)
+ end;
+ false ->
+ fun(_) ->
+ ok
+ end
+ end.
+
+
+%% -------------------------------------------------------------------
+
+%% info_msg(F, A) ->
+%% ?snmpm_info("NET-IF server: " ++ F, A).
+
+warning_msg(F, A) ->
+ ?snmpm_warning("NET-IF server: " ++ F, A).
+
+error_msg(F, A) ->
+ ?snmpm_error("NET-IF server: " ++ F, A).
+
+
+
+%%%-------------------------------------------------------------------
+
+% get_opt(Key, Opts) ->
+% ?vtrace("get option ~w", [Key]),
+% snmp_misc:get_option(Key, Opts).
+
+get_opt(Opts, Key, Def) ->
+ ?vtrace("get option ~w with default ~p", [Key, Def]),
+ snmp_misc:get_option(Key, Opts, Def).
+
+
+%% -------------------------------------------------------------------
+
+get_info(#state{sock = Id}) ->
+ ProcSize = proc_mem(self()),
+ PortInfo = get_port_info(Id),
+ [{process_memory, ProcSize}, {port_info, PortInfo}].
+
+proc_mem(P) when is_pid(P) ->
+ case (catch erlang:process_info(P, memory)) of
+ {memory, Sz} when is_integer(Sz) ->
+ Sz;
+ _ ->
+ undefined
+ end.
+%% proc_mem(_) ->
+%% undefined.
+
+
+get_port_info(Id) ->
+ PortInfo =
+ case (catch erlang:port_info(Id)) of
+ PI when is_list(PI) ->
+ [{port_info, PI}];
+ _ ->
+ []
+ end,
+ PortStatus =
+ case (catch prim_inet:getstatus(Id)) of
+ {ok, PS} ->
+ [{port_status, PS}];
+ _ ->
+ []
+ end,
+ PortAct =
+ case (catch inet:getopts(Id, [active])) of
+ {ok, PA} ->
+ [{port_act, PA}];
+ _ ->
+ []
+ end,
+ PortStats =
+ case (catch inet:getstat(Id)) of
+ {ok, Stat} ->
+ [{port_stats, Stat}];
+ _ ->
+ []
+ end,
+ IfList =
+ case (catch inet:getif(Id)) of
+ {ok, IFs} ->
+ [{interfaces, IFs}];
+ _ ->
+ []
+ end,
+ BufSz =
+ case (catch inet:getopts(Id, [recbuf, sndbuf, buffer])) of
+ {ok, Sz} ->
+ [{buffer_size, Sz}];
+ _ ->
+ []
+ end,
+ [{socket, Id}] ++
+ IfList ++
+ PortStats ++
+ PortInfo ++
+ PortStatus ++
+ PortAct ++
+ BufSz.
+
+
+%%-----------------------------------------------------------------
+%% Counter functions
+%%-----------------------------------------------------------------
+init_counters() ->
+ F = fun(Counter) -> maybe_create_counter(Counter) end,
+ lists:map(F, counters()).
+
+reset_counters() ->
+ F = fun(Counter) -> snmpm_config:reset_stats_counter(Counter) end,
+ lists:map(F, counters()).
+
+maybe_create_counter(Counter) ->
+ snmpm_config:maybe_cre_stats_counter(Counter, 0).
+
+counters() ->
+ [
+ netIfMsgOutDrops,
+ netIfMsgInDrops,
+ netIfPduOutDrops,
+ netIfPduInDrops
+ ].
+
+inc(Name) -> inc(Name, 1).
+inc(Name, N) -> snmpm_config:incr_stats_counter(Name, N).
+
+%% get_counters() ->
+%% Counters = counters(),
+%% get_counters(Counters, []).
+
+%% get_counters([], Acc) ->
+%% lists:reverse(Acc);
+%% get_counters([Counter|Counters], Acc) ->
+%% case snmpm_config:get_stats_counter(Counter) of
+%% {ok, CounterVal} ->
+%% get_counters(Counters, [{Counter, CounterVal}|Acc]);
+%% _ ->
+%% get_counters(Counters, Acc)
+%% end.
+
+
+%% ----------------------------------------------------------------
+
+call(Pid, Req) ->
+ call(Pid, Req, infinity).
+
+call(Pid, Req, Timeout) ->
+ gen_server:call(Pid, Req, Timeout).
+
+cast(Pid, Msg) ->
+ gen_server:cast(Pid, Msg).
+
diff --git a/lib/snmp/src/manager/snmpm_net_if_filter.erl b/lib/snmp/src/manager/snmpm_net_if_filter.erl
new file mode 100644
index 0000000000..eb0c6efb11
--- /dev/null
+++ b/lib/snmp/src/manager/snmpm_net_if_filter.erl
@@ -0,0 +1,53 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 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%
+%%
+-module(snmpm_net_if_filter).
+
+-export([accept_recv/2,
+ accept_send/2,
+ accept_recv_pdu/3,
+ accept_send_pdu/3]).
+
+-include("snmp_debug.hrl").
+
+accept_recv(_Addr, _Port) ->
+ ?d("accept_recv -> entry with"
+ "~n Addr: ~p"
+ "~n Port: ~p", [_Addr, _Port]),
+ true.
+
+accept_send(_Addr, _Port) ->
+ ?d("accept_send -> entry with"
+ "~n Addr: ~p"
+ "~n Port: ~p", [_Addr, _Port]),
+ true.
+
+accept_recv_pdu(_Addr, _Port, _PduType) ->
+ ?d("accept_recv_pdu -> entry with"
+ "~n Addr: ~p"
+ "~n Port: ~p"
+ "~n PduType: ~p", [_Addr, _Port, _PduType]),
+ true.
+
+accept_send_pdu(_Addr, _Port, _PduType) ->
+ ?d("accept_send_pdu -> entry with"
+ "~n Addr: ~p"
+ "~n Port: ~p"
+ "~n PduType: ~p", [_Addr, _Port, _PduType]),
+ true.
+
diff --git a/lib/snmp/src/manager/snmpm_network_interface.erl b/lib/snmp/src/manager/snmpm_network_interface.erl
new file mode 100644
index 0000000000..b830d45ce7
--- /dev/null
+++ b/lib/snmp/src/manager/snmpm_network_interface.erl
@@ -0,0 +1,37 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2004-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%
+%%
+
+-module(snmpm_network_interface).
+
+-export([behaviour_info/1]).
+
+behaviour_info(callbacks) ->
+ [{start_link, 2},
+ {stop, 1},
+ {send_pdu, 7},
+ {inform_response, 4},
+ {note_store, 2},
+ {info, 1},
+ {verbosity, 2},
+ %% {system_info_updated, 2},
+ {get_log_type, 1},
+ {set_log_type, 2}];
+behaviour_info(_) ->
+ undefined.
+
diff --git a/lib/snmp/src/manager/snmpm_network_interface_filter.erl b/lib/snmp/src/manager/snmpm_network_interface_filter.erl
new file mode 100644
index 0000000000..ae8b7cfce1
--- /dev/null
+++ b/lib/snmp/src/manager/snmpm_network_interface_filter.erl
@@ -0,0 +1,54 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 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%
+%%
+-module(snmpm_network_interface_filter).
+
+-export([behaviour_info/1]).
+-export([verify/1]).
+
+
+behaviour_info(callbacks) ->
+ [{accept_recv, 2},
+ {accept_send, 2},
+ {accept_recv_pdu, 3},
+ {accept_send_pdu, 3}];
+behaviour_info(_) ->
+ undefined.
+
+
+%% accept_recv(address(), port()) -> boolean()
+%% Called at the receiption of a message
+%% (before *any* processing has been done).
+%%
+%% accept_send(address(), port()) -> boolean()
+%% Called before the sending of a message
+%% (after *all* processing has been done).
+%%
+%% accept_recv_pdu(Addr, Port, pdu_type()) -> boolean()
+%% Called after the basic message processing (MPD) has been done,
+%% but before the pdu is handed over to the master-agent for
+%% primary processing.
+%%
+%% accept_send_pdu(Addr, Port, pdu_type()) -> boolean()
+%% Called before the basic message processing (MPD) is done,
+%% when a pdu has been received from the master-agent.
+%%
+
+
+verify(Module) ->
+ snmp_misc:verify_behaviour(?MODULE, Module).
diff --git a/lib/snmp/src/manager/snmpm_server.erl b/lib/snmp/src/manager/snmpm_server.erl
new file mode 100644
index 0000000000..30aacc0ec3
--- /dev/null
+++ b/lib/snmp/src/manager/snmpm_server.erl
@@ -0,0 +1,3117 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2004-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%
+%%
+
+-module(snmpm_server).
+
+%%----------------------------------------------------------------------
+%% This module implements a simple SNMP manager for Erlang.
+%%
+%%----------------------------------------------------------------------
+
+%% User interface
+-export([start_link/0, stop/0,
+ is_started/0,
+
+ load_mib/1, unload_mib/1,
+
+ register_user/4, register_user_monitor/4, unregister_user/1,
+
+ sync_get/4, sync_get/5, sync_get/6,
+ async_get/4, async_get/5, async_get/6,
+ sync_get_next/4, sync_get_next/5, sync_get_next/6,
+ async_get_next/4, async_get_next/5, async_get_next/6,
+ sync_get_bulk/6, sync_get_bulk/7, sync_get_bulk/8,
+ async_get_bulk/6, async_get_bulk/7, async_get_bulk/8,
+ sync_set/4, sync_set/5, sync_set/6,
+ async_set/4, async_set/5, async_set/6,
+ cancel_async_request/2,
+
+ %% discovery/2, discovery/3, discovery/4, discovery/5, discovery/6,
+
+ %% system_info_updated/2,
+ get_log_type/0, set_log_type/1,
+
+ reconfigure/0,
+
+ info/0,
+ verbosity/1, verbosity/2
+
+ ]).
+
+
+%% Internal exports
+-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
+ code_change/3, terminate/2]).
+
+%% GCT exports
+-export([gct_init/1, gct/2]).
+
+
+-include("snmpm_internal.hrl").
+-include("snmp_debug.hrl").
+-include("snmp_types.hrl").
+-include("STANDARD-MIB.hrl").
+-include("SNMP-FRAMEWORK-MIB.hrl").
+-include("snmp_verbosity.hrl").
+
+
+%%----------------------------------------------------------------------
+
+-define(SERVER, ?MODULE).
+
+-define(SYNC_GET_TIMEOUT, 5000).
+-define(SYNC_SET_TIMEOUT, 5000).
+-define(DEFAULT_ASYNC_EXPIRE, 5000).
+-define(EXTRA_INFO, undefined).
+
+-define(SNMP_AGENT_PORT, 161).
+
+
+-ifdef(snmp_debug).
+-define(GS_START_LINK(Args),
+ gen_server:start_link({local, ?SERVER}, ?MODULE, Args,
+ [{debug,[trace]}])).
+-else.
+-define(GS_START_LINK(Args),
+ gen_server:start_link({local, ?SERVER}, ?MODULE, Args, [])).
+-endif.
+
+
+
+%%----------------------------------------------------------------------
+
+-record(state,
+ {parent,
+ gct,
+ note_store,
+ note_store_ref,
+ net_if,
+ net_if_mod,
+ net_if_ref,
+ req, %% ???? Last request id in outgoing message
+ oid, %% ???? Last oid in request outgoing message
+ mini_mib
+ }
+ ).
+
+%% The active state is to ensure that nothing unpleasant happens
+%% during (after) a code_change. At the initial start of the
+%% application, this process (GCT) will make one run and then
+%% deactivate (unless some async request has been issued in the
+%% meantime).
+-record(gct, {parent, state = active, timeout}).
+
+-record(request,
+ {id,
+ user_id,
+ reg_type,
+ target,
+ addr,
+ port,
+ type,
+ data,
+ ref,
+ mon,
+ from,
+ discovery = false,
+ expire = infinity % When shall the request expire (time in ms)
+ }
+ ).
+
+-record(monitor,
+ {id,
+ mon,
+ proc
+ }
+ ).
+
+
+%%%-------------------------------------------------------------------
+%%% API
+%%%-------------------------------------------------------------------
+
+start_link() ->
+ ?d("start_link -> entry", []),
+ Args = [],
+ ?GS_START_LINK(Args).
+
+stop() ->
+ call(stop).
+
+is_started() ->
+ case (catch call(is_started, 1000)) of
+ Bool when ((Bool =:= true) orelse (Bool =:= false)) ->
+ Bool;
+ _ ->
+ false
+ end.
+
+load_mib(MibFile) when is_list(MibFile) ->
+ call({load_mib, MibFile}).
+
+unload_mib(Mib) when is_list(Mib) ->
+ call({unload_mib, Mib}).
+
+
+register_user(UserId, UserMod, UserData, DefaultAgentConfig) ->
+ snmpm_config:register_user(UserId, UserMod, UserData, DefaultAgentConfig).
+
+register_user_monitor(Id, Module, Data, DefaultAgentConfig) ->
+ case register_user(Id, Module, Data, DefaultAgentConfig) of
+ ok ->
+ case call({monitor_user, Id, self()}) of
+ ok ->
+ ok;
+ Error ->
+ unregister_user(Id),
+ Error
+ end;
+ Error ->
+ Error
+ end.
+
+unregister_user(UserId) ->
+ call({unregister_user, UserId}).
+
+
+%% -- [sync] get --
+
+sync_get(UserId, TargetName, CtxName, Oids) ->
+ sync_get(UserId, TargetName, CtxName, Oids,
+ ?SYNC_GET_TIMEOUT).
+
+sync_get(UserId, TargetName, CtxName, Oids, Timeout) ->
+ sync_get(UserId, TargetName, CtxName, Oids, Timeout, ?EXTRA_INFO).
+
+sync_get(UserId, TargetName, CtxName, Oids, Timeout, ExtraInfo)
+ when is_list(TargetName) andalso
+ is_list(CtxName) andalso
+ is_list(Oids) andalso
+ is_integer(Timeout) ->
+ call({sync_get, self(), UserId, TargetName, CtxName, Oids, Timeout, ExtraInfo}).
+
+%% -- [async] get --
+
+async_get(UserId, TargetName, CtxName, Oids) ->
+ async_get(UserId, TargetName, CtxName, Oids,
+ ?DEFAULT_ASYNC_EXPIRE, ?EXTRA_INFO).
+
+async_get(UserId, TargetName, CtxName, Oids, Expire) ->
+ async_get(UserId, TargetName, CtxName, Oids, Expire, ?EXTRA_INFO).
+
+async_get(UserId, TargetName, CtxName, Oids, Expire, ExtraInfo)
+ when (is_list(TargetName) andalso
+ is_list(CtxName) andalso
+ is_list(Oids) andalso
+ is_integer(Expire) andalso (Expire >= 0)) ->
+ call({async_get, self(), UserId, TargetName, CtxName, Oids, Expire,
+ ExtraInfo}).
+
+%% -- [sync] get-next --
+
+sync_get_next(UserId, TargetName, CtxName, Oids) ->
+ sync_get_next(UserId, TargetName, CtxName, Oids, ?SYNC_GET_TIMEOUT,
+ ?EXTRA_INFO).
+
+sync_get_next(UserId, TargetName, CtxName, Oids, Timeout) ->
+ sync_get_next(UserId, TargetName, CtxName, Oids, Timeout, ?EXTRA_INFO).
+
+sync_get_next(UserId, TargetName, CtxName, Oids, Timeout, ExtraInfo)
+ when is_list(TargetName) andalso
+ is_list(CtxName) andalso
+ is_list(Oids) andalso
+ is_integer(Timeout) ->
+ call({sync_get_next, self(), UserId, TargetName, CtxName, Oids, Timeout,
+ ExtraInfo}).
+
+%% -- [async] get-next --
+
+async_get_next(UserId, TargetName, CtxName, Oids) ->
+ async_get_next(UserId, TargetName, CtxName, Oids,
+ ?DEFAULT_ASYNC_EXPIRE, ?EXTRA_INFO).
+
+async_get_next(UserId, TargetName, CtxName, Oids, Expire) ->
+ async_get_next(UserId, TargetName, CtxName, Oids, Expire, ?EXTRA_INFO).
+
+async_get_next(UserId, TargetName, CtxName, Oids, Expire, ExtraInfo)
+ when (is_list(TargetName) andalso
+ is_list(CtxName) andalso
+ is_list(Oids) andalso
+ is_integer(Expire) andalso (Expire >= 0)) ->
+ call({async_get_next, self(), UserId, TargetName, CtxName, Oids,
+ Expire, ExtraInfo}).
+
+%% -- [sync] get-bulk --
+
+sync_get_bulk(UserId, TargetName, NonRep, MaxRep, CtxName, Oids) ->
+ sync_get_bulk(UserId, TargetName,
+ NonRep, MaxRep, CtxName, Oids,
+ ?SYNC_GET_TIMEOUT, ?EXTRA_INFO).
+
+sync_get_bulk(UserId, TargetName, NonRep, MaxRep, CtxName, Oids, Timeout) ->
+ sync_get_bulk(UserId, TargetName,
+ NonRep, MaxRep, CtxName, Oids,
+ Timeout, ?EXTRA_INFO).
+
+sync_get_bulk(UserId, TargetName, NonRep, MaxRep, CtxName, Oids, Timeout,
+ ExtraInfo)
+ when is_list(TargetName) andalso
+ is_integer(NonRep) andalso
+ is_integer(MaxRep) andalso
+ is_list(CtxName) andalso
+ is_list(Oids) andalso
+ is_integer(Timeout) ->
+ call({sync_get_bulk, self(), UserId, TargetName,
+ NonRep, MaxRep, CtxName, Oids, Timeout, ExtraInfo}).
+
+%% -- [async] get-bulk --
+
+async_get_bulk(UserId, TargetName, NonRep, MaxRep, CtxName, Oids) ->
+ async_get_bulk(UserId, TargetName,
+ NonRep, MaxRep, CtxName, Oids,
+ ?DEFAULT_ASYNC_EXPIRE, ?EXTRA_INFO).
+
+async_get_bulk(UserId, TargetName, NonRep, MaxRep, CtxName, Oids, Expire) ->
+ async_get_bulk(UserId, TargetName,
+ NonRep, MaxRep, CtxName, Oids,
+ Expire, ?EXTRA_INFO).
+
+async_get_bulk(UserId, TargetName, NonRep, MaxRep, CtxName, Oids, Expire,
+ ExtraInfo)
+ when is_list(TargetName) andalso
+ is_integer(NonRep) andalso
+ is_integer(MaxRep) andalso
+ is_list(CtxName) andalso
+ is_list(Oids) andalso
+ is_integer(Expire) ->
+ call({async_get_bulk, self(), UserId, TargetName,
+ NonRep, MaxRep, CtxName, Oids, Expire, ExtraInfo}).
+
+%% -- [sync] set --
+
+%% VarsAndValues is: {PlainOid, o|s|i, Value} (unknown mibs) | {Oid, Value}
+sync_set(UserId, TargetName, CtxName, VarsAndVals) ->
+ sync_set(UserId, TargetName, CtxName, VarsAndVals,
+ ?SYNC_SET_TIMEOUT, ?EXTRA_INFO).
+
+sync_set(UserId, TargetName, CtxName, VarsAndVals, Timeout) ->
+ sync_set(UserId, TargetName, CtxName, VarsAndVals,
+ Timeout, ?EXTRA_INFO).
+
+sync_set(UserId, TargetName, CtxName, VarsAndVals, Timeout, ExtraInfo)
+ when is_list(TargetName) andalso
+ is_list(CtxName) andalso
+ is_list(VarsAndVals) andalso
+ is_integer(Timeout) ->
+ call({sync_set, self(), UserId, TargetName,
+ CtxName, VarsAndVals, Timeout, ExtraInfo}).
+
+%% -- [async] set --
+
+async_set(UserId, TargetName, CtxName, VarsAndVals) ->
+ async_set(UserId, TargetName, CtxName, VarsAndVals,
+ ?DEFAULT_ASYNC_EXPIRE, ?EXTRA_INFO).
+
+async_set(UserId, TargetName, CtxName, VarsAndVals, Expire) ->
+ async_set(UserId, TargetName, CtxName, VarsAndVals,
+ Expire, ?EXTRA_INFO).
+
+async_set(UserId, TargetName, CtxName, VarsAndVals, Expire, ExtraInfo)
+ when (is_list(TargetName) andalso
+ is_list(CtxName) andalso
+ is_list(VarsAndVals) andalso
+ is_integer(Expire) andalso (Expire >= 0)) ->
+ call({async_set, self(), UserId, TargetName,
+ CtxName, VarsAndVals, Expire, ExtraInfo}).
+
+
+cancel_async_request(UserId, ReqId) ->
+ call({cancel_async_request, UserId, ReqId}).
+
+
+%% discovery(UserId, BAddr) ->
+%% discovery(UserId, BAddr, ?SNMP_AGENT_PORT, [],
+%% ?DEFAULT_ASYNC_EXPIRE, ?EXTRA_INFO).
+
+%% discovery(UserId, BAddr, Config) when is_list(Config) ->
+%% discovery(UserId, BAddr, ?SNMP_AGENT_PORT, Config,
+%% ?DEFAULT_ASYNC_EXPIRE, ?EXTRA_INFO);
+
+%% discovery(UserId, BAddr, Expire) when is_integer(Expire) ->
+%% discovery(UserId, BAddr, ?SNMP_AGENT_PORT, [], Expire, ?EXTRA_INFO).
+
+%% discovery(UserId, BAddr, Config, Expire) ->
+%% discovery(UserId, BAddr, ?SNMP_AGENT_PORT, Config, Expire, ?EXTRA_INFO).
+
+%% discovery(UserId, BAddr, Port, Config, Expire) ->
+%% discovery(UserId, BAddr, Port, Config, Expire, ?EXTRA_INFO).
+
+%% discovery(UserId, BAddr, Port, Config, Expire, ExtraInfo) ->
+%% call({discovery, self(), UserId, BAddr, Port, Config, Expire, ExtraInfo}).
+
+
+verbosity(Verbosity) ->
+ case ?vvalidate(Verbosity) of
+ Verbosity ->
+ call({verbosity, Verbosity});
+ _ ->
+ {error, {invalid_verbosity, Verbosity}}
+ end.
+
+info() ->
+ call(info).
+
+verbosity(net_if = Ref, Verbosity) ->
+ verbosity2(Ref, Verbosity);
+verbosity(note_store = Ref, Verbosity) ->
+ verbosity2(Ref, Verbosity).
+
+verbosity2(Ref, Verbosity) ->
+ case ?vvalidate(Verbosity) of
+ Verbosity ->
+ call({verbosity, Ref, Verbosity});
+ _ ->
+ {error, {invalid_verbosity, Verbosity}}
+ end.
+
+%% Target -> all | server | net_if
+%% system_info_updated(Target, What) ->
+%% call({system_info_updated, Target, What}).
+
+get_log_type() ->
+ call(get_log_type).
+
+set_log_type(NewType) ->
+ call({set_log_type, NewType}).
+
+reconfigure() ->
+ call(reconfigure).
+
+
+%%----------------------------------------------------------------------
+%% Options: List of
+%% {community, String ("public" is default}
+%% {mibs, List of Filenames}
+%% {trap_udp, integer() (default 5000)}
+%% {conf_dir, string()}
+%% {log_dir, string()}
+%% {db_dir, string()}
+%% {db_repair, true | false}
+%%----------------------------------------------------------------------
+init(_) ->
+ ?d("init -> entry", []),
+ case (catch do_init()) of
+ {ok, State} ->
+ {ok, State};
+ {error, Reason} ->
+ {stop, Reason}
+ end.
+
+
+%% Put all config stuff in a snmpm_config module/process.
+%% Tables should be protected so that it is cheap to
+%% read. Writing has to go through the interface...
+
+do_init() ->
+ process_flag(trap_exit, true),
+ {ok, Prio} = snmpm_config:system_info(prio),
+ process_flag(priority, Prio),
+
+ {ok, Verbosity} = snmpm_config:system_info(server_verbosity),
+ put(sname, mse),
+ put(verbosity, Verbosity),
+ ?vlog("starting", []),
+
+ %% Start the garbage collector timer process
+ {ok, Timeout} = snmpm_config:system_info(server_timeout),
+ {ok, GCT} = gct_start(Timeout),
+
+ %% -- Create request table --
+ ets:new(snmpm_request_table,
+ [set, protected, named_table, {keypos, #request.id}]),
+
+ %% -- Create monitor table --
+ ets:new(snmpm_monitor_table,
+ [set, protected, named_table, {keypos, #monitor.id}]),
+
+ %% -- Start the note-store and net-if processes --
+ {NoteStore, NoteStoreRef} = do_init_note_store(Prio),
+ {NetIf, NetIfModule, NetIfRef} = do_init_net_if(NoteStore),
+
+ MiniMIB = snmpm_config:make_mini_mib(),
+ State = #state{mini_mib = MiniMIB,
+ gct = GCT,
+ note_store = NoteStore,
+ note_store_ref = NoteStoreRef,
+ net_if = NetIf,
+ net_if_mod = NetIfModule,
+ net_if_ref = NetIfRef},
+ ?vlog("started", []),
+ {ok, State}.
+
+
+do_init_note_store(Prio) ->
+ ?vdebug("try start note store", []),
+ {ok, Verbosity} = snmpm_config:system_info(note_store_verbosity),
+ {ok, Timeout} = snmpm_config:system_info(note_store_timeout),
+ Opts = [{sname, mns},
+ {verbosity, Verbosity},
+ {timeout, Timeout}],
+ case snmpm_misc_sup:start_note_store(Prio, Opts) of
+ {ok, Pid} ->
+ ?vtrace("do_init_note_store -> Pid: ~p", [Pid]),
+ Ref = erlang:monitor(process, Pid),
+ {Pid, Ref};
+ {error, Reason} ->
+ ?vlog("failed starting note-store - Reason: "
+ "~n Reason: ~p"
+ "~n", [Reason]),
+ throw({error, {failed_starting_note_store, Reason}})
+ end.
+
+do_init_net_if(NoteStore) ->
+ ?vdebug("try start net if", []),
+ {ok, NetIfModule} = snmpm_config:system_info(net_if_module),
+ case snmpm_misc_sup:start_net_if(NetIfModule, NoteStore) of
+ {ok, Pid} ->
+ ?vtrace("do_init_net_if -> Pid: ~p", [Pid]),
+ Ref = erlang:monitor(process, Pid),
+ {Pid, NetIfModule, Ref};
+ {error, Reason} ->
+ ?vlog("failed starting net-if - Reason: "
+ "~n Reason: ~p"
+ "~n", [Reason]),
+ throw({error, {failed_starting_net_if, Reason}})
+ end.
+
+%% ---------------------------------------------------------------------
+%% ---------------------------------------------------------------------
+
+handle_call({monitor_user, Id, Pid}, _From, State) when is_pid(Pid) ->
+ ?vlog("received monitor_user request for ~w [~w]", [Id, Pid]),
+ Reply =
+ case ets:lookup(snmpm_monitor_table, Id) of
+ [#monitor{proc = Pid}] ->
+ ?vdebug("already monitored", []),
+ ok;
+
+ [#monitor{proc = OtherPid}] ->
+ ?vinfo("already registered to ~w", [OtherPid]),
+ {error, {already_monitored, OtherPid}};
+
+ [] ->
+ Ref = erlang:monitor(process, Pid),
+ ?vtrace("monitor ref: ~w", [Ref]),
+ Mon = #monitor{id = Id, mon = Ref, proc = Pid},
+ ets:insert(snmpm_monitor_table, Mon),
+ ok
+ end,
+ {reply, Reply, State};
+
+handle_call({unregister_user, UserId}, _From, State) ->
+ ?vlog("received request to unregister user ~p", [UserId]),
+
+ %% 1) If this user is monitored, then demonitor
+ ?vtrace("handle_call(unregister_user) -> maybe demonitor", []),
+ case ets:lookup(snmpm_monitor_table, UserId) of
+ [] ->
+ ok;
+ [#monitor{mon = M}] ->
+ maybe_demonitor(M), % This is really overkill (meybe_), but...
+ ok
+ end,
+
+ %% 2) Delete all outstanding requests from this user
+ ?vtrace("handle_call(unregister_user) -> "
+ "delete all outstanding requests for user", []),
+ Pat = #request{user_id = UserId,
+ id = '$1', ref = '$2', mon = '$3', _ = '_'},
+ Match = ets:match(snmpm_request_table, Pat),
+ ?vtrace("handle_call(unregister_user) -> Match: ~p", [Match]),
+ F1 = fun([ReqId, Ref, MonRef]) ->
+ ets:delete(snmpm_request_table, ReqId),
+ cancel_timer(Ref),
+ maybe_demonitor(MonRef),
+ ok
+ end,
+ lists:foreach(F1, Match),
+
+ %% 3) Unregister all agents registered by this user
+ ?vdebug("handle_call(unregister_user) -> "
+ "unregister all agents registered by user", []),
+ Agents = snmpm_config:which_agents(UserId),
+ ?vtrace("handle_call(unregister_user) -> Agents: ~p", [Agents]),
+ F2 = fun(TargetName) ->
+ snmpm_config:unregister_agent(UserId, TargetName)
+ end,
+ lists:foreach(F2, Agents),
+
+ %% 4) Unregister the user
+ ?vdebug("handle_call(unregister_user) -> unregister user", []),
+ Reply = snmpm_config:unregister_user(UserId),
+ ?vtrace("handle_call(unregister_user) -> Reply: ~p", [Reply]),
+ {reply, Reply, State};
+
+
+%% We will reply to this request later, when the reply comes in from the
+%% agent, or when the timeout hits (unless we get an error now).
+handle_call({sync_get, Pid, UserId, TargetName, CtxName, Oids, Timeout, ExtraInfo},
+ From, State) ->
+ ?vlog("received sync_get [~p] request", [CtxName]),
+ case (catch handle_sync_get(Pid,
+ UserId, TargetName, CtxName, Oids,
+ Timeout, ExtraInfo, From, State)) of
+ ok ->
+ {noreply, State};
+ Error ->
+ {reply, Error, State}
+ end;
+
+
+handle_call({sync_get_next, Pid, UserId, TargetName, CtxName, Oids, Timeout, ExtraInfo}, From, State) ->
+ ?vlog("received sync_get_next [~p] request", [CtxName]),
+ case (catch handle_sync_get_next(Pid,
+ UserId, TargetName, CtxName, Oids,
+ Timeout, ExtraInfo, From, State)) of
+ ok ->
+ {noreply, State};
+ Error ->
+ {reply, Error, State}
+ end;
+
+
+%% Check agent version? This op not in v1
+handle_call({sync_get_bulk, Pid, UserId, TargetName,
+ NonRep, MaxRep, CtxName, Oids, Timeout, ExtraInfo},
+ From, State) ->
+ ?vlog("received sync_get_bulk [~p] request", [CtxName]),
+ case (catch handle_sync_get_bulk(Pid,
+ UserId, TargetName, CtxName,
+ NonRep, MaxRep, Oids,
+ Timeout, ExtraInfo, From, State)) of
+ ok ->
+ {noreply, State};
+ Error ->
+ {reply, Error, State}
+ end;
+
+
+handle_call({sync_set, Pid, UserId, TargetName,
+ CtxName, VarsAndVals, Timeout, ExtraInfo},
+ From, State) ->
+ ?vlog("received sync_set [~p] request", [CtxName]),
+ case (catch handle_sync_set(Pid,
+ UserId, TargetName, CtxName, VarsAndVals,
+ Timeout, ExtraInfo, From, State)) of
+ ok ->
+ {noreply, State};
+ Error ->
+ {reply, Error, State}
+ end;
+
+
+handle_call({async_get, Pid, UserId, TargetName,
+ CtxName, Oids, Expire, ExtraInfo},
+ _From, State) ->
+ ?vlog("received async_get [~p] request", [CtxName]),
+ Reply = (catch handle_async_get(Pid, UserId, TargetName, CtxName, Oids,
+ Expire, ExtraInfo, State)),
+ {reply, Reply, State};
+
+
+handle_call({async_get_next, Pid, UserId, TargetName,
+ CtxName, Oids, Expire, ExtraInfo},
+ _From, State) ->
+ ?vlog("received async_get_next [~p] request", [CtxName]),
+ Reply = (catch handle_async_get_next(Pid, UserId, TargetName, CtxName,
+ Oids, Expire, ExtraInfo, State)),
+ {reply, Reply, State};
+
+
+%% Check agent version? This op not in v1
+handle_call({async_get_bulk, Pid, UserId, TargetName,
+ NonRep, MaxRep, CtxName, Oids, Expire, ExtraInfo},
+ _From, State) ->
+ ?vlog("received async_get_bulk [~p] request", [CtxName]),
+ Reply = (catch handle_async_get_bulk(Pid,
+ UserId, TargetName, CtxName,
+ NonRep, MaxRep, Oids,
+ Expire, ExtraInfo, State)),
+ {reply, Reply, State};
+
+
+handle_call({async_set, Pid, UserId, TargetName,
+ CtxName, VarsAndVals, Expire, ExtraInfo},
+ _From, State) ->
+ ?vlog("received async_set [~p] request", [CtxName]),
+ Reply = (catch handle_async_set(Pid, UserId, TargetName, CtxName,
+ VarsAndVals, Expire, ExtraInfo, State)),
+ {reply, Reply, State};
+
+
+handle_call({cancel_async_request, UserId, ReqId}, _From, State) ->
+ ?vlog("received cancel_async_request request", []),
+ Reply = (catch handle_cancel_async_request(UserId, ReqId, State)),
+ {reply, Reply, State};
+
+
+%% handle_call({discovery, Pid, UserId, BAddr, Port, Config, Expire, ExtraInfo},
+%% _From, State) ->
+%% ?vlog("received discovery request", []),
+%% Reply = (catch handle_discovery(Pid, UserId, BAddr, Port, Config,
+%% Expire, ExtraInfo, State)),
+%% {reply, Reply, State};
+
+
+handle_call({load_mib, Mib}, _From, State) ->
+ ?vlog("received load_mib request", []),
+ case snmpm_config:load_mib(Mib) of
+ ok ->
+ MiniMIB = snmpm_config:make_mini_mib(),
+ {reply, ok, State#state{mini_mib = MiniMIB}};
+ Error ->
+ {reply, Error, State}
+ end;
+
+
+handle_call({unload_mib, Mib}, _From, State) ->
+ ?vlog("received unload_mib request", []),
+ case snmpm_config:unload_mib(Mib) of
+ ok ->
+ MiniMIB = snmpm_config:make_mini_mib(),
+ {reply, ok, State#state{mini_mib = MiniMIB}};
+ Error ->
+ {reply, Error, State}
+ end;
+
+handle_call({verbosity, Verbosity}, _From, State) ->
+ ?vlog("received verbosity request", []),
+ put(verbosity, Verbosity),
+ {reply, ok, State};
+
+handle_call({verbosity, net_if, Verbosity}, _From,
+ #state{net_if = Pid, net_if_mod = Mod} = State) ->
+ ?vlog("received net_if verbosity request", []),
+ Mod:verbosity(Pid, Verbosity),
+ {reply, ok, State};
+
+handle_call({verbosity, note_store, Verbosity}, _From,
+ #state{note_store = Pid} = State) ->
+ ?vlog("received note_store verbosity request", []),
+ snmp_note_store:verbosity(Pid, Verbosity),
+ {reply, ok, State};
+
+handle_call(reconfigure, _From, State) ->
+ ?vlog("received reconfigure request", []),
+ Reply = {error, not_implemented},
+ {reply, Reply, State};
+
+handle_call(info, _From, State) ->
+ ?vlog("received info request", []),
+ Reply = get_info(State),
+ {reply, Reply, State};
+
+handle_call(is_started, _From, State) ->
+ ?vlog("received is_started request", []),
+ IsStarted = is_started(State),
+ {reply, IsStarted, State};
+
+%% handle_call({system_info_updated, Target, What}, _From, State) ->
+%% ?vlog("received system_info_updated request: "
+%% "~n Target: ~p"
+%% "~n What: ~p", [Target, What]),
+%% Reply = handle_system_info_updated(State, Target, What),
+%% {reply, Reply, State};
+
+handle_call(get_log_type, _From, State) ->
+ ?vlog("received get_log_type request", []),
+ Reply = handle_get_log_type(State),
+ {reply, Reply, State};
+
+handle_call({set_log_type, NewType}, _From, State) ->
+ ?vlog("received set_log_type request: "
+ "~n NewType: ~p", [NewType]),
+ Reply = handle_set_log_type(State, NewType),
+ {reply, Reply, State};
+
+handle_call(stop, _From, State) ->
+ ?vlog("received stop request", []),
+ {stop, normal, ok, State};
+
+
+handle_call(Req, _From, State) ->
+ warning_msg("received unknown request: ~n~p", [Req]),
+ {reply, {error, unknown_request}, State}.
+
+
+handle_cast(Msg, State) ->
+ warning_msg("received unknown message: ~n~p", [Msg]),
+ {noreply, State}.
+
+
+handle_info({sync_timeout, ReqId, From}, State) ->
+ ?vlog("received sync_timeout [~w] message", [ReqId]),
+ handle_sync_timeout(ReqId, From, State),
+ {noreply, State};
+
+
+handle_info({snmp_error, Pdu, Reason}, State) ->
+ ?vlog("received snmp_error message", []),
+ handle_snmp_error(Pdu, Reason, State),
+ {noreply, State};
+
+handle_info({snmp_error, Reason, Addr, Port}, State) ->
+ ?vlog("received snmp_error message", []),
+ handle_snmp_error(Addr, Port, -1, Reason, State),
+ {noreply, State};
+
+handle_info({snmp_error, ReqId, Reason, Addr, Port}, State) ->
+ ?vlog("received snmp_error message", []),
+ handle_snmp_error(Addr, Port, ReqId, Reason, State),
+ {noreply, State};
+
+%% handle_info({snmp_error, ReqId, Pdu, Reason, Addr, Port}, State) ->
+%% ?vlog("received snmp_error message", []),
+%% handle_snmp_error(Pdu, ReqId, Reason, Addr, Port, State),
+%% {noreply, State};
+
+
+handle_info({snmp_pdu, Pdu, Addr, Port}, State) ->
+ ?vlog("received snmp_pdu message", []),
+ handle_snmp_pdu(Pdu, Addr, Port, State),
+ {noreply, State};
+
+
+handle_info({snmp_trap, Trap, Addr, Port}, State) ->
+ ?vlog("received snmp_trap message", []),
+ handle_snmp_trap(Trap, Addr, Port, State),
+ {noreply, State};
+
+
+handle_info({snmp_inform, Ref, Pdu, Addr, Port}, State) ->
+ ?vlog("received snmp_inform message", []),
+ handle_snmp_inform(Ref, Pdu, Addr, Port, State),
+ {noreply, State};
+
+
+handle_info({snmp_report, {ok, Pdu}, Addr, Port}, State) ->
+ handle_snmp_report(Pdu, Addr, Port, State),
+ {noreply, State};
+
+handle_info({snmp_report, {error, ReqId, Info, Pdu}, Addr, Port}, State) ->
+ handle_snmp_report(ReqId, Pdu, Info, Addr, Port, State),
+ {noreply, State};
+
+
+handle_info(gc_timeout, #state{gct = GCT} = State) ->
+ ?vlog("received gc_timeout message", []),
+ handle_gc(GCT),
+ {noreply, State};
+
+
+handle_info({'DOWN', _MonRef, process, Pid, _Reason},
+ #state{note_store = NoteStore,
+ net_if = Pid} = State) ->
+ ?vlog("received 'DOWN' message regarding net_if", []),
+ {NetIf, _, Ref} = do_init_net_if(NoteStore),
+ {noreply, State#state{net_if = NetIf, net_if_ref = Ref}};
+
+
+handle_info({'DOWN', _MonRef, process, Pid, _Reason},
+ #state{note_store = Pid,
+ net_if = NetIf,
+ net_if_mod = Mod} = State) ->
+ ?vlog("received 'DOWN' message regarding note_store", []),
+ {ok, Prio} = snmpm_config:system_info(prio),
+ {NoteStore, Ref} = do_init_note_store(Prio),
+ Mod:note_store(NetIf, NoteStore),
+ {noreply, State#state{note_store = NoteStore, note_store_ref = Ref}};
+
+
+handle_info({'DOWN', MonRef, process, Pid, Reason}, State) ->
+ ?vlog("received 'DOWN' message (~w) from ~w "
+ "~n Reason: ~p", [MonRef, Pid, Reason]),
+ handle_down(MonRef),
+ {noreply, State};
+
+
+handle_info({'EXIT', Pid, Reason}, #state{gct = Pid} = State) ->
+ ?vlog("received 'EXIT' message from the GCT (~w) process: "
+ "~n ~p", [Pid, Reason]),
+ {ok, Timeout} = snmpm_config:system_info(server_timeout),
+ {ok, GCT} = gct_start(Timeout),
+ {noreply, State#state{gct = GCT}};
+
+
+handle_info(Info, State) ->
+ warning_msg("received unknown info: ~n~p", [Info]),
+ {noreply, State}.
+
+
+%%----------------------------------------------------------
+%% Code change
+%%----------------------------------------------------------
+
+% downgrade
+code_change({down, _Vsn}, #state{gct = Pid} = State, _Extra) ->
+ ?d("code_change(down) -> entry", []),
+ gct_code_change(Pid),
+ {ok, State};
+
+% upgrade
+code_change(_Vsn, #state{gct = Pid} = State0, _Extra) ->
+ ?d("code_change(up) -> entry", []),
+ gct_code_change(Pid),
+ MiniMIB = snmpm_config:make_mini_mib(),
+ State = State0#state{mini_mib = MiniMIB},
+ {ok, State}.
+
+
+%%----------------------------------------------------------
+%% Terminate
+%%----------------------------------------------------------
+
+terminate(Reason, #state{gct = GCT}) ->
+ ?vdebug("terminate: ~p",[Reason]),
+ gct_stop(GCT),
+ snmpm_misc_sup:stop_note_store(),
+ snmpm_misc_sup:stop_net_if(),
+ ok.
+
+
+%%----------------------------------------------------------------------
+%%
+%%----------------------------------------------------------------------
+
+handle_sync_get(Pid, UserId, TargetName, CtxName, Oids, Timeout, ExtraInfo,
+ From, State) ->
+ ?vtrace("handle_sync_get -> entry with"
+ "~n Pid: ~p"
+ "~n UserId: ~p"
+ "~n TargetName: ~p"
+ "~n CtxName: ~p"
+ "~n Oids: ~p"
+ "~n Timeout: ~p"
+ "~n From: ~p",
+ [Pid, UserId, TargetName, CtxName, Oids, Timeout, From]),
+ case agent_data(TargetName, CtxName) of
+ {ok, RegType, Addr, Port, Vsn, MsgData} ->
+ ?vtrace("handle_sync_get -> send a ~p message", [Vsn]),
+ ReqId = send_get_request(Oids, Vsn, MsgData, Addr, Port,
+ ExtraInfo, State),
+ ?vdebug("handle_sync_get -> ReqId: ~p", [ReqId]),
+ Msg = {sync_timeout, ReqId, From},
+ Ref = erlang:send_after(Timeout, self(), Msg),
+ MonRef = erlang:monitor(process, Pid),
+ ?vtrace("handle_sync_get -> MonRef: ~p", [MonRef]),
+ Req = #request{id = ReqId,
+ user_id = UserId,
+ reg_type = RegType,
+ target = TargetName,
+ addr = Addr,
+ port = Port,
+ type = get,
+ data = MsgData,
+ ref = Ref,
+ mon = MonRef,
+ from = From},
+ ets:insert(snmpm_request_table, Req),
+ ok;
+ Error ->
+ ?vinfo("failed retrieving agent data for get:"
+ "~n TargetName: ~p"
+ "~n Error: ~p", [TargetName, Error]),
+ Error
+ end.
+
+
+handle_sync_get_next(Pid, UserId, TargetName, CtxName, Oids, Timeout,
+ ExtraInfo, From, State) ->
+ ?vtrace("handle_sync_get_next -> entry with"
+ "~n Pid: ~p"
+ "~n UserId: ~p"
+ "~n TargetName: ~p"
+ "~n CtxName: ~p"
+ "~n Oids: ~p"
+ "~n Timeout: ~p"
+ "~n From: ~p",
+ [Pid, UserId, TargetName, CtxName, Oids, Timeout, From]),
+ case agent_data(TargetName, CtxName) of
+ {ok, RegType, Addr, Port, Vsn, MsgData} ->
+ ?vtrace("handle_sync_get_next -> send a ~p message", [Vsn]),
+ ReqId = send_get_next_request(Oids, Vsn, MsgData,
+ Addr, Port, ExtraInfo, State),
+ ?vdebug("handle_sync_get_next -> ReqId: ~p", [ReqId]),
+ Msg = {sync_timeout, ReqId, From},
+ Ref = erlang:send_after(Timeout, self(), Msg),
+ MonRef = erlang:monitor(process, Pid),
+ ?vtrace("handle_sync_get_next -> MonRef: ~p", [MonRef]),
+ Req = #request{id = ReqId,
+ user_id = UserId,
+ reg_type = RegType,
+ target = TargetName,
+ addr = Addr,
+ port = Port,
+ type = get_next,
+ data = MsgData,
+ ref = Ref,
+ mon = MonRef,
+ from = From},
+ ets:insert(snmpm_request_table, Req),
+ ok;
+
+ Error ->
+ ?vinfo("failed retrieving agent data for get-next:"
+ "~n TargetName: ~p"
+ "~n Error: ~p", [TargetName, Error]),
+ Error
+ end.
+
+
+handle_sync_get_bulk(Pid, UserId, TargetName, CtxName,
+ NonRep, MaxRep, Oids, Timeout,
+ ExtraInfo, From, State) ->
+ ?vtrace("handle_sync_get_bulk -> entry with"
+ "~n Pid: ~p"
+ "~n UserId: ~p"
+ "~n TargetName: ~p"
+ "~n CtxName: ~p"
+ "~n NonRep: ~p"
+ "~n MaxRep: ~p"
+ "~n Oids: ~p"
+ "~n Timeout: ~p"
+ "~n From: ~p",
+ [Pid, UserId, TargetName, CtxName, NonRep, MaxRep, Oids,
+ Timeout, From]),
+ case agent_data(TargetName, CtxName) of
+ {ok, RegType, Addr, Port, Vsn, MsgData} ->
+ ?vtrace("handle_sync_get_bulk -> send a ~p message", [Vsn]),
+ ReqId = send_get_bulk_request(Oids, Vsn, MsgData, Addr, Port,
+ NonRep, MaxRep, ExtraInfo, State),
+ ?vdebug("handle_sync_get_bulk -> ReqId: ~p", [ReqId]),
+ Msg = {sync_timeout, ReqId, From},
+ Ref = erlang:send_after(Timeout, self(), Msg),
+ MonRef = erlang:monitor(process, Pid),
+ ?vtrace("handle_sync_get_bulk -> MonRef: ~p", [MonRef]),
+ Req = #request{id = ReqId,
+ user_id = UserId,
+ reg_type = RegType,
+ target = TargetName,
+ addr = Addr,
+ port = Port,
+ type = get_bulk,
+ data = MsgData,
+ ref = Ref,
+ mon = MonRef,
+ from = From},
+ ets:insert(snmpm_request_table, Req),
+ ok;
+
+ Error ->
+ ?vinfo("failed retrieving agent data for get-bulk:"
+ "~n TargetName: ~p"
+ "~n Error: ~p", [TargetName, Error]),
+ Error
+ end.
+
+
+handle_sync_set(Pid, UserId, TargetName, CtxName, VarsAndVals, Timeout,
+ ExtraInfo, From, State) ->
+ ?vtrace("handle_sync_set -> entry with"
+ "~n Pid: ~p"
+ "~n UserId: ~p"
+ "~n TargetName: ~p"
+ "~n CtxName: ~p"
+ "~n VarsAndVals: ~p"
+ "~n Timeout: ~p"
+ "~n From: ~p",
+ [Pid, UserId, TargetName, CtxName, VarsAndVals, Timeout, From]),
+ case agent_data(TargetName, CtxName) of
+ {ok, RegType, Addr, Port, Vsn, MsgData} ->
+ ?vtrace("handle_sync_set -> send a ~p message", [Vsn]),
+ ReqId = send_set_request(VarsAndVals, Vsn, MsgData,
+ Addr, Port, ExtraInfo, State),
+ ?vdebug("handle_sync_set -> ReqId: ~p", [ReqId]),
+ Msg = {sync_timeout, ReqId, From},
+ Ref = erlang:send_after(Timeout, self(), Msg),
+ MonRef = erlang:monitor(process, Pid),
+ ?vtrace("handle_sync_set -> MonRef: ~p", [MonRef]),
+ Req = #request{id = ReqId,
+ user_id = UserId,
+ reg_type = RegType,
+ target = TargetName,
+ addr = Addr,
+ port = Port,
+ type = set,
+ data = MsgData,
+ ref = Ref,
+ mon = MonRef,
+ from = From},
+ ets:insert(snmpm_request_table, Req),
+ ok;
+
+ Error ->
+ ?vinfo("failed retrieving agent data for set:"
+ "~n TargetName: ~p"
+ "~n Error: ~p", [TargetName, Error]),
+ Error
+ end.
+
+
+handle_async_get(Pid, UserId, TargetName, CtxName, Oids, Expire, ExtraInfo,
+ State) ->
+ ?vtrace("handle_async_get -> entry with"
+ "~n Pid: ~p"
+ "~n UserId: ~p"
+ "~n TargetName: ~p"
+ "~n CtxName: ~p"
+ "~n Oids: ~p"
+ "~n Expire: ~p",
+ [Pid, UserId, TargetName, CtxName, Oids, Expire]),
+ case agent_data(TargetName, CtxName) of
+ {ok, RegType, Addr, Port, Vsn, MsgData} ->
+ ?vtrace("handle_async_get -> send a ~p message", [Vsn]),
+ ReqId = send_get_request(Oids, Vsn, MsgData, Addr, Port,
+ ExtraInfo, State),
+ ?vdebug("handle_async_get -> ReqId: ~p", [ReqId]),
+ Req = #request{id = ReqId,
+ user_id = UserId,
+ reg_type = RegType,
+ target = TargetName,
+ addr = Addr,
+ port = Port,
+ type = get,
+ data = MsgData,
+ expire = t() + Expire},
+
+ ets:insert(snmpm_request_table, Req),
+ gct_activate(State#state.gct),
+ {ok, ReqId};
+
+ Error ->
+ ?vinfo("failed retrieving agent data for get:"
+ "~n TargetName: ~p"
+ "~n Error: ~p", [TargetName, Error]),
+ Error
+ end.
+
+
+handle_async_get_next(Pid, UserId, TargetName, CtxName, Oids, Expire,
+ ExtraInfo, State) ->
+ ?vtrace("handle_async_get_next -> entry with"
+ "~n Pid: ~p"
+ "~n UserId: ~p"
+ "~n TargetName: ~p"
+ "~n CtxName: ~p"
+ "~n Oids: ~p"
+ "~n Expire: ~p",
+ [Pid, UserId, TargetName, CtxName, Oids, Expire]),
+ case agent_data(TargetName, CtxName) of
+ {ok, RegType, Addr, Port, Vsn, MsgData} ->
+ ?vtrace("handle_async_get_next -> send a ~p message", [Vsn]),
+ ReqId = send_get_next_request(Oids, Vsn, MsgData,
+ Addr, Port, ExtraInfo, State),
+ ?vdebug("handle_async_get_next -> ReqId: ~p", [ReqId]),
+ Req = #request{id = ReqId,
+ user_id = UserId,
+ reg_type = RegType,
+ target = TargetName,
+ addr = Addr,
+ port = Port,
+ type = get_next,
+ data = MsgData,
+ expire = t() + Expire},
+
+ ets:insert(snmpm_request_table, Req),
+ gct_activate(State#state.gct),
+ {ok, ReqId};
+
+ Error ->
+ ?vinfo("failed retrieving agent data for get-next:"
+ "~n TargetName: ~p"
+ "~n Error: ~p", [TargetName, Error]),
+ Error
+ end.
+
+
+handle_async_get_bulk(Pid, UserId, TargetName, CtxName,
+ NonRep, MaxRep, Oids, Expire,
+ ExtraInfo, State) ->
+ ?vtrace("handle_async_get_bulk -> entry with"
+ "~n Pid: ~p"
+ "~n UserId: ~p"
+ "~n TargetName: ~p"
+ "~n CtxName: ~p"
+ "~n NonRep: ~p"
+ "~n MaxRep: ~p"
+ "~n Oids: ~p"
+ "~n Expire: ~p",
+ [Pid, UserId, TargetName, CtxName, NonRep, MaxRep, Oids, Expire]),
+ case agent_data(TargetName, CtxName) of
+ {ok, RegType, Addr, Port, Vsn, MsgData} ->
+ ?vtrace("handle_async_get_bulk -> send a ~p message", [Vsn]),
+ ReqId = send_get_bulk_request(Oids, Vsn, MsgData, Addr, Port,
+ NonRep, MaxRep, ExtraInfo, State),
+ ?vdebug("handle_async_get_bulk -> ReqId: ~p", [ReqId]),
+ Req = #request{id = ReqId,
+ user_id = UserId,
+ reg_type = RegType,
+ target = TargetName,
+ addr = Addr,
+ port = Port,
+ type = get_bulk,
+ data = MsgData,
+ expire = t() + Expire},
+ ets:insert(snmpm_request_table, Req),
+ gct_activate(State#state.gct),
+ {ok, ReqId};
+
+ Error ->
+ ?vinfo("failed retrieving agent data for get-bulk:"
+ "~n TargetName: ~p"
+ "~n Error: ~p", [TargetName, Error]),
+ Error
+ end.
+
+
+handle_async_set(Pid, UserId, TargetName, CtxName, VarsAndVals, Expire,
+ ExtraInfo, State) ->
+ ?vtrace("handle_async_set -> entry with"
+ "~n Pid: ~p"
+ "~n UserId: ~p"
+ "~n TargetName: ~p"
+ "~n CtxName: ~p"
+ "~n VarsAndVals: ~p"
+ "~n Expire: ~p",
+ [Pid, UserId, TargetName, CtxName, VarsAndVals, Expire]),
+ case agent_data(TargetName, CtxName) of
+ {ok, RegType, Addr, Port, Vsn, MsgData} ->
+ ?vtrace("handle_async_set -> send a ~p message", [Vsn]),
+ ReqId = send_set_request(VarsAndVals, Vsn, MsgData,
+ Addr, Port, ExtraInfo, State),
+ ?vdebug("handle_async_set -> ReqId: ~p", [ReqId]),
+ Req = #request{id = ReqId,
+ user_id = UserId,
+ reg_type = RegType,
+ target = TargetName,
+ addr = Addr,
+ port = Port,
+ type = set,
+ data = MsgData,
+ expire = t() + Expire},
+
+ ets:insert(snmpm_request_table, Req),
+ gct_activate(State#state.gct),
+ {ok, ReqId};
+
+ Error ->
+ ?vinfo("failed retrieving agent data for set:"
+ "~n TargetName: ~p"
+ "~n Error: ~p", [TargetName, Error]),
+ Error
+ end.
+
+
+handle_cancel_async_request(UserId, ReqId, _State) ->
+ ?vtrace("handle_cancel_async_request -> entry with"
+ "~n UserId: ~p"
+ "~n ReqId: ~p", [UserId, ReqId]),
+ case ets:lookup(snmpm_request_table, ReqId) of
+ [#request{user_id = UserId,
+ ref = Ref}] ->
+ ?vdebug("handle_cancel_async_request -> demonitor and cancel timer"
+ "~n Ref: ~p", [Ref]),
+ cancel_timer(Ref),
+ ets:delete(snmpm_request_table, ReqId),
+ ok;
+
+ [#request{user_id = OtherUserId}] ->
+ ?vinfo("handle_cancel_async_request -> Not request owner"
+ "~n OtherUserId: ~p", [OtherUserId]),
+ {error, {not_owner, OtherUserId}};
+
+ [] ->
+ ?vlog("handle_cancel_async_request -> not found", []),
+ {error, not_found}
+ end.
+
+
+%% handle_system_info_updated(#state{net_if = Pid, net_if_mod = Mod} = _State,
+%% net_if = _Target, What) ->
+%% case (catch Mod:system_info_updated(Pid, What)) of
+%% {'EXIT', _} ->
+%% {error, not_supported};
+%% Else ->
+%% Else
+%% end;
+%% handle_system_info_updated(_State, Target, What) ->
+%% {error, {bad_target, Target, What}}.
+
+handle_get_log_type(#state{net_if = Pid, net_if_mod = Mod}) ->
+ case (catch Mod:get_log_type(Pid)) of
+ {'EXIT', _} ->
+ {error, not_supported};
+ Else ->
+ Else
+ end.
+
+handle_set_log_type(#state{net_if = Pid, net_if_mod = Mod}, NewType) ->
+ case (catch Mod:set_log_type(Pid, NewType)) of
+ {'EXIT', _} ->
+ {error, not_supported};
+ Else ->
+ Else
+ end.
+
+
+%% handle_discovery(Pid, UserId, BAddr, Port, Config, Expire, ExtraInfo, State) ->
+%% ?vtrace("handle_discovery -> entry with"
+%% "~n Pid: ~p"
+%% "~n UserId: ~p"
+%% "~n BAddr: ~p"
+%% "~n Port: ~p"
+%% "~n Config: ~p"
+%% "~n Expire: ~p",
+%% [Pid, UserId, BAddr, Port, Config, Expire]),
+%% case agent_data(default, default, "", Config) of
+%% {ok, Addr, Port, Vsn, MsgData} ->
+%% ?vtrace("handle_discovery -> send a ~p disco message", [Vsn]),
+%% ReqId = send_discovery(Vsn, MsgData, BAddr, Port, ExtraInfo,
+%% State),
+%% ?vdebug("handle_discovery -> ReqId: ~p", [ReqId]),
+%% MonRef = erlang:monitor(process, Pid),
+%% ?vtrace("handle_discovery -> MonRef: ~p", [MonRef]),
+%% Req = #request{id = ReqId,
+%% user_id = UserId,
+%% target = TargetName,
+%% addr = BAddr,
+%% port = Port,
+%% type = get,
+%% data = MsgData,
+%% mon = MonRef,
+%% discovery = true,
+%% expire = t() + Expire},
+%% ets:insert(snmpm_request_table, Req),
+%% gct_activate(State#state.gct),
+%% {ok, ReqId};
+
+%% Error ->
+%% ?vinfo("failed retrieving agent data for discovery (get):"
+%% "~n BAddr: ~p"
+%% "~n Port: ~p"
+%% "~n Error: ~p", [BAddr, Port, Error]),
+%% Error
+%% end.
+
+
+handle_sync_timeout(ReqId, From, State) ->
+ ?vtrace("handle_sync_timeout -> entry with"
+ "~n ReqId: ~p"
+ "~n From: ~p", [ReqId, From]),
+ case ets:lookup(snmpm_request_table, ReqId) of
+ [#request{mon = MonRef, from = From} = Req0] ->
+ ?vdebug("handle_sync_timeout -> "
+ "deliver reply (timeout) and demonitor: "
+ "~n Monref: ~p"
+ "~n From: ~p", [MonRef, From]),
+ gen_server:reply(From, {error, {timeout, ReqId}}),
+ maybe_demonitor(MonRef),
+
+ %%
+ %% Instead of deleting the request record now,
+ %% we leave it to the gc. But for that to work
+ %% we must update the expire value (which for
+ %% sync requests is infinity).
+ %%
+
+ Req = Req0#request{ref = undefined,
+ mon = undefined,
+ from = undefined,
+ expire = t()},
+ ets:insert(snmpm_request_table, Req),
+ gct_activate(State#state.gct),
+ ok;
+ _ ->
+ ok
+ end.
+
+
+handle_snmp_error(#pdu{request_id = ReqId} = Pdu, Reason, State) ->
+
+ ?vtrace("handle_snmp_error -> entry with"
+ "~n Reason: ~p"
+ "~n Pdu: ~p", [Reason, Pdu]),
+
+ case ets:lookup(snmpm_request_table, ReqId) of
+
+ %% Failed async request
+ [#request{user_id = UserId,
+ from = undefined,
+ ref = undefined,
+ mon = MonRef,
+ discovery = Disco}] ->
+
+ ?vdebug("handle_snmp_error -> "
+ "found corresponding request: "
+ "~n failed async request"
+ "~n UserId: ~p"
+ "~n ModRef: ~p"
+ "~n Disco: ~p", [UserId, MonRef, Disco]),
+
+ maybe_demonitor(MonRef),
+ case snmpm_config:user_info(UserId) of
+ {ok, UserMod, UserData} ->
+ handle_error(UserId, UserMod, Reason, ReqId,
+ UserData, State),
+ maybe_delete(Disco, ReqId);
+ _ ->
+ %% reply to outstanding request, for which there is no
+ %% longer any owner (the user has unregistered).
+ %% Therefor send it to the default user
+ case snmpm_config:user_info() of
+ {ok, DefUserId, DefMod, DefData} ->
+ handle_error(DefUserId, DefMod, Reason, ReqId,
+ DefData, State),
+ maybe_delete(Disco, ReqId);
+ _ ->
+ error_msg("failed retreiving the default user "
+ "info handling error [~w]: "
+ "~n~w", [ReqId, Reason])
+ end
+ end;
+
+
+ %% Failed sync request
+ %%
+ [#request{ref = Ref, mon = MonRef, from = From}] ->
+
+ ?vdebug("handle_snmp_error -> "
+ "found corresponding request: "
+ "~n failed sync request"
+ "~n Ref: ~p"
+ "~n ModRef: ~p"
+ "~n From: ~p", [Ref, MonRef, From]),
+
+ Remaining =
+ case (catch cancel_timer(Ref)) of
+ Rem when is_integer(Rem) ->
+ Rem;
+ _ ->
+ 0
+ end,
+
+ ?vtrace("handle_snmp_error -> Remaining: ~p", [Remaining]),
+
+ maybe_demonitor(MonRef),
+ Reply = {error, {send_failed, ReqId, Reason}},
+ ?vtrace("handle_snmp_error -> deliver (error-) reply",[]),
+ gen_server:reply(From, Reply),
+ ets:delete(snmpm_request_table, ReqId),
+ ok;
+
+
+ %% A very old reply, see if this agent is handled by
+ %% a user. In that case send it there, else to the
+ %% default user.
+ _ ->
+
+ ?vdebug("handle_snmp_error -> no request?", []),
+
+ case snmpm_config:user_info() of
+ {ok, DefUserId, DefMod, DefData} ->
+ handle_error(DefUserId, DefMod, Reason,
+ ReqId, DefData, State);
+ _ ->
+ error_msg("failed retreiving the default "
+ "user info handling error [~w]: "
+ "~n~w",[ReqId, Reason])
+ end
+ end;
+
+handle_snmp_error(CrapError, Reason, _State) ->
+ error_msg("received crap (snmp) error =>"
+ "~n~p~n~p", [CrapError, Reason]),
+ ok.
+
+handle_snmp_error(Addr, Port, ReqId, Reason, State) ->
+
+ ?vtrace("handle_snmp_error -> entry with"
+ "~n Addr: ~p"
+ "~n Port: ~p"
+ "~n ReqId: ~p"
+ "~n Reason: ~p", [Addr, Port, ReqId, Reason]),
+
+ case snmpm_config:get_agent_user_id(Addr, Port) of
+ {ok, UserId} ->
+ case snmpm_config:user_info(UserId) of
+ {ok, UserMod, UserData} ->
+ handle_error(UserId, UserMod, Reason, ReqId,
+ UserData, State);
+ _Error ->
+ case snmpm_config:user_info() of
+ {ok, DefUserId, DefMod, DefData} ->
+ handle_error(DefUserId, DefMod, Reason,
+ ReqId, DefData, State);
+ _Error ->
+ error_msg("failed retreiving the default user "
+ "info handling snmp error "
+ "<~p,~p>: ~n~w~n~w",
+ [Addr, Port, ReqId, Reason])
+ end
+ end;
+ _Error ->
+ case snmpm_config:user_info() of
+ {ok, DefUserId, DefMod, DefData} ->
+ handle_error(DefUserId, DefMod, Reason,
+ ReqId, DefData, State);
+ _Error ->
+ error_msg("failed retreiving the default user "
+ "info handling snmp error "
+ "<~p,~p>: ~n~w~n~w",
+ [Addr, Port, ReqId, Reason])
+ end
+ end.
+
+
+handle_error(_UserId, Mod, Reason, ReqId, Data, _State) ->
+ ?vtrace("handle_error -> entry when"
+ "~n Mod: ~p", [Mod]),
+ F = fun() -> (catch Mod:handle_error(ReqId, Reason, Data)) end,
+ handle_callback(F),
+ ok.
+
+
+handle_snmp_pdu(#pdu{type = 'get-response', request_id = ReqId} = Pdu,
+ Addr, Port, State) ->
+
+ ?vtrace("handle_snmp_pdu(get-response) -> entry with"
+ "~n Addr: ~p"
+ "~n Port: ~p"
+ "~n Pdu: ~p", [Addr, Port, Pdu]),
+
+ case ets:lookup(snmpm_request_table, ReqId) of
+
+ %% Reply to a async request or
+ %% possibly a late reply to a sync request
+ %% (ref is also undefined)
+ [#request{user_id = UserId,
+ reg_type = RegType,
+ target = Target,
+ from = undefined,
+ ref = undefined,
+ mon = MonRef,
+ discovery = Disco}] ->
+
+ ?vdebug("handle_snmp_pdu(get-response) -> "
+ "found corresponding request: "
+ "~n reply to async request or late reply to sync request"
+ "~n UserId: ~p"
+ "~n ModRef: ~p"
+ "~n Disco: ~p", [UserId, MonRef, Disco]),
+
+ maybe_demonitor(MonRef),
+ #pdu{error_status = EStatus,
+ error_index = EIndex,
+ varbinds = Varbinds} = Pdu,
+ Varbinds2 = fix_vbs_BITS(Varbinds),
+ SnmpResponse = {EStatus, EIndex, Varbinds2},
+ case snmpm_config:user_info(UserId) of
+ {ok, UserMod, UserData} ->
+ handle_pdu(UserId, UserMod,
+ RegType, Target, Addr, Port,
+ ReqId, SnmpResponse, UserData, State),
+ maybe_delete(Disco, ReqId);
+ _Error ->
+ %% reply to outstanding request, for which there is no
+ %% longer any owner (the user has unregistered).
+ %% Therefor send it to the default user
+ case snmpm_config:user_info() of
+ {ok, DefUserId, DefMod, DefData} ->
+ handle_pdu(DefUserId, DefMod,
+ RegType, Target, Addr, Port,
+ ReqId, SnmpResponse, DefData, State),
+ maybe_delete(Disco, ReqId);
+ Error ->
+ error_msg("failed retreiving the default user "
+ "info handling pdu from "
+ "~p <~p,~p>: ~n~w~n~w",
+ [Target, Addr, Port, Error, Pdu])
+ end
+ end;
+
+
+ %% Reply to a sync request
+ %%
+ [#request{ref = Ref, mon = MonRef, from = From}] ->
+
+ ?vdebug("handle_snmp_pdu(get-response) -> "
+ "found corresponding request: "
+ "~n reply to sync request"
+ "~n Ref: ~p"
+ "~n ModRef: ~p"
+ "~n From: ~p", [Ref, MonRef, From]),
+
+ Remaining =
+ case (catch cancel_timer(Ref)) of
+ Rem when is_integer(Rem) ->
+ Rem;
+ _ ->
+ 0
+ end,
+
+ ?vtrace("handle_snmp_pdu(get-response) -> Remaining: ~p",
+ [Remaining]),
+
+ maybe_demonitor(MonRef),
+ #pdu{error_status = EStatus,
+ error_index = EIndex,
+ varbinds = Varbinds} = Pdu,
+ Varbinds2 = fix_vbs_BITS(Varbinds),
+ SnmpReply = {EStatus, EIndex, Varbinds2},
+ Reply = {ok, SnmpReply, Remaining},
+ ?vtrace("handle_snmp_pdu(get-response) -> deliver reply",[]),
+ gen_server:reply(From, Reply),
+ ets:delete(snmpm_request_table, ReqId),
+ ok;
+
+
+ %% A very old reply, see if this agent is handled by
+ %% a user. In that case send it there, else to the
+ %% default user.
+ _ ->
+
+ ?vdebug("handle_snmp_pdu(get-response) -> "
+ "no corresponding request: "
+ "~n a very old reply", []),
+
+ #pdu{error_status = EStatus,
+ error_index = EIndex,
+ varbinds = Varbinds} = Pdu,
+ Varbinds2 = fix_vbs_BITS(Varbinds),
+ SnmpInfo = {EStatus, EIndex, Varbinds2},
+ case snmpm_config:get_agent_user_id(Addr, Port) of
+ {ok, UserId} ->
+ %% A very late reply or a reply to a request
+ %% that has been cancelled.
+ %%
+ ?vtrace("handle_snmp_pdu(get-response) -> "
+ "a very late reply:"
+ "~n UserId: ~p",[UserId]),
+ case snmpm_config:user_info(UserId) of
+ {ok, UserMod, UserData} ->
+ Reason = {unexpected_pdu, SnmpInfo},
+ handle_error(UserId, UserMod, Reason, ReqId,
+ UserData, State);
+ _Error ->
+ %% Ouch, found an agent but not it's user!!
+ case snmpm_config:user_info() of
+ {ok, DefUserId, DefMod, DefData} ->
+ Reason = {unexpected_pdu, SnmpInfo},
+ handle_error(DefUserId, DefMod, Reason,
+ ReqId, DefData, State);
+ Error ->
+ error_msg("failed retreiving the default "
+ "user info handling (old) "
+ "pdu from "
+ "<~p,~p>: ~n~w~n~w",
+ [Addr, Port, Error, Pdu])
+ end
+ end;
+
+ {error, _} ->
+ %% No agent, so either this agent has been
+ %% unregistered, or this is a very late reply
+ %% to a request (possibly a discovery), which
+ %% has since been cancelled (either because of
+ %% a timeout or that the user has unregistered
+ %% itself (and with it all it's requests)).
+ %% No way to know which.
+ %%
+ ?vtrace("handle_snmp_pdu(get-response) -> "
+ "no agent info found", []),
+ case snmpm_config:user_info() of
+ {ok, DefUserId, DefMod, DefData} ->
+ handle_agent(DefUserId, DefMod,
+ Addr, Port,
+ pdu, ignore,
+ SnmpInfo, DefData, State);
+ Error ->
+ error_msg("failed retreiving the default user "
+ "info handling (old) pdu when no user "
+ "found from "
+ "<~p,~p>: ~n~w~n~w",
+ [Addr, Port, Error, Pdu])
+ end
+ end
+ end;
+
+handle_snmp_pdu(CrapPdu, Addr, Port, _State) ->
+ error_msg("received crap (snmp) Pdu from ~w:~w =>"
+ "~p", [Addr, Port, CrapPdu]),
+ ok.
+
+
+handle_pdu(_UserId, Mod, target_name = _RegType, TargetName, _Addr, _Port,
+ ReqId, SnmpResponse, Data, _State) ->
+ ?vtrace("handle_pdu(target_name) -> entry when"
+ "~n Mod: ~p", [Mod]),
+ F = fun() ->
+ (catch Mod:handle_pdu(TargetName, ReqId, SnmpResponse, Data))
+ end,
+ handle_callback(F),
+ ok;
+handle_pdu(_UserId, Mod, addr_port = _RegType, _TargetName, Addr, Port,
+ ReqId, SnmpResponse, Data, _State) ->
+ ?vtrace("handle_pdu(addr_port) -> entry when"
+ "~n Mod: ~p", [Mod]),
+ F = fun() ->
+ (catch Mod:handle_pdu(Addr, Port, ReqId, SnmpResponse, Data))
+ end,
+ handle_callback(F),
+ ok.
+
+
+handle_agent(UserId, Mod, Addr, Port, Type, Ref, SnmpInfo, Data, State) ->
+ ?vtrace("handle_agent -> entry when"
+ "~n UserId: ~p"
+ "~n Type: ~p"
+ "~n Mod: ~p", [UserId, Type, Mod]),
+ F = fun() ->
+ do_handle_agent(UserId, Mod, Addr, Port,
+ Type, Ref, SnmpInfo, Data, State)
+ end,
+ handle_callback(F),
+ ok.
+
+do_handle_agent(DefUserId, DefMod,
+ Addr, Port,
+ Type, Ref,
+ SnmpInfo, DefData, State) ->
+ ?vdebug("do_handle_agent -> entry when"
+ "~n DefUserId: ~p", [DefUserId]),
+ case (catch DefMod:handle_agent(Addr, Port, Type, SnmpInfo, DefData)) of
+ {'EXIT', {undef, _}} when Type =:= pdu ->
+ %% Maybe, still on the old API
+ ?vdebug("do_handle_agent -> maybe still on the old api", []),
+ case (catch DefMod:handle_agent(Addr, Port, SnmpInfo, DefData)) of
+ {register, UserId2, Config} ->
+ ?vtrace("do_handle_agent -> register: "
+ "~n UserId2: ~p"
+ "~n Config: ~p", [UserId2, Config]),
+ TargetName = mk_target_name(Addr, Port, Config),
+ Config2 = [{reg_type, addr_port},
+ {address, Addr},
+ {port, Port} | Config],
+ case snmpm_config:register_agent(UserId2,
+ TargetName, Config2) of
+ ok ->
+ ok;
+ {error, Reason} ->
+ error_msg("failed registering agent - "
+ "handling agent "
+ "~p <~p,~p>: ~n~w",
+ [TargetName, Addr, Port, Reason]),
+ ok
+ end;
+ {register, UserId2, TargetName, Config} ->
+ ?vtrace("do_handle_agent -> register: "
+ "~n UserId2: ~p"
+ "~n TargetName: ~p"
+ "~n Config: ~p",
+ [UserId2, TargetName, Config]),
+ Config2 = ensure_present([{address, Addr}, {port, Port}],
+ Config),
+ Config3 = [{reg_type, target_name} | Config2],
+ case snmpm_config:register_agent(UserId2,
+ TargetName, Config3) of
+ ok ->
+ ok;
+ {error, Reason} ->
+ error_msg("failed registering agent - "
+ "handling agent "
+ "~p <~p,~p>: ~n~w",
+ [TargetName, Addr, Port, Reason]),
+ ok
+ end;
+ _Ignore ->
+ ?vdebug("do_handle_agent -> ignore", []),
+ ok
+ end;
+
+ {'EXIT', {undef, _}} ->
+ %% If the user does not implement the new API (but the
+ %% old), then this clause catches all non-pdu handle_agent
+ %% calls. These calls was previously never made,so we make
+ %% a best-effert call (using reg-type target_name) to the
+ %% various callback functions, and leave it to the user to
+ %% figure out
+
+ %% Backward compatibillity crap
+ RegType = target_name,
+ Target = mk_target_name(Addr, Port, default_agent_config()),
+ case Type of
+ report ->
+ SnmpInform = SnmpInfo,
+ handle_report(DefUserId, DefMod,
+ RegType, Target, Addr, Port,
+ SnmpInform, DefData, State);
+
+ inform ->
+ SnmpInform = SnmpInfo,
+ handle_inform(DefUserId, DefMod, Ref,
+ RegType, Target, Addr, Port,
+ SnmpInform, DefData, State);
+
+ trap ->
+ SnmpTrapInfo = SnmpInfo,
+ handle_trap(DefUserId, DefMod,
+ RegType, Target, Addr, Port,
+ SnmpTrapInfo, DefData, State);
+
+ _ ->
+ error_msg("failed delivering ~w info to default user - "
+ "regarding agent "
+ "<~p,~p>: ~n~w", [Type, Addr, Port, SnmpInfo])
+ end;
+
+ {register, UserId2, TargetName, Config} ->
+ ?vtrace("do_handle_agent -> register: "
+ "~n UserId2: ~p"
+ "~n TargetName: ~p"
+ "~n Config: ~p",
+ [UserId2, TargetName, Config]),
+ Config2 = ensure_present([{address, Addr}, {port, Port}], Config),
+ Config3 = [{reg_type, target_name} | Config2],
+ case snmpm_config:register_agent(UserId2,
+ TargetName, Config3) of
+ ok ->
+ ok;
+ {error, Reason} ->
+ error_msg("failed registering agent - "
+ "handling agent "
+ "~p <~p,~p>: ~n~w",
+ [TargetName, Addr, Port, Reason]),
+ ok
+ end;
+
+ _Ignore ->
+ ?vdebug("do_handle_agent -> ignore", []),
+ ok
+
+ end.
+
+ensure_present([], Config) ->
+ Config;
+ensure_present([{Key, _Val} = Elem|Ensure], Config) ->
+ case lists:keymember(Key, 1, Config) of
+ false ->
+ ensure_present(Ensure, [Elem|Config]);
+ true ->
+ ensure_present(Ensure, Config)
+ end.
+
+
+%% Retrieve user info for this agent.
+%% If this is an unknown agent, then use the default user
+handle_snmp_trap(#trappdu{enterprise = Enteprise,
+ generic_trap = Generic,
+ specific_trap = Spec,
+ time_stamp = Timestamp,
+ varbinds = Varbinds} = Trap,
+ Addr, Port, State) ->
+
+ ?vtrace("handle_snmp_trap [trappdu] -> entry with"
+ "~n Addr: ~p"
+ "~n Port: ~p"
+ "~n Trap: ~p", [Addr, Port, Trap]),
+
+ Varbinds2 = fix_vbs_BITS(Varbinds),
+ SnmpTrapInfo = {Enteprise, Generic, Spec, Timestamp, Varbinds2},
+ do_handle_snmp_trap(SnmpTrapInfo, Addr, Port, State);
+
+handle_snmp_trap(#pdu{error_status = EStatus,
+ error_index = EIndex,
+ varbinds = Varbinds} = Trap,
+ Addr, Port, State) ->
+
+ ?vtrace("handle_snmp_trap [pdu] -> entry with"
+ "~n Addr: ~p"
+ "~n Port: ~p"
+ "~n Trap: ~p", [Addr, Port, Trap]),
+
+ Varbinds2 = fix_vbs_BITS(Varbinds),
+ SnmpTrapInfo = {EStatus, EIndex, Varbinds2},
+ do_handle_snmp_trap(SnmpTrapInfo, Addr, Port, State);
+
+handle_snmp_trap(CrapTrap, Addr, Port, _State) ->
+ error_msg("received crap (snmp) trap from ~w:~w =>"
+ "~p", [Addr, Port, CrapTrap]),
+ ok.
+
+do_handle_snmp_trap(SnmpTrapInfo, Addr, Port, State) ->
+ case snmpm_config:get_agent_user_info(Addr, Port) of
+ {ok, UserId, Target, RegType} ->
+ ?vtrace("handle_snmp_trap -> found user: ~p", [UserId]),
+ case snmpm_config:user_info(UserId) of
+ {ok, Mod, Data} ->
+ handle_trap(UserId, Mod,
+ RegType, Target, Addr, Port,
+ SnmpTrapInfo, Data, State);
+
+ Error1 ->
+ %% User no longer exists, unregister agent
+ ?vlog("[trap] failed retreiving user info for "
+ "user ~p: "
+ "~n ~p", [UserId, Error1]),
+ case snmpm_config:unregister_agent(UserId, Target) of
+ ok ->
+ %% Try use the default user
+ case snmpm_config:user_info() of
+ {ok, DefUserId, DefMod, DefData} ->
+ handle_agent(DefUserId, DefMod,
+ Addr, Port,
+ trap, ignore,
+ SnmpTrapInfo, DefData, State);
+ Error2 ->
+ error_msg("failed retreiving the default "
+ "user info handling report from "
+ "~p <~p,~p>: ~n~w~n~w",
+ [Target, Addr, Port,
+ Error2, SnmpTrapInfo])
+ end;
+ Error3 ->
+ %% Failed unregister agent,
+ %% now its getting messy...
+ warning_msg("failed unregister agent ~p <~p,~p> "
+ "belonging to non-existing "
+ "user ~p, handling trap: "
+ "~n Error: ~w"
+ "~n Trap info: ~w",
+ [Target, Addr, Port, UserId,
+ Error3, SnmpTrapInfo])
+ end
+ end;
+
+ Error4 ->
+ %% Unknown agent, pass it on to the default user
+ ?vlog("[trap] failed retreiving user id for agent <~p,~p>: "
+ "~n ~p", [Addr, Port, Error4]),
+ case snmpm_config:user_info() of
+ {ok, DefUserId, DefMod, DefData} ->
+ handle_agent(DefUserId, DefMod,
+ Addr, Port,
+ trap, ignore,
+ SnmpTrapInfo, DefData, State);
+ Error5 ->
+ error_msg("failed retreiving "
+ "the default user info handling trap from "
+ "<~p,~p>: ~n~w~n~w",
+ [Addr, Port, Error5, SnmpTrapInfo])
+ end
+ end,
+ ok.
+
+
+handle_trap(UserId, Mod,
+ RegType, Target, Addr, Port, SnmpTrapInfo, Data, State) ->
+ ?vtrace("handle_trap -> entry with"
+ "~n UserId: ~p"
+ "~n Mod: ~p", [UserId, Mod]),
+ F = fun() ->
+ do_handle_trap(UserId, Mod,
+ RegType, Target, Addr, Port,
+ SnmpTrapInfo, Data, State)
+ end,
+ handle_callback(F),
+ ok.
+
+
+do_handle_trap(UserId, Mod,
+ RegType, Target, Addr, Port, SnmpTrapInfo, Data, _State) ->
+ ?vdebug("do_handle_trap -> entry with"
+ "~n UserId: ~p", [UserId]),
+ HandleTrap =
+ case RegType of
+ target_name ->
+ fun() -> Mod:handle_trap(Target, SnmpTrapInfo, Data) end;
+ addr_port ->
+ fun() -> Mod:handle_trap(Addr, Port, SnmpTrapInfo, Data) end
+ end,
+
+ case (catch HandleTrap()) of
+ {register, UserId2, Config} ->
+ ?vtrace("do_handle_trap -> register: "
+ "~n UserId2: ~p"
+ "~n Config: ~p", [UserId2, Config]),
+ Target2 = mk_target_name(Addr, Port, Config),
+ Config2 = [{reg_type, target_name},
+ {address, Addr}, {port, Port} | Config],
+ case snmpm_config:register_agent(UserId2, Target2, Config2) of
+ ok ->
+ ok;
+ {error, Reason} ->
+ error_msg("failed registering agent "
+ "handling trap "
+ "<~p,~p>: ~n~w",
+ [Addr, Port, Reason]),
+ ok
+ end;
+ {register, UserId2, Target2, Config} ->
+ ?vtrace("do_handle_trap -> register: "
+ "~n UserId2: ~p"
+ "~n Target2: ~p"
+ "~n Config: ~p", [UserId2, Target2, Config]),
+ %% The only user which would do this is the
+ %% default user
+ Config2 = [{reg_type, target_name} | Config],
+ case snmpm_config:register_agent(UserId2, Target2, Config2) of
+ ok ->
+ reply;
+ {error, Reason} ->
+ error_msg("failed registering agent "
+ "handling trap "
+ "~p <~p,~p>: ~n~w",
+ [Target2, Addr, Port, Reason]),
+ reply
+ end;
+ unregister ->
+ ?vtrace("do_handle_trap -> unregister", []),
+ case snmpm_config:unregister_agent(UserId,
+ Addr, Port) of
+ ok ->
+ ok;
+ {error, Reason} ->
+ error_msg("failed unregistering agent "
+ "handling trap "
+ "<~p,~p>: ~n~w",
+ [Addr, Port, Reason]),
+ ok
+ end;
+ _Ignore ->
+ ?vtrace("do_handle_trap -> ignore", []),
+ ok
+ end.
+
+
+handle_snmp_inform(Ref,
+ #pdu{error_status = EStatus,
+ error_index = EIndex,
+ varbinds = Varbinds} = Pdu, Addr, Port, State) ->
+
+ ?vtrace("handle_snmp_inform -> entry with"
+ "~n Addr: ~p"
+ "~n Port: ~p"
+ "~n Pdu: ~p", [Addr, Port, Pdu]),
+
+ Varbinds2 = fix_vbs_BITS(Varbinds),
+ SnmpInform = {EStatus, EIndex, Varbinds2},
+ case snmpm_config:get_agent_user_info(Addr, Port) of
+ {ok, UserId, Target, RegType} ->
+ case snmpm_config:user_info(UserId) of
+ {ok, Mod, Data} ->
+ ?vdebug("[inform] callback handle_inform with: "
+ "~n UserId: ~p"
+ "~n Mod: ~p", [UserId, Mod]),
+ handle_inform(UserId, Mod, Ref,
+ RegType, Target, Addr, Port,
+ SnmpInform, Data, State);
+ Error1 ->
+ %% User no longer exists, unregister agent
+ case snmpm_config:unregister_agent(UserId, Target) of
+ ok ->
+ %% Try use the default user
+ ?vlog("[inform] failed retreiving user "
+ "info for user ~p:"
+ "~n ~p", [UserId, Error1]),
+ case snmpm_config:user_info() of
+ {ok, DefUserId, DefMod, DefData} ->
+ handle_agent(DefUserId, DefMod,
+ Addr, Port,
+ inform, Ref,
+ SnmpInform, DefData, State);
+ Error2 ->
+ error_msg("failed retreiving the default "
+ "user info handling inform from "
+ "~p <~p,~p>: ~n~w~n~w",
+ [Target, Addr, Port,
+ Error2, Pdu])
+ end;
+ Error3 ->
+ %% Failed unregister agent,
+ %% now its getting messy...
+ warning_msg("failed unregister agent ~p <~p,~p> "
+ "~n belonging to non-existing "
+ "user ~p, handling inform: "
+ "~n Error: ~w"
+ "~n Pdu: ~w",
+ [Target, Addr, Port, UserId,
+ Error3, Pdu])
+ end
+ end;
+
+ Error4 ->
+ %% Unknown agent, pass it on to the default user
+ ?vlog("[inform] failed retreiving user id for agent <~p,~p>: "
+ "~n ~p", [Addr, Port, Error4]),
+ case snmpm_config:user_info() of
+ {ok, DefUserId, DefMod, DefData} ->
+ handle_agent(DefUserId, DefMod,
+ Addr, Port,
+ inform, Ref,
+ SnmpInform, DefData, State);
+ Error5 ->
+ error_msg("failed retreiving "
+ "the default user info handling inform from "
+ "<~p,~p>: ~n~w~n~w",
+ [Addr, Port, Error5, Pdu])
+ end
+ end,
+ ok;
+
+handle_snmp_inform(_Ref, CrapInform, Addr, Port, _State) ->
+ error_msg("received crap (snmp) inform from ~w:~w =>"
+ "~p", [Addr, Port, CrapInform]),
+ ok.
+
+handle_inform(UserId, Mod, Ref,
+ RegType, Target, Addr, Port, SnmpInform, Data, State) ->
+ ?vtrace("handle_inform -> entry with"
+ "~n UserId: ~p"
+ "~n Mod: ~p", [UserId, Mod]),
+ F = fun() ->
+ do_handle_inform(UserId, Mod, Ref,
+ RegType, Target, Addr, Port, SnmpInform,
+ Data, State)
+ end,
+ handle_callback(F),
+ ok.
+
+do_handle_inform(UserId, Mod, Ref,
+ RegType, Target, Addr, Port, SnmpInform, Data, State) ->
+ ?vdebug("do_handle_inform -> entry with"
+ "~n UserId: ~p", [UserId]),
+ HandleInform =
+ case RegType of
+ target_name ->
+ fun() -> Mod:handle_inform(Target, SnmpInform, Data) end;
+ addr_port ->
+ fun() -> Mod:handle_inform(Addr, Port, SnmpInform, Data) end
+ end,
+
+ Rep =
+ case (catch HandleInform()) of
+ {register, UserId2, Config} ->
+ ?vtrace("do_handle_inform -> register: "
+ "~n UserId2: ~p"
+ "~n Config: ~p", [UserId2, Config]),
+ %% The only user which would do this is the
+ %% default user
+ Target2 = mk_target_name(Addr, Port, Config),
+ Config2 = [{reg_type, target_name},
+ {address, Addr}, {port, Port} | Config],
+ case snmpm_config:register_agent(UserId2, Target2, Config2) of
+ ok ->
+ reply;
+ {error, Reason} ->
+ error_msg("failed registering agent "
+ "handling inform "
+ "~p <~p,~p>: ~n~w",
+ [Target2, Addr, Port, Reason]),
+ reply
+ end;
+ {register, UserId2, Target2, Config} ->
+ ?vtrace("do_handle_inform -> register: "
+ "~n UserId2: ~p"
+ "~n Target2: ~p"
+ "~n Config: ~p", [UserId2, Target2, Config]),
+ %% The only user which would do this is the
+ %% default user
+ Config2 = [{reg_type, target_name} | Config],
+ case snmpm_config:register_agent(UserId2, Target2, Config2) of
+ ok ->
+ reply;
+ {error, Reason} ->
+ error_msg("failed registering agent "
+ "handling inform "
+ "~p <~p,~p>: ~n~w",
+ [Target2, Addr, Port, Reason]),
+ reply
+ end;
+ unregister ->
+ ?vtrace("do_handle_inform -> unregister", []),
+ case snmpm_config:unregister_agent(UserId,
+ Addr, Port) of
+ ok ->
+ reply;
+ {error, Reason} ->
+ error_msg("failed unregistering agent "
+ "handling inform "
+ "<~p,~p>: ~n~w",
+ [Addr, Port, Reason]),
+ reply
+ end;
+ no_reply ->
+ ?vtrace("do_handle_inform -> no_reply", []),
+ no_reply;
+ _Ignore ->
+ ?vtrace("do_handle_inform -> ignore", []),
+ reply
+ end,
+ handle_inform_response(Rep, Ref, Addr, Port, State),
+ ok.
+
+
+handle_inform_response(_, ignore, _Addr, _Port, _State) ->
+ ignore;
+handle_inform_response(no_reply, _Ref, _Addr, _Port, _State) ->
+ no_reply;
+handle_inform_response(_, Ref, Addr, Port,
+ #state{net_if = Pid, net_if_mod = Mod}) ->
+ ?vdebug("handle_inform -> response", []),
+ (catch Mod:inform_response(Pid, Ref, Addr, Port)).
+
+handle_snmp_report(#pdu{error_status = EStatus,
+ error_index = EIndex,
+ varbinds = Varbinds} = Pdu, Addr, Port, State) ->
+
+ ?vtrace("handle_snmp_report -> entry with"
+ "~n Addr: ~p"
+ "~n Port: ~p"
+ "~n Pdu: ~p", [Addr, Port, Pdu]),
+
+ Varbinds2 = fix_vbs_BITS(Varbinds),
+ SnmpReport = {EStatus, EIndex, Varbinds2},
+ case snmpm_config:get_agent_user_info(Addr, Port) of
+ {ok, UserId, Target, RegType} ->
+ case snmpm_config:user_info(UserId) of
+ {ok, Mod, Data} ->
+ ?vdebug("[report] callback handle_report with: "
+ "~n ~p"
+ "~n ~p"
+ "~n ~p"
+ "~n ~p", [UserId, Mod, Target, SnmpReport]),
+ handle_report(UserId, Mod,
+ RegType, Target, Addr, Port,
+ SnmpReport, Data, State);
+ Error1 ->
+ %% User no longer exists, unregister agent
+ ?vlog("[report] failed retreiving user info "
+ "for user ~p:"
+ " ~n ~p", [UserId, Error1]),
+ case snmpm_config:unregister_agent(UserId, Target) of
+ ok ->
+ %% Try use the default user
+ case snmpm_config:user_info() of
+ {ok, DefUserId, DefMod, DefData} ->
+ handle_agent(DefUserId, DefMod,
+ Addr, Port,
+ report, ignore,
+ SnmpReport, DefData, State);
+
+ Error2 ->
+ error_msg("failed retreiving the default "
+ "user info handling report from "
+ "~p <~p,~p>: ~n~w~n~w",
+ [Target, Addr, Port,
+ Error2, Pdu])
+ end;
+ Error3 ->
+ %% Failed unregister agent,
+ %% now its getting messy...
+ warning_msg("failed unregister agent ~p <~p,~p> "
+ "belonging to non-existing "
+ "user ~p, handling report: "
+ "~n Error: ~w"
+ "~n Report: ~w",
+ [Target, Addr, Port, UserId,
+ Error3, Pdu])
+ end
+ end;
+
+ Error4 ->
+ %% Unknown agent, pass it on to the default user
+ ?vlog("[report] failed retreiving user id for agent <~p,~p>: "
+ "~n ~p", [Addr, Port, Error4]),
+ case snmpm_config:user_info() of
+ {ok, DefUserId, DefMod, DefData} ->
+ handle_agent(DefUserId, DefMod,
+ Addr, Port,
+ report, ignore,
+ SnmpReport, DefData, State);
+ Error5 ->
+ error_msg("failed retreiving "
+ "the default user info handling report from "
+ "<~p,~p>: ~n~w~n~w",
+ [Addr, Port, Error5, Pdu])
+ end
+ end,
+ ok;
+
+handle_snmp_report(CrapReport, Addr, Port, _State) ->
+ error_msg("received crap (snmp) report from ~w:~w =>"
+ "~p", [Addr, Port, CrapReport]),
+ ok.
+
+%% This could be from a failed get-request, so we might have a user
+%% waiting for a reply here. If there is, we handle this as an failed
+%% get-response (except for tha data which is different). Otherwise,
+%% we handle it as an error (reported via the handle_error callback
+%% function).
+handle_snmp_report(ReqId,
+ #pdu{error_status = EStatus,
+ error_index = EIndex,
+ varbinds = Varbinds} = Pdu,
+ {ReportReason, Info} = Rep,
+ Addr, Port, State)
+ when is_integer(ReqId) ->
+
+ ?vtrace("handle_snmp_report -> entry with"
+ "~n Addr: ~p"
+ "~n Port: ~p"
+ "~n ReqId: ~p"
+ "~n Rep: ~p"
+ "~n Pdu: ~p", [Addr, Port, ReqId, Rep, Pdu]),
+
+ Varbinds2 = fix_vbs_BITS(Varbinds),
+ SnmpReport = {EStatus, EIndex, Varbinds2},
+ Reason = {ReportReason, Info, SnmpReport},
+
+ %% Check if there is someone waiting for this request
+
+ case ets:lookup(snmpm_request_table, ReqId) of
+
+ [#request{from = From,
+ ref = Ref,
+ mon = MonRef}] when (From =/= undefined) andalso
+ (Ref =/= undefined) ->
+
+ ?vdebug("handle_snmp_report -> "
+ "found corresponding request: "
+ "~n reply to sync request"
+ "~n Ref: ~p"
+ "~n ModRef: ~p"
+ "~n From: ~p", [Ref, MonRef, From]),
+
+ Remaining =
+ case (catch cancel_timer(Ref)) of
+ Rem when is_integer(Rem) ->
+ Rem;
+ _ ->
+ 0
+ end,
+
+ ?vtrace("handle_snmp_pdu(get-response) -> Remaining: ~p",
+ [Remaining]),
+
+ maybe_demonitor(MonRef),
+
+ Reply = {error, Reason},
+ ?vtrace("handle_snmp_report -> deliver reply",[]),
+ gen_server:reply(From, Reply),
+ ets:delete(snmpm_request_table, ReqId),
+ ok;
+
+ _ ->
+ %% Either not a sync request or no such request. Either
+ %% way, this is error info, so handle it as such.
+
+ case snmpm_config:get_agent_user_id(Addr, Port) of
+ {ok, UserId} ->
+ case snmpm_config:user_info(UserId) of
+ {ok, Mod, Data} ->
+ ?vdebug("[report] callback handle_error with: "
+ "~n ~p"
+ "~n ~p"
+ "~n ~p", [UserId, Mod, Reason]),
+ handle_error(UserId, Mod, Reason, ReqId,
+ Data, State);
+ Error ->
+ %% Oh crap, use the default user
+ ?vlog("[report] failed retreiving user info for "
+ "user ~p:"
+ " ~n ~p", [UserId, Error]),
+ case snmpm_config:user_info() of
+ {ok, DefUserId, DefMod, DefData} ->
+ handle_error(DefUserId, DefMod, Reason,
+ ReqId, DefData, State);
+ Error ->
+ error_msg("failed retreiving the "
+ "default user "
+ "info handling report from "
+ "<~p,~p>: ~n~w~n~w~n~w",
+ [Addr, Port, Error,
+ ReqId, Reason])
+ end
+ end;
+ Error ->
+ %% Unknown agent, pass it on to the default user
+ ?vlog("[report] failed retreiving user id for "
+ "agent <~p,~p>: "
+ "~n ~p", [Addr, Port, Error]),
+ case snmpm_config:user_info() of
+ {ok, DefUserId, DefMod, DefData} ->
+ handle_error(DefUserId, DefMod, Reason, ReqId,
+ DefData, State);
+ Error ->
+ error_msg("failed retreiving "
+ "the default user info handling "
+ "report from "
+ "<~p,~p>: ~n~w~n~w~n~w",
+ [Addr, Port, Error, ReqId, Reason])
+ end
+ end
+ end,
+ ok;
+
+handle_snmp_report(CrapReqId, CrapReport, CrapInfo, Addr, Port, _State) ->
+ error_msg("received crap (snmp) report from ~w:~w =>"
+ "~n~p~n~p~n~p", [Addr, Port, CrapReqId, CrapReport, CrapInfo]),
+ ok.
+
+
+handle_report(UserId, Mod, RegType, Target, Addr, Port,
+ SnmpReport, Data, State) ->
+ ?vtrace("handle_report -> entry with"
+ "~n UserId: ~p"
+ "~n Mod: ~p", [UserId, Mod]),
+ F = fun() ->
+ do_handle_report(UserId, Mod, RegType, Target, Addr, Port,
+ SnmpReport, Data, State)
+ end,
+ handle_callback(F),
+ ok.
+
+do_handle_report(UserId, Mod,
+ RegType, Target, Addr, Port, SnmpReport, Data, _State) ->
+ ?vdebug("do_handle_report -> entry with"
+ "~n UserId: ~p", [UserId]),
+ HandleReport =
+ case RegType of
+ target_name ->
+ fun() -> Mod:handle_report(Target, SnmpReport, Data) end;
+ addr_port ->
+ fun() -> Mod:handle_report(Addr, Port, SnmpReport, Data) end
+ end,
+
+ case (catch HandleReport()) of
+ {register, UserId2, Config} ->
+ ?vtrace("do_handle_report -> register: "
+ "~n UserId2: ~p"
+ "~n Config: ~p", [UserId2, Config]),
+ %% The only user which would do this is the
+ %% default user
+ Target2 = mk_target_name(Addr, Port, Config),
+ Config2 = [{reg_type, target_name},
+ {address, Addr}, {port, Port} | Config],
+ case snmpm_config:register_agent(UserId2, Target2, Config2) of
+ ok ->
+ ok;
+ {error, Reason} ->
+ error_msg("failed registering agent "
+ "handling report "
+ "<~p,~p>: ~n~w",
+ [Addr, Port, Reason]),
+ ok
+ end;
+ {register, UserId2, Target2, Config} ->
+ ?vtrace("do_handle_report -> register: "
+ "~n UserId2: ~p"
+ "~n Target2: ~p"
+ "~n Config: ~p", [UserId2, Target2, Config]),
+ %% The only user which would do this is the
+ %% default user
+ Config2 = [{reg_type, target_name} | Config],
+ case snmpm_config:register_agent(UserId2, Target2, Config2) of
+ ok ->
+ reply;
+ {error, Reason} ->
+ error_msg("failed registering agent "
+ "handling report "
+ "~p <~p,~p>: ~n~w",
+ [Target2, Addr, Port, Reason]),
+ reply
+ end;
+ unregister ->
+ ?vtrace("do_handle_trap -> unregister", []),
+ case snmpm_config:unregister_agent(UserId,
+ Addr, Port) of
+ ok ->
+ ok;
+ {error, Reason} ->
+ error_msg("failed unregistering agent "
+ "handling report "
+ "<~p,~p>: ~n~w",
+ [Addr, Port, Reason]),
+ ok
+ end;
+ _Ignore ->
+ ?vtrace("do_handle_report -> ignore", []),
+ ok
+ end.
+
+
+handle_callback(F) ->
+ V = get(verbosity),
+ erlang:spawn(
+ fun() ->
+ put(sname, msew),
+ put(verbosity, V),
+ F()
+ end).
+
+
+handle_down(MonRef) ->
+ (catch do_handle_down(MonRef)).
+
+do_handle_down(MonRef) ->
+ %% Clear out all requests from this client
+ handle_down_requests_cleanup(MonRef),
+
+ %%
+ %% Check also if this was a monitored user, and if so
+ %% unregister all agents registered by this user, and
+ %% finally unregister the user itself
+ %%
+ handle_down_user_cleanup(MonRef),
+
+ ok.
+
+
+handle_down_requests_cleanup(MonRef) ->
+ Pat = #request{id = '$1', ref = '$2', mon = MonRef, _ = '_'},
+ Match = ets:match(snmpm_request_table, Pat),
+ Fun = fun([Id, Ref]) ->
+ ?vtrace("delete request: ~p", [Id]),
+ ets:delete(snmpm_request_table, Id),
+ cancel_timer(Ref),
+ ok
+ end,
+ lists:foreach(Fun, Match).
+
+handle_down_user_cleanup(MonRef) ->
+ Pat = #monitor{id = '$1', mon = MonRef, _ = '_'},
+ Match = ets:match(snmpm_monitor_table, Pat),
+ Fun = fun([Id]) ->
+ Agents = snmpm_config:which_agents(Id),
+ lists:foreach(
+ fun({Addr,Port}) ->
+ %% ** Previous format **
+ %% Just in case this happens during code upgrade
+ ?vtrace("unregister agent of monitored user "
+ "~w: <~w,~w>", [Id,Addr,Port]),
+ snmpm_config:unregister_agent(Id, Addr, Port);
+ (TargetName) ->
+ ?vtrace("unregister agent of monitored user "
+ "~w: ~p", [Id,TargetName]),
+ snmpm_config:unregister_agent(Id, TargetName)
+ end,
+ Agents),
+ ?vtrace("unregister monitored user: ~w", [Id]),
+ ets:delete(snmpm_monitor_table, Id),
+ snmpm_config:unregister_user(Id),
+ ok
+ end,
+ lists:foreach(Fun, Match).
+
+cancel_timer(undefined) ->
+ ok;
+cancel_timer(Ref) ->
+ (catch erlang:cancel_timer(Ref)).
+
+handle_gc(GCT) ->
+ ets:safe_fixtable(snmpm_request_table, true),
+ case do_gc(ets:first(snmpm_request_table), t()) of
+ 0 ->
+ gct_deactivate(GCT);
+ _ ->
+ ok
+ end,
+ ets:safe_fixtable(snmpm_request_table, false).
+
+
+
+%% We are deleting at the same time as we are traversing the table!!!
+do_gc('$end_of_table', _) ->
+ ets:info(snmpm_request_table, size);
+do_gc(Key, Now) ->
+ Next = ets:next(snmpm_request_table, Key),
+ case ets:lookup(snmpm_request_table, Key) of
+ [#request{expire = BestBefore}] when (BestBefore < Now) ->
+ ets:delete(snmpm_request_table, Key);
+ _ ->
+ ok
+ end,
+ do_gc(Next, Now).
+
+
+
+%%----------------------------------------------------------------------
+%%
+%%----------------------------------------------------------------------
+
+send_get_request(Oids, Vsn, MsgData, Addr, Port, ExtraInfo,
+ #state{net_if = NetIf,
+ net_if_mod = Mod,
+ mini_mib = MiniMIB}) ->
+ Pdu = make_pdu(get, Oids, MiniMIB),
+ ?vtrace("send_get_request -> send get-request:"
+ "~n Mod: ~p"
+ "~n NetIf: ~p"
+ "~n Pdu: ~p"
+ "~n Vsn: ~p"
+ "~n MsgData: ~p"
+ "~n Addr: ~p"
+ "~n Port: ~p", [Mod, NetIf, Pdu, Vsn, MsgData, Addr, Port]),
+ (catch Mod:send_pdu(NetIf, Pdu, Vsn, MsgData, Addr, Port, ExtraInfo)),
+ Pdu#pdu.request_id.
+
+send_get_next_request(Oids, Vsn, MsgData, Addr, Port, ExtraInfo,
+ #state{mini_mib = MiniMIB,
+ net_if = NetIf,
+ net_if_mod = Mod}) ->
+ Pdu = make_pdu(get_next, Oids, MiniMIB),
+ Mod:send_pdu(NetIf, Pdu, Vsn, MsgData, Addr, Port, ExtraInfo),
+ Pdu#pdu.request_id.
+
+send_get_bulk_request(Oids, Vsn, MsgData, Addr, Port,
+ NonRep, MaxRep, ExtraInfo,
+ #state{mini_mib = MiniMIB,
+ net_if = NetIf,
+ net_if_mod = Mod}) ->
+ Pdu = make_pdu(bulk, {NonRep, MaxRep, Oids}, MiniMIB),
+ Mod:send_pdu(NetIf, Pdu, Vsn, MsgData, Addr, Port, ExtraInfo),
+ Pdu#pdu.request_id.
+
+send_set_request(VarsAndVals, Vsn, MsgData, Addr, Port, ExtraInfo,
+ #state{mini_mib = MiniMIB,
+ net_if = NetIf,
+ net_if_mod = Mod}) ->
+ Pdu = make_pdu(set, VarsAndVals, MiniMIB),
+ Mod:send_pdu(NetIf, Pdu, Vsn, MsgData, Addr, Port, ExtraInfo),
+ Pdu#pdu.request_id.
+
+%% send_discovery(Vsn, MsgData, Addr, Port, ExtraInfo,
+%% #state{net_if = NetIf,
+%% net_if_mod = Mod}) ->
+%% Pdu = make_discovery_pdu(),
+%% Mod:send_pdu(NetIf, Pdu, Vsn, MsgData, Addr, Port, ExtraInfo),
+%% Pdu#pdu.request_id.
+
+
+
+%%----------------------------------------------------------------------
+%%
+%%----------------------------------------------------------------------
+
+%% make_discovery_pdu() ->
+%% Oids = [?sysObjectID_instance, ?sysDescr_instance, ?sysUpTime_instance],
+%% make_pdu_impl(get, Oids).
+
+make_pdu(set, VarsAndVals, MiniMIB) ->
+ VBs = [var_and_value_to_varbind(VAV, MiniMIB) || VAV <- VarsAndVals],
+ make_pdu_impl(set, VBs);
+
+make_pdu(bulk, {NonRepeaters, MaxRepetitions, Oids}, MiniMIB) ->
+ Foids = [flatten_oid(Oid, MiniMIB) || Oid <- Oids],
+ #pdu{type = 'get-bulk-request',
+ request_id = request_id(),
+ error_status = NonRepeaters,
+ error_index = MaxRepetitions,
+ varbinds = [make_vb(Foid) || Foid <- Foids]};
+
+make_pdu(Op, Oids, MiniMIB) ->
+ Foids = [flatten_oid(Oid, MiniMIB) || Oid <- Oids],
+ make_pdu_impl(Op, Foids).
+
+
+make_pdu_impl(get, Oids) ->
+ #pdu{type = 'get-request',
+ request_id = request_id(),
+ error_status = noError,
+ error_index = 0,
+ varbinds = [make_vb(Oid) || Oid <- Oids]};
+
+make_pdu_impl(get_next, Oids) ->
+ #pdu{type = 'get-next-request',
+ request_id = request_id(),
+ error_status = noError,
+ error_index = 0,
+ varbinds = [make_vb(Oid) || Oid <- Oids]};
+
+make_pdu_impl(set, Varbinds) ->
+ #pdu{type = 'set-request',
+ request_id = request_id(),
+ error_status = noError,
+ error_index = 0,
+ varbinds = Varbinds}.
+
+
+fix_vbs_BITS(Varbinds) ->
+ [fix_vb_BITS(Varbind) || Varbind <- Varbinds].
+
+fix_vb_BITS(#varbind{oid = Oid,
+ variabletype = 'OCTET STRING' = _Type,
+ value = Value} = Varbind) ->
+ %% BITS are encoded as OCTET STRING, so this could be a BITS
+ %% check with the MiniMIB
+ case type_of_oid(Oid) of
+ {error, _} ->
+ Varbind;
+ {ok, NewType = 'BITS'} ->
+ NewValue = snmp_pdus:octet_str_to_bits(Value),
+ Varbind#varbind{variabletype = NewType,
+ value = NewValue};
+ _ ->
+ Varbind
+ end;
+fix_vb_BITS(Vb) ->
+ Vb.
+
+type_of_oid(Oid) ->
+ Oid2 = case lists:reverse(Oid) of
+ [0|T] ->
+ lists:reverse(T);
+ _ ->
+ Oid
+ end,
+ snmpm_config:oid_to_type(Oid2).
+
+
+%%----------------------------------------------------------------------
+%% Purpose: Unnesting of oids like [myTable, 3, 4, "hej", 45] to
+%% [1,2,3,3,4,104,101,106,45]
+%%----------------------------------------------------------------------
+
+flatten_oid([A|T], MiniMIB) when is_atom(A) ->
+ Oid = [alias2oid(A, MiniMIB)|T],
+ check_is_pure_oid(lists:flatten(Oid));
+flatten_oid(Oid, _) when is_list(Oid) ->
+ check_is_pure_oid(lists:flatten(Oid));
+flatten_oid(Shit, _) ->
+ throw({error, {invalid_oid, Shit}}).
+
+check_is_pure_oid([]) -> [];
+check_is_pure_oid([X | T]) when is_integer(X) andalso (X >= 0) ->
+ [X | check_is_pure_oid(T)];
+check_is_pure_oid([X | _T]) ->
+ throw({error, {invalid_oid, X}}).
+
+
+var_and_value_to_varbind({Oid, Type, Value}, MiniMIB) ->
+ Oid2 = flatten_oid(Oid, MiniMIB),
+ #varbind{oid = Oid2,
+ variabletype = char_to_type(Type),
+ value = Value};
+var_and_value_to_varbind({Oid, Value}, MiniMIB) ->
+ Oid2 = flatten_oid(Oid, MiniMIB),
+ #varbind{oid = Oid2,
+ variabletype = oid2type(Oid2, MiniMIB),
+ value = Value}.
+
+char_to_type(i) ->
+ 'INTEGER';
+char_to_type(u) ->
+ 'Unsigned32';
+char_to_type(g) -> % Gauge, Gauge32
+ 'Unsigned32';
+char_to_type(b) ->
+ 'BITS';
+char_to_type(ip) ->
+ 'IpAddress';
+char_to_type(ia) ->
+ 'IpAddress';
+char_to_type(op) ->
+ 'Opaque';
+char_to_type(c32) ->
+ 'Counter32';
+char_to_type(c64) ->
+ 'Counter64';
+char_to_type(tt) ->
+ 'TimeTicks';
+char_to_type(o) ->
+ 'OBJECT IDENTIFIER';
+char_to_type(s) ->
+ 'OCTET STRING';
+char_to_type(C) ->
+ throw({error, {invalid_value_type, C}}).
+
+
+alias2oid(AliasName, MiniMIB) when is_atom(AliasName) ->
+ case lists:keysearch(AliasName, 2, MiniMIB) of
+ {value, {Oid, _Aliasname, _Type}} ->
+ Oid;
+ false ->
+ throw({error, {unknown_aliasname, AliasName}})
+ end.
+
+oid2type(Oid, MiniMIB) ->
+ Oid2 = case lists:reverse(Oid) of
+ [0|T] ->
+ lists:reverse(T);
+ _ ->
+ Oid
+ end,
+ oid2type(Oid2, MiniMIB, utter_nonsense).
+
+oid2type(_Oid, [], utter_nonsense) ->
+ throw({error, no_type});
+oid2type(_Oid, [], Type) ->
+ Type;
+oid2type(Oid, [{Oid2, _, Type}|MiniMIB], Res) when (Oid2 =< Oid) ->
+ case lists:prefix(Oid2, Oid) of
+ true ->
+ oid2type(Oid, MiniMIB, Type); % A better guess
+ false ->
+ oid2type(Oid, MiniMIB, Res)
+ end;
+oid2type(_Oid, _MiniMIB, utter_nonsense) ->
+ throw({error, no_type});
+oid2type(_Oid, _MiniMIB, Type) ->
+ Type.
+
+
+make_vb(Oid) ->
+ #varbind{oid = Oid, variabletype = 'NULL', value = 'NULL'}.
+
+
+%%----------------------------------------------------------------------
+
+request_id() ->
+ snmpm_mpd:next_req_id().
+
+
+%%----------------------------------------------------------------------
+
+agent_data(TargetName, CtxName) ->
+ agent_data(TargetName, CtxName, []).
+
+agent_data(TargetName, CtxName, Config) ->
+ case snmpm_config:agent_info(TargetName, all) of
+ {ok, Info} ->
+ {value, {_, Version}} = lists:keysearch(version, 1, Info),
+ MsgData =
+ case Version of
+ v3 ->
+ DefSecModel = agent_data_item(sec_model, Info),
+ DefSecName = agent_data_item(sec_name, Info),
+ DefSecLevel = agent_data_item(sec_level, Info),
+
+ EngineId = agent_data_item(engine_id, Info),
+
+ SecModel = agent_data_item(sec_model,
+ Config,
+ DefSecModel),
+ SecName = agent_data_item(sec_name,
+ Config,
+ DefSecName),
+ SecLevel = agent_data_item(sec_level,
+ Config,
+ DefSecLevel),
+
+ {SecModel, SecName, mk_sec_level_flag(SecLevel),
+ EngineId, CtxName, TargetName};
+ _ ->
+ DefComm = agent_data_item(community, Info),
+ DefSecModel = agent_data_item(sec_model, Info),
+
+ Comm = agent_data_item(community,
+ Config,
+ DefComm),
+ SecModel = agent_data_item(sec_model,
+ Config,
+ DefSecModel),
+
+ {Comm, SecModel}
+ end,
+ Addr = agent_data_item(address, Info),
+ Port = agent_data_item(port, Info),
+ RegType = agent_data_item(reg_type, Info),
+ {ok, RegType, Addr, Port, version(Version), MsgData};
+ Error ->
+ Error
+ end.
+
+agent_data_item(Item, Info) ->
+ {value, {_, Val}} = lists:keysearch(Item, 1, Info),
+ Val.
+
+agent_data_item(Item, Info, Default) ->
+ case lists:keysearch(Item, 1, Info) of
+ {value, {_, Val}} ->
+ Val;
+ false ->
+ Default
+ end.
+
+
+version(v1) ->
+ 'version-1';
+version(v2) ->
+ 'version-2';
+version(v3) ->
+ 'version-3'.
+
+
+%%-----------------------------------------------------------------
+%% Convert the SecurityLevel into a flag value used by snmpm_mpd
+%%-----------------------------------------------------------------
+mk_sec_level_flag(?'SnmpSecurityLevel_noAuthNoPriv') -> 0;
+mk_sec_level_flag(?'SnmpSecurityLevel_authNoPriv') -> 1;
+mk_sec_level_flag(?'SnmpSecurityLevel_authPriv') -> 3.
+
+
+%%----------------------------------------------------------------------
+%% Request Garbage Collector timer
+%%----------------------------------------------------------------------
+
+gct_start(Timeout) ->
+ ?vdebug("start gc timer process (~p)", [Timeout]),
+ State = #gct{parent = self(), timeout = Timeout},
+ proc_lib:start_link(?MODULE, gct_init, [State]).
+
+gct_stop(GCT) ->
+ GCT ! {stop, self()}.
+
+gct_activate(GCT) ->
+ GCT ! {activate, self()}.
+
+gct_deactivate(GCT) ->
+ GCT ! {deactivate, self()}.
+
+gct_code_change(GCT) ->
+ GCT ! {code_change, self()}.
+
+gct_init(#gct{parent = Parent, timeout = Timeout} = State) ->
+ proc_lib:init_ack(Parent, {ok, self()}),
+ gct(State, Timeout).
+
+gct(#gct{parent = Parent, state = active} = State, Timeout) ->
+ T = t(),
+ receive
+ {stop, Parent} ->
+ ok;
+
+ %% This happens when a new request is received.
+ {activate, Parent} ->
+ ?MODULE:gct(State, new_timeout(Timeout, T));
+
+ {deactivate, Parent} ->
+ %% Timeout is of no consequence in the idle state,
+ %% but just to be sure
+ NewTimeout = State#gct.timeout,
+ ?MODULE:gct(State#gct{state = idle}, NewTimeout);
+
+ {code_change, Parent} ->
+ %% Let the server take care of this
+ exit(normal);
+
+ {'EXIT', Parent, _Reason} ->
+ ok;
+
+ _ -> % Crap
+ ?MODULE:gct(State, Timeout)
+
+ after Timeout ->
+ Parent ! gc_timeout,
+ NewTimeout = State#gct.timeout,
+ ?MODULE:gct(State, NewTimeout)
+ end;
+
+gct(#gct{parent = Parent, state = idle} = State, Timeout) ->
+ receive
+ {stop, Parent} ->
+ ok;
+
+ {deactivate, Parent} ->
+ ?MODULE:gct(State, Timeout);
+
+ {activate, Parent} ->
+ NewTimeout = State#gct.timeout,
+ ?MODULE:gct(State#gct{state = active}, NewTimeout);
+
+ {code_change, Parent} ->
+ %% Let the server take care of this
+ exit(normal);
+
+ {'EXIT', Parent, _Reason} ->
+ ok;
+
+ _ -> % Crap
+ ?MODULE:gct(State, Timeout)
+
+ after Timeout ->
+ ?MODULE:gct(State, Timeout)
+ end.
+
+new_timeout(T1, T2) ->
+ case T1 - (t() - T2) of
+ T when (T > 0) ->
+ T;
+ _ ->
+ 0
+ end.
+
+
+%%----------------------------------------------------------------------
+
+maybe_delete(false, ReqId) ->
+ ets:delete(snmpm_request_table, ReqId);
+maybe_delete(true, _) ->
+ ok.
+
+maybe_demonitor(undefined) ->
+ ok;
+maybe_demonitor(MonRef) ->
+ erlang:demonitor(MonRef).
+
+%% Time in milli seconds
+t() ->
+ {A,B,C} = erlang:now(),
+ A*1000000000+B*1000+(C div 1000).
+
+mk_target_name(Addr, Port, Config) ->
+ snmpm_config:mk_target_name(Addr, Port, Config).
+
+default_agent_config() ->
+ case snmpm_config:agent_info() of
+ {ok, Config} ->
+ Config;
+ _ ->
+ []
+ end.
+
+
+%%----------------------------------------------------------------------
+
+is_started(#state{net_if = _Pid, net_if_mod = _Mod}) ->
+ %% Mod:is_started(Pid) and snmpm_config:is_started().
+ case snmpm_config:is_started() of
+ true ->
+ true;
+ _ ->
+ false
+ end.
+
+
+%%----------------------------------------------------------------------
+
+call(Req) ->
+ call(Req, infinity).
+
+call(Req, To) ->
+ gen_server:call(?SERVER, Req, To).
+
+%% cast(Msg) ->
+%% gen_server:cast(?SERVER, Msg).
+
+%% info_msg(F, A) ->
+%% ?snmpm_info("Server: " ++ F, A).
+
+warning_msg(F, A) ->
+ ?snmpm_warning("Server: " ++ F, A).
+
+error_msg(F, A) ->
+ ?snmpm_error("Server: " ++ F, A).
+
+
+%%----------------------------------------------------------------------
+
+get_info(#state{gct = GCT,
+ net_if = NI, net_if_mod = NIMod,
+ note_store = NS}) ->
+ Info = [{server, server_info(GCT)},
+ {config, config_info()},
+ {net_if, net_if_info(NI, NIMod)},
+ {note_store, note_store_info(NS)},
+ {stats_counters, get_stats_counters()}],
+ Info.
+
+server_info(GCT) ->
+ ProcSize = proc_mem(self()),
+ GCTSz = proc_mem(GCT),
+ RTSz = tab_size(snmpm_request_table),
+ MTSz = tab_size(snmpm_monitor_table),
+ [{process_memory, [{server, ProcSize}, {gct, GCTSz}]},
+ {db_memory, [{request, RTSz}, {monitor, MTSz}]}].
+
+proc_mem(P) when is_pid(P) ->
+ case (catch erlang:process_info(P, memory)) of
+ {memory, Sz} when is_integer(Sz) ->
+ Sz;
+ _ ->
+ undefined
+ end;
+proc_mem(_) ->
+ undefined.
+
+tab_size(T) ->
+ case (catch ets:info(T, memory)) of
+ Sz when is_integer(Sz) ->
+ Sz;
+ _ ->
+ undefined
+ end.
+
+config_info() ->
+ case (catch snmpm_config:info()) of
+ Info when is_list(Info) ->
+ Info;
+ E ->
+ [{error, E}]
+ end.
+
+get_stats_counters() ->
+ lists:sort(snmpm_config:get_stats_counters()).
+
+
+net_if_info(Pid, Mod) ->
+ case (catch Mod:info(Pid)) of
+ Info when is_list(Info) ->
+ Info;
+ E ->
+ [{error, E}]
+ end.
+
+note_store_info(Pid) ->
+ case (catch snmp_note_store:info(Pid)) of
+ Info when is_list(Info) ->
+ Info;
+ E ->
+ [{error, E}]
+ end.
+
+
+%%----------------------------------------------------------------------
+
+
+%%----------------------------------------------------------------------
+%% Debug
+%%----------------------------------------------------------------------
+
+% sz(L) when is_list(L) ->
+% length(lists:flatten(L));
+% sz(B) when is_binary(B) ->
+% size(B).
+
+%% p(F) ->
+%% p(F, []).
+
+%% p(F, A) ->
+%% io:format("~w:" ++ F ++ "~n", [?MODULE | A]).
+
diff --git a/lib/snmp/src/manager/snmpm_server_sup.erl b/lib/snmp/src/manager/snmpm_server_sup.erl
new file mode 100644
index 0000000000..16238e4aaf
--- /dev/null
+++ b/lib/snmp/src/manager/snmpm_server_sup.erl
@@ -0,0 +1,110 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2006-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%
+%%
+
+-module(snmpm_server_sup).
+
+-behaviour(supervisor).
+
+
+%% External exports
+-export([start_link/2, stop/0]).
+
+%% supervisor callbacks
+-export([init/1]).
+
+
+-define(SERVER, ?MODULE).
+
+-include("snmp_debug.hrl").
+
+
+%%%-------------------------------------------------------------------
+%%% API
+%%%-------------------------------------------------------------------
+start_link(_Type, Opts) ->
+ ?d("start_link -> entry with"
+ "~n Opts: ~p", [Opts]),
+ SupName = {local, ?MODULE},
+ supervisor:start_link(SupName, ?MODULE, [Opts]).
+
+stop() ->
+ ?d("stop -> entry", []),
+ case whereis(?SERVER) of
+ Pid when is_pid(Pid) ->
+ ?d("stop -> Pid: ~p", [Pid]),
+ exit(Pid, shutdown),
+ ?d("stop -> stopped", []),
+ ok;
+ _ ->
+ ?d("stop -> not running", []),
+ not_running
+ end.
+
+
+%%%-------------------------------------------------------------------
+%%% Callback functions from supervisor
+%%%-------------------------------------------------------------------
+
+%%--------------------------------------------------------------------
+%% Func: init/1
+%% Returns: {ok, {SupFlags, [ChildSpec]}} |
+%% ignore |
+%% {error, Reason}
+%%--------------------------------------------------------------------
+init([Opts]) ->
+ ?d("init -> entry with"
+ "~n Opts: ~p", [Opts]),
+ Restart = get_restart(Opts),
+ Flags = {one_for_all, 5, 500},
+ Server = worker_spec(snmpm_server, [], Restart, [gen_server]),
+ Sups = [Server],
+ {ok, {Flags, Sups}}.
+
+
+%%%-------------------------------------------------------------------
+%%% Internal functions
+%%%-------------------------------------------------------------------
+
+get_restart(Opts) ->
+ get_opt(Opts, restart_type, transient).
+
+get_opt(Opts, Key, Def) ->
+ snmp_misc:get_option(Key, Opts, Def).
+
+%% sup_spec(Name, Args, Restart) ->
+%% ?d("sup_spec -> entry with"
+%% "~n Name: ~p"
+%% "~n Args: ~p"
+%% "~n Restart: ~p", [Name, Args, Restart]),
+%% {Name,
+%% {Name, start_link, Args},
+%% Restart, 2000, supervisor, [Name,supervisor]}.
+
+worker_spec(Name, Args, Restart, Modules) ->
+ ?d("worker_spec -> entry with"
+ "~n Name: ~p"
+ "~n Args: ~p"
+ "~n Restart: ~p"
+ "~n Modules: ~p", [Name, Args, Restart, Modules]),
+ {Name,
+ {Name, start_link, Args},
+ Restart, 2000, worker, [Name] ++ Modules}.
+
+
+
diff --git a/lib/snmp/src/manager/snmpm_supervisor.erl b/lib/snmp/src/manager/snmpm_supervisor.erl
new file mode 100644
index 0000000000..8f43310c14
--- /dev/null
+++ b/lib/snmp/src/manager/snmpm_supervisor.erl
@@ -0,0 +1,115 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2004-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%
+%%
+
+-module(snmpm_supervisor).
+
+-behaviour(supervisor).
+
+
+%% External exports
+-export([start_link/2, stop/0]).
+
+%% supervisor callbacks
+-export([init/1]).
+
+
+-define(SERVER, ?MODULE).
+
+-include("snmp_debug.hrl").
+
+
+%%%-------------------------------------------------------------------
+%%% API
+%%%-------------------------------------------------------------------
+start_link(Type, Opts) ->
+ ?d("start_link -> entry with"
+ "~n Opts: ~p", [Opts]),
+ SupName = {local, ?MODULE},
+ supervisor:start_link(SupName, ?MODULE, [Type, Opts]).
+
+stop() ->
+ ?d("stop -> entry", []),
+ case whereis(?SERVER) of
+ Pid when is_pid(Pid) ->
+ ?d("stop -> Pid: ~p", [Pid]),
+ exit(Pid, shutdown),
+ ?d("stop -> stopped", []),
+ ok;
+ _ ->
+ ?d("stop -> not running", []),
+ not_running
+ end.
+
+
+%%%-------------------------------------------------------------------
+%%% Callback functions from supervisor
+%%%-------------------------------------------------------------------
+
+%%--------------------------------------------------------------------
+%% Func: init/1
+%% Returns: {ok, {SupFlags, [ChildSpec]}} |
+%% ignore |
+%% {error, Reason}
+%%--------------------------------------------------------------------
+init([Opts]) when is_list(Opts) -> %% OTP-5963: Due to the addition
+ init([normal, Opts]); %% OTP-5963: of server_sup
+init([Type, Opts]) ->
+ ?d("init -> entry with"
+ "~n Type: ~p"
+ "~n Opts: ~p", [Type, Opts]),
+ Restart = get_restart(Opts),
+ Flags = {one_for_all, 0, 3600},
+ Config = worker_spec(snmpm_config, [Opts], Restart, [gen_server]),
+ MiscSup = sup_spec(snmpm_misc_sup, [], Restart),
+ ServerSup = sup_spec(snmpm_server_sup, [Type, Opts], Restart),
+ Sups = [Config, MiscSup, ServerSup],
+ {ok, {Flags, Sups}}.
+
+
+%%%-------------------------------------------------------------------
+%%% Internal functions
+%%%-------------------------------------------------------------------
+
+get_restart(Opts) ->
+ get_opt(Opts, restart_type, transient).
+
+get_opt(Opts, Key, Def) ->
+ snmp_misc:get_option(Key, Opts, Def).
+
+sup_spec(Name, Args, Restart) ->
+ ?d("sup_spec -> entry with"
+ "~n Name: ~p"
+ "~n Args: ~p"
+ "~n Restart: ~p", [Name, Args, Restart]),
+ {Name,
+ {Name, start_link, Args},
+ Restart, 2000, supervisor, [Name,supervisor]}.
+
+worker_spec(Name, Args, Restart, Modules) ->
+ ?d("worker_spec -> entry with"
+ "~n Name: ~p"
+ "~n Args: ~p"
+ "~n Restart: ~p"
+ "~n Modules: ~p", [Name, Args, Restart, Modules]),
+ {Name,
+ {Name, start_link, Args},
+ Restart, 2000, worker, [Name] ++ Modules}.
+
+
+
diff --git a/lib/snmp/src/manager/snmpm_user.erl b/lib/snmp/src/manager/snmpm_user.erl
new file mode 100644
index 0000000000..78aa560b2e
--- /dev/null
+++ b/lib/snmp/src/manager/snmpm_user.erl
@@ -0,0 +1,97 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2004-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%
+%%
+
+-module(snmpm_user).
+
+-export([behaviour_info/1]).
+
+behaviour_info(callbacks) ->
+ [{handle_error, 3},
+ {handle_agent, 5},
+ {handle_pdu, 4},
+ {handle_trap, 3},
+ {handle_inform, 3},
+ {handle_report, 3}];
+behaviour_info(_) ->
+ undefined.
+
+
+%% handle_error(ReqId, Reason, UserData) -> Reply
+%% ReqId -> integer()
+%% Reason -> term()
+%% UserData -> term() (supplied when the user register)
+%% Reply -> ignore
+
+%% handle_agent(Addr, Port, Type, SnmpInfo, UserData) -> Reply
+%% Addr -> term()
+%% Port -> integer()
+%% Type -> pdu | trap | inform | report
+%% SnmpInfo -> {ErrorStatus, ErrorIndex, Varbinds}
+%% UserId -> term()
+%% ErrorStatus -> atom()
+%% ErrorIndex -> integer()
+%% Varbinds -> [varbind()]
+%% UserData -> term() (supplied when the user register)
+%% Reply -> ignore | {register, UserId, agent_info()}
+%% agent_info() -> [{agent_info_item(), agent_info_value()}]
+%% This is the same info as in update_agent_info/4
+
+%% handle_pdu(TargetName, ReqId, SnmpResponse, UserData) -> Reply
+%% TargetName -> target_name()
+%% ReqId -> term() (returned when calling ag(...), ...)
+%% SnmpResponse -> {ErrorStatus, ErrorIndex, Varbinds}
+%% ErrorStatus -> atom()
+%% ErrorIndex -> integer()
+%% Varbinds -> [varbind()]
+%% UserData -> term() (supplied when the user register)
+%% Reply -> ignore
+
+%% handle_trap(TargetName, SnmpTrapInfo, UserData) -> Reply
+%% TargetName -> target_name()
+%% SnmpTrapInfo -> {Enteprise, Generic, Spec, Timestamp, Varbinds} |
+%% {ErrorStatus, ErrorIndex, Varbinds}
+%% Enteprise -> oid()
+%% Generic -> integer()
+%% Spec -> integer()
+%% Timestamp -> integer()
+%% ErrorStatus -> atom()
+%% ErrorIndex -> integer()
+%% Varbinds -> [varbind()]
+%% UserData -> term() (supplied when the user register)
+%% Reply -> ignore | unregister | {register, UserId, agent_info()}
+
+%% handle_inform(TargetName, SnmpInform, UserData) -> Reply
+%% TargetName -> target_name()
+%% SnmpInform -> {ErrorStatus, ErrorIndex, Varbinds}
+%% ErrorStatus -> atom()
+%% ErrorIndex -> integer()
+%% Varbinds -> [varbind()]
+%% UserData -> term() (supplied when the user register)
+%% Reply -> ignore | unregister | {register, UserId, agent_info()}
+%%
+
+%% handle_report(TargetName, SnmpReport, UserData) -> Reply
+%% TargetName -> target_name()
+%% SnmpReport -> {ErrorStatus, ErrorIndex, Varbinds}
+%% ErrorStatus -> integer()
+%% ErrorIndex -> integer()
+%% Varbinds -> [varbind()]
+%% UserData -> term() (supplied when the user register)
+%% Reply -> ignore | unregister | {register, UserId, agent_info()}
+
diff --git a/lib/snmp/src/manager/snmpm_user_default.erl b/lib/snmp/src/manager/snmpm_user_default.erl
new file mode 100644
index 0000000000..d90fc3f258
--- /dev/null
+++ b/lib/snmp/src/manager/snmpm_user_default.erl
@@ -0,0 +1,87 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2004-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%
+%%
+
+-module(snmpm_user_default).
+
+-behaviour(snmpm_user).
+
+-export([handle_error/3,
+ handle_agent/5,
+ handle_pdu/4,
+ handle_trap/3,
+ handle_inform/3,
+ handle_report/3]).
+
+handle_error(ReqId, Reason, UserData) ->
+ info("received handle_error:"
+ "~n ReqId: ~p"
+ "~n Reason: ~p"
+ "~n UserData: ~p", [ReqId, Reason, UserData]),
+ ignore.
+
+
+handle_agent(Addr, Port, Type, SnmpInfo, UserData) ->
+ info("received handle_agent:"
+ "~n Addr: ~p"
+ "~n Port: ~p"
+ "~n Type: ~p"
+ "~n SnmpInfo: ~p"
+ "~n UserData: ~p", [Addr, Port, Type, SnmpInfo, UserData]),
+ ignore.
+
+
+handle_pdu(TargetName, ReqId, SnmpResponse, UserData) ->
+ info("received handle_pdu:"
+ "~n TargetName: ~p"
+ "~n ReqId: ~p"
+ "~n SnmpResponse: ~p"
+ "~n UserData: ~p",
+ [TargetName, ReqId, SnmpResponse, UserData]),
+ ignore.
+
+
+handle_trap(TargetName, SnmpTrap, UserData) ->
+ info("received handle_trap:"
+ "~n TargetName: ~p"
+ "~n SnmpTrap: ~p"
+ "~n UserData: ~p",
+ [TargetName, SnmpTrap, UserData]),
+ ok.
+
+
+handle_inform(TargetName, SnmpInform, UserData) ->
+ info("received handle_inform:"
+ "~n TargetName: ~p"
+ "~n SnmpInform: ~p"
+ "~n UserData: ~p",
+ [TargetName, SnmpInform, UserData]),
+ no_reply.
+
+
+handle_report(TargetName, SnmpReport, UserData) ->
+ info("received handle_inform:"
+ "~n TargetName: ~p"
+ "~n SnmpReport: ~p"
+ "~n UserData: ~p",
+ [TargetName, SnmpReport, UserData]),
+ ok.
+
+
+info(F, A) ->
+ error_logger:info_msg("SNMPM default user callback " ++ F ++ "~n", A).
diff --git a/lib/snmp/src/manager/snmpm_user_old.erl b/lib/snmp/src/manager/snmpm_user_old.erl
new file mode 100644
index 0000000000..69b1470790
--- /dev/null
+++ b/lib/snmp/src/manager/snmpm_user_old.erl
@@ -0,0 +1,33 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 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%
+%%
+
+-module(snmpm_user_old).
+
+-export([behaviour_info/1]).
+
+behaviour_info(callbacks) ->
+ [{handle_error, 3},
+ {handle_agent, 4},
+ {handle_pdu, 5},
+ {handle_trap, 4},
+ {handle_inform, 4},
+ {handle_report, 4}];
+behaviour_info(_) ->
+ undefined.
+
diff --git a/lib/snmp/src/manager/snmpm_usm.erl b/lib/snmp/src/manager/snmpm_usm.erl
new file mode 100644
index 0000000000..8cb3062d4b
--- /dev/null
+++ b/lib/snmp/src/manager/snmpm_usm.erl
@@ -0,0 +1,512 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2004-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%
+%%
+%%-----------------------------------------------------------------
+%% This module implements the User Based Security Model for SNMP,
+%% as defined in rfc2274.
+%%-----------------------------------------------------------------
+
+-module(snmpm_usm).
+
+-export([init/0,
+ reset/0,
+ process_incoming_msg/4, generate_outgoing_msg/5]).
+
+-define(SNMP_USE_V3, true).
+-include("snmp_types.hrl").
+-include("snmpm_usm.hrl").
+-include("SNMP-USER-BASED-SM-MIB.hrl").
+-include("SNMP-USM-AES-MIB.hrl").
+% -include("SNMPv2-TC.hrl").
+
+-define(VMODULE,"M-USM").
+-include("snmp_verbosity.hrl").
+
+
+%%-----------------------------------------------------------------
+
+-define(i32(Int), (Int bsr 24) band 255, (Int bsr 16) band 255, (Int bsr 8) band 255, Int band 255).
+-define(i64(Int), (Int bsr 56) band 255, (Int bsr 48) band 255, (Int bsr 40) band 255, (Int bsr 32) band 255, (Int bsr 24) band 255, (Int bsr 16) band 255, (Int bsr 8) band 255, Int band 255).
+
+
+init() ->
+ init_counters().
+
+
+%%-----------------------------------------------------------------
+%% Func: process_incoming_msg(Packet, Data, SecParams, SecLevel) ->
+%% {ok, {SecEngineID, SecName, ScopedPDUBytes, SecData}} |
+%% {error, Reason} | {error, Reason, ErrorInfo}
+%% Return value may be throwed.
+%% Types: Reason -> term()
+%% Purpose:
+%%-----------------------------------------------------------------
+process_incoming_msg(Packet, Data, SecParams, SecLevel) ->
+ %% 3.2.1
+ ?vtrace("process_incoming_msg -> [3.2.1] check security parms",[]),
+ UsmSecParams =
+ case (catch snmp_pdus:dec_usm_security_parameters(SecParams)) of
+ {'EXIT', Reason} ->
+ inc(snmpInASNParseErrs),
+ error({parseError, Reason}, []);
+ Res ->
+ Res
+ end,
+
+ %% Part of 3.2.2
+ #usmSecurityParameters{msgAuthoritativeEngineID = MsgAuthEngineID,
+ msgUserName = MsgUserName} = UsmSecParams,
+ ?vlog("process_incoming_msg -> [3.2.2]"
+ "~n authEngineID: ~p"
+ "~n userName: ~p", [MsgAuthEngineID, MsgUserName]),
+
+ %% 3.2.3 (b)
+ ?vtrace("process_incoming_msg -> [3.2.3-b] check engine id",[]),
+ case snmpm_config:is_usm_engine_id_known(MsgAuthEngineID) of
+ true ->
+ ok;
+ false ->
+ SecData1 = [MsgUserName],
+ error(usmStatsUnknownEngineIDs,
+ ?usmStatsUnknownEngineIDs_instance,
+ undefined, [{sec_data, SecData1}])
+ end,
+
+ %% 3.2.4
+ ?vtrace("process_incoming_msg -> [3.2.4] retrieve usm user",[]),
+ SecUser =
+ case snmpm_config:get_usm_user(MsgAuthEngineID, MsgUserName) of
+ {ok, User} ->
+ User;
+ _ -> % undefined user
+ SecData2 = [MsgUserName],
+ error(usmStatsUnknownUserNames,
+ ?usmStatsUnknownUserNames_instance, %% OTP-3542
+ undefined, [{sec_data, SecData2}])
+ end,
+
+ %% 3.2.5 - implicit in following checks
+ %% 3.2.6 - 3.2.7
+ ?vtrace("process_incoming_msg -> "
+ "[3.2.5 - 3.2.7] authenticate incoming",[]),
+ authenticate_incoming(Packet, UsmSecParams, SecUser, SecLevel),
+
+ %% 3.2.8
+ ?vtrace("process_incoming_msg -> [3.2.8] decrypt scoped data",[]),
+ ScopedPDUBytes = decrypt(Data, SecUser, UsmSecParams, SecLevel),
+
+ %% 3.2.9
+ %% Means that if AuthKey/PrivKey are changed; the old values
+ %% will be used.
+ CachedSecData = {MsgUserName,
+ SecUser#usm_user.auth,
+ SecUser#usm_user.auth_key,
+ SecUser#usm_user.priv,
+ SecUser#usm_user.priv_key},
+ SecName = SecUser#usm_user.sec_name,
+ {ok, {MsgAuthEngineID, SecName, ScopedPDUBytes, CachedSecData}}.
+
+
+authenticate_incoming(Packet, UsmSecParams, UsmUser, SecLevel) ->
+ %% 3.2.6
+ ?vtrace("authenticate incoming: 3.2.6",[]),
+ #usmSecurityParameters{msgAuthoritativeEngineID = MsgAuthEngineID,
+ msgAuthoritativeEngineBoots = MsgAuthEngineBoots,
+ msgAuthoritativeEngineTime = MsgAuthEngineTime,
+ msgAuthenticationParameters = MsgAuthParams} =
+ UsmSecParams,
+ case snmp_misc:is_auth(SecLevel) of
+ true ->
+ SecName = UsmUser#usm_user.sec_name,
+ case is_auth(UsmUser#usm_user.auth,
+ UsmUser#usm_user.auth_key,
+ MsgAuthParams,
+ Packet,
+ SecName,
+ MsgAuthEngineID,
+ MsgAuthEngineBoots,
+ MsgAuthEngineTime) of
+ true ->
+ ok;
+ false ->
+ error(usmStatsWrongDigests,
+ ?usmStatsWrongDigests_instance, SecName)
+ end;
+ false -> % noAuth
+ ok
+ end.
+
+
+
+is_auth(usmNoAuthProtocol, _, _, _, SecName, _, _, _) -> % 3.2.5
+ error(usmStatsUnsupportedSecLevels,
+ ?usmStatsUnsupportedSecLevels_instance, SecName);
+is_auth(AuthProtocol, AuthKey, AuthParams, Packet, SecName,
+ MsgAuthEngineID, MsgAuthEngineBoots, MsgAuthEngineTime) ->
+ case auth_in(AuthProtocol, AuthKey, AuthParams, Packet) of
+ true ->
+ %% 3.2.7
+ ?vtrace("retrieve EngineBoots and EngineTime: 3.2.7",[]),
+ SnmpEngineID = get_engine_id(),
+ ?vtrace("SnmpEngineID: ~p",[SnmpEngineID]),
+ case MsgAuthEngineID of
+ SnmpEngineID -> %% 3.2.7a
+ ?vtrace("we are authoritative: 3.2.7a",[]),
+ SnmpEngineBoots = get_engine_boots(),
+ ?vtrace("SnmpEngineBoots: ~p",[SnmpEngineBoots]),
+ SnmpEngineTime = get_engine_time(),
+ ?vtrace("SnmpEngineTime: ~p",[SnmpEngineTime]),
+ InTimeWindow =
+ if
+ SnmpEngineBoots == 2147483647 -> false;
+ MsgAuthEngineBoots /= SnmpEngineBoots -> false;
+ MsgAuthEngineTime + 150 < SnmpEngineTime -> false;
+ MsgAuthEngineTime - 150 > SnmpEngineTime -> false;
+ true -> true
+ end,
+ case InTimeWindow of
+ true ->
+ true;
+ %% OTP-4090 (OTP-3542)
+ false ->
+ error(usmStatsNotInTimeWindows,
+ ?usmStatsNotInTimeWindows_instance,
+ SecName,
+ [{securityLevel, 1}]) % authNoPriv
+ end;
+ _ -> %% 3.2.7b - we're non-authoritative
+ ?vtrace("we are non-authoritative: 3.2.7b",[]),
+ SnmpEngineBoots = get_engine_boots(MsgAuthEngineID),
+ ?vtrace("SnmpEngineBoots: ~p",[SnmpEngineBoots]),
+ SnmpEngineTime = get_engine_time(MsgAuthEngineID),
+ ?vtrace("SnmpEngineTime: ~p",[SnmpEngineTime]),
+ LatestRecvTime = get_engine_latest_time(MsgAuthEngineID),
+ ?vtrace("LatestRecvTime: ~p",[LatestRecvTime]),
+ UpdateLCD =
+ if
+ MsgAuthEngineBoots > SnmpEngineBoots -> true;
+ MsgAuthEngineBoots == SnmpEngineBoots,
+ MsgAuthEngineTime > LatestRecvTime -> true;
+ true -> false
+ end,
+ case UpdateLCD of
+ true -> %% 3.2.7b1
+ ?vtrace("update msgAuthoritativeEngineID: 3.2.7b1",
+ []),
+ set_engine_boots(MsgAuthEngineID,
+ MsgAuthEngineBoots),
+ set_engine_time(MsgAuthEngineID,
+ MsgAuthEngineTime),
+ set_engine_latest_time(MsgAuthEngineID,
+ MsgAuthEngineTime);
+ false ->
+ ok
+ end,
+ %% 3.2.7.b2
+ ?vtrace("check if message is outside time window: 3.2.7b2",
+ []),
+ InTimeWindow =
+ if
+ SnmpEngineBoots == 2147483647 ->
+ {false, [{engine, SnmpEngineID},
+ {boots, at_max}]};
+ MsgAuthEngineBoots < SnmpEngineBoots ->
+ {false, [{engine, MsgAuthEngineID},
+ {boots, MsgAuthEngineBoots}]};
+ MsgAuthEngineBoots == SnmpEngineBoots,
+ MsgAuthEngineTime < (SnmpEngineTime - 150) ->
+ {false, [{engine, MsgAuthEngineID},
+ {time, MsgAuthEngineTime}]};
+ true -> true
+ end,
+ case InTimeWindow of
+ {false, Reason} ->
+ ?vinfo("not in time window[3.2.7b2]: ~p",
+ [Reason]),
+ error(notInTimeWindow, Reason);
+ true ->
+ ok
+ end,
+ true
+ end;
+ false ->
+ false
+ end.
+
+
+decrypt(Data, UsmUser, UsmSecParams, SecLevel) ->
+ case snmp_misc:is_priv(SecLevel) of
+ true ->
+ do_decrypt(Data, UsmUser, UsmSecParams);
+ false ->
+ Data
+ end.
+
+do_decrypt(Data, #usm_user{sec_name = SecName,
+ priv = PrivP,
+ priv_key = PrivKey},
+ #usmSecurityParameters{msgPrivacyParameters = PrivParms}) ->
+ EncryptedPDU = snmp_pdus:dec_scoped_pdu_data(Data),
+ try_decrypt(PrivP, PrivKey, PrivParms, EncryptedPDU, SecName).
+
+try_decrypt(usmNoPrivProtocol, _, _, _, SecName) -> % 3.2.5
+ error(usmStatsUnsupportedSecLevels,
+ ?usmStatsUnsupportedSecLevels_instance, SecName);
+try_decrypt(usmDESPrivProtocol,
+ PrivKey, MsgPrivParams, EncryptedPDU, SecName) ->
+ case (catch des_decrypt(PrivKey, MsgPrivParams, EncryptedPDU)) of
+ {ok, DecryptedData} ->
+ DecryptedData;
+ _ ->
+ error(usmStatsDecryptionErrors,
+ ?usmStatsDecryptionErrors, SecName)
+ end;
+try_decrypt(usmAesCfb128Protocol,
+ PrivKey, UsmSecParams, EncryptedPDU, SecName) ->
+ case (catch aes_decrypt(PrivKey, UsmSecParams, EncryptedPDU)) of
+ {ok, DecryptedData} ->
+ DecryptedData;
+ _ ->
+ error(usmStatsDecryptionErrors,
+ ?usmStatsDecryptionErrors, SecName)
+ end.
+
+
+%%-----------------------------------------------------------------
+%% Func: process_outgoing_msg(Message, SecEngineID, SecName,
+%% SecData, SecLevel) ->
+%% {ok, {SecEngineID, SecName, ScopedPDUBytes, SecData}} |
+%% {error, Reason} | {error, Reason, ErrorInfo}
+%% Return value may be throwed.
+%% Types: Reason -> term()
+%% Purpose:
+%%-----------------------------------------------------------------
+generate_outgoing_msg(Message, SecEngineID, SecName, SecData, SecLevel) ->
+ %% 3.1.1
+ ?vtrace("generate_outgoing_msg -> entry (3.1.1)",[]),
+ {UserName, AuthProtocol, AuthKey, PrivProtocol, PrivKey} =
+ case SecData of
+ [] -> % 3.1.1b
+ %% Not a response - read from LCD
+ case snmpm_config:get_usm_user_from_sec_name(SecEngineID,
+ SecName) of
+ {ok, User} ->
+ {User#usm_user.name,
+ User#usm_user.auth,
+ User#usm_user.auth_key,
+ User#usm_user.priv,
+ User#usm_user.priv_key};
+ _ ->
+ error(unknownSecurityName)
+ end;
+ [MsgUserName] ->
+ %% This means the user at the engine is unknown
+ {MsgUserName, usmNoAuthProtocol, "", usmNoPrivProtocol, ""};
+ _ -> % 3.1.1a
+ SecData
+ end,
+ %% 3.1.4
+ ?vtrace("generate_outgoing_msg -> (3.1.4)",[]),
+ ScopedPduBytes = Message#message.data,
+ {ScopedPduData, MsgPrivParams} =
+ encrypt(ScopedPduBytes, PrivProtocol, PrivKey, SecLevel),
+ SnmpEngineID = get_engine_id(),
+ ?vtrace("SnmpEngineID: ~p (3.1.6)",[SnmpEngineID]),
+ %% 3.1.6
+ {MsgAuthEngineBoots, MsgAuthEngineTime} =
+ case snmp_misc:is_auth(SecLevel) of
+ false when SecData == [] -> % not a response
+ {0, 0};
+ true when SecEngineID /= SnmpEngineID ->
+ {get_engine_boots(SecEngineID), get_engine_time(SecEngineID)};
+ _ ->
+ {get_engine_boots(), get_engine_time()}
+ end,
+ %% 3.1.5 - 3.1.7
+ ?vtrace("generate_outgoing_msg -> (3.1.5 - 3.1.7)",[]),
+ UsmSecParams =
+ #usmSecurityParameters{msgAuthoritativeEngineID = SecEngineID,
+ msgAuthoritativeEngineBoots = MsgAuthEngineBoots,
+ msgAuthoritativeEngineTime = MsgAuthEngineTime,
+ msgUserName = UserName,
+ msgPrivacyParameters = MsgPrivParams},
+ Message2 = Message#message{data = ScopedPduData},
+ %% 3.1.8
+ ?vtrace("generate_outgoing_msg -> (3.1.8)",[]),
+ authenticate_outgoing(Message2, UsmSecParams,
+ AuthKey, AuthProtocol, SecLevel).
+
+
+%% Ret: {ScopedPDU, MsgPrivParams} - both are already encoded as OCTET STRINGs
+encrypt(Data, PrivProtocol, PrivKey, SecLevel) ->
+ case snmp_misc:is_priv(SecLevel) of
+ false -> % 3.1.4b
+ {Data, []};
+ true -> % 3.1.4a
+ case (catch try_encrypt(PrivProtocol, PrivKey, Data)) of
+ {ok, ScopedPduData, MsgPrivParams} ->
+ {snmp_pdus:enc_oct_str_tag(ScopedPduData), MsgPrivParams};
+ {error, Reason} ->
+ error(Reason);
+ _ ->
+ error(encryptionError)
+ end
+ end.
+
+try_encrypt(usmNoPrivProtocol, _PrivKey, _Data) -> % 3.1.2
+ error(unsupportedSecurityLevel);
+try_encrypt(usmDESPrivProtocol, PrivKey, Data) ->
+ des_encrypt(PrivKey, Data);
+try_encrypt(usmAesCfb128Protocol, PrivKey, Data) ->
+ aes_encrypt(PrivKey, Data).
+
+authenticate_outgoing(Message, UsmSecParams,
+ AuthKey, AuthProtocol, SecLevel) ->
+ Message2 =
+ case snmp_misc:is_auth(SecLevel) of
+ true ->
+ auth_out(AuthProtocol, AuthKey, Message, UsmSecParams);
+ false ->
+ set_msg_auth_params(Message, UsmSecParams)
+ end,
+ snmp_pdus:enc_message_only(Message2).
+
+
+
+%%-----------------------------------------------------------------
+%% Auth and priv algorithms
+%%-----------------------------------------------------------------
+auth_in(AuthProtocol, AuthKey, AuthParams, Packet) ->
+ snmp_usm:auth_in(AuthProtocol, AuthKey, AuthParams, Packet).
+
+auth_out(AuthProtocol, AuthKey, Message, UsmSecParams) ->
+ snmp_usm:auth_out(AuthProtocol, AuthKey, Message, UsmSecParams).
+
+set_msg_auth_params(Message, UsmSecParams) ->
+ snmp_usm:set_msg_auth_params(Message, UsmSecParams, []).
+
+des_encrypt(PrivKey, Data) ->
+ snmp_usm:des_encrypt(PrivKey, Data, fun get_des_salt/0).
+
+des_decrypt(PrivKey, MsgPrivParams, EncData) ->
+ snmp_usm:des_decrypt(PrivKey, MsgPrivParams, EncData).
+
+get_des_salt() ->
+ SaltInt = snmpm_config:incr_counter(usm_des_salt, 1),
+ EngineBoots = get_engine_boots(),
+ [?i32(EngineBoots), ?i32(SaltInt)].
+
+aes_encrypt(PrivKey, Data) ->
+ snmp_usm:aes_encrypt(PrivKey, Data, fun get_aes_salt/0).
+
+aes_decrypt(PrivKey, UsmSecParams, EncData) ->
+ #usmSecurityParameters{msgPrivacyParameters = MsgPrivParams,
+ msgAuthoritativeEngineTime = EngineTime,
+ msgAuthoritativeEngineBoots = EngineBoots} =
+ UsmSecParams,
+ snmp_usm:aes_decrypt(PrivKey, MsgPrivParams, EncData,
+ EngineBoots, EngineTime).
+
+get_aes_salt() ->
+ SaltInt = snmpm_config:incr_counter(usm_aes_salt, 1),
+ [?i64(SaltInt)].
+
+%%-----------------------------------------------------------------
+
+get_engine_id() ->
+ {ok, EngineID} = snmpm_config:get_engine_id(),
+ EngineID.
+
+get_engine_boots() ->
+ {ok, Boots} = snmpm_config:get_engine_boots(),
+ Boots.
+
+get_engine_time() ->
+ {ok, Diff} = snmpm_config:get_engine_time(),
+ Diff.
+
+
+%%-----------------------------------------------------------------
+%% We cache the local values of all non-auth engines we know.
+%% See section 2.3 (Time Synchronization) of the RFC.
+%%-----------------------------------------------------------------
+get_engine_boots(SnmpEngineID) ->
+ {ok, Boots} = snmpm_config:get_usm_eboots(SnmpEngineID),
+ Boots.
+
+get_engine_time(SnmpEngineID) ->
+ {ok, Diff} = snmpm_config:get_usm_etime(SnmpEngineID),
+ Diff.
+
+get_engine_latest_time(SnmpEngineID) ->
+ {ok, Time} = snmpm_config:get_usm_eltime(SnmpEngineID),
+ Time.
+
+
+set_engine_boots(SnmpEngineID, EngineBoots) ->
+ snmpm_config:set_usm_eboots(SnmpEngineID, EngineBoots).
+
+set_engine_time(SnmpEngineID, EngineTime) ->
+ Diff = snmp_misc:now(sec) - EngineTime,
+ snmpm_config:set_usm_etime(SnmpEngineID, Diff).
+
+set_engine_latest_time(SnmpEngineID, EngineTime) ->
+ snmpm_config:set_usm_eltime(SnmpEngineID, EngineTime).
+
+
+%%-----------------------------------------------------------------
+%% Utility functions
+%%-----------------------------------------------------------------
+error(Reason) ->
+ throw({error, Reason}).
+
+error(Reason, ErrorInfo) ->
+ throw({error, Reason, ErrorInfo}).
+
+error(Variable, Oid, SecName) ->
+ error(Variable, Oid, SecName, []).
+error(Variable, Oid, SecName, Opts) ->
+ Val = inc(Variable),
+ ErrorInfo = {#varbind{oid = Oid,
+ variabletype = 'Counter32',
+ value = Val},
+ SecName,
+ Opts},
+ throw({error, Variable, ErrorInfo}).
+
+
+%%-----------------------------------------------------------------
+
+init_counters() ->
+ F = fun(Counter) -> snmpm_config:maybe_cre_stats_counter(Counter, 0) end,
+ lists:map(F, counters()).
+
+reset() ->
+ F = fun(Counter) -> snmpm_config:reset_stats_counter(Counter) end,
+ lists:map(F, counters()).
+
+counters() ->
+ [usmStatsUnsupportedSecLevels,
+ usmStatsNotInTimeWindows,
+ usmStatsUnknownUserNames,
+ usmStatsUnknownEngineIDs,
+ usmStatsWrongDigests,
+ usmStatsDecryptionErrors].
+
+inc(Name) -> snmpm_config:incr_stats_counter(Name, 1).
+
diff --git a/lib/snmp/src/manager/snmpm_usm.hrl b/lib/snmp/src/manager/snmpm_usm.hrl
new file mode 100644
index 0000000000..1939ad6ed9
--- /dev/null
+++ b/lib/snmp/src/manager/snmpm_usm.hrl
@@ -0,0 +1,27 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2004-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%
+%%
+
+-record(usm_user, {engine_id,
+ name,
+ sec_name, % Default value is name
+ auth = usmNoAuthProtocol,
+ auth_key = [],
+ priv = usmNoPrivProtocol,
+ priv_key = []}).
+
diff --git a/lib/snmp/src/misc/Makefile b/lib/snmp/src/misc/Makefile
new file mode 100644
index 0000000000..48d76bdbed
--- /dev/null
+++ b/lib/snmp/src/misc/Makefile
@@ -0,0 +1,122 @@
+#-*-makefile-*- ; force emacs to enter makefile-mode
+
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2003-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%
+
+include $(ERL_TOP)/make/target.mk
+
+EBIN = ../../ebin
+
+include $(ERL_TOP)/make/$(TARGET)/otp.mk
+
+# ----------------------------------------------------
+# Application version
+# ----------------------------------------------------
+include ../../vsn.mk
+
+VSN = $(SNMP_VSN)
+
+# ----------------------------------------------------
+# Release directory specification
+# ----------------------------------------------------
+RELSYSDIR = $(RELEASE_PATH)/lib/snmp-$(VSN)
+
+
+# ----------------------------------------------------
+# Target Specs
+# ----------------------------------------------------
+
+include modules.mk
+
+ERL_FILES = $(MODULES:%=%.erl)
+
+HRL_FILES = $(HRLS:%=%.hrl)
+
+TARGET_FILES = $(MODULES:%=$(EBIN)/%.$(EMULATOR))
+
+
+# ----------------------------------------------------
+# SNMP FLAGS
+# ----------------------------------------------------
+ifeq ($(SNMP_DEFAULT_VERBOSITY),)
+ SNMP_FLAGS = -Ddefault_verbosity=silence
+else
+ SNMP_FLAGS = -Ddefault_verbosity=$(SNMP_DEFAULT_VERBOSITY)
+endif
+
+# SNMP_DEBUG=d
+ifeq ($(SNMP_DEBUG),d)
+ SNMP_FLAGS += -Dsnmp_debug
+endif
+
+
+# ----------------------------------------------------
+# FLAGS
+# ----------------------------------------------------
+
+ERL_COMPILE_FLAGS += -pa $(ERL_TOP)/lib/snmp/ebin
+
+ifeq ($(WARN_UNUSED_VARS),true)
+ERL_COMPILE_FLAGS += +warn_unused_vars
+endif
+
+ERL_COMPILE_FLAGS += -I../../include \
+ -I../compile \
+ -Dversion=\"$(VSN)$(PRE_VSN)\" \
+ +'{parse_transform,sys_pre_attributes}' \
+ +'{attribute,insert,app_vsn,$(APP_VSN)}' \
+ -I$(ERL_TOP)/lib/stdlib \
+ $(SNMP_FLAGS)
+
+# ----------------------------------------------------
+# Targets
+# ----------------------------------------------------
+
+debug:
+ @$(MAKE) TYPE=debug opt
+
+opt: $(TARGET_FILES)
+
+
+clean:
+ rm -f $(TARGET_FILES)
+ rm -f core *~
+
+docs:
+
+info:
+ @echo "TARGET_FILES: $(TARGET_FILES)"
+ @echo ""
+
+
+# ----------------------------------------------------
+# Release Target
+# ----------------------------------------------------
+include $(ERL_TOP)/make/otp_release_targets.mk
+
+release_spec: opt
+ $(INSTALL_DIR) $(RELSYSDIR)/src
+ $(INSTALL_DIR) $(RELSYSDIR)/src/misc
+ $(INSTALL_DATA) $(ERL_FILES) $(HRL_FILES) $(RELSYSDIR)/src/misc
+ $(INSTALL_DIR) $(RELSYSDIR)/ebin
+ $(INSTALL_DATA) $(TARGET_FILES) $(RELSYSDIR)/ebin
+# $(INSTALL_DIR) $(RELSYSDIR)/include
+# $(INSTALL_DATA) $(EXT_HRL_FILES) $(RELSYSDIR)/include
+
+release_docs_spec:
+
+include depend.mk
diff --git a/lib/snmp/src/misc/depend.mk b/lib/snmp/src/misc/depend.mk
new file mode 100644
index 0000000000..dea0f75048
--- /dev/null
+++ b/lib/snmp/src/misc/depend.mk
@@ -0,0 +1,58 @@
+#-*-makefile-*- ; force emacs to enter makefile-mode
+
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2004-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%
+
+$(EBIN)/snmp_conf.$(EMULATOR): \
+ snmp_conf.erl \
+ snmp_verbosity.hrl \
+ ../../include/snmp_types.hrl
+
+$(EBIN)/snmp_config.$(EMULATOR): \
+ snmp_config.erl \
+ ../../include/snmp_types.hrl
+
+$(EBIN)/snmp_log.$(EMULATOR): \
+ snmp_log.erl \
+ snmp_verbosity.hrl \
+ ../../include/snmp_types.hrl
+
+$(EBIN)/snmp_misc.$(EMULATOR): \
+ snmp_misc.erl \
+ snmp_verbosity.hrl \
+ ../compile/snmpc_misc.hrl \
+ ../../include/snmp_types.hrl
+
+$(EBIN)/snmp_note_store.$(EMULATOR): \
+ snmp_note_store.erl \
+ ../misc/snmp_debug.hrl \
+ ../misc/snmp_verbosity.hrl
+
+$(EBIN)/snmp_pdu.$(EMULATOR): \
+ snmp_pdu.erl \
+ snmp_verbosity.hrl \
+ ../../include/snmp_types.hrl
+
+$(EBIN)/snmp_usm.$(EMULATOR): \
+ snmp_usm.erl \
+ snmp_verbosity.hrl \
+ ../../include/snmp_types.hrl
+
+$(EBIN)/snmp_verbosity.$(EMULATOR): \
+ snmp_verbosity.erl
+
+
diff --git a/lib/snmp/src/misc/modules.mk b/lib/snmp/src/misc/modules.mk
new file mode 100644
index 0000000000..32092aaae2
--- /dev/null
+++ b/lib/snmp/src/misc/modules.mk
@@ -0,0 +1,33 @@
+#-*-makefile-*- ; force emacs to enter makefile-mode
+
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2004-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%
+
+MODULES = \
+ snmp_conf \
+ snmp_config \
+ snmp_log \
+ snmp_mini_mib \
+ snmp_misc \
+ snmp_note_store \
+ snmp_pdus \
+ snmp_usm \
+ snmp_verbosity
+
+HRLS = snmp_verbosity snmp_debug
+
+
diff --git a/lib/snmp/src/misc/snmp_conf.erl b/lib/snmp/src/misc/snmp_conf.erl
new file mode 100644
index 0000000000..63762ac17b
--- /dev/null
+++ b/lib/snmp/src/misc/snmp_conf.erl
@@ -0,0 +1,421 @@
+%%
+%% %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%
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Basic module for reading and verifying config files
+%%----------------------------------------------------------------------
+-module(snmp_conf).
+
+
+%% External exports
+-export([read_files/2, read/2]).
+
+%% Basic (type) check functions
+-export([check_mandatory/2,
+ check_integer/1, check_integer/2,
+
+ check_string/1, check_string/2,
+
+ check_atom/2,
+
+ check_timer/1,
+
+ check_ip/1, check_taddress/1,
+
+ check_packet_size/1,
+
+ check_oid/1,
+
+ check_mp_model/1,
+ check_sec_model/1, check_sec_model/2, check_sec_model/3,
+ check_sec_level/1,
+
+ all_integer/1
+ ]).
+
+
+-define(SNMP_USE_V3, true).
+-include("snmp_types.hrl").
+-include("SNMP-FRAMEWORK-MIB.hrl").
+
+-define(VMODULE,"CONF").
+-include("snmp_verbosity.hrl").
+
+
+%%-----------------------------------------------------------------
+
+read_files(Dir, Files) when is_list(Dir) andalso is_list(Files) ->
+ read_files(Dir, Files, []).
+
+read_files(_Dir, [], Res) ->
+ lists:reverse(Res);
+read_files(Dir, [{Gen, Filter, Check, FileName}|Files], Res)
+ when is_function(Filter) andalso
+ is_function(Check) andalso
+ is_list(FileName) ->
+ ?vdebug("read_files -> entry with"
+ "~n FileName: ~p", [FileName]),
+ File = filename:join(Dir, FileName),
+ case file:read_file_info(File) of
+ {ok, _} ->
+ Confs = read(File, Check),
+ read_files(Dir, Files, [Filter(Confs)|Res]);
+ {error, R} ->
+ ?vlog("failed reading file info for ~s: "
+ "~n ~p", [FileName, R]),
+ Gen(Dir),
+ read_files(Dir, Files, [Filter([])|Res])
+ end.
+
+
+%% Ret. Res | exit(Reason)
+read(File, Check) when is_function(Check) ->
+ ?vdebug("read -> entry with"
+ "~n File: ~p", [File]),
+ Fd = open_file(File),
+
+ case loop(Fd, [], Check, 1, File) of
+ {error, Reason} ->
+ file:close(Fd),
+ error(Reason);
+ {ok, Res} ->
+ file:close(Fd),
+ Res
+ end.
+
+open_file(File) ->
+ case file:open(File, [read]) of
+ {ok, Fd} ->
+ Fd;
+ {error, Reason} ->
+ error({failed_open, File, Reason})
+ end.
+
+loop(Fd, Res, Check, StartLine, File) ->
+ case do_read(Fd, "", StartLine) of
+ {ok, Row, EndLine} ->
+ ?vtrace("loop -> "
+ "~n Row: ~p"
+ "~n EndLine: ~p", [Row, EndLine]),
+ case (catch Check(Row)) of
+ ok ->
+ ?vtrace("loop -> ok", []),
+ loop(Fd, [Row | Res], Check, EndLine, File);
+ {ok, NewRow} ->
+ ?vtrace("loop -> ok: "
+ "~n NewRow: ~p", [NewRow]),
+ loop(Fd, [NewRow | Res], Check, EndLine, File);
+ {error, Reason} ->
+ ?vtrace("loop -> check error: "
+ "~n Reason: ~p", [Reason]),
+ {error, {failed_check, File, StartLine, EndLine, Reason}};
+ Error ->
+ ?vtrace("loop -> check failure: "
+ "~n Error: ~p", [Error]),
+ {error, {failed_check, File, StartLine, EndLine, Error}}
+ end;
+ {error, EndLine, Error} ->
+ ?vtrace("loop -> read failure: "
+ "~n Error: ~p", [Error]),
+ {error, {failed_reading, File, StartLine, EndLine, Error}};
+ eof ->
+ {ok, Res}
+ end.
+
+
+do_read(Io, Prompt, StartLine) ->
+ case io:request(Io, {get_until,Prompt,erl_scan,tokens,[StartLine]}) of
+ {ok, Toks, EndLine} ->
+ case erl_parse:parse_term(Toks) of
+ {ok, Term} ->
+ {ok, Term, EndLine};
+ {error, {Line, erl_parse, Error}} ->
+ {error, Line, {parse_error, Error}}
+ end;
+ {error,E,EndLine} ->
+ {error, EndLine, E};
+ {eof, _EndLine} ->
+ eof;
+ Other ->
+ Other
+ end.
+
+
+%%-----------------------------------------------------------------
+
+
+check_mandatory(L, [{Key, Value}|T]) ->
+ case lists:keymember(Key, 1, L) of
+ true ->
+ check_mandatory(L, T);
+ false when Value == mandatory ->
+ error({missing_mandatory, Key});
+ false ->
+ {value, V} = Value,
+ check_mandatory([{Key, V} | L], T)
+ end;
+check_mandatory(L, []) ->
+ {ok, L}.
+
+
+%% ---------
+
+check_integer(I) -> check_integer(I, any).
+
+check_integer(I, any) when is_integer(I) -> ok;
+check_integer(I, pos) when is_integer(I), I > 0 -> ok;
+check_integer(I, neg) when is_integer(I), I < 0 -> ok;
+check_integer(I1, {gt, I2})
+ when is_integer(I1) andalso is_integer(I2) andalso (I1 > I2) -> ok;
+check_integer(I1, {gte, I2})
+ when is_integer(I1) andalso is_integer(I2) andalso (I1 >= I2) -> ok;
+check_integer(I1, {lt, I2})
+ when is_integer(I1) andalso is_integer(I2) andalso (I1 < I2) -> ok;
+check_integer(I1, {lte, I2})
+ when is_integer(I1) andalso is_integer(I2) andalso (I1 =< I2) -> ok;
+check_integer(I1, {eq, I1})
+ when is_integer(I1) -> ok;
+check_integer(I, {range, L, U})
+ when (is_integer(I) andalso
+ is_integer(L) andalso
+ is_integer(U) andalso
+ (I >= L) andalso (I =< U)) -> ok;
+check_integer(I, _) -> error({invalid_integer, I}).
+
+check_packet_size(S) ->
+ case (catch check_integer(S, {range, 484, 2147483647})) of
+ ok ->
+ ok;
+ {error, _} ->
+ error({invalid_packet_size, S})
+ end.
+
+%% ---------
+
+check_string(X) when is_list(X) -> ok;
+check_string(X) -> error({invalid_string, X}).
+
+check_string(X, any)
+ when is_list(X) -> ok;
+check_string(X, {gt, Len})
+ when is_list(X) andalso (length(X) > Len) -> ok;
+check_string(X, {gt, _Len})
+ when is_list(X) -> error({invalid_length, X});
+check_string(X, {gte, Len})
+ when is_list(X) andalso (length(X) >= Len) -> ok;
+check_string(X, {gte, _Len})
+ when is_list(X) -> error({invalid_length, X});
+check_string(X, {lt, Len})
+ when is_list(X) andalso (length(X) < Len) -> ok;
+check_string(X, {lt, _Len})
+ when is_list(X) -> error({invalid_length, X});
+check_string(X, {lte, Len})
+ when is_list(X) andalso (length(X) =< Len) -> ok;
+check_string(X, {lte, _Len})
+ when is_list(X) -> error({invalid_length, X});
+check_string(X, Len)
+ when is_list(X) andalso is_integer(Len) andalso (length(X) =:= Len) -> ok;
+check_string(X, _Len) when is_list(X) -> error({invalid_length, X});
+check_string(X, _Len) -> error({invalid_string, X}).
+
+
+check_atom(X, Atoms) ->
+ case lists:keysearch(X, 1, Atoms) of
+ {value, {X, Val}} ->
+ {ok, Val};
+ _ ->
+ error({invalid_atom, X, Atoms})
+ end.
+
+
+%% ---------
+
+check_mp_model(MPModel) when is_atom(MPModel) ->
+ All = [{v1, ?MP_V1}, {v2c, ?MP_V2C}, {v3, ?MP_V3}],
+ check_atom(MPModel, All);
+check_mp_model(?MP_V1) ->
+ {ok, ?MP_V1};
+check_mp_model(?MP_V2C) ->
+ {ok, ?MP_V2C};
+check_mp_model(?MP_V3) ->
+ {ok, ?MP_V3};
+check_mp_model(BadMpModel) ->
+ error({invalid_mp_model, BadMpModel}).
+
+
+%% ---------
+
+check_sec_model(SecModel) when is_atom(SecModel) ->
+ check_sec_model(SecModel, []);
+check_sec_model(?SEC_ANY) ->
+ {ok, ?SEC_ANY};
+check_sec_model(?SEC_V1) ->
+ {ok, ?SEC_V1};
+check_sec_model(?SEC_V2C) ->
+ {ok, ?SEC_V2C};
+check_sec_model(?SEC_USM) ->
+ {ok, ?SEC_USM};
+check_sec_model(BadSecModel) ->
+ error({invalid_sec_model, BadSecModel}).
+
+check_sec_model(SecModel, Exclude) when is_atom(SecModel) ->
+ All = [{any, ?SEC_ANY},
+ {v1, ?SEC_V1},
+ {v2c, ?SEC_V2C},
+ {usm, ?SEC_USM}],
+ Alt = [{X, Y} || {X, Y} <- All, not lists:member(X, Exclude)],
+ case (catch check_atom(SecModel, Alt) ) of
+ {error, _} ->
+ error({invalid_sec_model, SecModel});
+ OK ->
+ OK
+ end;
+check_sec_model(BadSecModel, _Exclude) ->
+ error({invalid_sec_model, BadSecModel}).
+
+check_sec_model(v1, v1, Exclude) ->
+ check_sec_model2(v1, ?SEC_V1, Exclude);
+check_sec_model(v1, SecModel, _Exclude) ->
+ error({invalid_sec_model, v1, SecModel});
+check_sec_model(v2c, v2c, Exclude) ->
+ check_sec_model2(v2c, ?SEC_V2C, Exclude);
+check_sec_model(v2c, SecModel, _Exclude) ->
+ error({invalid_sec_model, v2c, SecModel});
+check_sec_model(v3, usm, Exclude) ->
+ check_sec_model2(v3, ?SEC_USM, Exclude);
+check_sec_model(v3, SecModel, _Exclude) ->
+ error({invalid_sec_model, v3, SecModel});
+check_sec_model(M1, M2, _Exclude) ->
+ error({invalid_sec_model, M1, M2}).
+
+check_sec_model2(SecModel, SM, Exclude) ->
+ case lists:member(SecModel, Exclude) of
+ false ->
+ {ok, SM};
+ true ->
+ error({invalid_sec_model, SecModel})
+ end.
+
+
+%% ---------
+
+check_sec_level(SecLevel) when is_atom(SecLevel) ->
+ All = [{noAuthNoPriv, ?'SnmpSecurityLevel_noAuthNoPriv'},
+ {authNoPriv, ?'SnmpSecurityLevel_authNoPriv'},
+ {authPriv, ?'SnmpSecurityLevel_authPriv'}],
+ case (catch check_atom(SecLevel, All)) of
+ {error, _} ->
+ error({invalid_sec_level, SecLevel});
+ OK ->
+ OK
+ end;
+check_sec_level(?'SnmpSecurityLevel_noAuthNoPriv' = SL) ->
+ {ok, SL};
+check_sec_level(?'SnmpSecurityLevel_authNoPriv' = SL) ->
+ {ok, SL};
+check_sec_level(?'SnmpSecurityLevel_authPriv' = SL) ->
+ {ok, SL};
+check_sec_level(BadSecLevel) ->
+ error({invalid_sec_level, BadSecLevel}).
+
+
+%% ---------
+
+check_taddress(X) when is_list(X) andalso (length(X) =:= 6) ->
+ case (catch all_integer(X)) of
+ true ->
+ ok;
+ false ->
+ error({invalid_taddress, X})
+ end;
+check_taddress(X) ->
+ error({invalid_taddress, X}).
+
+
+%% ---------
+
+check_timer(infinity) ->
+ {ok, infinity};
+check_timer(T) when is_record(T, snmp_incr_timer) ->
+ {ok, T};
+check_timer({WaitFor, Factor, Incr, Retry} = T) ->
+ case (catch do_check_timer(WaitFor, Factor, Incr, Retry)) of
+ ok ->
+ {ok, #snmp_incr_timer{wait_for = WaitFor,
+ factor = Factor,
+ incr = Incr,
+ max_retries = Retry}};
+ _Err ->
+ error({invalid_timer, T})
+ end;
+check_timer(Timeout) ->
+ case (catch check_integer(Timeout, {gt, 0})) of
+ ok ->
+ {ok, #snmp_incr_timer{wait_for = Timeout,
+ factor = 1,
+ incr = 0,
+ max_retries = 0}};
+ _Err ->
+ error({invalid_timer, Timeout})
+ end.
+
+do_check_timer(WaitFor, Factor, Incr, Retry) ->
+ check_integer(WaitFor, {gt, 0}),
+ check_integer(Factor, {gt, 0}),
+ check_integer(Incr, {gte, 0}),
+ check_integer(Retry, {gte, 0}),
+ ok.
+
+%% ---------
+
+check_ip(X) when is_list(X) andalso (length(X) =:= 4) ->
+ case (catch all_integer(X)) of
+ true ->
+ ok;
+ false ->
+ error({invalid_ip_address, X})
+ end;
+check_ip(X) ->
+ error({invalid_ip_address, X}).
+
+
+%% ---------
+
+check_oid([E1,E2|_] = X) when E1 * 40 + E2 =< 255 ->
+ case all_integer(X) of
+ true ->
+ ok;
+ _ ->
+ error({invalid_object_identifier, X})
+ end;
+check_oid(X) ->
+ error({invalid_object_identifier, X}).
+
+
+%% ---------
+
+all_integer([H|T]) when is_integer(H) -> all_integer(T);
+all_integer([_H|_T]) -> false;
+all_integer([]) -> true.
+
+
+%% ---------
+
+error(Reason) ->
+ throw({error, Reason}).
+
diff --git a/lib/snmp/src/misc/snmp_config.erl b/lib/snmp/src/misc/snmp_config.erl
new file mode 100644
index 0000000000..ad41eaf160
--- /dev/null
+++ b/lib/snmp/src/misc/snmp_config.erl
@@ -0,0 +1,2348 @@
+%%
+%% %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%
+%%
+
+-module(snmp_config).
+
+-include_lib("kernel/include/file.hrl").
+-include("snmp_types.hrl").
+
+-export([config/0]).
+
+-export([write_config_file/4, append_config_file/4, read_config_file/3]).
+
+-export([write_agent_snmp_files/7, write_agent_snmp_files/12,
+
+ write_agent_snmp_conf/5,
+ write_agent_snmp_context_conf/1,
+ write_agent_snmp_community_conf/1,
+ write_agent_snmp_standard_conf/2,
+ write_agent_snmp_target_addr_conf/4,
+ write_agent_snmp_target_addr_conf/6,
+ write_agent_snmp_target_params_conf/2,
+ write_agent_snmp_notify_conf/2,
+ write_agent_snmp_usm_conf/5,
+ write_agent_snmp_vacm_conf/3,
+
+ write_manager_snmp_files/8,
+ write_manager_snmp_conf/5,
+ write_manager_snmp_users_conf/2,
+ write_manager_snmp_agents_conf/2,
+ write_manager_snmp_usm_conf/2
+
+ ]).
+
+-export([write_agent_config/3,
+ update_agent_config/2,
+
+ write_agent_context_config/3,
+ update_agent_context_config/2,
+
+ write_agent_community_config/3,
+ update_agent_community_config/2,
+
+ write_agent_standard_config/3,
+ update_agent_standard_config/2,
+
+ write_agent_target_addr_config/3,
+ update_agent_target_addr_config/2,
+
+ write_agent_target_params_config/3,
+ update_agent_target_params_config/2,
+
+ write_agent_notify_config/3,
+ update_agent_notify_config/2,
+
+ write_agent_vacm_config/3,
+ update_agent_vacm_config/2,
+
+ write_agent_usm_config/3,
+ update_agent_usm_config/2,
+
+ write_manager_config/3,
+ update_manager_config/2,
+
+ write_manager_users_config/3,
+ update_manager_users_config/2,
+
+ write_manager_agents_config/3,
+ update_manager_agents_config/2,
+
+ write_manager_usm_config/3,
+ update_manager_usm_config/2
+ ]).
+
+
+%%----------------------------------------------------------------------
+%% Handy SNMP configuration
+%%----------------------------------------------------------------------
+
+config() ->
+ case (catch config2()) of
+ ok ->
+ ok;
+ {error, Reason} ->
+ {error, Reason};
+ E ->
+ {error, {failed, E}}
+ end.
+
+
+config2() ->
+ intro(),
+ SysAgentConfig =
+ case config_agent() of
+ [] ->
+ [];
+ SAC ->
+ [{agent, SAC}]
+ end,
+ SysMgrConfig =
+ case config_manager() of
+ [] ->
+ [];
+ SMC ->
+ [{manager, SMC}]
+ end,
+ config_sys(SysAgentConfig ++ SysMgrConfig),
+ ok.
+
+
+intro() ->
+ i("~nSimple SNMP configuration tool (version ~s)", [?version]),
+ i("------------------------------------------------"),
+ i("Note: Non-trivial configurations still has to be"),
+ i(" done manually. IP addresses may be entered "),
+ i(" as dront.ericsson.se (UNIX only) or"),
+ i(" 123.12.13.23"),
+ i("------------------------------------------------"),
+ ok.
+
+
+config_agent() ->
+ case (catch snmp_agent2()) of
+ ok ->
+ [];
+ {ok, SysConf} ->
+ SysConf;
+ {error, Reason} ->
+ error(Reason);
+ {'EXIT', Reason} ->
+ error(Reason);
+ E ->
+ error({agent_config_failed, E})
+ end.
+
+snmp_agent2() ->
+ case ask("~nConfigure an agent (y/n)?", "y", fun verify_yes_or_no/1) of
+ yes ->
+ {Vsns, ConfigDir, SysConf} = config_agent_sys(),
+ config_agent_snmp(ConfigDir, Vsns),
+ {ok, SysConf};
+ no ->
+ ok
+ end.
+
+
+config_manager() ->
+ case (catch config_manager2()) of
+ ok ->
+ [];
+ {ok, SysConf} ->
+ SysConf;
+ {error, Reason} ->
+ error(Reason);
+ {'EXIT', Reason} ->
+ error(Reason);
+ E ->
+ error({manager_config_failed, E})
+ end.
+
+config_manager2() ->
+ case ask("~nConfigure a manager (y/n)?", "y", fun verify_yes_or_no/1) of
+ yes ->
+ {Vsns, ConfigDir, SysConf} = config_manager_sys(),
+ config_manager_snmp(ConfigDir, Vsns),
+ {ok, SysConf};
+ no ->
+ ok
+ end.
+
+
+config_sys(SysConfig) ->
+ i("~n--------------------"),
+ {ok, DefDir} = file:get_cwd(),
+ ConfigDir = ask("Configuration directory for system file (absolute path)?",
+ DefDir, fun verify_dir/1),
+ write_sys_config_file(ConfigDir, SysConfig).
+
+
+%% -------------------
+
+config_agent_sys() ->
+ i("~nAgent system config: "
+ "~n--------------------"),
+ Prio = ask("1. Agent process priority (low/normal/high)",
+ "normal", fun verify_prio/1),
+ Vsns = ask("2. What SNMP version(s) should be used "
+ "(1,2,3,1&2,1&2&3,2&3)?", "3", fun verify_versions/1),
+ %% d("Vsns: ~p", [Vsns]),
+ {ok, DefDir} = file:get_cwd(),
+ {DefConfDir, Warning} = default_agent_dir(DefDir),
+ ConfQ =
+ if
+ Warning == "" ->
+ "3. Configuration directory (absolute path)?";
+ true ->
+ lists:flatten(
+ io_lib:format("3. Configuration directory (absolute path)?"
+ "~n ~s", [Warning]))
+ end,
+ ConfigDir = ask(ConfQ, DefConfDir, fun verify_dir/1),
+ ConfigVerb = ask("4. Config verbosity "
+ "(silence/info/log/debug/trace)?",
+ "silence",
+ fun verify_verbosity/1),
+ DbDir = ask("5. Database directory (absolute path)?", DefDir,
+ fun verify_dir/1),
+ MibStorageType = ask("6. Mib storage type (ets/dets/mnesia)?", "ets",
+ fun verify_mib_storage_type/1),
+ MibStorage =
+ case MibStorageType of
+ ets ->
+ ets;
+ dets ->
+ DetsDir = ask("6b. Mib storage directory (absolute path)?",
+ DbDir, fun verify_dir/1),
+ DetsAction = ask("6c. Mib storage [dets] database start "
+ "action "
+ "(default/clear/keep)?",
+ "default", fun verify_mib_storage_action/1),
+ case DetsAction of
+ default ->
+ {dets, DetsDir};
+ _ ->
+ {dets, DetsDir, DetsAction}
+ end;
+ mnesia ->
+% Nodes = ask("Mib storage nodes?", "none",
+% fun verify_mib_storage_nodes/1),
+ Nodes = [],
+ MnesiaAction = ask("6b. Mib storage [mnesia] database start "
+ "action "
+ "(default/clear/keep)?",
+ "default", fun verify_mib_storage_action/1),
+ case MnesiaAction of
+ default ->
+ {mnesia, Nodes};
+ _ ->
+ {mnesia, Nodes, MnesiaAction}
+ end
+ end,
+ TargetCacheVerb = ask("7. Target cache verbosity "
+ "(silence/info/log/debug/trace)?", "silence",
+ fun verify_verbosity/1),
+ SymStoreVerb = ask("8. Symbolic store verbosity "
+ "(silence/info/log/debug/trace)?", "silence",
+ fun verify_verbosity/1),
+ LocalDbVerb = ask("9. Local DB verbosity "
+ "(silence/info/log/debug/trace)?", "silence",
+ fun verify_verbosity/1),
+ LocalDbRepair = ask("10. Local DB repair (true/false/force)?", "true",
+ fun verify_dets_repair/1),
+ LocalDbAutoSave = ask("11. Local DB auto save (infinity/milli seconds)?",
+ "5000", fun verify_dets_auto_save/1),
+ ErrorMod = ask("12. Error report module?", "snmpa_error_logger", fun verify_module/1),
+ Type = ask("13. Agent type (master/sub)?", "master",
+ fun verify_agent_type/1),
+ AgentConfig =
+ case Type of
+ master ->
+ MasterAgentVerb = ask("14. Master-agent verbosity "
+ "(silence/info/log/debug/trace)?",
+ "silence",
+ fun verify_verbosity/1),
+ ForceLoad = ask("15. Shall the agent re-read the "
+ "configuration files during startup ~n"
+ " (and ignore the configuration "
+ "database) (true/false)?", "true",
+ fun verify_bool/1),
+ MultiThreaded = ask("16. Multi threaded agent (true/false)?",
+ "false",
+ fun verify_bool/1),
+ MeOverride = ask("17. Check for duplicate mib entries when "
+ "installing a mib (true/false)?", "false",
+ fun verify_bool/1),
+ TrapOverride = ask("18. Check for duplicate trap names when "
+ "installing a mib (true/false)?", "false",
+ fun verify_bool/1),
+ MibServerVerb = ask("19. Mib server verbosity "
+ "(silence/info/log/debug/trace)?",
+ "silence",
+ fun verify_verbosity/1),
+ MibServerCache = ask("20. Mib server cache "
+ "(true/false)?",
+ "true",
+ fun verify_bool/1),
+ NoteStoreVerb = ask("21. Note store verbosity "
+ "(silence/info/log/debug/trace)?",
+ "silence",
+ fun verify_verbosity/1),
+ NoteStoreTimeout = ask("22. Note store GC timeout?", "30000",
+ fun verify_timeout/1),
+ ATL =
+ case ask("23. Shall the agent use an audit trail log "
+ "(y/n)?",
+ "n", fun verify_yes_or_no/1) of
+ yes ->
+ ATLType = ask("23b. Audit trail log type "
+ "(write/read_write)?",
+ "read_write", fun verify_atl_type/1),
+ ATLDir = ask("23c. Where to store the "
+ "audit trail log?",
+ DefDir, fun verify_dir/1),
+ ATLMaxFiles = ask("23d. Max number of files?",
+ "10",
+ fun verify_pos_integer/1),
+ ATLMaxBytes = ask("23e. Max size (in bytes) "
+ "of each file?",
+ "10240",
+ fun verify_pos_integer/1),
+ ATLSize = {ATLMaxBytes, ATLMaxFiles},
+ ATLRepair = ask("23f. Audit trail log repair "
+ "(true/false/truncate/snmp_repair)?", "true",
+ fun verify_atl_repair/1),
+ [{audit_trail_log, [{type, ATLType},
+ {dir, ATLDir},
+ {size, ATLSize},
+ {repair, ATLRepair}]}];
+ no ->
+ []
+ end,
+ NetIfVerb = ask("24. Network interface verbosity "
+ "(silence/info/log/debug/trace)?",
+ "silence",
+ fun verify_verbosity/1),
+ NetIfMod = ask("25. Which network interface module shall be used?",
+ "snmpa_net_if", fun verify_module/1),
+ NetIfOpts =
+ case NetIfMod of
+ snmpa_net_if ->
+ NetIfBindTo =
+ ask("25a. Bind the agent IP address "
+ "(true/false)?",
+ "false", fun verify_bool/1),
+ NetIfNoReuse =
+ ask("25b. Shall the agents "
+ "IP address "
+ "and port be not reusable "
+ "(true/false)?",
+ "false", fun verify_bool/1),
+ NetIfReqLimit =
+ ask("25c. Agent request limit "
+ "(used for flow control) "
+ "(infinity/pos integer)?",
+ "infinity",
+ fun verify_netif_req_limit/1),
+ NetIfRecbuf =
+ case ask("25d. Receive buffer size of the "
+ "agent (in bytes) "
+ "(default/pos integer)?",
+ "default",
+ fun verify_netif_recbuf/1) of
+ default ->
+ [];
+ RecBufSz ->
+ [{recbuf, RecBufSz}]
+ end,
+ NetIfSndbuf =
+ case ask("25e. Send buffer size of the agent "
+ "(in bytes) (default/pos integer)?",
+ "default",
+ fun verify_netif_sndbuf/1) of
+ default ->
+ [];
+ SndBufSz ->
+ [{sndbuf, SndBufSz}]
+ end,
+ NetIfFilter =
+ case ask("25f. Do you wish to specify a "
+ "network interface filter module "
+ "(or use default)",
+ "default", fun verify_module/1) of
+ default ->
+ [];
+ NetIfFilterMod ->
+ [{filter, [{module, NetIfFilterMod}]}]
+ end,
+ [{bind_to, NetIfBindTo},
+ {no_reuse, NetIfNoReuse},
+ {req_limit, NetIfReqLimit}] ++
+ NetIfRecbuf ++ NetIfSndbuf ++ NetIfFilter;
+ _ ->
+ []
+ end,
+ NetIf = [{module, NetIfMod},
+ {verbosity, NetIfVerb},
+ {options, NetIfOpts}],
+ [{agent_type, master},
+ {agent_verbosity, MasterAgentVerb},
+ {config, [{dir, ConfigDir},
+ {force_load, ForceLoad},
+ {verbosity, ConfigVerb}]},
+ {multi_threaded, MultiThreaded},
+ {mib_server, [{mibentry_override, MeOverride},
+ {trapentry_override, TrapOverride},
+ {verbosity, MibServerVerb},
+ {cache, MibServerCache}]},
+ {note_store, [{timeout, NoteStoreTimeout},
+ {verbosity, NoteStoreVerb}]},
+ {net_if, NetIf}] ++ ATL;
+ sub ->
+ SubAgentVerb = ask("14. Sub-agent verbosity "
+ "(silence/info/log/debug/trace)?",
+ "silence",
+ fun verify_verbosity/1),
+ [{agent_type, sub},
+ {agent_verbosity, SubAgentVerb},
+ {config, [{dir, ConfigDir}]}]
+ end,
+ SysConfig =
+ [{priority, Prio},
+ {versions, Vsns},
+ {db_dir, DbDir},
+ {mib_storage, MibStorage},
+ {target_cache, [{verbosity, TargetCacheVerb}]},
+ {symbolic_store, [{verbosity, SymStoreVerb}]},
+ {local_db, [{repair, LocalDbRepair},
+ {auto_save, LocalDbAutoSave},
+ {verbosity, LocalDbVerb}]},
+ {error_report_module, ErrorMod}] ++ AgentConfig,
+ {Vsns, ConfigDir, SysConfig}.
+
+
+config_agent_snmp(Dir, Vsns) ->
+ i("~nAgent snmp config: "
+ "~n------------------"),
+ AgentName = guess_agent_name(),
+ EngineName = guess_engine_name(),
+ SysName = ask("1. System name (sysName standard variable)",
+ AgentName, fun verify_system_name/1),
+ EngineID = ask("2. Engine ID (snmpEngineID standard variable)",
+ EngineName, fun verify_engine_id/1),
+ MMS = ask("3. Max message size?", "484",
+ fun verify_max_message_size/1),
+ AgentUDP = ask("4. The UDP port the agent listens to. "
+ "(standard 161)",
+ "4000", fun verify_port_number/1),
+ Host = host(),
+ AgentIP = ask("5. IP address for the agent (only used as id ~n"
+ " when sending traps)", Host, fun verify_address/1),
+ ManagerIP = ask("6. IP address for the manager (only this manager ~n"
+ " will have access to the agent, traps are sent ~n"
+ " to this one)", Host, fun verify_address/1),
+ TrapUdp = ask("7. To what UDP port at the manager should traps ~n"
+ " be sent (standard 162)?", "5000",
+ fun verify_port_number/1),
+ SecType = ask("8. Do you want a none- minimum- or semi-secure"
+ " configuration? ~n"
+ " Note that if you chose v1 or v2, you won't get any"
+ " security for these~n"
+ " requests (none, minimum, semi_des, semi_aes)",
+ "minimum",
+ fun verify_sec_type/1),
+ Passwd =
+ case lists:member(v3, Vsns) and (SecType /= none) of
+ true ->
+ ensure_crypto_started(),
+ ask("8b. Give a password of at least length 8. It is used to "
+ "generate ~n"
+ " private keys for the configuration: ",
+ mandatory, fun verify_passwd/1);
+ false ->
+ ""
+ end,
+ NotifType =
+ case lists:member(v1, Vsns) of
+ true ->
+ Overwrite = ask("9. Current configuration files will "
+ "now be overwritten. "
+ "Ok (y/n)?", "y", fun verify_yes_or_no/1),
+ case Overwrite of
+ no ->
+ error(overwrite_not_allowed);
+ yes ->
+ ok
+ end,
+ trap;
+ false ->
+ NT = ask("9. Should notifications be sent as traps or informs "
+ "(trap/inform)?", "trap", fun verify_notif_type/1),
+ Overwrite = ask("10. Current configuration files will "
+ "now be overwritten. "
+ "Ok (y/n)?", "y", fun verify_yes_or_no/1),
+ case Overwrite of
+ no ->
+ error(overwrite_not_allowed);
+ yes ->
+ ok
+ end,
+ NT
+ end,
+ case (catch write_agent_snmp_files(Dir,
+ Vsns, ManagerIP, TrapUdp,
+ AgentIP, AgentUDP,
+ SysName, NotifType, SecType,
+ Passwd, EngineID, MMS)) of
+ ok ->
+ i("~n- - - - - - - - - - - - -"),
+ i("Info: 1. SecurityName \"initial\" has noAuthNoPriv read access~n"
+ " and authenticated write access to the \"restricted\"~n"
+ " subtree."),
+ i(" 2. SecurityName \"all-rights\" has noAuthNoPriv "
+ "read/write~n"
+ " access to the \"internet\" subtree."),
+ i(" 3. Standard traps are sent to the manager."),
+ case lists:member(v1, Vsns) or lists:member(v2, Vsns) of
+ true ->
+ i(" 4. Community \"public\" is mapped to security name"
+ " \"initial\"."),
+ i(" 5. Community \"all-rights\" is mapped to security"
+ " name \"all-rights\".");
+ false ->
+ ok
+ end,
+ i("The following agent files were written: agent.conf, "
+ "community.conf,~n"
+ "standard.conf, target_addr.conf, "
+ "target_params.conf, ~n"
+ "notify.conf" ++
+ case lists:member(v3, Vsns) of
+ true -> ", vacm.conf and usm.conf";
+ false -> " and vacm.conf"
+ end),
+ i("- - - - - - - - - - - - -"),
+ ok;
+ E ->
+ error({failed_writing_files, E})
+ end.
+
+
+%% -------------------
+
+config_manager_sys() ->
+ i("~nManager system config: "
+ "~n----------------------"),
+ Prio = ask("1. Manager process priority (low/normal/high)",
+ "normal", fun verify_prio/1),
+ Vsns = ask("2. What SNMP version(s) should be used "
+ "(1,2,3,1&2,1&2&3,2&3)?", "3", fun verify_versions/1),
+ {ok, DefDir} = file:get_cwd(),
+ {DefConfDir, Warning} = default_manager_dir(DefDir),
+ ConfQ =
+ if
+ Warning == "" ->
+ "3. Configuration directory (absolute path)?";
+ true ->
+ lists:flatten(
+ io_lib:format("3. Configuration directory (absolute path)?"
+ "~n ~s", [Warning]))
+ end,
+ ConfigDir = ask(ConfQ, DefConfDir, fun verify_dir/1),
+ ConfigVerb = ask("4. Config verbosity "
+ "(silence/info/log/debug/trace)?",
+ "silence",
+ fun verify_verbosity/1),
+ ConfigDbDir = ask("5. Database directory (absolute path)?",
+ DefDir, fun verify_dir/1),
+ ConfigDbRepair = ask("6. Database repair "
+ "(true/false/force)?", "true",
+ fun verify_dets_repair/1),
+ ConfigDbAutoSave = ask("7. Database auto save "
+ "(infinity/milli seconds)?",
+ "5000", fun verify_dets_auto_save/1),
+ IRB =
+ case ask("8. Inform request behaviour (auto/user)?",
+ "auto", fun verify_irb/1) of
+ auto ->
+ auto;
+ user ->
+ case ask("8b. Use default GC timeout"
+ "(default/seconds)?",
+ "default", fun verify_irb_user/1) of
+ default ->
+ user;
+ IrbGcTo ->
+ {user, IrbGcTo}
+ end
+ end,
+ ServerVerb = ask("9. Server verbosity "
+ "(silence/info/log/debug/trace)?",
+ "silence",
+ fun verify_verbosity/1),
+ ServerTimeout = ask("10. Server GC timeout?", "30000",
+ fun verify_timeout/1),
+ NoteStoreVerb = ask("11. Note store verbosity "
+ "(silence/info/log/debug/trace)?",
+ "silence",
+ fun verify_verbosity/1),
+ NoteStoreTimeout = ask("12. Note store GC timeout?", "30000",
+ fun verify_timeout/1),
+ NetIfMod = ask("13. Which network interface module shall be used?",
+ "snmpm_net_if", fun verify_module/1),
+ NetIfVerb = ask("14. Network interface verbosity "
+ "(silence/info/log/debug/trace)?", "silence",
+ fun verify_verbosity/1),
+ NetIfBindTo = ask("15. Bind the manager IP address "
+ "(true/false)?",
+ "false", fun verify_bool/1),
+ NetIfNoReuse = ask("16. Shall the manager IP address and port "
+ "be not reusable (true/false)?",
+ "false", fun verify_bool/1),
+ NetIfRecbuf =
+ case ask("17. Receive buffer size of the manager (in bytes) "
+ "(default/pos integer)?", "default",
+ fun verify_netif_recbuf/1) of
+ default ->
+ [];
+ RecBufSz ->
+ [{recbuf, RecBufSz}]
+ end,
+ NetIfSndbuf =
+ case ask("18. Send buffer size of the manager (in bytes) "
+ "(default/pos integer)?", "default",
+ fun verify_netif_sndbuf/1) of
+ default ->
+ [];
+ SndBufSz ->
+ [{sndbuf, SndBufSz}]
+ end,
+ NetIfOpts =
+ [{bind_to, NetIfBindTo},
+ {no_reuse, NetIfNoReuse}] ++ NetIfRecbuf ++ NetIfSndbuf,
+ NetIf =
+ [{module, NetIfMod},
+ {verbosity, NetIfVerb},
+ {options, NetIfOpts}],
+ ATL =
+ case ask("19. Shall the manager use an audit trail log "
+ "(y/n)?",
+ "n", fun verify_yes_or_no/1) of
+ yes ->
+ ATLDir = ask("19b. Where to store the "
+ "audit trail log?",
+ DefDir, fun verify_dir/1),
+ ATLMaxFiles = ask("19c. Max number of files?",
+ "10",
+ fun verify_pos_integer/1),
+ ATLMaxBytes = ask("19d. Max size (in bytes) "
+ "of each file?",
+ "10240",
+ fun verify_pos_integer/1),
+ ATLSize = {ATLMaxBytes, ATLMaxFiles},
+ ATLRepair = ask("19e. Audit trail log repair "
+ "(true/false/truncate/snmp_repair)?", "true",
+ fun verify_atl_repair/1),
+ [{audit_trail_log, [{dir, ATLDir},
+ {size, ATLSize},
+ {repair, ATLRepair}]}];
+ no ->
+ []
+ end,
+ DefUser =
+ case ask("20. Do you wish to assign a default user [yes] or use~n"
+ " the default settings [no] (y/n)?", "n",
+ fun verify_yes_or_no/1) of
+ yes ->
+ DefUserMod = ask("20b. Default user module?",
+ "snmpm_user_default",
+ fun verify_module/1),
+ DefUserData = ask("20c. Default user data?", "undefined",
+ fun verify_user_data/1),
+ [{def_user_mod, DefUserMod},
+ {def_user_data, DefUserData}];
+ no ->
+ []
+ end,
+ SysConfig =
+ [{priority, Prio},
+ {versions, Vsns},
+ {config, [{dir, ConfigDir},
+ {verbosity, ConfigVerb},
+ {db_dir, ConfigDbDir},
+ {repair, ConfigDbRepair},
+ {auto_save, ConfigDbAutoSave}]},
+ {inform_request_behaviour, IRB},
+ {mibs, []},
+ {server, [{timeout, ServerTimeout},
+ {verbosity, ServerVerb}]},
+ {note_store, [{timeout, NoteStoreTimeout},
+ {verbosity, NoteStoreVerb}]},
+ {net_if, NetIf}] ++ ATL ++ DefUser,
+ {Vsns, ConfigDir, SysConfig}.
+
+
+config_manager_snmp(Dir, Vsns) ->
+ i("~nManager snmp config: "
+ "~n--------------------"),
+ EngineName = guess_engine_name(),
+ EngineID = ask("1. Engine ID (snmpEngineID standard variable)",
+ EngineName, fun verify_engine_id/1),
+ MMS = ask("2. Max message size?", "484",
+ fun verify_max_message_size/1),
+ Host = host(),
+ IP = ask("3. IP address for the manager (only used as id ~n"
+ " when sending requests)",
+ Host, fun verify_address/1),
+ Port = ask("4. Port number (standard 162)?", "5000",
+ fun verify_port_number/1),
+ Users = config_manager_snmp_users([]),
+ Agents = config_manager_snmp_agents([]),
+ Usms = config_manager_snmp_usms([]),
+ Overwrite = ask("8. Current configuration files will now be overwritten. "
+ "Ok (y/n)?", "y", fun verify_yes_or_no/1),
+ case Overwrite of
+ no ->
+ error(overwrite_not_allowed);
+ yes ->
+ ok
+ end,
+ case (catch write_manager_snmp_files(Dir,
+ IP, Port, MMS, EngineID,
+ Users, Agents, Usms)) of
+ ok ->
+ i("~n- - - - - - - - - - - - -"),
+ i("The following manager files were written: "
+ "manager.conf, agents.conf " ++
+ case lists:member(v3, Vsns) of
+ true ->
+ ", users.conf and usm.conf";
+ false ->
+ " and users.conf"
+ end),
+ i("- - - - - - - - - - - - -"),
+ ok;
+ E ->
+ error({failed_writing_files, E})
+ end.
+
+
+config_manager_snmp_users(Users) ->
+ case ask("5. Configure a user of this manager (y/n)?",
+ "y", fun verify_yes_or_no/1) of
+ yes ->
+ User = config_manager_snmp_user(),
+ config_manager_snmp_users([User|Users]);
+ no ->
+ lists:reverse(Users)
+ end.
+
+config_manager_snmp_user() ->
+ UserId = ask("5b. User id?", mandatory,
+ fun verify_user_id/1),
+ UserMod = ask("5c. User callback module?", mandatory,
+ fun verify_module/1),
+ UserData = ask("5d. User (callback) data?", "undefined",
+ fun verify_user_data/1),
+ {UserId, UserMod, UserData}.
+
+
+config_manager_snmp_agents(Agents) ->
+ case ask("6. Configure an agent handled by this manager (y/n)?",
+ "y", fun verify_yes_or_no/1) of
+ yes ->
+ Agent = config_manager_snmp_agent(),
+ config_manager_snmp_agents([Agent|Agents]);
+ no ->
+ lists:reverse(Agents)
+ end.
+
+config_manager_snmp_agent() ->
+ UserId = ask("6b. User id?", mandatory,
+ fun verify_user_id/1),
+ TargetName = ask("6c. Target name?", guess_agent_name(),
+ fun verify_system_name/1),
+ Version = ask("6d. Version (1/2/3)?", "1",
+ fun verify_version/1),
+ Comm = ask("6e. Community string ?", "public",
+ fun verify_community/1),
+ EngineID = ask("6f. Engine ID (snmpEngineID standard variable)",
+ guess_engine_name(), fun verify_engine_id/1),
+ IP = ask("6g. IP address for the agent", host(),
+ fun verify_address/1),
+ Port = ask("6h. The UDP port the agent listens to. "
+ "(standard 161)", "4000", fun verify_port_number/1),
+ Timeout = ask("6i. Retransmission timeout (infinity/pos integer)?",
+ "infinity", fun verify_retransmission_timeout/1),
+ MMS = ask("6j. Max message size?", "484",
+ fun verify_max_message_size/1),
+ SecModel = ask("6k. Security model (any/v1/v2c/usm)?", "any",
+ fun verify_sec_model/1),
+ SecName = ask("6l. Security name?", "\"initial\"",
+ fun verify_sec_name/1),
+ SecLevel = ask("6m. Security level (noAuthNoPriv/authNoPriv/authPriv)?",
+ "noAuthNoPriv", fun verify_sec_level/1),
+ {UserId,
+ TargetName, Comm, IP, Port, EngineID, Timeout, MMS,
+ Version, SecModel, SecName, SecLevel}.
+
+
+config_manager_snmp_usms(Usms) ->
+ case ask("7. Configure an usm user handled by this manager (y/n)?",
+ "y", fun verify_yes_or_no/1) of
+ yes ->
+ Usm = config_manager_snmp_usm(),
+ config_manager_snmp_usms([Usm|Usms]);
+ no ->
+ lists:reverse(Usms)
+ end.
+
+config_manager_snmp_usm() ->
+ EngineID = ask("7a. Engine ID", guess_engine_name(),
+ fun verify_engine_id/1),
+ UserName = ask("7b. User name?", mandatory, fun verify_usm_name/1),
+ SecName = ask("7c. Security name?", UserName,
+ fun verify_usm_sec_name/1),
+ AuthP = ask("7d. Authentication protocol (no/sha/md5)?", "no",
+ fun verify_usm_auth_protocol/1),
+ AuthKey = ask_auth_key("7e", AuthP),
+ PrivP = ask("7e. Priv protocol (no/des/aes)?", "no",
+ fun verify_usm_priv_protocol/1),
+ PrivKey = ask_priv_key("7f", PrivP),
+ {EngineID, UserName,
+ SecName, AuthP, AuthKey, PrivP, PrivKey}.
+
+
+%% ------------------------------------------------------------------
+
+is_members([], _Files) ->
+ true;
+is_members([H|T], Files) ->
+ lists:member(H, Files) andalso is_members(T, Files).
+
+default_agent_dir(DefDir) ->
+ default_dir("agent", DefDir).
+
+default_manager_dir(DefDir) ->
+ default_dir("manager", DefDir).
+
+default_dir(Component, DefDir) ->
+ %% Look for the component dir, if found use that as default
+ {ok, Files} = file:list_dir(DefDir),
+ case lists:member(Component, Files) of
+ true ->
+ {filename:join(DefDir, Component), ""};
+ false ->
+ %% No luck,
+ %% so check if cwd contains either agent and/or
+ %% manager config files. If it does, issue a warning
+
+ %% Check for presence of agent config files
+ %% If all the agent config files are present,
+ %% issue a warning
+ AgentConfs =
+ [
+ "agent.conf",
+ "context.conf",
+ "community.conf",
+ "notify.conf",
+ "standard.conf",
+ "target_params.conf",
+ "target_addr.conf",
+ "usm.conf",
+ "vacm.conf"
+ ],
+ IsAgentDir = is_members(AgentConfs, Files),
+
+ %% Check for presence of manager config files
+ %% If all the manager config files are present,
+ %% issue a warning
+ ManagerConfs =
+ [
+ "agents.conf",
+ "manager.conf",
+ "users.conf",
+ "usm.conf"
+ ],
+ IsManagerDir = is_members(ManagerConfs, Files),
+ Warning =
+ if
+ IsAgentDir and IsManagerDir ->
+ "Note that the default directory contains both agent and manager config files";
+ IsAgentDir ->
+ "Note that the default directory contains agent config files";
+ IsManagerDir ->
+ "Note that the default directory contains manager config files";
+ true ->
+ ""
+ end,
+ {DefDir, Warning}
+ end.
+
+
+%% ------------------------------------------------------------------
+
+ask_auth_key(_Prefix, usmNoAuthProtocol) ->
+ "";
+ask_auth_key(Prefix, usmHMACSHAAuthProtocol) ->
+ ask(Prefix ++ " Authentication [sha] key (length 0 or 20)?", "\"\"",
+ fun verify_usm_auth_sha_key/1);
+ask_auth_key(Prefix, usmHMACMD5AuthProtocol) ->
+ ask(Prefix ++ " Authentication [md5] key (length 0 or 16)?", "\"\"",
+ fun verify_usm_auth_md5_key/1).
+
+ask_priv_key(_Prefix, usmNoPrivProtocol) ->
+ "";
+ask_priv_key(Prefix, usmDESPrivProtocol) ->
+ ask(Prefix ++ " Priv [des] key (length 0 or 16)?", "\"\"",
+ fun verify_usm_priv_des_key/1);
+ask_priv_key(Prefix, usmAesCfb128Protocol) ->
+ ask(Prefix ++ " Priv [aes] key (length 0 or 16)?", "\"\"",
+ fun verify_usm_priv_aes_key/1).
+
+
+%% ------------------------------------------------------------------
+
+verify_yes_or_no("y") ->
+ {ok, yes};
+verify_yes_or_no("yes") ->
+ {ok, yes};
+verify_yes_or_no("n") ->
+ {ok, no};
+verify_yes_or_no("no") ->
+ {ok, no};
+verify_yes_or_no(YON) ->
+ {error, "invalid yes or no: " ++ YON}.
+
+
+verify_prio("low") ->
+ {ok, low};
+verify_prio("normal") ->
+ {ok, normal};
+verify_prio("high") ->
+ {ok, high};
+verify_prio(Prio) ->
+ {error, "invalid process priority: " ++ Prio}.
+
+
+verify_system_name(Name) -> {ok, Name}.
+
+
+verify_engine_id(Name) -> {ok, Name}.
+
+
+verify_max_message_size(MMS) ->
+ case (catch list_to_integer(MMS)) of
+ I when is_integer(I) andalso (I >= 484) ->
+ {ok, I};
+ I when is_integer(I) ->
+ {error, "invalid max message size (must be atleast 484): " ++ MMS};
+ _ ->
+ {error, "invalid max message size: " ++ MMS}
+ end.
+
+
+verify_port_number(P) ->
+ case (catch list_to_integer(P)) of
+ N when is_integer(N) andalso (N > 0) ->
+ {ok, N};
+ _ ->
+ {error, "invalid port number: " ++ P}
+ end.
+
+
+verify_versions("1") -> {ok, [v1]};
+verify_versions("2") -> {ok, [v2]};
+verify_versions("3") -> {ok, [v3]};
+verify_versions("1&2") -> {ok, [v1,v2]};
+verify_versions("1&3") -> {ok, [v1,v3]};
+verify_versions("2&3") -> {ok, [v2,v3]};
+verify_versions("1&2&3") -> {ok, [v1,v2,v3]};
+verify_versions(V) -> {error, "incorrect version(s): " ++ V}.
+
+verify_version("1") -> {ok, v1};
+verify_version("2") -> {ok, v2};
+verify_version("3") -> {ok, v3};
+verify_version(V) -> {error, "incorrect version: " ++ V}.
+
+
+verify_passwd(Passwd) when length(Passwd) >= 8 ->
+ {ok, Passwd};
+verify_passwd(_P) ->
+ {error, "invalid password"}.
+
+
+verify_dir(Dir) ->
+ case filename:pathtype(Dir) of
+ absolute ->
+ case file:read_file_info(Dir) of
+ {ok, #file_info{type = directory}} ->
+ {ok, snmp_misc:ensure_trailing_dir_delimiter(Dir)};
+ {ok, _FileInfo} ->
+ {error, Dir ++ " is not a directory"};
+ _ ->
+ {error, "invalid directory: " ++ Dir}
+ end;
+ _E ->
+ {error, "invalid directory (not absolute): " ++ Dir}
+ end.
+
+
+verify_notif_type("trap") -> {ok, trap};
+verify_notif_type("inform") -> {ok, inform};
+verify_notif_type(NT) -> {error, "invalid notifcation type: " ++ NT}.
+
+
+verify_sec_type("none") -> {ok, none};
+verify_sec_type("minimum") -> {ok, minimum};
+verify_sec_type("semi_des") -> {ok, {semi, des}};
+verify_sec_type("semi_aes") -> {ok, {semi, aes}};
+verify_sec_type(ST) -> {error, "invalid security type: " ++ ST}.
+
+
+verify_address(A) ->
+ case (catch snmp_misc:ip(A)) of
+ {ok, IP} ->
+ {ok, tuple_to_list(IP)};
+ {error, _} ->
+ {error, "invalid address: " ++ A};
+ _E ->
+ {error, "invalid address: " ++ A}
+ end.
+
+
+verify_mib_storage_type("m") ->
+ {ok, mnesia};
+verify_mib_storage_type("mnesia") ->
+ {ok, mnesia};
+verify_mib_storage_type("d") ->
+ {ok, dets};
+verify_mib_storage_type("dets") ->
+ {ok, dets};
+verify_mib_storage_type("e") ->
+ {ok, ets};
+verify_mib_storage_type("ets") ->
+ {ok, ets};
+verify_mib_storage_type(T) ->
+ {error, "invalid mib storage type: " ++ T}.
+
+verify_mib_storage_action("default") ->
+ {ok, default};
+verify_mib_storage_action("clear") ->
+ {ok, clear};
+verify_mib_storage_action("keep") ->
+ {ok, keep};
+verify_mib_storage_action(A) ->
+ {error, "invalid mib storage action: " ++ A}.
+
+
+verify_verbosity("silence") ->
+ {ok, silence};
+verify_verbosity("info") ->
+ {ok, info};
+verify_verbosity("log") ->
+ {ok, log};
+verify_verbosity("debug") ->
+ {ok, debug};
+verify_verbosity("trace") ->
+ {ok, trace};
+verify_verbosity(V) ->
+ {error, "invalid verbosity: " ++ V}.
+
+
+verify_dets_repair("true") ->
+ {ok, true};
+verify_dets_repair("false") ->
+ {ok, false};
+verify_dets_repair("force") ->
+ {ok, force};
+verify_dets_repair(R) ->
+ {error, "invalid repair: " ++ R}.
+
+verify_dets_auto_save("infinity") ->
+ {ok, infinity};
+verify_dets_auto_save(I0) ->
+ case (catch list_to_integer(I0)) of
+ I when is_integer(I) andalso (I > 0) ->
+ {ok, I};
+ _ ->
+ {error, "invalid auto save timeout time: " ++ I0}
+ end.
+
+
+%% I know that this is a little of the edge, but...
+verify_module(M0) ->
+ case (catch list_to_atom(M0)) of
+ M when is_atom(M) ->
+ {ok, M};
+ _ ->
+ {error, "invalid module: " ++ M0}
+ end.
+
+
+verify_agent_type("master") ->
+ {ok, master};
+verify_agent_type("sub") ->
+ {ok, sub};
+verify_agent_type(AT) ->
+ {error, "invalid agent type: " ++ AT}.
+
+
+verify_bool("true") ->
+ {ok, true};
+verify_bool("false") ->
+ {ok, false};
+verify_bool(B) ->
+ {error, "invalid boolean: " ++ B}.
+
+
+verify_timeout(T0) ->
+ case (catch list_to_integer(T0)) of
+ T when is_integer(T) andalso (T > 0) ->
+ {ok, T};
+ _ ->
+ {error, "invalid timeout time: '" ++ T0 ++ "'"}
+ end.
+
+
+verify_retransmission_timeout("infinity") ->
+ {ok, infinity};
+verify_retransmission_timeout([${|R] = Timer) ->
+ case lists:reverse(R) of
+ [$}|R2] ->
+ case string:tokens(lists:reverse(R2), ", ") of
+ [WaitForStr, FactorStr, IncrStr, RetryStr] ->
+ WaitFor = incr_timer_value(WaitForStr, 1),
+ Factor = incr_timer_value(FactorStr, 1),
+ Incr = incr_timer_value(IncrStr, 0),
+ Retry = incr_timer_value(RetryStr, 0),
+ {ok, {WaitFor, Factor, Incr, Retry}};
+ _ ->
+ {error, "invalid retransmission timer: '" ++ Timer ++ "'"}
+ end;
+ _ ->
+ {error, "invalid retransmission timer: '" ++ Timer ++ "'"}
+ end;
+verify_retransmission_timeout(T0) ->
+ case (catch list_to_integer(T0)) of
+ T when is_integer(T) andalso (T > 0) ->
+ {ok, T};
+ _ ->
+ {error, "invalid timeout time: '" ++ T0 ++ "'"}
+ end.
+
+incr_timer_value(Str, Min) ->
+ case (catch list_to_integer(Str)) of
+ I when is_integer(I) andalso (I >= Min) ->
+ I;
+ I when is_integer(I) ->
+ E = lists:flatten(io_lib:format("invalid incremental timer value "
+ "(min value is ~w): " ++ Str,
+ [Min])),
+ error(E);
+ _ ->
+ error("invalid incremental timer value: " ++ Str)
+ end.
+
+
+%% verify_atl_type("read") ->
+%% {ok, read};
+verify_atl_type("write") ->
+ {ok, write};
+verify_atl_type("read_write") ->
+ {ok, read_write};
+verify_atl_type(T) ->
+ {error, "invalid log type: " ++ T}.
+
+verify_atl_repair("true") ->
+ {ok, true};
+verify_atl_repair("false") ->
+ {ok, false};
+verify_atl_repair("truncate") ->
+ {ok, truncate};
+verify_atl_repair("snmp_repair") ->
+ {ok, snmp_repair};
+verify_atl_repair(R) ->
+ {error, "invalid audit trail log repair: " ++ R}.
+
+
+verify_pos_integer(I0) ->
+ case (catch list_to_integer(I0)) of
+ I when is_integer(I) andalso (I > 0) ->
+ {ok, I};
+ _ ->
+ {error, "invalid integer value: " ++ I0}
+ end.
+
+
+verify_netif_req_limit("infinity") ->
+ {ok, infinity};
+verify_netif_req_limit(I0) ->
+ case (catch list_to_integer(I0)) of
+ I when is_integer(I) andalso (I > 0) ->
+ {ok, I};
+ _ ->
+ {error, "invalid network interface request limit: " ++ I0}
+ end.
+
+verify_netif_recbuf(Val) ->
+ verify_netif_recbuf_or_sndbuf(Val, "recbuf").
+
+verify_netif_sndbuf(Val) ->
+ verify_netif_recbuf_or_sndbuf(Val, "sndbuf").
+
+verify_netif_recbuf_or_sndbuf("default", _) ->
+ {ok, default};
+verify_netif_recbuf_or_sndbuf(I0, Buf) ->
+ case (catch list_to_integer(I0)) of
+ I when is_integer(I) andalso (I > 0) ->
+ {ok, I};
+ _ ->
+ {error, "invalid network interface " ++ Buf ++ " size: " ++ I0}
+ end.
+
+
+verify_irb("auto") ->
+ {ok, auto};
+verify_irb("user") ->
+ {ok, user};
+verify_irb(IRB) ->
+ E = lists:flatten(io_lib:format("invalid irb: ~p", [IRB])),
+ {error, E}.
+
+
+verify_irb_user("default") ->
+ {ok, default};
+verify_irb_user(TO) ->
+ case (catch list_to_integer(TO)) of
+ I when is_integer(I) andalso (I > 0) ->
+ {ok, I*1000}; % Time is given in seconds
+ _ ->
+ {error, "invalid IRB GC time: " ++ TO}
+ end.
+
+
+
+verify_user_id(UserId) when is_list(UserId) ->
+ case (catch list_to_atom(UserId)) of
+ A when is_atom(A) ->
+ {ok, A};
+ _ ->
+ {error, "invalid user id: " ++ UserId}
+ end;
+verify_user_id(UserId) when is_atom(UserId) ->
+ {ok, UserId};
+verify_user_id(UserId) ->
+ E = lists:flatten(io_lib:format("invalid user id: ~p", [UserId])),
+ {error, E}.
+
+verify_user_data("undefined") ->
+ {ok, undefined};
+verify_user_data(UserData) ->
+ {ok, UserData}.
+
+
+verify_community("\"\"") ->
+ {ok, ""};
+verify_community(Comm) ->
+ {ok, Comm}.
+
+
+% verify_context_name("\"\"") ->
+% {ok, ""};
+% verify_context_name(Ctx) ->
+% {ok, Ctx}.
+
+
+% verify_mp_model("v1") ->
+% {ok, v1};
+% verify_mp_model("v2c") ->
+% {ok, v2c};
+% verify_mp_model("v3") ->
+% {ok, v3};
+% verify_mp_model(M) ->
+% {error, "invalid mp model: " ++ M}.
+
+
+verify_sec_model("any") ->
+ {ok, any};
+verify_sec_model("v1") ->
+ {ok, v1};
+verify_sec_model("v2c") ->
+ {ok, v2c};
+verify_sec_model("usm") ->
+ {ok, usm};
+verify_sec_model(M) ->
+ {error, "invalid sec model: " ++ M}.
+
+verify_sec_name("\"initial\"") ->
+ {ok, "initial"};
+verify_sec_name(N) ->
+ {ok, N}.
+
+
+verify_sec_level("noAuthNoPriv") ->
+ {ok, noAuthNoPriv};
+verify_sec_level("authNoPriv") ->
+ {ok, authNoPriv};
+verify_sec_level("authPriv") ->
+ {ok, authPriv};
+verify_sec_level(L) ->
+ {error, "invalid sec level: " ++ L}.
+
+
+verify_usm_name(Name) ->
+ {ok, Name}.
+
+verify_usm_sec_name(Name) ->
+ {ok, Name}.
+
+
+verify_usm_auth_protocol("no") ->
+ {ok, usmNoAuthProtocol};
+verify_usm_auth_protocol("sha") ->
+ {ok, usmHMACSHAAuthProtocol};
+verify_usm_auth_protocol("md5") ->
+ {ok, usmHMACMD5AuthProtocol};
+verify_usm_auth_protocol(AuthP) ->
+ {error, "invalid auth protocol: " ++ AuthP}.
+
+verify_usm_auth_sha_key(Key) ->
+ verify_usm_key("auth sha", Key, 20).
+
+verify_usm_auth_md5_key(Key) ->
+ verify_usm_key("auth md5", Key, 16).
+
+verify_usm_priv_protocol("no") ->
+ {ok, usmNoPrivProtocol};
+verify_usm_priv_protocol("des") ->
+ {ok, usmDESPrivProtocol};
+verify_usm_priv_protocol("aes") ->
+ {ok, usmAesCfb128Protocol};
+verify_usm_priv_protocol(AuthP) ->
+ {error, "invalid priv protocol: " ++ AuthP}.
+
+verify_usm_priv_des_key(Key) ->
+ verify_usm_key("priv des", Key, 16).
+
+verify_usm_priv_aes_key(Key) ->
+ verify_usm_key("priv aes", Key, 16).
+
+verify_usm_key(_What, "\"\"", _ExpectLength) ->
+ {ok, ""};
+verify_usm_key(_What, Key, ExpectLength) when length(Key) =:= ExpectLength ->
+ {ok, Key};
+verify_usm_key(What, [$[|RestKey] = Key0, ExpectLength) ->
+ case lists:reverse(RestKey) of
+ [$]|RevRestKey] ->
+ Key1 = lists:reverse(RevRestKey),
+ verify_usm_key2(What, Key1, ExpectLength);
+ _ ->
+ %% Its not a list ([...]) and its not the correct length, ...
+ {error, "invalid " ++ What ++ " key length: " ++ Key0}
+ end;
+verify_usm_key(What, Key, ExpectLength) ->
+ verify_usm_key2(What, Key, ExpectLength).
+
+verify_usm_key2(What, Key0, ExpectLength) ->
+ case string:tokens(Key0, [$,]) of
+ Key when length(Key) =:= ExpectLength ->
+ convert_usm_key(Key, []);
+ _ ->
+ {error, "invalid " ++ What ++ " key length: " ++ Key0}
+ end.
+
+convert_usm_key([], Acc) ->
+ {ok, lists:reverse(Acc)};
+convert_usm_key([I|Is], Acc) ->
+ case (catch list_to_integer(I)) of
+ Int when is_integer(Int) ->
+ convert_usm_key(Is, [Int|Acc]);
+ _Err ->
+ {error, "invalid key number: " ++ I}
+ end.
+
+
+% ip(Host) ->
+% case catch snmp_misc:ip(Host) of
+% {ok, IPtuple} -> tuple_to_list(IPtuple);
+% {error, Reason} -> throw({error, Reason});
+% _Q -> throw({error, {"ip conversion failed", Host}})
+% end.
+
+% make_ip(Str) ->
+% case catch snmp_misc:ip(Str) of
+% {ok, IPtuple} -> tuple_to_list(IPtuple);
+% _Q -> ip(Str)
+% end.
+
+
+print_q(Q, mandatory) ->
+ io:format(Q ++ " ",[]);
+print_q(Q, Default) when is_list(Default) ->
+ io:format(Q ++ " [~s] ",[Default]).
+
+%% Defval = string() | mandatory
+ask(Q, Default, Verify) when is_list(Q) andalso is_function(Verify) ->
+ print_q(Q, Default),
+ PrelAnsw = io:get_line(''),
+ Answer =
+ case remove_newline(PrelAnsw) of
+ "" when Default =/= mandatory -> Default;
+ "" -> ask(Q, Default, Verify);
+ A -> A
+ end,
+ case (catch Verify(Answer)) of
+ {ok, Answer2} ->
+ Answer2;
+ {error, ReasonStr} ->
+ i("ERROR: " ++ ReasonStr),
+ ask(Q, Default, Verify)
+ end.
+
+
+host() ->
+ case (catch inet:gethostname()) of
+ {ok, Name} ->
+ case (catch inet:getaddr(Name, inet)) of
+ {ok, Addr} when is_tuple(Addr) ->
+ lists:flatten(
+ io_lib:format("~w.~w.~w.~w", tuple_to_list(Addr)));
+ _ ->
+ "127.0.0.1"
+ end;
+ _ ->
+ "127.0.0.1"
+ end.
+
+guess_agent_name() ->
+ case os:type() of
+ {unix, _} ->
+ lists:append(remove_newline(os:cmd("echo $USER")), "'s agent");
+ {_,_} -> "my agent"
+ end.
+
+guess_engine_name() ->
+ case os:type() of
+ {unix, _} ->
+ lists:append(remove_newline(os:cmd("echo $USER")), "'s engine");
+ {_,_} -> "my engine"
+ end.
+
+% guess_user_id() ->
+% case os:type() of
+% {unix, _} ->
+% lists:append(remove_newline(os:cmd("echo $USER")), "'s user");
+% {_,_} -> "user_id"
+% end.
+
+
+remove_newline(Str) ->
+ lists:delete($\n, Str).
+
+
+%%======================================================================
+%% File generation
+%%======================================================================
+
+%%----------------------------------------------------------------------
+%% Dir: string() (ex: "../conf/")
+%% ManagerIP, AgentIP: [int(),int(),int(),int()]
+%% TrapUdp, AgentUDP: integer()
+%% SysName: string()
+%%----------------------------------------------------------------------
+write_agent_snmp_files(Dir, Vsns, ManagerIP, TrapUdp,
+ AgentIP, AgentUDP, SysName)
+ when is_list(Dir) andalso
+ is_list(Vsns) andalso
+ is_list(ManagerIP) andalso
+ is_integer(TrapUdp) andalso
+ is_list(AgentIP) andalso
+ is_integer(AgentUDP) andalso
+ is_list(SysName) ->
+ write_agent_snmp_files(Dir, Vsns, ManagerIP, TrapUdp, AgentIP, AgentUDP,
+ SysName, "trap", none, "", "agentEngine", 484).
+
+%%
+%% ----- Agent config files generator functions -----
+%%
+
+write_agent_snmp_files(Dir, Vsns, ManagerIP, TrapUdp, AgentIP, AgentUDP,
+ SysName, NotifType, SecType, Passwd, EngineID, MMS) ->
+ write_agent_snmp_conf(Dir, AgentIP, AgentUDP, EngineID, MMS),
+ write_agent_snmp_context_conf(Dir),
+ write_agent_snmp_community_conf(Dir),
+ write_agent_snmp_standard_conf(Dir, SysName),
+ write_agent_snmp_target_addr_conf(Dir, ManagerIP, TrapUdp, Vsns),
+ write_agent_snmp_target_params_conf(Dir, Vsns),
+ write_agent_snmp_notify_conf(Dir, NotifType),
+ write_agent_snmp_usm_conf(Dir, Vsns, EngineID, SecType, Passwd),
+ write_agent_snmp_vacm_conf(Dir, Vsns, SecType),
+ ok.
+
+
+%%
+%% ------ [agent] agent.conf ------
+%%
+
+write_agent_snmp_conf(Dir, AgentIP, AgentUDP, EngineID, MMS) ->
+ Comment =
+"%% This file defines the Agent local configuration info\n"
+"%% The data is inserted into the snmpEngine* variables defined\n"
+"%% in SNMP-FRAMEWORK-MIB, and the intAgent* variables defined\n"
+"%% in OTP-SNMPEA-MIB.\n"
+"%% Each row is a 2-tuple:\n"
+"%% {AgentVariable, Value}.\n"
+"%% For example\n"
+"%% {intAgentUDPPort, 4000}.\n"
+"%% The ip address for the agent is sent as id in traps.\n"
+"%% {intAgentIpAddress, [127,42,17,5]}.\n"
+"%% {snmpEngineID, \"agentEngine\"}.\n"
+"%% {snmpEngineMaxMessageSize, 484}.\n"
+"%%\n\n",
+ Hdr = header() ++ Comment,
+ Conf = [{intAgentUDPPort, AgentUDP},
+ {intAgentIpAddress, AgentIP},
+ {snmpEngineID, EngineID},
+ {snmpEngineMaxMessageSize, MMS}],
+ write_agent_config(Dir, Hdr, Conf).
+
+write_agent_config(Dir, Hdr, Conf) ->
+ snmpa_conf:write_agent_config(Dir, Hdr, Conf).
+
+update_agent_config(Dir, Conf) ->
+ snmpa_conf:append_agent_config(Dir, Conf).
+
+
+%%
+%% ------ [agent] context.conf ------
+%%
+
+write_agent_snmp_context_conf(Dir) ->
+ Comment =
+"%% This file defines the contexts known to the agent.\n"
+"%% The data is inserted into the vacmContextTable defined\n"
+"%% in SNMP-VIEW-BASED-ACM-MIB.\n"
+"%% Each row is a string:\n"
+"%% ContextName.\n"
+"%%\n"
+"%% The empty string is the default context.\n"
+"%% For example\n"
+"%% \"bridge1\".\n"
+"%% \"bridge2\".\n"
+"%%\n\n",
+ Hdr = header() ++ Comment,
+ Conf = [""],
+ write_agent_context_config(Dir, Hdr, Conf).
+
+write_agent_context_config(Dir, Hdr, Conf) ->
+ snmpa_conf:write_context_config(Dir, Hdr, Conf).
+
+update_agent_context_config(Dir, Conf) ->
+ snmpa_conf:append_context_config(Dir, Conf).
+
+
+%%
+%% ------ community.conf ------
+%%
+
+write_agent_snmp_community_conf(Dir) ->
+ Comment =
+"%% This file defines the community info which maps to VACM parameters.\n"
+"%% The data is inserted into the snmpCommunityTable defined\n"
+"%% in SNMP-COMMUNITY-MIB.\n"
+"%% Each row is a 5-tuple:\n"
+"%% {CommunityIndex, CommunityName, SecurityName, ContextName, TransportTag}.\n"
+"%% For example\n"
+"%% {\"1\", \"public\", \"initial\", \"\", \"\"}.\n"
+"%% {\"2\", \"secret\", \"secret_name\", \"\", \"tag\"}.\n"
+"%% {\"3\", \"bridge1\", \"initial\", \"bridge1\", \"\"}.\n"
+"%%\n\n",
+ Hdr = header() ++ Comment,
+ Conf = [{"public", "public", "initial", "", ""},
+ {"all-rights", "all-rights", "all-rights", "", ""},
+ {"standard trap", "standard trap", "initial", "", ""}],
+ write_agent_community_config(Dir, Hdr, Conf).
+
+write_agent_community_config(Dir, Hdr, Conf) ->
+ snmpa_conf:write_community_config(Dir, Hdr, Conf).
+
+update_agent_community_config(Dir, Conf) ->
+ snmpa_conf:append_community_config(Dir, Conf).
+
+
+%%
+%% ------ standard.conf ------
+%%
+
+write_agent_snmp_standard_conf(Dir, SysName) ->
+ Comment =
+"%% This file defines the STANDARD-MIB info.\n"
+"%% Each row is a 2-tuple:\n"
+"%% {StandardVariable, Value}.\n"
+"%% For example\n"
+"%% {sysDescr, \"Erlang SNMP agent\"}.\n"
+"%% {sysObjectID, [1,2,3]}.\n"
+"%% {sysContact, \"{mbj,eklas}@erlang.ericsson.se\"}.\n"
+"%% {sysName, \"test\"}.\n"
+"%% {sysLocation, \"erlang\"}.\n"
+"%% {sysServices, 72}.\n"
+"%% {snmpEnableAuthenTraps, enabled}.\n"
+"%%\n\n",
+ Hdr = header() ++ Comment,
+ Conf = [{sysDescr, "Erlang SNMP agent"},
+ {sysObjectID, [1,2,3]},
+ {sysContact, "{mbj,eklas}@erlang.ericsson.se"},
+ {sysLocation, "erlang"},
+ {sysServices, 72},
+ {snmpEnableAuthenTraps, enabled},
+ {sysName, SysName}],
+ write_agent_standard_config(Dir, Hdr, Conf).
+
+write_agent_standard_config(Dir, Hdr, Conf) ->
+ snmpa_conf:write_standard_config(Dir, Hdr, Conf).
+
+update_agent_standard_config(Dir, Conf) ->
+ snmpa_conf:append_standard_config(Dir, Conf).
+
+
+%%
+%% ------ target_addr.conf ------
+%%
+
+write_agent_snmp_target_addr_conf(Dir, ManagerIp, UDP, Vsns) ->
+ Timeout = 1500,
+ RetryCount = 3,
+ write_agent_snmp_target_addr_conf(Dir, ManagerIp, UDP,
+ Timeout, RetryCount,
+ Vsns).
+
+write_agent_snmp_target_addr_conf(Dir, ManagerIp, UDP,
+ Timeout, RetryCount,
+ Vsns) ->
+ Comment =
+"%% This file defines the target address parameters.\n"
+"%% The data is inserted into the snmpTargetAddrTable defined\n"
+"%% in SNMP-TARGET-MIB, and in the snmpTargetAddrExtTable defined\n"
+"%% in SNMP-COMMUNITY-MIB.\n"
+"%% Each row is a 10-tuple:\n"
+"%% {Name, Ip, Udp, Timeout, RetryCount, TagList, ParamsName, EngineId,\n"
+"%% TMask, MaxMessageSize}.\n"
+"%% The EngineId value is only used if Inform-Requests are sent to this\n"
+"%% target. If Informs are not sent, this value is ignored, and can be\n"
+"%% e.g. an empty string. However, if Informs are sent, it is essential\n"
+"%% that the value of EngineId matches the value of the target's\n"
+"%% actual snmpEngineID.\n"
+"%% For example\n"
+"%% {\"1.2.3.4 v1\", [1,2,3,4], 162, \n"
+"%% 1500, 3, \"std_inform\", \"otp_v2\", \"\",\n"
+"%% [127,0,0,0], 2048}.\n"
+"%%\n\n",
+ Hdr = header() ++ Comment,
+ F = fun(v1 = Vsn, Acc) ->
+ [{mk_ip(ManagerIp, Vsn),
+ ManagerIp, UDP, Timeout, RetryCount,
+ "std_trap", mk_param(Vsn), "", [], 2048}| Acc];
+ (v2 = Vsn, Acc) ->
+ [{mk_ip(ManagerIp, Vsn),
+ ManagerIp, UDP, Timeout, RetryCount,
+ "std_trap", mk_param(Vsn), "", [], 2048},
+ {lists:flatten(io_lib:format("~s.2",[mk_ip(ManagerIp, Vsn)])),
+ ManagerIp, UDP, Timeout, RetryCount,
+ "std_inform", mk_param(Vsn), "", [], 2048}| Acc];
+ (v3 = Vsn, Acc) ->
+ [{mk_ip(ManagerIp, Vsn),
+ ManagerIp, UDP, Timeout, RetryCount,
+ "std_trap", mk_param(Vsn), "", [], 2048},
+ {lists:flatten(io_lib:format("~s.3",[mk_ip(ManagerIp, Vsn)])),
+ ManagerIp, UDP, Timeout, RetryCount,
+ "std_inform", mk_param(Vsn), "mgrEngine", [], 2048}| Acc]
+ end,
+ Conf = lists:foldl(F, [], Vsns),
+ write_agent_target_addr_config(Dir, Hdr, Conf).
+
+mk_param(Vsn) ->
+ lists:flatten(io_lib:format("target_~w", [Vsn])).
+
+mk_ip([A,B,C,D], Vsn) ->
+ lists:flatten(io_lib:format("~w.~w.~w.~w ~w", [A,B,C,D,Vsn])).
+
+write_agent_target_addr_config(Dir, Hdr, Conf) ->
+ snmpa_conf:write_target_addr_config(Dir, Hdr, Conf).
+
+update_agent_target_addr_config(Dir, Conf) ->
+ snmpa_conf:append_target_addr_config(Dir, Conf).
+
+
+%%
+%% ------ target_params.conf ------
+%%
+
+write_agent_snmp_target_params_conf(Dir, Vsns) ->
+ Comment =
+"%% This file defines the target parameters.\n"
+"%% The data is inserted into the snmpTargetParamsTable defined\n"
+"%% in SNMP-TARGET-MIB.\n"
+"%% Each row is a 5-tuple:\n"
+"%% {Name, MPModel, SecurityModel, SecurityName, SecurityLevel}.\n"
+"%% For example\n"
+"%% {\"target_v3\", v3, usm, \"\", noAuthNoPriv}.\n"
+"%%\n\n",
+ Hdr = header() ++ Comment,
+ Conf = [fun(V) ->
+ MP = if V == v1 -> v1;
+ V == v2 -> v2c;
+ V == v3 -> v3
+ end,
+ SM = if V == v1 -> v1;
+ V == v2 -> v2c;
+ V == v3 -> usm
+ end,
+ Name = lists:flatten(
+ io_lib:format("target_~w", [V])),
+ {Name, MP, SM, "initial", noAuthNoPriv}
+ end(Vsn) || Vsn <- Vsns],
+ write_agent_target_params_config(Dir, Hdr, Conf).
+
+write_agent_target_params_config(Dir, Hdr, Conf) ->
+ snmpa_conf:write_target_params_config(Dir, Hdr, Conf).
+
+update_agent_target_params_config(Dir, Conf) ->
+ snmpa_conf:append_target_params_config(Dir, Conf).
+
+
+%%
+%% ------ notify.conf ------
+%%
+
+write_agent_snmp_notify_conf(Dir, NotifyType) ->
+ Comment =
+"%% This file defines the notification parameters.\n"
+"%% The data is inserted into the snmpNotifyTable defined\n"
+"%% in SNMP-NOTIFICATION-MIB.\n"
+"%% The Name is used as CommunityString for v1 and v2c.\n"
+"%% Each row is a 3-tuple:\n"
+"%% {Name, Tag, Type}.\n"
+"%% For example\n"
+"%% {\"standard trap\", \"std_trap\", trap}.\n"
+"%% {\"standard inform\", \"std_inform\", inform}.\n"
+"%%\n\n",
+ Hdr = header() ++ Comment,
+ Conf = [{"stadard_trap", "std_trap", NotifyType}],
+ write_agent_notify_config(Dir, Hdr, Conf).
+
+write_agent_notify_config(Dir, Hdr, Conf) ->
+ snmpa_conf:write_notify_config(Dir, Hdr, Conf).
+
+update_agent_notify_config(Dir, Conf) ->
+ snmpa_conf:append_notify_config(Dir, Conf).
+
+
+%%
+%% ------ usm.conf ------
+%%
+
+write_agent_snmp_usm_conf(Dir, Vsns, EngineID, SecType, Passwd) ->
+ case lists:member(v3, Vsns) of
+ false -> ok;
+ true -> write_agent_snmp_usm_conf(Dir, EngineID, SecType, Passwd)
+ end.
+
+write_agent_snmp_usm_conf(Dir, EngineID, SecType, Passwd) ->
+ Comment =
+"%% This file defines the security parameters for the user-based\n"
+"%% security model.\n"
+"%% The data is inserted into the usmUserTable defined\n"
+"%% in SNMP-USER-BASED-SM-MIB.\n"
+"%% Each row is a 14-tuple:\n"
+"%% {EngineID, UserName, SecName, Clone, AuthP, AuthKeyC, OwnAuthKeyC,\n"
+"%% PrivP, PrivKeyC, OwnPrivKeyC, Public, AuthKey, PrivKey}.\n"
+"%% For example\n"
+"%% {\"agentEngine\", \"initial\", \"initial\", zeroDotZero,\n"
+"%% usmNoAuthProtocol, \"\", \"\", usmNoPrivProtocol, \"\", \"\", \"\",\n"
+"%% \"\", \"\"}.\n"
+"%%\n\n",
+ Hdr = header() ++ Comment,
+ Conf = write_agent_snmp_usm_conf2(EngineID, SecType, Passwd),
+ write_agent_usm_config(Dir, Hdr, Conf).
+
+write_agent_snmp_usm_conf2(EngineID, none, _Passwd) ->
+ [{EngineID, "initial", "initial", zeroDotZero,
+ usmNoAuthProtocol, "", "",
+ usmNoPrivProtocol, "", "",
+ "", "", ""}];
+write_agent_snmp_usm_conf2(EngineID, SecType, Passwd) ->
+ Secret16 = agent_snmp_mk_secret(md5, Passwd, EngineID),
+ Secret20 = agent_snmp_mk_secret(sha, Passwd, EngineID),
+ {PrivProt, PrivSecret} =
+ case SecType of
+ minimum ->
+ {usmNoPrivProtocol, ""};
+ {semi, des} ->
+ {usmDESPrivProtocol, Secret16};
+ {semi, aes} ->
+ {usmAesCfb128Protocol, Secret16}
+ end,
+ [{EngineID, "initial", "initial", zeroDotZero,
+ usmHMACMD5AuthProtocol, "", "",
+ PrivProt, "", "",
+ "", Secret16, PrivSecret},
+
+ {EngineID, "templateMD5", "templateMD5", zeroDotZero,
+ usmHMACMD5AuthProtocol, "", "",
+ PrivProt, "", "",
+ "", Secret16, PrivSecret},
+
+ {EngineID, "templateSHA", "templateSHA", zeroDotZero,
+ usmHMACSHAAuthProtocol, "", "",
+ PrivProt, "", "",
+ "", Secret20, PrivSecret}].
+
+write_agent_usm_config(Dir, Hdr, Conf) ->
+ snmpa_conf:write_usm_config(Dir, Hdr, Conf).
+
+update_agent_usm_config(Dir, Conf) ->
+ snmpa_conf:append_usm_config(Dir, Conf).
+
+
+%%
+%% ------ vacm.conf ------
+%%
+
+write_agent_snmp_vacm_conf(Dir, Vsns, SecType) ->
+ Comment =
+"%% This file defines the Mib Views.\n"
+"%% The data is inserted into the vacm* tables defined\n"
+"%% in SNMP-VIEW-BASED-ACM-MIB.\n"
+"%% Each row is one of 3 tuples; one for each table in the MIB:\n"
+"%% {vacmSecurityToGroup, SecModel, SecName, GroupName}.\n"
+"%% {vacmAccess, GroupName, Prefix, SecModel, SecLevel, Match, RV, WV, NV}.\n"
+"%% {vacmViewTreeFamily, ViewIndex, ViewSubtree, ViewStatus, ViewMask}.\n"
+"%% For example\n"
+"%% {vacmSecurityToGroup, v2c, \"initial\", \"initial\"}.\n"
+"%% {vacmSecurityToGroup, usm, \"initial\", \"initial\"}.\n"
+"%% read/notify access to system\n"
+"%% {vacmAccess, \"initial\", \"\", any, noAuthNoPriv, exact,\n"
+"%% \"system\", \"\", \"system\"}.\n"
+"%% {vacmViewTreeFamily, \"system\", [1,3,6,1,2,1,1], included, null}.\n"
+"%% {vacmViewTreeFamily, \"exmib\", [1,3,6,1,3], included, null}."
+" % for EX1-MIB\n"
+"%% {vacmViewTreeFamily, \"internet\", [1,3,6,1], included, null}.\n"
+"%%\n\n",
+ Hdr = lists:flatten(header()) ++ Comment,
+ Groups =
+ lists:foldl(
+ fun(V, Acc) ->
+ [{vacmSecurityToGroup, vacm_ver(V),
+ "initial", "initial"},
+ {vacmSecurityToGroup, vacm_ver(V),
+ "all-rights", "all-rights"}|
+ Acc]
+ end, [], Vsns),
+ Acc =
+ [{vacmAccess, "initial", "", any, noAuthNoPriv, exact,
+ "restricted", "", "restricted"},
+ {vacmAccess, "initial", "", usm, authNoPriv, exact,
+ "internet", "internet", "internet"},
+ {vacmAccess, "initial", "", usm, authPriv, exact,
+ "internet", "internet", "internet"},
+ {vacmAccess, "all-rights", "", any, noAuthNoPriv, exact,
+ "internet", "internet", "internet"}],
+ VTF0 =
+ case SecType of
+ none ->
+ [{vacmViewTreeFamily,
+ "restricted", [1,3,6,1], included, null}];
+ minimum ->
+ [{vacmViewTreeFamily,
+ "restricted", [1,3,6,1], included, null}];
+ {semi, _} ->
+ [{vacmViewTreeFamily,
+ "restricted", [1,3,6,1,2,1,1], included, null},
+ {vacmViewTreeFamily,
+ "restricted", [1,3,6,1,2,1,11], included, null},
+ {vacmViewTreeFamily,
+ "restricted", [1,3,6,1,6,3,10,2,1], included, null},
+ {vacmViewTreeFamily,
+ "restricted", [1,3,6,1,6,3,11,2,1], included, null},
+ {vacmViewTreeFamily,
+ "restricted", [1,3,6,1,6,3,15,1,1], included, null}]
+ end,
+ VTF = VTF0 ++ [{vacmViewTreeFamily,"internet",[1,3,6,1],included,null}],
+ write_agent_vacm_config(Dir, Hdr, Groups ++ Acc ++ VTF).
+
+vacm_ver(v1) -> v1;
+vacm_ver(v2) -> v2c;
+vacm_ver(v3) -> usm.
+
+write_agent_vacm_config(Dir, Hdr, Conf) ->
+ snmpa_conf:write_vacm_config(Dir, Hdr, Conf).
+
+update_agent_vacm_config(Dir, Conf) ->
+ snmpa_conf:append_vacm_config(Dir, Conf).
+
+
+%%
+%% ----- Manager config files generator functions -----
+%%
+
+write_manager_snmp_files(Dir, IP, Port, MMS, EngineID,
+ Users, Agents, Usms) ->
+ write_manager_snmp_conf(Dir, IP, Port, MMS, EngineID),
+ write_manager_snmp_users_conf(Dir, Users),
+ write_manager_snmp_agents_conf(Dir, Agents),
+ write_manager_snmp_usm_conf(Dir, Usms),
+ ok.
+
+
+%%
+%% ------ manager.conf ------
+%%
+
+write_manager_snmp_conf(Dir, IP, Port, MMS, EngineID) ->
+ Comment =
+"%% This file defines the Manager local configuration info\n"
+"%% Each row is a 2-tuple:\n"
+"%% {Variable, Value}.\n"
+"%% For example\n"
+"%% {port, 5000}.\n"
+"%% {address, [127,42,17,5]}.\n"
+"%% {engine_id, \"managerEngine\"}.\n"
+"%% {max_message_size, 484}.\n"
+"%%\n\n",
+ Hdr = header() ++ Comment,
+ Conf = [{port, Port},
+ {address, IP},
+ {engine_id, EngineID},
+ {max_message_size, MMS}],
+ write_manager_config(Dir, Hdr, Conf).
+
+write_manager_config(Dir, Hdr, Conf) ->
+ snmpm_conf:write_manager_config(Dir, Hdr, Conf).
+
+update_manager_config(Dir, Conf) ->
+ snmpm_conf:append_manager_config(Dir, Conf).
+
+
+%%
+%% ------ users.conf ------
+%%
+
+write_manager_snmp_users_conf(Dir, Users) ->
+ Comment =
+"%% This file defines the users the manager handles\n"
+"%% Each row is a 3-tuple:\n"
+"%% {UserId, UserMod, UserData}.\n"
+"%% For example\n"
+"%% {kalle, kalle_callback_user_mod, \"dummy\"}.\n"
+"%%\n\n",
+ Hdr = header() ++ Comment,
+ write_manager_users_config(Dir, Hdr, Users).
+
+write_manager_users_config(Dir, Hdr, Users) ->
+ snmpm_conf:write_users_config(Dir, Hdr, Users).
+
+update_manager_users_config(Dir, Users) ->
+ snmpm_conf:append_users_config(Dir, Users).
+
+
+%%
+%% ------ agents.conf ------
+%%
+
+write_manager_snmp_agents_conf(Dir, Agents) ->
+ Comment =
+"%% This file defines the agents the manager handles\n"
+"%% Each row is a 12-tuple:\n"
+"%% {UserId, \n"
+"%% TargetName, Comm, Ip, Port, EngineID, Timeout, \n"
+"%% MaxMessageSize, Version, SecModel, SecName, SecLevel}\n"
+"%%\n\n",
+ Hdr = header() ++ Comment,
+ write_manager_agents_config(Dir, Hdr, Agents).
+
+write_manager_agents_config(Dir, Hdr, Agents) ->
+ snmpm_conf:write_agents_config(Dir, Hdr, Agents).
+
+update_manager_agents_config(Dir, Agents) ->
+ snmpm_conf:append_agents_config(Dir, Agents).
+
+
+%%
+%% ------ usm.conf -----
+%%
+
+write_manager_snmp_usm_conf(Dir, Usms) ->
+ Comment =
+"%% This file defines the usm users the manager handles\n"
+"%% Each row is a 6 or 7-tuple:\n"
+"%% {EngineID, UserName, AuthP, AuthKey, PrivP, PrivKey}\n"
+"%% {EngineID, UserName, SecName, AuthP, AuthKey, PrivP, PrivKey}\n"
+"%%\n\n",
+ Hdr = header() ++ Comment,
+ write_manager_usm_config(Dir, Hdr, Usms).
+
+write_manager_usm_config(Dir, Hdr, Usms) ->
+ snmpm_conf:write_usm_config(Dir, Hdr, Usms).
+
+update_manager_usm_config(Dir, Usms) ->
+ snmpm_conf:append_usm_config(Dir, Usms).
+
+
+%%
+%% -------------------------------------------------------------------------
+%%
+
+write_sys_config_file(Dir, Services) ->
+ {ok, Fid} = file:open(filename:join(Dir,"sys.config"), [write]),
+ ok = io:format(Fid, "~s", [header()]),
+ ok = io:format(Fid, "[{snmp, ~n", []),
+ ok = io:format(Fid, " [~n", []),
+ write_sys_config_file_services(Fid, Services),
+ ok = io:format(Fid, " ]~n", []),
+ ok = io:format(Fid, " }~n", []),
+ ok = io:format(Fid, "].~n", []),
+ ok.
+
+write_sys_config_file_services(Fid, [Service]) ->
+ write_sys_config_file_service(Fid, Service),
+ ok = io:format(Fid, "~n", []),
+ ok;
+write_sys_config_file_services(Fid, [Service|Services]) ->
+ write_sys_config_file_service(Fid, Service),
+ ok = io:format(Fid, ", ~n", []),
+ write_sys_config_file_services(Fid, Services).
+
+write_sys_config_file_service(Fid, {Service, Opts}) ->
+ ok = io:format(Fid, " {~w,~n", [Service]),
+ ok = io:format(Fid, " [~n", []),
+ write_sys_config_file_service_opts(Fid, Service, Opts),
+ ok = io:format(Fid, " ]~n", []),
+ ok = io:format(Fid, " }", []),
+ true.
+
+write_sys_config_file_service_opts(Fid, agent, Opts) ->
+ write_sys_config_file_agent_opts(Fid, Opts);
+write_sys_config_file_service_opts(Fid, manager, Opts) ->
+ write_sys_config_file_manager_opts(Fid, Opts).
+
+
+write_sys_config_file_agent_opts(Fid, [Opt]) ->
+ write_sys_config_file_agent_opt(Fid, Opt),
+ ok = io:format(Fid, "~n", []),
+ ok;
+write_sys_config_file_agent_opts(Fid, [Opt|Opts]) ->
+ write_sys_config_file_agent_opt(Fid, Opt),
+ ok = io:format(Fid, ", ~n", []),
+ write_sys_config_file_agent_opts(Fid, Opts).
+
+
+write_sys_config_file_agent_opt(Fid, {mibs, []}) ->
+ ok = io:format(Fid, " {mibs, []}", []);
+write_sys_config_file_agent_opt(Fid, {priority, Prio}) ->
+ ok = io:format(Fid, " {priority, ~w}", [Prio]);
+write_sys_config_file_agent_opt(Fid, {error_report_mod, Mod}) ->
+ ok = io:format(Fid, " {error_report_mod, ~w}", [Mod]);
+write_sys_config_file_agent_opt(Fid, {versions, Vsns}) ->
+ ok = io:format(Fid, " {versions, ~w}", [Vsns]);
+write_sys_config_file_agent_opt(Fid, {multi_threaded, B}) ->
+ ok = io:format(Fid, " {multi_threaded, ~w}", [B]);
+write_sys_config_file_agent_opt(Fid, {config, Opts}) ->
+ ok = io:format(Fid, " {config, [", []),
+ write_sys_config_file_agent_config_opts(Fid, Opts),
+ ok = io:format(Fid, "}", []);
+write_sys_config_file_agent_opt(Fid, {db_dir, Dir}) ->
+ ok = io:format(Fid, " {db_dir, \"~s\"}", [Dir]);
+write_sys_config_file_agent_opt(Fid, {mib_storage, ets}) ->
+ ok = io:format(Fid, " {mib_storage, ets}", []);
+write_sys_config_file_agent_opt(Fid, {mib_storage, {dets, Dir}}) ->
+ ok = io:format(Fid, " {mib_storage, {dets, \"~s\"}}", [Dir]);
+write_sys_config_file_agent_opt(Fid, {mib_storage, {dets, Dir, Act}}) ->
+ ok = io:format(Fid, " {mib_storage, {dets, \"~s\", ~w}}",
+ [Dir, Act]);
+write_sys_config_file_agent_opt(Fid, {mib_storage, {mnesia, Nodes}}) ->
+ ok = io:format(Fid, " {mib_storage, {mnesia, ~w}}", [Nodes]);
+write_sys_config_file_agent_opt(Fid, {mib_storage, {mnesia, Nodes, Act}}) ->
+ ok = io:format(Fid, " {mib_storage, {mnesia, ~w, ~w}}",
+ [Nodes, Act]);
+write_sys_config_file_agent_opt(Fid, {target_cache, Opts}) ->
+ ok = io:format(Fid, " {target_cache, ~w}", [Opts]);
+write_sys_config_file_agent_opt(Fid, {local_db, Opts}) ->
+ ok = io:format(Fid, " {local_db, ~w}", [Opts]);
+write_sys_config_file_agent_opt(Fid, {note_store, Opts}) ->
+ ok = io:format(Fid, " {note_store, ~w}", [Opts]);
+write_sys_config_file_agent_opt(Fid, {symbolic_store, Opts}) ->
+ ok = io:format(Fid, " {symbolic_store, ~w}", [Opts]);
+write_sys_config_file_agent_opt(Fid, {agent_type, Type}) ->
+ ok = io:format(Fid, " {agent_type, ~w}", [Type]);
+write_sys_config_file_agent_opt(Fid, {agent_verbosity, Verb}) ->
+ ok = io:format(Fid, " {agent_verbosity, ~w}", [Verb]);
+write_sys_config_file_agent_opt(Fid, {audit_trail_log, Opts}) ->
+ ok = io:format(Fid, " {audit_trail_log, [", []),
+ write_sys_config_file_agent_atl_opts(Fid, Opts),
+ ok = io:format(Fid, "}", []);
+write_sys_config_file_agent_opt(Fid, {net_if, Opts}) ->
+ ok = io:format(Fid, " {net_if, ~w}", [Opts]);
+write_sys_config_file_agent_opt(Fid, {mib_server, Opts}) ->
+ ok = io:format(Fid, " {mib_server, ~w}", [Opts]);
+write_sys_config_file_agent_opt(Fid, {Key, Val}) ->
+ ok = io:format(Fid, " {~w, ~w}", [Key, Val]).
+
+
+%% Mandatory option dir, means that this is never empty:
+write_sys_config_file_agent_config_opts(Fid, [Opt]) ->
+ write_sys_config_file_agent_config_opt(Fid, Opt),
+ ok = io:format(Fid, "]", []),
+ ok;
+write_sys_config_file_agent_config_opts(Fid, [Opt|Opts]) ->
+ write_sys_config_file_agent_config_opt(Fid, Opt),
+ ok = io:format(Fid, ", ", []),
+ write_sys_config_file_agent_config_opts(Fid, Opts).
+
+write_sys_config_file_agent_config_opt(Fid, {dir, Dir}) ->
+ ok = io:format(Fid, "{dir, \"~s\"}", [Dir]);
+write_sys_config_file_agent_config_opt(Fid, {force_load, Bool}) ->
+ ok = io:format(Fid, "{force_load, ~w}", [Bool]);
+write_sys_config_file_agent_config_opt(Fid, {verbosity, Verb}) ->
+ ok = io:format(Fid, "{verbosity, ~w}", [Verb]).
+
+
+%% This is only present if there is atleast one option
+write_sys_config_file_agent_atl_opts(Fid, [Opt]) ->
+ write_sys_config_file_agent_atl_opt(Fid, Opt),
+ ok = io:format(Fid, "]", []),
+ ok;
+write_sys_config_file_agent_atl_opts(Fid, [Opt|Opts]) ->
+ write_sys_config_file_agent_atl_opt(Fid, Opt),
+ ok = io:format(Fid, ", ", []),
+ write_sys_config_file_agent_atl_opts(Fid, Opts).
+
+write_sys_config_file_agent_atl_opt(Fid, {dir, Dir}) ->
+ ok = io:format(Fid, "{dir, \"~s\"}", [Dir]);
+write_sys_config_file_agent_atl_opt(Fid, {type, Type}) ->
+ ok = io:format(Fid, "{type, ~w}", [Type]);
+write_sys_config_file_agent_atl_opt(Fid, {size, Size}) ->
+ ok = io:format(Fid, "{size, ~w}", [Size]);
+write_sys_config_file_agent_atl_opt(Fid, {repair, Rep}) ->
+ ok = io:format(Fid, "{repair, ~w}", [Rep]).
+
+
+write_sys_config_file_manager_opts(Fid, [Opt]) ->
+ write_sys_config_file_manager_opt(Fid, Opt),
+ ok = io:format(Fid, "~n", []),
+ ok;
+write_sys_config_file_manager_opts(Fid, [Opt|Opts]) ->
+ write_sys_config_file_manager_opt(Fid, Opt),
+ ok = io:format(Fid, ", ~n", []),
+ write_sys_config_file_manager_opts(Fid, Opts).
+
+
+write_sys_config_file_manager_opt(Fid, {mibs, []}) ->
+ ok = io:format(Fid, " {mibs, []}", []);
+write_sys_config_file_manager_opt(Fid, {priority, Prio}) ->
+ ok = io:format(Fid, " {priority, ~w}", [Prio]);
+write_sys_config_file_manager_opt(Fid, {versions, Vsns}) ->
+ ok = io:format(Fid, " {versions, ~w}", [Vsns]);
+write_sys_config_file_manager_opt(Fid, {config, Opts}) ->
+ ok = io:format(Fid, " {config, [", []),
+ write_sys_config_file_manager_config_opts(Fid, Opts),
+ ok = io:format(Fid, "}", []);
+write_sys_config_file_manager_opt(Fid, {server, Opts}) ->
+ ok = io:format(Fid, " {server, ~w}", [Opts]);
+write_sys_config_file_manager_opt(Fid, {note_store, Opts}) ->
+ ok = io:format(Fid, " {note_store, ~w}", [Opts]);
+write_sys_config_file_manager_opt(Fid, {audit_trail_log, Opts}) ->
+ ok = io:format(Fid, " {audit_trail_log, [", []),
+ write_sys_config_file_manager_atl_opts(Fid, Opts),
+ ok = io:format(Fid, "}", []);
+write_sys_config_file_manager_opt(Fid, {net_if, Opts}) ->
+ ok = io:format(Fid, " {net_if, ~w}", [Opts]);
+write_sys_config_file_manager_opt(Fid, {Key, Val}) ->
+ ok = io:format(Fid, " {~w, ~w}", [Key, Val]).
+
+%% Mandatory option dir, means that this is never empty:
+write_sys_config_file_manager_config_opts(Fid, [Opt]) ->
+ write_sys_config_file_manager_config_opt(Fid, Opt),
+ ok = io:format(Fid, "]", []),
+ ok;
+write_sys_config_file_manager_config_opts(Fid, [Opt|Opts]) ->
+ write_sys_config_file_manager_config_opt(Fid, Opt),
+ ok = io:format(Fid, ", ", []),
+ write_sys_config_file_manager_config_opts(Fid, Opts).
+
+write_sys_config_file_manager_config_opt(Fid, {dir, Dir}) ->
+ ok = io:format(Fid, "{dir, \"~s\"}", [Dir]);
+write_sys_config_file_manager_config_opt(Fid, {db_dir, Dir}) ->
+ ok = io:format(Fid, "{db_dir, \"~s\"}", [Dir]);
+write_sys_config_file_manager_config_opt(Fid, {repair, Rep}) ->
+ ok = io:format(Fid, "{repair, ~w}", [Rep]);
+write_sys_config_file_manager_config_opt(Fid, {auto_save, As}) ->
+ ok = io:format(Fid, "{auto_save, ~w}", [As]);
+write_sys_config_file_manager_config_opt(Fid, {verbosity, Verb}) ->
+ ok = io:format(Fid, "{verbosity, ~w}", [Verb]).
+
+
+%% This is only present if there is atleast one option
+write_sys_config_file_manager_atl_opts(Fid, [Opt]) ->
+ write_sys_config_file_manager_atl_opt(Fid, Opt),
+ ok = io:format(Fid, "]", []),
+ ok;
+write_sys_config_file_manager_atl_opts(Fid, [Opt|Opts]) ->
+ write_sys_config_file_manager_atl_opt(Fid, Opt),
+ ok = io:format(Fid, ", ", []),
+ write_sys_config_file_manager_atl_opts(Fid, Opts).
+
+write_sys_config_file_manager_atl_opt(Fid, {dir, Dir}) ->
+ ok = io:format(Fid, "{dir, \"~s\"}", [Dir]);
+write_sys_config_file_manager_atl_opt(Fid, {type, Type}) ->
+ ok = io:format(Fid, "{type, ~w}", [Type]);
+write_sys_config_file_manager_atl_opt(Fid, {size, Size}) ->
+ ok = io:format(Fid, "{size, ~w}", [Size]);
+write_sys_config_file_manager_atl_opt(Fid, {repair, Rep}) ->
+ ok = io:format(Fid, "{repair, ~w}", [Rep]).
+
+
+header() ->
+ {Y,Mo,D} = date(),
+ {H,Mi,S} = time(),
+ io_lib:format("%% This file was generated by "
+ "snmp_config (version-~s) ~w-~2.2.0w-~2.2.0w "
+ "~2.2.0w:~2.2.0w:~2.2.0w\n",
+ [?version,Y,Mo,D,H,Mi,S]).
+
+
+write_config_file(Dir, FileName, Verify, Write)
+ when (is_list(Dir) andalso
+ is_list(FileName) andalso
+ is_function(Verify) andalso
+ is_function(Write)) ->
+ (catch do_write_config_file(Dir, FileName, Verify, Write)).
+
+do_write_config_file(Dir, FileName, Verify, Write) ->
+ Verify(),
+ case file:open(filename:join(Dir, FileName), [write]) of
+ {ok, Fd} ->
+ (catch Write(Fd)),
+ file:close(Fd),
+ ok;
+ Error ->
+ Error
+ end.
+
+
+append_config_file(Dir, FileName, Verify, Write)
+ when (is_list(Dir) andalso
+ is_list(FileName) andalso
+ is_function(Verify) andalso
+ is_function(Write)) ->
+ (catch do_append_config_file(Dir, FileName, Verify, Write)).
+
+do_append_config_file(Dir, FileName, Verify, Write) ->
+ Verify(),
+ case file:open(filename:join(Dir, FileName), [read, write]) of
+ {ok, Fd} ->
+ file:position(Fd, eof),
+ (catch Write(Fd)),
+ file:close(Fd),
+ ok;
+ Error ->
+ Error
+ end.
+
+
+read_config_file(Dir, FileName, Verify)
+ when is_list(Dir) andalso is_list(FileName) andalso is_function(Verify) ->
+ (catch do_read_config_file(Dir, FileName, Verify)).
+
+do_read_config_file(Dir, FileName, Verify) ->
+ case file:open(filename:join(Dir, FileName), [read]) of
+ {ok, Fd} ->
+ Result = read_loop(Fd, [], Verify, 1),
+ file:close(Fd),
+ Result;
+ {error, Reason} ->
+ {error, {Reason, FileName}}
+ end.
+
+read_loop(Fd, Acc, Check, StartLine) ->
+ case read_term(Fd, StartLine) of
+ {ok, Term, EndLine} ->
+ case (catch Check(Term)) of
+ ok ->
+ read_loop(Fd, [Term | Acc], Check, EndLine);
+ {error, Reason} ->
+ {error, {failed_check, StartLine, EndLine, Reason}};
+ Error ->
+ {error, {failed_check, StartLine, EndLine, Error}}
+ end;
+ {error, EndLine, Error} ->
+ {error, {failed_reading, StartLine, EndLine, Error}};
+ eof ->
+ {ok, lists:reverse(Acc)}
+ end.
+
+read_term(Fd, StartLine) ->
+ case io:request(Fd, {get_until, "", erl_scan, tokens, [StartLine]}) of
+ {ok, Tokens, EndLine} ->
+ case erl_parse:parse_term(Tokens) of
+ {ok, Term} ->
+ {ok, Term, EndLine};
+ {error, {Line, erl_parse, Error}} ->
+ {error, Line, {parse_error, Error}}
+ end;
+ {error, E, EndLine} ->
+ {error, EndLine, E};
+ {eof, _EndLine} ->
+ eof;
+ Other ->
+ Other
+ end.
+
+
+agent_snmp_mk_secret(Alg, Passwd, EngineID) ->
+ snmp_usm:passwd2localized_key(Alg, Passwd, EngineID).
+
+
+ensure_crypto_started() ->
+ i("making sure crypto server is started..."),
+ ensure_started(crypto).
+
+ensure_started(App) ->
+ case (catch App:start()) of
+ ok ->
+ ok;
+ {error, {already_started, App}} ->
+ ok;
+ E ->
+ error({failed_starting, App, E})
+ end.
+
+
+%% -------------------------------------------------------------------------
+
+% d(F, A) ->
+% i("DBG: " ++ F, A).
+
+i(F) ->
+ i(F, []).
+
+i(F, A) ->
+ io:format(F ++ "~n", A).
+
+error(R) ->
+ throw({error, R}).
diff --git a/lib/snmp/src/misc/snmp_debug.hrl b/lib/snmp/src/misc/snmp_debug.hrl
new file mode 100644
index 0000000000..dc916ac96a
--- /dev/null
+++ b/lib/snmp/src/misc/snmp_debug.hrl
@@ -0,0 +1,38 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2000-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%
+%%
+
+-ifdef(snmp_debug).
+-define(d(F,A),
+ io:format("~p:~p:~p:" ++ F ++ "~n",[self(),?MODULE,?LINE]++A)).
+
+%% Same as 'd' but without the ending newline ('~n').
+-define(d_b(F,A),
+ io:format("~p:~p:~p:" ++ F,[self(),?MODULE,?LINE]++A)).
+%% To be used together with 'd_b'. Note: NO ending newline ('~n')..
+-define(d_e(F,A),
+ io:format(F,A)).
+-else.
+-define(d(F,A),ok).
+-define(d_b(F,A),ok).
+-define(d_e(F,A),ok).
+-endif.
+
+
+
+
diff --git a/lib/snmp/src/misc/snmp_log.erl b/lib/snmp/src/misc/snmp_log.erl
new file mode 100644
index 0000000000..c3932ccc08
--- /dev/null
+++ b/lib/snmp/src/misc/snmp_log.erl
@@ -0,0 +1,584 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1997-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%
+%%
+
+-module(snmp_log).
+
+
+-export([
+ create/4, create/5,
+ change_size/2, close/1, sync/1, info/1,
+ log/4,
+ log_to_txt/5, log_to_txt/6, log_to_txt/7,
+ log_to_io/4, log_to_io/5, log_to_io/6
+ ]).
+
+
+-define(SNMP_USE_V3, true).
+-include("snmp_types.hrl").
+
+-define(VMODULE,"LOG").
+-include("snmp_verbosity.hrl").
+
+-define(LOG_FORMAT, internal).
+-define(LOG_TYPE, wrap).
+
+
+%% --------------------------------------------------------------------
+%% Exported functions
+%% --------------------------------------------------------------------
+
+
+%% -- create ---
+
+create(Name, File, Size, Repair) ->
+ create(Name, File, Size, Repair, false).
+
+create(Name, File, Size, Repair, Notify) ->
+ ?vtrace("create -> entry with"
+ "~n Name: ~p"
+ "~n File: ~p"
+ "~n Size: ~p"
+ "~n Repair: ~p"
+ "~n Notify: ~p", [Name, File, Size, Repair, Notify]),
+ log_open(Name, File, Size, Repair, Notify).
+
+
+%% -- close ---
+
+close(Log) ->
+ ?vtrace("close -> entry with"
+ "~n Log: ~p", [Log]),
+ disk_log:close(Log).
+
+
+%% -- close ---
+
+sync(Log) ->
+ ?vtrace("sync -> entry with"
+ "~n Log: ~p", [Log]),
+ disk_log:sync(Log).
+
+%% -- info ---
+
+info(Log) ->
+ case disk_log:info(Log) of
+ Info when is_list(Info) ->
+ Items = [no_current_bytes, no_current_items,
+ current_file, no_overflows],
+ info_filter(Items, Info, []);
+ Else ->
+ Else
+ end.
+
+info_filter([], _Info, Acc) ->
+ {ok, Acc};
+info_filter([Item|Items], Info, Acc) ->
+ case lists:keysearch(Item, 1, Info) of
+ {value, New} ->
+ info_filter(Items, Info, [New|Acc]);
+ false ->
+ info_filter(Items, Info, Acc)
+ end.
+
+
+%% -- log ---
+
+%%-----------------------------------------------------------------
+%% For efficiency reasons, we want to log the packet as a binary.
+%% This is only possible for messages that are not encrypted.
+%% Therefore, Packet can be either a binary (encoded message), or
+%% a tuple {V3Hdr, ScopedPduBytes}
+%%
+%% log(Log, Packet, Addr, Port)
+%%-----------------------------------------------------------------
+
+
+log(Log, Packet, Addr, Port) ->
+ ?vtrace("log -> entry with"
+ "~n Log: ~p"
+ "~n Addr: ~p"
+ "~n Port: ~p", [Log, Addr, Port]),
+ Entry = {timestamp(), Packet, Addr, Port},
+ disk_log:alog(Log, Entry).
+
+
+
+%% -- change_size ---
+
+change_size(Log, NewSize) ->
+ ?vtrace("change_size -> entry with"
+ "~n Log: ~p"
+ "~n NewSize: ~p", [Log, NewSize]),
+ disk_log:change_size(Log, NewSize).
+
+
+%% -- log_to_txt ---
+
+log_to_txt(Log, FileName, Dir, Mibs, TextFile) ->
+ log_to_txt(Log, FileName, Dir, Mibs, TextFile, null, null).
+
+log_to_txt(Log, FileName, Dir, Mibs, TextFile, Start) ->
+ log_to_txt(Log, FileName, Dir, Mibs, TextFile, Start, null).
+
+log_to_txt(Log, FileName, Dir, Mibs, TextFile, Start, Stop)
+ when is_list(Mibs) andalso is_list(TextFile) ->
+ ?vtrace("log_to_txt -> entry with"
+ "~n Log: ~p"
+ "~n FileName: ~p"
+ "~n Dir: ~p"
+ "~n Mibs: ~p"
+ "~n TextFile: ~p"
+ "~n Start: ~p"
+ "~n Stop: ~p",
+ [Log, FileName, Dir, Mibs, TextFile, Start, Stop]),
+ File = filename:join(Dir, FileName),
+ Converter = fun(L) ->
+ do_log_to_file(L, TextFile, Mibs, Start, Stop)
+ end,
+ log_convert(Log, File, Converter).
+
+
+%% -- log_to_io ---
+
+log_to_io(Log, FileName, Dir, Mibs) ->
+ log_to_io(Log, FileName, Dir, Mibs, null, null).
+
+log_to_io(Log, FileName, Dir, Mibs, Start) ->
+ log_to_io(Log, FileName, Dir, Mibs, Start, null).
+
+log_to_io(Log, FileName, Dir, Mibs, Start, Stop)
+ when is_list(Mibs) ->
+ File = filename:join(Dir, FileName),
+ Converter = fun(L) ->
+ do_log_to_io(L, Mibs, Start, Stop)
+ end,
+ log_convert(Log, File, Converter).
+
+
+%% --------------------------------------------------------------------
+%% Internal functions
+%% --------------------------------------------------------------------
+
+
+%% -- log_convert ---
+
+log_convert(Log, File, Converter) ->
+ %% First check if the caller process has already opened the
+ %% log, because if we close an already open log we will cause
+ %% a runtime error.
+ case is_owner(Log) of
+ true ->
+ Converter(Log);
+ false ->
+ %% Not yet member of the ruling party, apply for membership...
+ %% If a log is opened as read_write it is not possible to
+ %% open it as read_only. So, to get around this we open
+ %% it under a different name...
+ Log2 = convert_name(Log),
+ case log_open(Log2, File) of
+ {ok, _} ->
+ Res = Converter(Log2),
+ disk_log:close(Log2),
+ Res;
+ {error, {name_already_open, _}} ->
+ Converter(Log2);
+ {error, Reason} ->
+ {error, {Log, Reason}}
+ end
+ end.
+
+convert_name(Name) when is_list(Name) ->
+ Name ++ "_tmp";
+convert_name(Name) when is_atom(Name) ->
+ list_to_atom(atom_to_list(Name) ++ "_tmp");
+convert_name(Name) ->
+ lists:flatten(io_lib:format("~w_tmp", [Name])).
+
+
+%% -- do_log_to_text ---
+
+do_log_to_file(Log, TextFile, Mibs, Start, Stop) ->
+ case file:open(TextFile, [write]) of
+ {ok, Fd} ->
+ MiniMib = snmp_mini_mib:create(Mibs),
+ Write = fun(X) ->
+ case format_msg(X, MiniMib, Start, Stop) of
+ {ok, S} ->
+ io:format(Fd, "~s", [S]);
+ _ ->
+ ok
+ end
+ end,
+ Res = (catch loop(disk_log:chunk(Log, start), Log, Write)),
+ snmp_mini_mib:delete(MiniMib),
+ file:close(Fd),
+ Res;
+ {error, Reason} ->
+ {error, {TextFile, Reason}}
+ end.
+
+
+do_log_to_io(Log, Mibs, Start, Stop) ->
+ MiniMib = snmp_mini_mib:create(Mibs),
+ Write = fun(X) ->
+ case format_msg(X, MiniMib, Start, Stop) of
+ {ok, S} ->
+ io:format("~s", [S]);
+ _ ->
+ ok
+ end
+ end,
+ (catch loop(disk_log:chunk(Log, start), Log, Write)),
+ snmp_mini_mib:delete(MiniMib),
+ ok.
+
+
+loop(eof, _Log, _Write) ->
+ ok;
+loop({error, _} = Error, _Log, _Write) ->
+ Error;
+loop({corrupt_log_file, _} = Reason, _Log, _Write) ->
+ {error, Reason};
+loop({Cont, Terms}, Log, Write) ->
+ case (catch lists:foreach(Write, Terms)) of
+ {'EXIT', Reason} ->
+ {error, Reason};
+ _ ->
+ loop(disk_log:chunk(Log, Cont), Log, Write)
+ end;
+loop({Cont, Terms, BadBytes}, Log, Write) ->
+ error_logger:error_msg("Skipping ~w bytes while converting ~p~n~n",
+ [BadBytes, Log]),
+ case (catch lists:foreach(Write, Terms)) of
+ {'EXIT', Reason} ->
+ {error, Reason};
+ _ ->
+ loop(disk_log:chunk(Log, Cont), Log, Write)
+ end;
+loop(Error, _Log, _Write) ->
+ Error.
+
+format_msg({TimeStamp, {V3Hdr, ScopedPdu}, {Addr, Port}},
+ Mib, Start, Stop) ->
+ format_msg({TimeStamp, {V3Hdr, ScopedPdu}, Addr, Port},
+ Mib, Start, Stop);
+format_msg({TimeStamp, {V3Hdr, ScopedPdu}, Addr, Port},
+ Mib, Start, Stop) ->
+% io:format("format_msg -> entry with"
+% "~n TimeStamp: ~p"
+% "~n Start: ~p"
+% "~n Stop: ~p", [TimeStamp, Start, Stop]),
+ case timestamp_filter(TimeStamp, Start, Stop) of
+ true ->
+ case (catch snmp_pdus:dec_scoped_pdu(ScopedPdu)) of
+ ScopedPDU when is_record(ScopedPDU, scopedPdu) ->
+ Msg = #message{version = 'version-3',
+ vsn_hdr = V3Hdr,
+ data = ScopedPDU},
+ f(ts2str(TimeStamp), Msg, Addr, Port, Mib);
+ {'EXIT', Reason} ->
+ format_tab("** error in log file at ~s from ~p:~w ~p\n\n",
+ [ts2str(TimeStamp), ip(Addr), Port, Reason])
+ end;
+ false ->
+ ignore
+ end;
+format_msg({TimeStamp, Packet, {Addr, Port}}, Mib, Start, Stop) ->
+ format_msg({TimeStamp, Packet, Addr, Port}, Mib, Start, Stop);
+format_msg({TimeStamp, Packet, Addr, Port}, Mib, Start, Stop) ->
+ case timestamp_filter(TimeStamp, Start, Stop) of
+ true ->
+ case (catch snmp_pdus:dec_message(binary_to_list(Packet))) of
+ Msg when is_record(Msg, message) ->
+ f(ts2str(TimeStamp), Msg, Addr, Port, Mib);
+ {'EXIT', Reason} ->
+ format_tab("** error in log file ~p\n\n", [Reason])
+ end;
+ false ->
+ ignore
+ end;
+format_msg(_, _Mib, _Start, _Stop) ->
+ format_tab("** unknown entry in log file\n\n", []).
+
+f(TimeStamp, #message{version = Vsn, vsn_hdr = VsnHdr, data = Data},
+ Addr, Port, Mib) ->
+ Str = format_pdu(Data, Mib),
+ HdrStr = format_header(Vsn, VsnHdr),
+ case get_type(Data) of
+ trappdu ->
+ f_trap(TimeStamp, Vsn, HdrStr, Str, Addr, Port);
+ 'snmpv2-trap' ->
+ f_trap(TimeStamp, Vsn, HdrStr, Str, Addr, Port);
+ 'inform-request' ->
+ f_inform(TimeStamp, Vsn, HdrStr, Str, Addr, Port);
+ 'get-response' ->
+ f_response(TimeStamp, Vsn, HdrStr, Str, Addr, Port);
+ report ->
+ f_report(TimeStamp, Vsn, HdrStr, Str, Addr, Port);
+ _ ->
+ f_request(TimeStamp, Vsn, HdrStr, Str, Addr, Port)
+ end.
+
+f_request(TimeStamp, Vsn, HdrStr, Str, Addr, Port) ->
+ format_tab("request ~s:~w - ~s [~s] ~w\n~s",
+ [ip(Addr), Port, HdrStr, TimeStamp, Vsn, Str]).
+
+f_response(TimeStamp, Vsn, HdrStr, Str, Addr, Port) ->
+ format_tab("response ~s:~w - ~s [~s] ~w\n~s",
+ [ip(Addr), Port, HdrStr, TimeStamp, Vsn, Str]).
+
+f_report(TimeStamp, Vsn, HdrStr, Str, Addr, Port) ->
+ format_tab("report ~s:~w - ~s [~s] ~w\n~s",
+ [ip(Addr), Port, HdrStr, TimeStamp, Vsn, Str]).
+
+f_trap(TimeStamp, Vsn, HdrStr, Str, Addr, Port) ->
+ format_tab("trap ~s:~w - ~s [~s] ~w\n~s",
+ [ip(Addr), Port, HdrStr, TimeStamp, Vsn, Str]).
+
+f_inform(TimeStamp, Vsn, HdrStr, Str, Addr, Port) ->
+ format_tab("inform ~s:~w - ~s [~s] ~w\n~s",
+ [ip(Addr), Port, HdrStr, TimeStamp, Vsn, Str]).
+
+
+%% Convert a timestamp 2-tupple to a printable string
+%%
+ts2str({Local,Universal}) ->
+ dat2str(Local) ++ " , " ++ dat2str(Universal);
+ts2str(_) ->
+ "".
+
+%% Convert a datetime 2-tupple to a printable string
+%%
+dat2str({{Y,M,D},{H,Min,S}}) ->
+ io_lib:format("~w-~w-~w,~w:~w:~w",[Y,M,D,H,Min,S]).
+
+
+timestamp_filter({Local,Universal},Start,Stop) ->
+ tsf_ge(Local,Universal,Start) and tsf_le(Local,Universal,Stop);
+timestamp_filter(_,_Start,_Stop) ->
+ true.
+
+tsf_ge(_Local,_Universal,null) ->
+ true;
+tsf_ge(Local,_Universal,{local_time,DateTime}) ->
+ tsf_ge(Local,DateTime);
+tsf_ge(_Local,Universal,{universal_time,DateTime}) ->
+ tsf_ge(Universal,DateTime);
+tsf_ge(Local,_Universal,DateTime) ->
+ tsf_ge(Local,DateTime).
+
+tsf_ge(TimeStamp,DateTime) ->
+ T1 = calendar:datetime_to_gregorian_seconds(TimeStamp),
+ T2 = calendar:datetime_to_gregorian_seconds(DateTime),
+ T1 >= T2.
+
+tsf_le(_Local,_Universal,null) ->
+ true;
+tsf_le(Local,_Universal,{local_time,DateTime}) ->
+ tsf_le(Local,DateTime);
+tsf_le(_Local,Universal,{universal_time,DateTime}) ->
+ tsf_le(Universal,DateTime);
+tsf_le(Local,_Universal,DateTime) ->
+ tsf_le(Local,DateTime).
+
+tsf_le(TimeStamp,DateTime) ->
+ T1 = calendar:datetime_to_gregorian_seconds(TimeStamp),
+ T2 = calendar:datetime_to_gregorian_seconds(DateTime),
+ T1 =< T2.
+
+
+%% In the output replace TAB by ESC TAB, and add a single trailing TAB.
+%%
+format_tab(Format, Args) ->
+ Str = lists:flatten(io_lib:format(Format, Args)),
+ DStr = lists:map(fun($\t) -> "\e\t"; (C) -> C end, Str),
+ {ok, io_lib:format("~s\t", [DStr])}.
+
+
+format_header('version-1', CommunityStr) ->
+ CommunityStr;
+format_header('version-2', CommunityStr) ->
+ CommunityStr;
+format_header('version-3', #v3_hdr{msgFlags = MsgFlags,
+ msgSecurityModel = SecModel,
+ msgSecurityParameters = SecParams}) ->
+ SecLevel = snmp_misc:get_sec_level(MsgFlags),
+ case SecModel of
+ ?SEC_USM ->
+ case catch snmp_pdus:dec_usm_security_parameters(SecParams) of
+ #usmSecurityParameters{msgAuthoritativeEngineID = AuthEngineID,
+ msgUserName = UserName} ->
+ io_lib:format("~w:\"~s\":\"~s\"",
+ [SecLevel, AuthEngineID, UserName]);
+ _ ->
+ "-"
+ end;
+ _ ->
+ "\"unknown security model\""
+ end.
+
+
+format_pdu(#scopedPdu{contextName = Context, data = Pdu}, Mib) ->
+ io_lib:format("Context: \"~s\"\n~s",
+ [Context, snmp_misc:format_pdu(Pdu, Mib)]);
+format_pdu(Pdu, Mib) ->
+ snmp_misc:format_pdu(Pdu, Mib).
+
+get_type(#scopedPdu{data = Pdu}) ->
+ get_type(Pdu);
+get_type(Pdu) when is_record(Pdu, trappdu) ->
+ trappdu;
+get_type(#pdu{type = Type}) ->
+ Type.
+
+
+ip({A,B,C,D}) ->
+ io_lib:format("~w.~w.~w.~w", [A,B,C,D]).
+
+
+
+%% -------------------------------------------------------------------
+%% Various utility functions
+%% -------------------------------------------------------------------
+
+log_open(Name, File, Size, Repair, Notify) ->
+ case do_log_open(Name, File, Size, Repair, Notify) of
+ {ok, Log} ->
+ {ok, Log};
+ {repaired, Log, Rec, Bad} ->
+ ?vlog("log_open -> repaired: "
+ "~n Rec: ~p"
+ "~n Bad: ~p", [Rec, Bad]),
+ {ok, Log};
+ Error ->
+ Error
+ end.
+
+%% We need to make sure we do not end up in an infinit loop
+%% Take the number of files of the wrap log and add 2 (for
+%% the index and size files).
+do_log_open(Name, File, {_, N} = Size, snmp_repair = _Repair, Notify) ->
+ do_snmp_log_open(Name, File, Size, N+2, Notify);
+
+do_log_open(Name, File, Size, snmp_repair = _Repair, Notify) ->
+ do_snmp_log_open(Name, File, Size, 1, Notify);
+
+do_log_open(Name, File, Size, Repair, Notify) ->
+ do_std_log_open(Name, File, Size, Repair, Notify).
+
+
+do_snmp_log_open(Name, File, Size, N, Notify) when N =< 0 ->
+ do_std_log_open(Name, File, Size, true, Notify);
+do_snmp_log_open(Name, File, Size, N, Notify) ->
+ case do_std_log_open(Name, File, Size, true, Notify) of
+ {error, {not_a_log_file, XFile}} ->
+ case file:rename(XFile, lists:append([XFile, ".MOVED"])) of
+ ok ->
+ ?vinfo("Failed open log file (even with repair) - "
+ "not a logfile:"
+ "~n Attempting to move file aside (.MOVED)"
+ "~n ~s", [XFile]),
+ do_snmp_log_open(Name, File, Size, N-1, Notify);
+ Error ->
+ {error, {rename_failed, Error}}
+ end;
+ {error, Reason} ->
+ ?vinfo("Failed open log file (even with repair) - "
+ "~n Attempting to move old log file aside (.MOVED)"
+ "~n~p", [Reason]),
+ move_log(File),
+ do_std_log_open(Name, File, Size, true, Notify);
+ Else ->
+ Else
+ end.
+
+
+%% First try to open the log without the size-spec. This will
+%% succeed if the log has already been created. In that case,
+%% we'll use whatever size the log had at the time it was closed.
+do_std_log_open(Name, File, Size, Repair, Notify) ->
+ Opts = [{name, Name},
+ {file, File},
+ {type, ?LOG_TYPE},
+ {format, ?LOG_FORMAT},
+ {mode, read_write},
+ {notify, Notify},
+ {repair, Repair}],
+ case disk_log:open(Opts) of
+ {error, {badarg, size}} ->
+ %% The log didn't exist, try with the size-spec
+ disk_log:open([{size, Size} | Opts]);
+ Else ->
+ Else
+ end.
+
+
+log_open(Name, File) ->
+ Opts = [{name, Name},
+ {file, File},
+ {type, ?LOG_TYPE},
+ {format, ?LOG_FORMAT},
+ {mode, read_only}],
+ case disk_log:open(Opts) of
+ {error, {badarg, size}} ->
+ {error, no_such_log};
+ Else ->
+ Else
+ end.
+
+
+move_log(File) ->
+ Dir = filename:dirname(File),
+ FileName = filename:basename(File),
+ case file:list_dir(Dir) of
+ {ok, Files0} ->
+ Files = [F || F <- Files0, lists:prefix(FileName, F)],
+ F = fun(XFile) ->
+ file:rename(XFile, lists:append([XFile, ".MOVED"]))
+ end,
+ lists:foreach(F, Files);
+ _ ->
+ ok
+ end.
+
+
+is_owner(Log) ->
+ lists:member(self(), log_owners(Log)).
+
+log_owners(Log) ->
+ Info = log_info(Log),
+ case lists:keysearch(owners, 1, Info) of
+ {value, {_, Pids}} ->
+ [P || {P, _} <- Pids];
+ _ ->
+ []
+ end.
+
+log_info(Log) ->
+ case disk_log:info(Log) of
+ Info when is_list(Info) ->
+ Info;
+ _ ->
+ []
+ end.
+
+
+timestamp() ->
+ {calendar:local_time(), calendar:universal_time()}.
+
diff --git a/lib/snmp/src/misc/snmp_mini_mib.erl b/lib/snmp/src/misc/snmp_mini_mib.erl
new file mode 100644
index 0000000000..d80270d5c2
--- /dev/null
+++ b/lib/snmp/src/misc/snmp_mini_mib.erl
@@ -0,0 +1,151 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2006-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%
+%%
+
+-module(snmp_mini_mib).
+
+%% need definition of mib record
+-include("snmp_types.hrl").
+
+-export([
+ create/1,
+ delete/1,
+ aliasname/2,
+ oid/2,
+ type/2
+ ]).
+
+
+-record(mini_mib, {cache, db = []}).
+
+
+%%%--------------------------------------------------
+%%% The Mini MIB representation
+%%%--------------------------------------------------
+
+%% Returns a Mini MIB
+create(Mibs) ->
+ Loaded = lists:append([load_mib(Mib) || Mib <- Mibs]),
+ Sorted = lists:keysort(1, Loaded),
+ Db = remove_dubbletts(Sorted),
+ Cache = ets:new(snmp_mini_mib_cache, [set, {keypos, 1}]),
+ #mini_mib{cache = Cache,
+ db = Db}.
+
+delete(#mini_mib{cache = Cache}) ->
+ ets:delete(Cache),
+ ok.
+
+
+%%----------------------------------------------------------------------
+%% Returns: A list of {Oid, Aliasname, Type}
+%%----------------------------------------------------------------------
+load_mib(MIB) ->
+ F1 = snmp_misc:strip_extension_from_filename(MIB, ".bin"),
+ ActualFileName = lists:append(F1, ".bin"),
+ case snmp_misc:read_mib(ActualFileName) of
+ {ok, #mib{mes = MEs, traps = Traps}} ->
+ make_mini_mib_elem(MEs++Traps);
+ {error, Reason} ->
+ exit({error, {MIB, Reason}})
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Pre: List is sorted (dublettes are list neighbours)
+%%----------------------------------------------------------------------
+remove_dubbletts([]) -> [];
+remove_dubbletts([X]) -> [X];
+remove_dubbletts([X,X|T]) -> remove_dubbletts([X|T]);
+remove_dubbletts([X|T]) -> [X|remove_dubbletts(T)].
+
+
+%%----------------------------------------------------------------------
+%% Args: A list if Mes
+%% Returns: a list of {Oid, Aliasname, Type}
+%%----------------------------------------------------------------------
+make_mini_mib_elem([]) -> [];
+make_mini_mib_elem([#me{aliasname = N,
+ oid = Oid,
+ entrytype = variable,
+ asn1_type = #asn1_type{bertype = Type}} | T]) ->
+ [{Oid, N, Type} | make_mini_mib_elem(T)];
+make_mini_mib_elem([#me{aliasname = N,
+ oid = Oid,
+ entrytype = table_column,
+ asn1_type = ASN1}|T])
+ when is_record(ASN1, asn1_type)->
+ [{Oid, N, ASN1#asn1_type.bertype} | make_mini_mib_elem(T)];
+make_mini_mib_elem([#me{aliasname = N,
+ oid = Oid,
+ asn1_type = undefined}|T]) ->
+ [{Oid, N, undefined} | make_mini_mib_elem(T)];
+make_mini_mib_elem([#notification{trapname = N,
+ oid = Oid}|T]) ->
+ [{Oid, N, undefined} | make_mini_mib_elem(T)];
+make_mini_mib_elem([_|T]) ->
+ make_mini_mib_elem(T).
+
+
+%%----------------------------------------------------------------------
+%% Returns: false | {Oid, Aliasname, Type}
+%%----------------------------------------------------------------------
+
+aliasname(#mini_mib{cache = Cache, db = Db}, Oid) ->
+ Key = {Oid, aliasname},
+ case ets:lookup(Cache, Key) of
+ [{_, Value}] ->
+ Value;
+ _ ->
+ Value = aliasname(Db, Oid, false),
+ ets:insert(Cache, {Key, Value}),
+ Value
+ end.
+
+aliasname([], _Oid, Res) ->
+ Res;
+aliasname([{Oid, _Aliasname, _Type} = OidData|T], OidX, Res)
+ when Oid =< OidX ->
+ case lists:prefix(Oid, OidX) of
+ true ->
+ aliasname(T, OidX, OidData);
+ false ->
+ aliasname(T, OidX, Res)
+ end;
+aliasname([{_Oid, _Aliasname, _Type}|_T], _OidX, Res) ->
+ Res.
+
+
+oid(#mini_mib{db = Db}, AliasName) ->
+ case lists:keysearch(AliasName, 2, Db) of
+ {value, {Oid, _Aliasname, _Type}} ->
+ Oid;
+ false ->
+ false
+ end.
+
+
+type(MiniMIB, Oid) ->
+ case aliasname(MiniMIB, Oid) of
+ {_Oid, _AliasName, Type} ->
+ Type;
+ Else ->
+ Else
+ end.
+
+
diff --git a/lib/snmp/src/misc/snmp_misc.erl b/lib/snmp/src/misc/snmp_misc.erl
new file mode 100644
index 0000000000..1b535743a4
--- /dev/null
+++ b/lib/snmp/src/misc/snmp_misc.erl
@@ -0,0 +1,465 @@
+%%
+%% %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%
+%%
+
+-module(snmp_misc).
+
+%% need definition of mib record
+-include("snmp_types.hrl").
+-include("snmpc_misc.hrl").
+
+-define(VMODULE,"MISC").
+-include("snmp_verbosity.hrl").
+
+
+-export([assq/2,
+ bits_to_int/2,
+ diff/2,
+ ensure_trailing_dir_delimiter/1,
+ foreach/3,
+ format_pdu/2,
+ format_val/4,
+ format_vb/2,
+ format_vbs/2,
+ format/3,
+ get_option/2,
+ get_option/3,
+ get_sec_level/1,
+ ip/1,
+ is_auth/1,
+ is_BitString/1,
+ is_oid/1,
+ is_priv/1,
+ is_reportable/1,
+ is_reportable_pdu/1,
+ is_string/1,
+ is_tag_member/2,
+ is_tmask_match/3,
+ keyreplaceadd/4,
+ mem_size/1,
+ mk_msg_flags/2,
+ multi_map/2,
+ %% now/0,
+ now/1,
+ read_mib/1,
+ set_option/3,
+ sleep/1,
+ strip_extension_from_filename/2,
+ str_xor/2,
+ time/3,
+
+ verify_behaviour/2
+ ]).
+
+
+verify_behaviour(Behaviour, UserMod)
+ when is_atom(Behaviour) andalso is_atom(UserMod) ->
+ case (catch UserMod:module_info(exports)) of
+ Exps when is_list(Exps) ->
+ Callbacks = Behaviour:behaviour_info(callbacks),
+ (catch verify_behaviour2(Callbacks, Exps));
+ _ ->
+ {error, {bad_module, UserMod}}
+ end;
+verify_behaviour(_, BadModule) ->
+ {error, {bad_module, BadModule}}.
+
+verify_behaviour2([], _) ->
+ ok;
+verify_behaviour2([{Func, Arity} = FuncArity|Callbacks], Exps) ->
+ case lists:member(FuncArity, Exps) of
+ true ->
+ verify_behaviour2(Callbacks, Exps);
+ false ->
+ throw({error, {bad_module, {function, Func, Arity}}})
+ end.
+
+
+sleep(Time) ->
+ receive
+ after Time ->
+ true
+ end.
+
+
+%% Returns time in ms = sec/1000
+% now() -> now(ms).
+now(ms) ->
+ Now = erlang:now(),
+ element(1,Now)*1000000000+
+ element(2,Now)*1000+
+ (element(3,Now) div 1000);
+%% Returns time in cs = sec/100
+now(cs) ->
+ Now = erlang:now(),
+ element(1,Now)*100000000+
+ element(2,Now)*100+
+ (element(3,Now) div 10000);
+now(sec) ->
+ Now = erlang:now(),
+ element(1,Now)*1000000+
+ element(2,Now)+
+ (element(3,Now) div 1000000).
+
+
+is_string([]) -> true;
+is_string([Tkn | Str])
+ when is_integer(Tkn) andalso (Tkn >= 0) andalso (Tkn =< 255) ->
+ is_string(Str);
+is_string(_) -> false.
+
+
+is_oid([E1, E2| Rest])
+ when (length(Rest) =< 126) andalso (E1 *40 + E2 =< 255) ->
+ is_oid2(Rest);
+is_oid([E1]) when E1 =< 2 ->
+ true;
+is_oid(_) -> false.
+
+is_oid2([]) -> true;
+is_oid2([Nbr | RestOid])
+ when is_integer(Nbr) andalso (0 =< Nbr) andalso (Nbr =< 2147483647) ->
+ is_oid2(RestOid);
+is_oid2(_) -> false.
+
+is_BitString([]) -> true;
+is_BitString([Nbr | RestBitstring])
+ when is_integer(Nbr) andalso (Nbr >= 0) andalso (Nbr =< 1) ->
+ is_BitString(RestBitstring);
+is_BitString(_) -> false.
+
+
+%% Check if a Tag is a member in a TagList. Tags and TagLists are defined
+%% in SNMP-TARGET-MIB
+is_tag_member(Tag, TagList) ->
+ check_tag_list(TagList, [], lists:reverse(Tag)).
+
+check_tag_list([32 | T], Res, Gat) ->
+ tag_delimiter_found(Res, Gat, T);
+check_tag_list([9 | T], Res, Gat) ->
+ tag_delimiter_found(Res, Gat, T);
+check_tag_list([13 | T], Res, Gat) ->
+ tag_delimiter_found(Res, Gat, T);
+check_tag_list([11 | T], Res, Gat) ->
+ tag_delimiter_found(Res, Gat, T);
+check_tag_list([Char | T], Res, Gat) ->
+ check_tag_list(T, [Char | Res], Gat);
+check_tag_list([], Res, Gat) ->
+ tag_delimiter_found(Res, Gat, []).
+
+tag_delimiter_found(Gat, Gat, _T) ->
+ true;
+tag_delimiter_found(_Res, _Gat, []) ->
+ false;
+tag_delimiter_found(_Res, Gat, T) ->
+ check_tag_list(T, [], Gat).
+
+
+%% Pre: length(TAddr1) == length(TAddr2)
+%% length(TMask) == 0 | length(TAddr1)
+is_tmask_match(_TAddr1, _TAddr2, []) ->
+ true;
+is_tmask_match([H1 | T1], [H2 | T2], [M1 | M2]) ->
+ if
+ (H1 band M1) == (H2 band M1) ->
+ is_tmask_match(T1, T2, M2);
+ true ->
+ false
+ end.
+
+
+%%--------------------------------------------------
+%% Not a real assq, but what the heck, it's useful.
+%%--------------------------------------------------
+assq(Key, List) ->
+ case lists:keysearch(Key, 1, List) of
+ {value, {Key, Val}} -> {value, Val};
+ _ -> false
+ end.
+
+get_option(Key, Options) ->
+ case lists:keysearch(Key, 1, Options) of
+ {value, {_Key, Value}} ->
+ Value;
+ _ ->
+ throw({error, {not_found, Key}})
+ end.
+
+get_option(Key, Options, Default) ->
+ case lists:keysearch(Key, 1, Options) of
+ {value, {_Key, Value}} ->
+ Value;
+ _ ->
+ Default
+ end.
+
+set_option(Key, Val, Opts) ->
+ keyreplaceadd(Key, 1, Opts, {Key, Val}).
+
+keyreplaceadd(Key, Pos, List, New) ->
+ case lists:keysearch(Key, Pos, List) of
+ {value, _} -> lists:keyreplace(Key, Pos, List, New);
+ _ -> [New | List]
+ end.
+
+is_auth(SecLevel) ->
+ 1 == (SecLevel band 1).
+
+is_priv(SecLevel) ->
+ 2 == (SecLevel band 2).
+
+is_reportable([MsgFlag]) ->
+ 4 == (MsgFlag band 4).
+
+%% [OTP-3416]
+%% [RFC 2571] Confirmed Class: GetRequest-PDU, GetNextRequest-PDU,
+%% GetBulkRequest-PDU, SetRequest-PDU, and InformRequest-PDU.
+%% Unconfirmed Class: Report-PDU, Trapv2-PDU, and GetResponse-PDU.
+%% [RFC 2572] The reportableFlag MUST always be zero when the message
+%% contains a PDU from the Unconfirmed Class; it MUST always be one
+%% for a PDU from the Confirmed Class,
+%%
+is_reportable_pdu('get-request') -> true;
+is_reportable_pdu('get-next-request') -> true;
+is_reportable_pdu('get-bulk-request') -> true;
+is_reportable_pdu('set-request') -> true;
+is_reportable_pdu('inform-request') -> true;
+is_reportable_pdu(_) -> false.
+
+mk_msg_flags(PduType, SecLevel) ->
+ Flags1 = case is_reportable_pdu(PduType) of
+ true -> 4;
+ false -> 0
+ end,
+ [Flags1 bor SecLevel].
+
+get_sec_level([Flag]) ->
+ SecLevel = Flag band 3,
+ case {is_auth(SecLevel), is_priv(SecLevel)} of
+ {false, false} -> noAuthNoPriv;
+ {true, false} -> authNoPriv;
+ {true, true} -> authPriv
+ end.
+
+
+%% diff(L1, L2) -> L1 - L2.
+%% Ex. [1, 2, 3, 4] - [1, 3, 4] = [2, 3, 4]
+diff(L1, []) -> L1;
+diff([H | T1], [H | T2]) -> diff(T1, T2);
+diff(L1, _) -> L1.
+
+foreach(Function, ExtraArgs, [H | T]) ->
+ apply(Function, [H | ExtraArgs]),
+ foreach(Function, ExtraArgs, T);
+foreach(_Function, _ExtraArgs, []) -> true.
+
+str_xor([H1|T1], [H2|T2]) ->
+ [H1 bxor H2 | str_xor(T1, T2)];
+str_xor([], []) ->
+ [].
+
+
+%%-----------------------------------------------------------------
+%% Pre: ListOfLists is a list of N lists, each of length M.
+%% Func is a function of arity N.
+%% Returns: A list of length M where element Y is the result of
+%% applying Func on [Elem(Y, List1), ..., Elem(Y, ListN)].
+%%-----------------------------------------------------------------
+multi_map(_Func, [[] | _ListOfLists]) ->
+ [];
+multi_map(Func, ListOfLists) ->
+ HD = [hd(L) || L <- ListOfLists],
+ TL = [tl(L) || L <- ListOfLists],
+%% io:format("multi_map -> "
+%% "~n HD: ~p"
+%% "~n TL: ~p", [HD, TL]),
+ [
+ apply(Func, HD) | multi_map(Func, TL)
+ ].
+
+%% Primitive performance analysis.
+time(M,F,A) ->
+ statistics(runtime),
+ R = apply(M, F, A),
+ {R, statistics(runtime)}.
+
+%% How much memory is allocated for X? At least some kind of upper estimation...
+mem_size(X) ->
+ E = ets:new(tmp, [set, protected]),
+ M1 = ets:info(E, memory),
+ ets:insert(E, {make_ref(), X}),
+ M2 = ets:info(E, memory),
+ ets:delete(E),
+ M2 - M1.
+
+
+strip_extension_from_filename(FileName, Ext) when is_atom(FileName) ->
+ strip_extension_from_filename(atom_to_list(FileName), Ext);
+
+strip_extension_from_filename(FileName, Ext) when is_list(FileName) ->
+ case lists:suffix(Ext, FileName) of
+ true -> lists:sublist(FileName, 1, length(FileName) - length(Ext));
+ false -> FileName
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Returns: {ok, Mib}|{error, Reason}
+%%
+%%----------------------------------------------------------------------
+read_mib(FileName) ->
+ (catch do_read_mib(FileName)).
+
+do_read_mib(FileName) ->
+ ?read_mib(FileName).
+
+
+%%----------------------------------------------------------------------
+%% Converts a list of named bits to the integer value.
+%% Returns: integer()|error
+%%----------------------------------------------------------------------
+bits_to_int(Val,Kibbles) ->
+ bits_to_int(Val,Kibbles,0).
+
+bits_to_int([],_Kibbles,Res) -> Res;
+bits_to_int([Kibble|Ks],Kibbles,Res) ->
+ case snmp_misc:assq(Kibble,Kibbles) of
+ {value,V} ->
+ bits_to_int(Ks,Kibbles,Res + round(math:pow(2,V)));
+ _ ->
+ error
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Returns: {ok, {int(),int(),int(),int()}} | {error, Reason}
+%%----------------------------------------------------------------------
+ip(Host) ->
+ inet:getaddr(Host, inet).
+
+ensure_trailing_dir_delimiter([]) -> "/";
+ensure_trailing_dir_delimiter(DirSuggestion) ->
+ case lists:last(DirSuggestion) of
+ $/ -> DirSuggestion;
+ _ -> lists:append(DirSuggestion,"/")
+ end.
+
+
+format_pdu(PDU, MiniMib) when is_record(PDU, pdu) ->
+ #pdu{type = T,
+ error_status = ES,
+ error_index = EI,
+ request_id = RID,
+ varbinds = VBs} = PDU,
+ Txt1 = if
+ (ES =:= noError) andalso (EI =:= 0) ->
+ "";
+ (T =:= 'get-bulk-request') ->
+ "";
+ true ->
+ io_lib:format("*!*!* An error occured. *!*!* ~n"
+ "Error status = ~w, index = ~w.~n",
+ [ES, EI])
+ end,
+ Txt2 = if T =:= 'snmpv2-trap' ->
+ io_lib:format("v2 Trap, Request Id:~w~n", [RID]);
+ T =:= 'get-request' ->
+ io_lib:format("Get request, Request Id:~w~n", [RID]);
+ T =:= 'get-next-request' ->
+ io_lib:format("Get-Next request, Request Id:~w~n", [RID]);
+ T =:= 'get-bulk-request' ->
+ io_lib:format("Get-Bulk request, Request Id:~w~n"
+ " Non-repeaters = ~w~n"
+ " Max-repetitions = ~w~n", [RID, ES, EI]);
+ T =:= 'set-request' ->
+ io_lib:format("Set request, Request Id:~w~n", [RID]);
+ T =:= 'get-response' ->
+ io_lib:format("Response, Request Id:~w~n", [RID]);
+ T =:= 'inform-request' ->
+ io_lib:format("Inform Request Request Id:~w~n", [RID]);
+ T =:= report ->
+ io_lib:format("Report Request Id:~w~n", [RID]);
+ true ->
+ ""
+ end,
+ [Txt1, Txt2, format_vbs(VBs, MiniMib)|"\n"];
+
+format_pdu(#trappdu{enterprise = Enterprise,
+ agent_addr = AgentAddr,
+ generic_trap = GenericTrap,
+ specific_trap = SpecificTrap,
+ time_stamp = TimeStamp,
+ varbinds = VBs}, MiniMib) ->
+ [io_lib:format("v1 Trap~n"
+ " Generic: ~w~n"
+ " Enterprise: ~w~n"
+ " Specific: ~w~n"
+ " Agent addr: ~w~n"
+ " TimeStamp: ~w~n",
+ [GenericTrap,
+ element(1,symbolify_oid(MiniMib,Enterprise)),SpecificTrap,
+ AgentAddr, TimeStamp]),
+ format_vbs(VBs, MiniMib) | "\n"].
+
+format_vbs(Vbs, MiniMib) ->
+ [format_vb(VB, MiniMib) || VB <- Vbs].
+
+format_vb(#varbind{oid = Oid,
+ variabletype = Type,
+ value = Value}, MiniMib) ->
+ {Soid, Mtype} = symbolify_oid(MiniMib, Oid),
+ [io_lib:format(" ~w = ", [Soid]),
+ format_val(Type, Mtype, Value, MiniMib) | "\n"].
+
+format(Max, F, A) when is_integer(Max) ->
+ case lists:flatten(io_lib:format(F,A)) of
+ S when length(S) > Max ->
+ case lists:suffix("\n", S) of
+ true ->
+ lists:concat([lists:sublist(S,Max), "...\n"]);
+ false ->
+ lists:concat([lists:sublist(S,Max), "..."])
+ end;
+ S ->
+ S
+ end.
+
+
+%%----------------------------------------------------------------------
+%% Returns: (a nested) symbolified oid.
+%%----------------------------------------------------------------------
+symbolify_oid(MiniMib, Oid) ->
+ case snmp_mini_mib:aliasname(MiniMib, Oid) of
+ false ->
+ {Oid, unknown};
+ {FoundOid, Aliasname, Type} ->
+ Rest = snmp_misc:diff(Oid, FoundOid),
+ {[Aliasname| Rest], Type}
+ end.
+
+format_val('OCTET STRING', 'BITS', Val, _MiniMib) ->
+ io_lib:format("~w", [snmp_pdus:octet_str_to_bits(Val)]);
+format_val('OBJECT IDENTIFIER', _, Val, MiniMib) ->
+ {NVal, _} = symbolify_oid(MiniMib, Val),
+ io_lib:format("~w", [NVal]);
+format_val(_, _, Val, _MiniMib) ->
+ io_lib:format("~p", [Val]).
+
+
+
+
diff --git a/lib/snmp/src/misc/snmp_note_store.erl b/lib/snmp/src/misc/snmp_note_store.erl
new file mode 100644
index 0000000000..a21a6209f1
--- /dev/null
+++ b/lib/snmp/src/misc/snmp_note_store.erl
@@ -0,0 +1,450 @@
+%%
+%% %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%
+%%
+
+-module(snmp_note_store).
+
+-behaviour(gen_server).
+
+-include_lib("snmp/src/app/snmp_internal.hrl").
+-include("snmp_debug.hrl").
+-include("snmp_verbosity.hrl").
+
+%% External exports
+-export([start_link/3, stop/1,
+ get_note/2,
+ set_note/3, set_note/4,
+ info/1, verbosity/2]).
+
+%% Internal exports
+-export([init/1,
+ handle_call/3,
+ handle_cast/2,
+ handle_info/2,
+ terminate/2,
+ code_change/3]).
+
+-export([timer/3]).
+
+-define(timeout, 30000). % Perform gc twice in a minute.
+
+-ifndef(default_verbosity).
+-define(default_verbosity,silence).
+-endif.
+
+-ifdef(snmp_debug).
+-define(GS_START_LINK(Args),
+ gen_server:start_link(?MODULE, Args, [{debug,[trace]}])).
+-else.
+-define(GS_START_LINK(Args),
+ gen_server:start_link(?MODULE, Args, [])).
+-endif.
+
+
+-record(state, {mod, notes, timer, timeout, active = false}).
+
+
+%%%-----------------------------------------------------------------
+%%% Implements a database for notes with a lifetime. Once in a
+%%% while, the database will be gc:ed, to get rid of old notes.
+%%% This database will not contain much data.
+%%% Options is a list of Option, where Option is
+%%% {verbosity, silence|log|debug|trace} % undocumented feature
+%%%-----------------------------------------------------------------
+start_link(Prio, Mod, Opts) ->
+ ?d("start_link -> entry with"
+ "~n Prio: ~p"
+ "~n Mod: ~p"
+ "~n Opts: ~p", [Prio, Mod, Opts]),
+ ?GS_START_LINK([Prio, Mod, Opts]).
+
+
+%%-----------------------------------------------------------------
+%% Interface functions.
+%%-----------------------------------------------------------------
+
+stop(Pid) ->
+ call(Pid, stop).
+
+get_note(Pid, Key) ->
+ call(Pid, {get_note, Key}).
+
+%% Lifetime is in 1/10 sec or infinity
+set_note(Pid, Key, Value) ->
+ set_note(Pid, infinity, Key, Value).
+set_note(Pid, Lifetime, Key, Value) ->
+ call(Pid, {set_note, Lifetime, Key, Value}).
+
+info(Pid) ->
+ call(Pid, info).
+
+verbosity(Pid, Verbosity) ->
+ cast(Pid, {verbosity, Verbosity}).
+
+
+init([Prio, Mod, Opts]) ->
+ ?d("init -> entry with"
+ "~n Prio: ~p"
+ "~n Mod: ~p"
+ "~n Opts: ~p", [Prio, Mod, Opts]),
+ case (catch do_init(Prio, Mod, Opts)) of
+ {ok, State} ->
+ {ok, State};
+ E ->
+ error_msg("failed starting note-store: ~n~p", [E]),
+ {stop, E}
+ end.
+
+do_init(Prio, Mod, Opts) ->
+ process_flag(trap_exit, true),
+ process_flag(priority, Prio),
+ put(sname, get_sname(Opts)),
+ put(verbosity, get_verbosity(Opts)),
+ put(snmp_component, get_component(Mod)),
+ ?vlog("starting",[]),
+ Notes = ets:new(snmp_note_store, [set, protected]),
+ Timeout = get_timeout(Opts),
+ State = #state{mod = Mod,
+ notes = Notes,
+ timeout = Timeout,
+ timer = start_timer(Timeout)},
+ ?vdebug("started",[]),
+ {ok, State}.
+
+
+%%-----------------------------------------------------------------
+%% A note is any internal information that has to be
+%% stored for some time (the Lifetime).
+%% A note is stored in ets as {Key, {BestBefore, Value}},
+%% where BestBefore is currentTime + Lifetime.
+%% A GC-op can destroy any notes with CurTime > BestBore.
+%% Lifetime is in centiseconds or infinity, in which case
+%% the note is eternal.
+%%-----------------------------------------------------------------
+handle_call({set_note, Lifetime, Key, Value}, _From,
+ #state{mod = Mod, notes = Notes} = State)
+ when is_integer(Lifetime) ->
+ ?vlog("set note <~p,~p> with life time ~p", [Key,Value,Lifetime]),
+ case (catch Mod:system_start_time()) of
+ SysStartTime when is_integer(SysStartTime) ->
+ ?vtrace("handle_call(set_note) -> SysStartTime: ~p",
+ [SysStartTime]),
+ Now = snmp_misc:now(cs),
+ ?vtrace("handle_call(set_note) -> Now: ~p", [Now]),
+ RealUpTime = Now - SysStartTime,
+ ?vtrace("handle_call(set_note) -> RealUpTime: ~p", [RealUpTime]),
+ BestBefore = RealUpTime + Lifetime,
+ ?vtrace("handle_call(set_note) -> BestBefore: ~p", [BestBefore]),
+ Val = ets:insert(Notes, {Key, {BestBefore, Value}}),
+ NState = activate_timer(State),
+ {reply, Val, NState};
+ _Crap ->
+ ?vinfo("handle_call(set_note) -> "
+ "failed retreiving system start time from ~w: "
+ "~n ~p", [Mod, _Crap]),
+ {reply, {error, failed_retreive_system_start_time}, State}
+ end;
+
+handle_call({set_note, infinity, Key, Value}, _From,
+ #state{notes = Notes} = State) ->
+ ?vlog("set note <~p,~p>",[Key,Value]),
+ Val = ets:insert(Notes, {Key, {infinity, Value}}),
+ ?vdebug("set note; old value: ~p",[Val]),
+ {reply, Val, State};
+
+handle_call({get_note, Key}, _From,
+ #state{mod = Mod, notes = Notes} = State) ->
+ ?vlog("get note ~p",[Key]),
+ Val = handle_get_note(Notes, Mod, Key),
+ ?vdebug("get note: ~p",[Val]),
+ {reply, Val, State};
+
+handle_call(info, _From, #state{timer = Pid, notes = Notes} = State) ->
+ ?vlog("info",[]),
+ Info = get_info(Pid, Notes),
+ {reply, Info, State};
+
+handle_call(stop, _From, State) ->
+ ?vlog("stop",[]),
+ {stop, normal, ok, State};
+
+handle_call(Req, From, State) ->
+ warning_msg("received unexpected request from ~p: ~n~p",[From, Req]),
+ {reply, {error, {unknown_request, Req}}, State}.
+
+
+handle_cast({verbosity,Verbosity}, State) ->
+ ?vlog("verbosity: ~p -> ~p",[get(verbosity),Verbosity]),
+ put(verbosity,snmp_verbosity:validate(Verbosity)),
+ {noreply, State};
+
+handle_cast(Msg, State) ->
+ warning_msg("received unexpected message: ~n~p",[Msg]),
+ {noreply, State}.
+
+
+%%-----------------------------------------------------------------
+%% If there are no possible garbage left, we don't
+%% have to wait for timeout, and perform another
+%% gc, because we won't do anything. So
+%% we switch the timeout off in that case.
+%% It will be switched on as soon as we get some
+%% other message.
+%%-----------------------------------------------------------------
+handle_info(timeout, State) ->
+ ?vdebug("timeout",[]),
+ case gc(State) of
+ nothing_left ->
+ NState = deactivate_timer(State),
+ {noreply, NState};
+ work_to_do ->
+ NState = activate_timer(State),
+ {noreply, NState}
+ end;
+
+handle_info({'EXIT', Pid, Reason},
+ #state{timer = Pid, timeout = Timeout} = State) ->
+ ?vinfo("exit message from the timer process ~p for reason ~p",
+ [Pid, Reason]),
+ set_state(State#state{timer = start_timer(Timeout)});
+
+handle_info({'EXIT',Pid,Reason}, State) ->
+ ?vlog("exit message from ~p for reason ~p",[Pid,Reason]),
+ {noreply, State};
+
+handle_info(Info, State) ->
+ warning_msg("received unexpected info: ~n~p",[Info]),
+ {noreply, State}.
+
+
+set_state(S) ->
+ case gc(S) of
+ nothing_left ->
+ NState = deactivate_timer(S),
+ {noreply, NState};
+ work_to_do ->
+ NState = activate_timer(S),
+ {noreply, NState}
+ end.
+
+
+terminate(Reason, _State) ->
+ ?vdebug("terminate: ~p",[Reason]),
+ ok.
+
+
+%%----------------------------------------------------------
+%% Code change
+%%----------------------------------------------------------
+
+% downgrade
+code_change({down, _Vsn}, State, _Extra) ->
+ NState = activate_timer(deactivate_timer(State)),
+ {ok, NState};
+
+% upgrade
+code_change(_Vsn, State, _Extra) ->
+ process_flag(trap_exit, true),
+ NState = restart_timer(State),
+ {ok, NState}.
+
+
+%%----------------------------------------------------------
+%% Timer
+%%----------------------------------------------------------
+
+activate_timer(#state{timer = Pid, active = false} = State) ->
+ Pid ! activate,
+ receive
+ activated -> ok
+ end,
+ State#state{active = true};
+activate_timer(State) ->
+ State.
+
+deactivate_timer(#state{timer = Pid, active = true} = State) ->
+ Pid ! deactivate,
+ receive
+ deactivated -> ok
+ end,
+ State#state{timeout = false};
+deactivate_timer(State) ->
+ State.
+
+start_timer(Timeout) ->
+ spawn_link(?MODULE, timer, [self(), passive, Timeout]).
+
+%% Kill, restart and activate timer.
+restart_timer(#state{timer = Pid, timeout = Timeout} = State) ->
+ ?d("restart_timer -> kill current timer process ~p",[Pid]),
+ exit(Pid, kill),
+ ?d("restart_timer -> await acknowledgement",[]),
+ receive
+ {'EXIT', Pid, _Reason} ->
+ ok
+ end,
+ ?d("restart_timer -> start a new timer process",[]),
+ activate_timer(State#state{timer = start_timer(Timeout), active = false}).
+
+timer(Pid, passive, Timeout) ->
+ receive
+ deactivate ->
+ ?d("timer(passive) -> deactivate request, just send ack",[]),
+ Pid ! deactivated,
+ ?MODULE:timer(Pid, passive, Timeout);
+
+ activate ->
+ ?d("timer(deactive) -> activate request, send ack",[]),
+ Pid ! activated,
+ ?d("timer(deactive) -> activate",[]),
+ ?MODULE:timer(Pid, active, Timeout) % code replacement
+ after
+ Timeout ->
+ ?d("timer(deactive) -> timeout",[]),
+ ?MODULE:timer(Pid, passive, Timeout)
+ end;
+timer(Pid, active, Timeout) ->
+ receive
+ activate ->
+ ?d("timer(active) -> activate request, just send ack",[]),
+ Pid ! activated,
+ ?MODULE:timer(Pid, active, Timeout);
+
+ deactivate ->
+ ?d("timer(active) -> deactivate request, send ack",[]),
+ Pid ! deactivated,
+ ?d("timer(active) -> deactivate",[]),
+ ?MODULE:timer(Pid, passive, Timeout)
+ after
+ Timeout ->
+ ?d("timer(active) -> timeout",[]),
+ Pid ! timeout,
+ ?MODULE:timer(Pid, active, Timeout)
+ end.
+
+
+handle_get_note(Notes, Mod, Key) ->
+ case ets:lookup(Notes, Key) of
+ [{Key, {infinity, Val}}] ->
+ Val;
+ [{Key, {BestBefore, Val}}] ->
+ ?vtrace("get note -> BestBefore: ~w", [BestBefore]),
+ StartTime = Mod:system_start_time(),
+ ?vtrace("get note -> StartTime: ~w", [StartTime]),
+ Now = snmp_misc:now(cs),
+ ?vtrace("get note -> Now: ~w", [Now]),
+ case (Now - StartTime) of
+ Diff when BestBefore >= Diff ->
+ ?vtrace("get note -> Diff: ~w", [Diff]),
+ Val;
+ OldDiff ->
+ ?vtrace("get note -> note to old [~w] - delete", [OldDiff]),
+ ets:delete(Notes, Key),
+ undefined
+ end;
+ [] ->
+ undefined
+ end.
+
+
+%%-----------------------------------------------------------------
+%% Clean up all old notes in the database.
+%%-----------------------------------------------------------------
+gc(#state{mod = Mod, notes = Notes}) ->
+ RealUpTime = snmp_misc:now(cs) - Mod:system_start_time(),
+ gc(nothing_left, ets:tab2list(Notes), Notes, RealUpTime).
+
+gc(Flag, [{_Key, {infinity, _}} | T], Tab, Now) -> gc(Flag, T, Tab, Now);
+gc(Flag, [{Key, {BestBefore, _}} | T], Tab, Now)
+ when is_integer(BestBefore) andalso (BestBefore < Now) ->
+ ets:delete(Tab, Key),
+ gc(Flag, T, Tab, Now);
+gc(_Flag, [_ | T], Tab, Now) -> gc(work_to_do, T, Tab, Now);
+gc(Flag, [], _Tab, _Now) -> Flag.
+
+
+%%-----------------------------------------------------------------
+
+get_info(Tmr, Notes) ->
+ ProcSize = proc_mem(self()),
+ TMRSz = proc_mem(Tmr),
+ NotesSz = tab_size(Notes),
+ [{process_memory, [{notes, ProcSize}, {timer, TMRSz}]},
+ {db_memory, [{notes, NotesSz}]}].
+
+proc_mem(P) when is_pid(P) ->
+ case (catch erlang:process_info(P, memory)) of
+ {memory, Sz} ->
+ Sz;
+ _ ->
+ undefined
+ end;
+proc_mem(_) ->
+ undefined.
+
+tab_size(T) ->
+ case (catch ets:info(T, memory)) of
+ Sz when is_integer(Sz) ->
+ Sz;
+ _ ->
+ undefined
+ end.
+
+
+%%-----------------------------------------------------------------
+
+call(Pid, Req) ->
+ call(Pid, Req, infinity).
+
+call(Pid, Req, Timeout) ->
+ gen_server:call(Pid, Req, Timeout).
+
+cast(Pid, Msg) ->
+ gen_server:cast(Pid, Msg).
+
+
+%%-----------------------------------------------------------------
+
+%% info_msg(F, A) ->
+%% ?snmp_info(get(snmp_component), "Note store server " ++ F, A).
+
+warning_msg(F, A) ->
+ ?snmp_warning(get(snmp_component), "Note store server " ++ F, A).
+
+error_msg(F, A) ->
+ ?snmp_error(get(snmp_component), "Note store server " ++ F, A).
+
+
+%%-----------------------------------------------------------------
+
+get_verbosity(Opts) ->
+ snmp_misc:get_option(verbosity, Opts, ?default_verbosity).
+
+get_sname(Opts) ->
+ snmp_misc:get_option(sname, Opts, ns).
+
+get_timeout(Opts) ->
+ snmp_misc:get_option(timeout, Opts, ?timeout).
+
+get_component(snmpm) ->
+ "manager";
+get_component(snmpa) ->
+ "agent";
+get_component(_) ->
+ "".
+
diff --git a/lib/snmp/src/misc/snmp_pdus.erl b/lib/snmp/src/misc/snmp_pdus.erl
new file mode 100644
index 0000000000..6c80fc3876
--- /dev/null
+++ b/lib/snmp/src/misc/snmp_pdus.erl
@@ -0,0 +1,770 @@
+%%
+%% %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%
+%%
+
+-module(snmp_pdus).
+
+-define(SNMP_USE_V3, true).
+-include("snmp_types.hrl").
+
+-define(VMODULE,"PDUS").
+-include("snmp_verbosity.hrl").
+
+%% See RFC1155, RFC1157, RFC1901, RFC1902, RFC1905, RFC2272
+
+
+%% API
+-export([enc_message/1, enc_message_only/1, enc_pdu/1,
+ enc_varbind/1,
+ enc_oct_str_tag/1, enc_scoped_pdu/1,
+ enc_usm_security_parameters/1,
+ dec_message/1, dec_message_only/1, dec_pdu/1,
+ dec_scoped_pdu_data/1, dec_scoped_pdu/1,
+ dec_usm_security_parameters/1,
+ strip_encrypted_scoped_pdu_data/1,
+ octet_str_to_bits/1, bits_to_str/1,
+ get_encoded_length/1]).
+
+%% Returns the number of octets required to encode Length.
+get_encoded_length(Length) ->
+ length(elength(Length)).
+
+dec_message([48 | Bytes]) ->
+ Bytes2 = get_data_bytes(Bytes),
+ case dec_snmp_version(Bytes2) of
+ {'version-3', Rest} ->
+ dec_rest_v3_msg(Rest);
+ {Vsn, Rest} -> % 1 or 2
+ dec_rest_v1_v2_msg(Vsn, Rest)
+ end.
+
+dec_message_only([48 | Bytes]) ->
+ Bytes2 = get_data_bytes(Bytes),
+ case dec_snmp_version(Bytes2) of
+ {'version-3', Rest} ->
+ dec_rest_v3_msg_only(Rest);
+ {Vsn, Rest} -> % 1 or 2
+ dec_rest_v1_v2_msg_only(Vsn, Rest)
+ end.
+
+dec_snmp_version(Bytes) ->
+ case (catch dec_int_tag(Bytes, 10)) of
+ {error, {bad_integer, BadInt}} ->
+ exit({bad_version, BadInt});
+ {SNMPversion, Rest} when is_integer(SNMPversion) andalso is_list(Rest) ->
+ {dec_snmp_ver(SNMPversion), Rest};
+ {'EXIT', Reason} ->
+ exit(Reason)
+ end.
+
+
+dec_snmp_ver(0) ->
+ 'version-1';
+dec_snmp_ver(1) ->
+ 'version-2';
+dec_snmp_ver(3) ->
+ 'version-3';
+dec_snmp_ver(Vsn) ->
+ exit({bad_version, Vsn}).
+
+dec_rest_v1_v2_msg(Vsn, Rest1) ->
+ {Community, Rest2} = dec_oct_str_tag(Rest1),
+ PDU = dec_pdu(Rest2),
+ #message{version = Vsn, vsn_hdr = Community, data = PDU}.
+
+dec_rest_v1_v2_msg_only(Vsn, Rest1) ->
+ {Community, Rest2} = dec_oct_str_tag(Rest1),
+ #message{version = Vsn, vsn_hdr = Community, data = Rest2}.
+
+dec_rest_v3_msg_only([48 | Bytes]) -> % starts with header data sequence
+ {Size, Tail} = dec_len(Bytes),
+ {HBytes, Bytes1} = split_at(Tail, Size, []),
+ %% Decode HeaderData
+ {MsgID, HBytes1} = dec_int_tag(HBytes),
+ chk_msg_id(MsgID),
+ {MsgMaxSize, HBytes2} = dec_int_tag(HBytes1),
+ chk_msg_max_size(MsgMaxSize),
+ {MsgFlags, HBytes3} = dec_oct_str_tag(HBytes2),
+ {MsgSecurityModel, []} = dec_int_tag(HBytes3),
+ chk_msg_sec_model(MsgSecurityModel),
+ %% Continue with Message
+% {MsgSecurityParameters, Bytes2} = dec_oct_str_tag(Bytes1),
+
+ [4 | Bytes1a] = Bytes1,
+ {Size1a, Tail1a} = dec_len(Bytes1a),
+ {MsgSecurityParameters, Bytes2} = split_at(Tail1a, Size1a, []),
+
+ %% [48 , HdrDataLen, HdrData, 4, MsgSecLen, MsgSec, ...]
+ %% NOTE: HdrDataLen is always so small that one octet is enough to
+ %% encode its length.
+ %% MsgSecLen is worse... but for USM, it is small enough for
+ %% one octet. USM is currently the only secmodel.
+ %% 1 + 1 + Size + 1 + 1 + Size1a
+ HdrSize = Size + Size1a + 4,
+ V3Hdr = #v3_hdr{msgID = MsgID,
+ msgMaxSize = MsgMaxSize,
+ msgFlags = MsgFlags, %dec_msg_flags(MsgFlags),
+ msgSecurityModel = MsgSecurityModel,
+ msgSecurityParameters = MsgSecurityParameters,
+ hdr_size = HdrSize},
+ #message{version = 'version-3', vsn_hdr = V3Hdr, data = Bytes2}.
+
+dec_rest_v3_msg(Bytes) ->
+ Message = dec_rest_v3_msg_only(Bytes),
+ Data = Message#message.data,
+ Message#message{data = dec_scoped_pdu_data(Data)}.
+
+dec_scoped_pdu_data([48 | Bytes]) -> % plaintext
+ {ScopedPdu, []} = dec_scoped_pdu_notag(Bytes),
+ ScopedPdu;
+dec_scoped_pdu_data([4 | Bytes]) -> % encryptedPDU
+ {EncryptedPDU, []} = dec_oct_str_notag(Bytes),
+ EncryptedPDU.
+
+
+dec_scoped_pdu([48 | Bytes]) ->
+ element(1, dec_scoped_pdu_notag(Bytes)).
+
+dec_scoped_pdu_notag(Bytes) ->
+ Bytes1 = get_data_bytes(Bytes),
+ {ContextEngineID, Bytes2} = dec_oct_str_tag(Bytes1),
+ {ContextName, Bytes3} = dec_oct_str_tag(Bytes2),
+ Pdu = dec_pdu(Bytes3),
+ {#scopedPdu{contextEngineID = ContextEngineID,
+ contextName = ContextName,
+ data = Pdu},
+ []}.
+
+dec_pdu_tag(160) ->
+ 'get-request';
+dec_pdu_tag(161) ->
+ 'get-next-request';
+dec_pdu_tag(162) ->
+ 'get-response';
+dec_pdu_tag(163) ->
+ 'set-request';
+%% 164 SNMPv1 Trap
+%% 165 Bulk
+dec_pdu_tag(166) ->
+ 'inform-request';
+dec_pdu_tag(167) ->
+ 'snmpv2-trap';
+dec_pdu_tag(168) ->
+ report.
+
+
+dec_pdu([164 | Bytes]) -> % It's a trap
+ Bytes2 = get_data_bytes(Bytes),
+ {Enterprise, Rest1} = dec_oid_tag(Bytes2),
+ {{'IpAddress', AgentAddr}, Rest2} = dec_value(Rest1),
+ {GenericTrap, Rest3} = dec_int_tag(Rest2),
+ {SpecificTrap, Rest4} = dec_int_tag(Rest3),
+ {{'TimeTicks', TimeStamp}, VBBytes} = dec_value(Rest4),
+ VBs = dec_VBs(VBBytes),
+ #trappdu{enterprise = Enterprise, agent_addr = AgentAddr,
+ generic_trap = GenericTrap, specific_trap = SpecificTrap,
+ time_stamp = TimeStamp, varbinds = VBs};
+
+dec_pdu([165 | Bytes]) -> % Bulk
+ Bytes2 = get_data_bytes(Bytes),
+ {RequestID, Rest1} = dec_int_tag(Bytes2),
+ {NonRepeaters, Rest2} = dec_int_tag(Rest1),
+ {MaxRepetitions,VBbytes} = dec_int_tag(Rest2),
+ VBs = dec_VBs(VBbytes),
+ #pdu{type = 'get-bulk-request', request_id = RequestID,
+ error_status = NonRepeaters, error_index = MaxRepetitions,
+ varbinds = VBs};
+
+dec_pdu([PduTag | Bytes]) ->
+ Type = dec_pdu_tag(PduTag),
+ Bytes2 = get_data_bytes(Bytes),
+ {RequestID, Rest1} = dec_int_tag(Bytes2),
+ {ErrStat, Rest2} = dec_int_tag(Rest1),
+ ErrStatus = case lists:keysearch(ErrStat, 2, errMsgs()) of
+ {value, {ErrStatName, _ErrStat}} ->
+ ErrStatName;
+ false ->
+ ErrStat
+ end,
+ {ErrIndex, VarbindsBytes} = dec_int_tag(Rest2),
+ VBs = dec_VBs(VarbindsBytes),
+ #pdu{type = Type, request_id = RequestID, error_status = ErrStatus,
+ error_index = ErrIndex, varbinds = VBs}.
+
+dec_VBs([48 | Bytes]) ->
+ Bytes1 = get_data_bytes(Bytes),
+ dec_individual_VBs(Bytes1, 1, []).
+
+dec_individual_VBs([], _No, VBs) ->
+ lists:reverse(VBs);
+dec_individual_VBs([48 | Bytes], OrgIndex, AccVBs) ->
+ {_SizeOfThisVB, Bytes2} = dec_len(Bytes),
+ {Oid, Rest} = dec_oid_tag(Bytes2),
+ {{Type, Value}, Rest2} = dec_value(Rest),
+ % perhaps we should check that we have eaten SizeOfThisVB bytes, but we
+ % don't consider ourselves to have time for such list traversing stuff.
+ dec_individual_VBs(Rest2, OrgIndex + 1, [#varbind{oid = Oid,
+ variabletype = Type,
+ value = Value,
+ org_index = OrgIndex}
+ | AccVBs]).
+
+dec_usm_security_parameters([48 | Bytes1]) ->
+ {_Len, Bytes2} = dec_len(Bytes1),
+ {MsgAuthEngineID, Bytes3} = dec_oct_str_tag(Bytes2),
+ {MsgAuthEngineBoots, Bytes4} = dec_int_tag(Bytes3),
+ {MsgAuthEngineTime, Bytes5} = dec_int_tag(Bytes4),
+ {MsgUserName, Bytes6} = dec_oct_str_tag(Bytes5),
+ {MsgAuthParams, Bytes7} = dec_oct_str_tag(Bytes6),
+ {MsgPrivParams, []} = dec_oct_str_tag(Bytes7),
+ #usmSecurityParameters{msgAuthoritativeEngineID = MsgAuthEngineID,
+ msgAuthoritativeEngineBoots = MsgAuthEngineBoots,
+ msgAuthoritativeEngineTime = MsgAuthEngineTime,
+ msgUserName = MsgUserName,
+ msgAuthenticationParameters = MsgAuthParams,
+ msgPrivacyParameters = MsgPrivParams}.
+
+strip_encrypted_scoped_pdu_data([48 | Bytes]) ->
+ {Size, Tail} = dec_len(Bytes),
+ [48 | elength(Size)] ++ strip(Size, Tail).
+
+strip(N, [H|T]) when N > 0 -> [H | strip(N-1, T)];
+strip(0, _Tail) ->
+ [].
+
+
+%%----------------------------------------------------------------------
+%% Returns:{Type, Value}
+%%----------------------------------------------------------------------
+dec_value([6 | Bytes]) ->
+ {Value, Rest} = dec_oid_notag(Bytes),
+ {{'OBJECT IDENTIFIER', Value}, Rest};
+dec_value([5,0 | T]) ->
+ {{'NULL', 'NULL'}, T};
+dec_value([2 | Bytes]) ->
+ {Value, Rest} = dec_integer_notag(Bytes),
+ {{'INTEGER', Value}, Rest};
+dec_value([4 | Bytes]) ->
+ {Value, Rest} = dec_oct_str_notag(Bytes),
+ {{'OCTET STRING', Value}, Rest};
+dec_value([64 | Bytes]) ->
+ {Value, Rest} = dec_oct_str_notag(Bytes),
+ {{'IpAddress', Value}, Rest};
+dec_value([65 | Bytes]) ->
+ {Value, Rest} = dec_integer_notag(Bytes),
+ if Value >= 0, Value =< 4294967295 ->
+ {{'Counter32', Value}, Rest};
+ true ->
+ exit({error, {bad_counter32, Value}})
+ end;
+dec_value([66 | Bytes]) ->
+ {Value, Rest} = dec_integer_notag(Bytes),
+ if Value >= 0, Value =< 4294967295 ->
+ {{'Unsigned32', Value}, Rest};
+ true ->
+ exit({error, {bad_unsigned32, Value}})
+ end;
+dec_value([67 | Bytes]) ->
+ {Value, Rest} = dec_integer_notag(Bytes),
+ if Value >= 0, Value =< 4294967295 ->
+ {{'TimeTicks', Value}, Rest};
+ true ->
+ exit({error, {bad_timeticks, Value}})
+ end;
+dec_value([68 | Bytes]) ->
+ {Value, Rest} = dec_oct_str_notag(Bytes),
+ {{'Opaque', Value}, Rest};
+dec_value([70 | Bytes]) ->
+ {Value, Rest} = dec_integer_notag(Bytes),
+ if Value >= 0, Value =< 18446744073709551615 ->
+ {{'Counter64', Value}, Rest};
+ true ->
+ exit({error, {bad_counter64, Value}})
+ end;
+dec_value([128,0|T]) ->
+ {{'NULL', noSuchObject}, T};
+dec_value([129,0|T]) ->
+ {{'NULL', noSuchInstance}, T};
+dec_value([130,0|T]) ->
+ {{'NULL', endOfMibView}, T}.
+
+
+%%----------------------------------------------------------------------
+%% Purpose: Uses the beginning length bytes to return the actual data.
+%% If data has the wrong length, the program is exited.
+%% Pre: Tag is removed.
+%%----------------------------------------------------------------------
+get_data_bytes(Bytes) ->
+ {Size, Tail} = dec_len(Bytes),
+ if
+ length(Tail) =:= Size ->
+ Tail;
+ true ->
+ exit({error, {wrong_length, Bytes}})
+ end.
+
+split_at(L, 0, Acc) ->
+ {lists:reverse(Acc), L};
+split_at([H|T], N, Acc) ->
+ split_at(T, N-1, [H|Acc]).
+
+%%----------------------------------------------------------------------
+%% All decoding routines return: {Data, RestBytes}
+%%----------------------------------------------------------------------
+
+dec_int_tag([2 | Bytes]) ->
+ dec_integer_notag(Bytes).
+dec_int_tag([2 | Bytes], SizeLimit) ->
+ dec_integer_notag(Bytes, SizeLimit).
+
+dec_integer_notag(Ints) ->
+ dec_integer_notag(Ints, infinity).
+dec_integer_notag(Ints, SizeLimit) ->
+ case dec_len(Ints) of
+ {Size, Ints2} when SizeLimit =:= infinity ->
+ do_dec_integer_notag(Size, Ints2);
+ {Size, Ints2} when (is_integer(SizeLimit) andalso
+ (Size =< SizeLimit)) ->
+ do_dec_integer_notag(Size, Ints2);
+ {BadSize, _BadInts2} ->
+ throw({error, {bad_integer, {BadSize, SizeLimit}}})
+ end.
+
+do_dec_integer_notag(Size, Ints) ->
+ if hd(Ints) band 128 == 0 -> %% Positive number
+ dec_pos_int(Ints, Size, 8 * (Size - 1));
+ true -> %% Negative
+ dec_neg_int(Ints, Size, 8 * (Size - 1))
+ end.
+
+
+dec_pos_int(T, 0, _) -> {0, T};
+dec_pos_int([Byte|Tail], Size, Shift) ->
+ {Int, Rest} = dec_pos_int(Tail, Size - 1, Shift - 8),
+ {(Byte bsl Shift) bor Int, Rest}.
+
+dec_neg_int(T, 0, _) -> {0, T};
+dec_neg_int([Byte|Tail], Size, Shift) ->
+ {Int, Rest} = dec_pos_int(Tail, Size - 1, Shift-8),
+ {(-128 + (Byte band 127) bsl Shift) bor Int, Rest}.
+
+dec_oct_str_tag([4 | Bytes]) ->
+ dec_oct_str_notag(Bytes).
+
+dec_oct_str_notag(Bytes) ->
+ {Size, Tail} = dec_len(Bytes),
+ split_at(Tail, Size, []).
+
+dec_oid_tag([6 | Bytes]) ->
+ dec_oid_notag(Bytes).
+
+dec_oid_notag(Bytes) ->
+ {Size, [H | Tail]} = dec_len(Bytes),
+ {Oid, Rest} = dec_oid_elements(Tail, Size - 1, []),
+ {[H div 40, H rem 40 | Oid], Rest}.
+
+dec_oid_elements(L, 0, Acc) ->
+ {lists:reverse(Acc), L};
+dec_oid_elements([Dig|Tail], Size, Acc) when Dig < 128 ->
+ dec_oid_elements(Tail, Size - 1, [Dig | Acc]);
+dec_oid_elements([Dig|Tail], Size, Acc) ->
+ {Num, Neaten, Tl} = dec_oid_element(Tail,1,Dig band 127),
+ dec_oid_elements(Tl, Size - Neaten, [Num|Acc]).
+
+dec_oid_element([Dig|Tail], Neaten, Num) when Dig < 128 ->
+ {Num*128+Dig,Neaten+1,Tail};
+dec_oid_element([Dig|Tail],Neaten, Num) ->
+ dec_oid_element(Tail, Neaten+1, Num*128 + (Dig band 127)).
+
+chk_msg_id(MsgId) when (MsgId >= 0) andalso (MsgId =< 2147483647) -> ok;
+chk_msg_id(MsgId) -> exit({bad_msg_id, MsgId}).
+
+chk_msg_max_size(MMS) when (MMS >= 484) andalso (MMS =< 2147483647) -> ok;
+chk_msg_max_size(MMS) -> exit({bad_msg_max_size, MMS}).
+
+chk_msg_sec_model(MsgSecurityModel) when MsgSecurityModel >= 0,
+ MsgSecurityModel =< 2147483647 -> ok;
+chk_msg_sec_model(MsgSecurityModel) ->
+ exit({bad_msg_sec_model, MsgSecurityModel}).
+
+%%----------------------------------------------------------------------
+%% Code copied from the original ASN.1 compiler written by
+%%----------------------------------------------------------------------
+
+%%----------------------------------------------------------------------
+%% Returns: {Len, Tail}
+%%----------------------------------------------------------------------
+dec_len([128|_Tail]) ->
+ %% indefinite form - not allowed in SNMP
+ exit({asn1_error, indefinite_length});
+
+dec_len([Hd|Tl]) when Hd >= 0 ->
+ %% definite form
+ if
+ Hd < 128 -> % 8th bit is cleared
+ %% Short form (actually, we can remove this test, since snmp_pdus
+ %% performs this test _before_ calling this function)
+ {Hd,Tl};
+ true ->
+ %% Long form
+ No = Hd band 127, % clear 8th bit
+ {DigList, Rest} = head(No, Tl),
+ Size = dec_integer_len(DigList),
+ {Size, Rest}
+ end.
+
+dec_integer_len([D]) ->
+ D;
+dec_integer_len([A,B]) ->
+ (A bsl 8) bor B;
+dec_integer_len([A,B,C]) ->
+ (A bsl 16) bor (B bsl 8) bor C;
+%% More than 3 elements for length => either *very* long packet
+%% (which we don't handle), or the length is encoded with more octets
+%% than necessary (in which case the first octet must be 0).
+dec_integer_len([0 | T]) ->
+ dec_integer_len(T).
+
+%%-----------------------------------------------------------------
+%% head(N, List) -> {List1, List2}
+%% List == List1 ++ List2
+%% length(List1) == N
+%%-----------------------------------------------------------------
+head(L,List) ->
+ head(L,List,[]).
+
+head(0,L,Res) ->
+ {lists:reverse(Res),L};
+
+head(Int,[H|Tail],Res) ->
+ head(Int-1,Tail,[H|Res]);
+head(Int, [], _Res) ->
+ exit({asn1_error, {bad_length, Int}}).
+
+%%%----------------------------------------------------------------------
+%%% ENCODING ENCODING ENCODING ENCODING ENCODING ENCODING ENCODING ENCODING
+%%%----------------------------------------------------------------------
+
+enc_message(#message{version = Ver, vsn_hdr = VsnHdr, data = Data}) ->
+ VerBytes = enc_version(Ver),
+ Bytes =
+ case Ver of
+ 'version-3' ->
+ V3HeaderBytes = enc_v3_header(VsnHdr),
+ DataBytes = enc_scoped_pdu(Data),
+ V3HeaderBytes ++ DataBytes;
+ _ ->
+ ComBytes = enc_community(VsnHdr),
+ DataBytes = enc_pdu(Data),
+ ComBytes ++ DataBytes
+ end,
+ Bytes2 = VerBytes ++ Bytes,
+ Len = elength(length(Bytes2)),
+ [48 | Len] ++ Bytes2.
+
+enc_message_only(#message{version = Ver, vsn_hdr = VsnHdr, data = DataBytes}) ->
+ VerBytes = enc_version(Ver),
+ Bytes =
+ case Ver of
+ 'version-3' ->
+ V3HeaderBytes = enc_v3_header(VsnHdr),
+ V3HeaderBytes ++ DataBytes;
+ _ ->
+ ComBytes = enc_community(VsnHdr),
+ ComBytes ++ DataBytes
+ end,
+ Bytes2 = VerBytes ++ Bytes,
+ Len = elength(length(Bytes2)),
+ [48 | Len] ++ Bytes2.
+
+enc_version('version-1') ->
+ [2,1,0];
+enc_version('version-2') ->
+ [2,1,1];
+enc_version('version-3') ->
+ [2,1,3].
+
+enc_community(Com) ->
+ enc_oct_str_tag(Com).
+
+enc_v3_header(#v3_hdr{msgID = MsgID,
+ msgMaxSize = MsgMaxSize,
+ msgFlags = MsgFlags,
+ msgSecurityModel = MsgSecurityModel,
+ msgSecurityParameters = MsgSecurityParameters}) ->
+ Bytes = lists:append([enc_integer_tag(MsgID),
+ enc_integer_tag(MsgMaxSize),
+ enc_oct_str_tag(MsgFlags),
+ enc_integer_tag(MsgSecurityModel)]),
+ Len = elength(length(Bytes)),
+ lists:append([[48 | Len], Bytes, enc_oct_str_tag(MsgSecurityParameters)]).
+
+enc_scoped_pdu(#scopedPdu{contextEngineID = ContextEngineID,
+ contextName = ContextName,
+ data = Data}) ->
+ Bytes = lists:append([enc_oct_str_tag(ContextEngineID),
+ enc_oct_str_tag(ContextName),
+ enc_pdu(Data)]),
+ Len = elength(length(Bytes)),
+ [48 | Len] ++ Bytes.
+
+
+enc_pdu(PDU) when PDU#pdu.type =:= 'get-request' ->
+ enc_pdu(160, PDU);
+enc_pdu(PDU) when PDU#pdu.type =:= 'get-next-request' ->
+ enc_pdu(161, PDU);
+enc_pdu(PDU) when PDU#pdu.type =:= 'get-response' ->
+ enc_pdu(162, PDU);
+enc_pdu(PDU) when PDU#pdu.type =:= 'set-request' ->
+ enc_pdu(163, PDU);
+enc_pdu(PDU) when PDU#pdu.type =:= 'get-bulk-request' ->
+ enc_pdu(165, PDU);
+enc_pdu(PDU) when PDU#pdu.type =:= 'inform-request' ->
+ enc_pdu(166, PDU);
+enc_pdu(PDU) when PDU#pdu.type =:= 'snmpv2-trap' ->
+ enc_pdu(167, PDU);
+enc_pdu(PDU) when PDU#pdu.type =:= report ->
+ enc_pdu(168, PDU);
+enc_pdu(TrapPDU) when is_record(TrapPDU, trappdu) ->
+ enc_Trap(TrapPDU).
+
+
+enc_pdu(Tag,PDU) ->
+ Bytes2 = enc_pdu2(PDU),
+ Len2 = elength(length(Bytes2)),
+ lists:append([Tag | Len2], Bytes2).
+
+enc_pdu2(#pdu{type = Type, request_id = ReqId, error_index = ErrIndex,
+ error_status = ErrStat, varbinds = VBs}) ->
+ ReqBytes = enc_integer_tag(ReqId),
+ Val = err_val(ErrStat,Type),
+ ErrStatBytes = enc_integer_tag(Val),
+ ErrIndexBytes = enc_integer_tag(ErrIndex),
+ VBsBytes = enc_VarBindList(VBs),
+ lists:append([ReqBytes, ErrStatBytes, ErrIndexBytes, VBsBytes]).
+
+enc_usm_security_parameters(
+ #usmSecurityParameters{msgAuthoritativeEngineID = MsgAuthEngineID,
+ msgAuthoritativeEngineBoots = MsgAuthEngineBoots,
+ msgAuthoritativeEngineTime = MsgAuthEngineTime,
+ msgUserName = MsgUserName,
+ msgAuthenticationParameters = MsgAuthParams,
+ msgPrivacyParameters = MsgPrivParams}) ->
+ Bytes1 = enc_oct_str_tag(MsgAuthEngineID),
+ Bytes2 = enc_integer_tag(MsgAuthEngineBoots),
+ Bytes3 = enc_integer_tag(MsgAuthEngineTime),
+ Bytes4 = enc_oct_str_tag(MsgUserName),
+ Bytes5 = enc_oct_str_tag(MsgAuthParams),
+ Bytes6 = enc_oct_str_tag(MsgPrivParams),
+ Bytes7 = lists:append([Bytes1, Bytes2, Bytes3, Bytes4, Bytes5, Bytes6]),
+ Len = elength(length(Bytes7)),
+ [48 | Len] ++ Bytes7.
+
+err_val(Int,'get-bulk-request') when is_integer(Int) -> Int;
+err_val(ErrStat, _) ->
+ {value, {_ErrStat, Val}} = lists:keysearch(ErrStat, 1, errMsgs()),
+ Val.
+
+errMsgs() ->
+ [{noError,0},{tooBig,1},{noSuchName,2},
+ {badValue,3},{readOnly,4},{genErr,5},
+ %% v2
+ {noAccess,6},{wrongType,7},{wrongLength,8},{wrongEncoding,9},
+ {wrongValue,10},{noCreation,11},{inconsistentValue,12},
+ {resourceUnavailable,13},{commitFailed,14},{undoFailed,15},
+ {authorizationError,16},{notWritable,17},{inconsistentName,18}].
+
+enc_VarBindList(EncodedVBs) when is_integer(hd(EncodedVBs)) ->
+ Len1 = elength(length(EncodedVBs)),
+ lists:append([48 | Len1],EncodedVBs);
+enc_VarBindList(VBs) ->
+ Bytes1 = lists:append(lists:map(fun enc_varbind/1, VBs)),
+ Len1 = elength(length(Bytes1)),
+ lists:append([48 | Len1],Bytes1).
+
+enc_varbind(Varbind) ->
+ Bytes1 = enc_VarBind_attributes(Varbind),
+ Len1 = elength(length(Bytes1)),
+ lists:append([48 | Len1],Bytes1).
+
+
+enc_VarBind_attributes(#varbind{oid = Oid, variabletype = Type,value = Val}) ->
+ OidBytes = enc_oid_tag(Oid),
+ ValueBytes = enc_value(Type, Val),
+ lists:append(OidBytes, ValueBytes).
+
+enc_value('INTEGER',Val) ->
+ enc_integer_tag(Val);
+enc_value('OCTET STRING', Val) ->
+ enc_oct_str_tag(Val);
+enc_value('BITS', Val) ->
+ enc_oct_str_tag(bits_to_str(Val));
+enc_value('OBJECT IDENTIFIER', Val) ->
+ enc_oid_tag(Val);
+enc_value('IpAddress',Val) ->
+ Bytes2 = enc_oct_str_notag(Val),
+ Len2 = elength(length(Bytes2)),
+ lists:append([64 | Len2],Bytes2);
+enc_value('Opaque', Val) ->
+ Bytes2 = enc_oct_str_notag(Val),
+ Len2 = elength(length(Bytes2)),
+ lists:append([68 | Len2],Bytes2);
+enc_value(_Type, noSuchObject) ->
+ [128,0];
+enc_value(_Type, noSuchInstance) ->
+ [129,0];
+enc_value(_Type, endOfMibView) ->
+ [130,0];
+enc_value('NULL', _Val) ->
+ [5,0];
+enc_value(Type, Val) ->
+ Bytes2 = enc_integer_notag(Val),
+ Len2 = elength(length(Bytes2)),
+ lists:append([enc_val_tag(Type,Val) | Len2],Bytes2).
+
+enc_val_tag('Counter32',Val) when (Val >= 0) andalso (Val =< 4294967295) ->
+ 65;
+enc_val_tag('Unsigned32', Val) when (Val >= 0) andalso (Val =< 4294967295) ->
+ 66;
+enc_val_tag('TimeTicks', Val) when (Val >= 0) andalso (Val =< 4294967295) ->
+ 67;
+enc_val_tag('Counter64', Val) when ((Val >= 0) andalso
+ (Val =< 18446744073709551615)) ->
+ 70.
+
+
+%%----------------------------------------------------------------------
+%% Impl according to RFC1906, section 8
+%% For example: the number 1010 0000 (=160) 0100 0001 (=65) is represented as
+%% the octet string: 1000 0010, 0000 0101 (=[130,5])
+%%----------------------------------------------------------------------
+bits_to_str(0) -> "";
+bits_to_str(Int) ->
+ [rev_int8(Int band 255) | bits_to_str(Int div 256)].
+
+rev_int8(Val) ->
+ rev_int(Val,0,1,128).
+
+rev_int(_Val,Res,256,0) -> Res;
+rev_int(Val,Res,OldBit,NewBit) when Val band OldBit =/= 0 ->
+ rev_int(Val,Res+NewBit,OldBit*2,NewBit div 2);
+rev_int(Val,Res,OldBit,NewBit) ->
+ rev_int(Val,Res,OldBit*2,NewBit div 2).
+
+octet_str_to_bits(Str) ->
+ octet_str_to_bits(Str,1).
+
+octet_str_to_bits("",_) -> 0;
+octet_str_to_bits([Byte|Bytes],Mul) ->
+ Mul*rev_int8(Byte)+octet_str_to_bits(Bytes,Mul*256).
+
+
+enc_Trap(TrapPdu) when is_record(TrapPdu, trappdu) ->
+ Bytes1 = enc_trap_data(TrapPdu),
+ Len1 = elength(length(Bytes1)),
+ lists:append([164 | Len1],Bytes1).
+
+
+enc_trap_data(#trappdu{enterprise = Enterprise,
+ agent_addr = AgentAddr,
+ generic_trap = GenericTrap,
+ specific_trap = SpecificTrap,
+ time_stamp = TimeStamp,
+ varbinds = VBs}) ->
+ L1 = enc_oid_tag(Enterprise),
+ L2 = enc_value('IpAddress', AgentAddr),
+ L3 = enc_integer_tag(GenericTrap),
+ L4 = enc_integer_tag(SpecificTrap),
+ L5 = enc_value('TimeTicks', TimeStamp),
+ L6 = enc_VarBindList(VBs),
+ lists:append([L1,L2,L3,L4,L5,L6]).
+
+enc_oid_tag([E1,E2|RestOid]) when E1 * 40 + E2 =< 255 ->
+ Head = 40*E1 + E2, % weird
+ Res = e_object_elements(RestOid, []),
+ lists:append([6 | elength(length(Res) + 1)],[Head|Res]).
+
+e_object_elements([Num | T], Res) ->
+ e_object_elements(T, lists:append(e_object_element(Num),Res));
+
+e_object_elements([], Res) -> lists:reverse(Res).
+
+%%----------------------------------------------------------------------
+%% The reversed encoding for an oid-element
+%%----------------------------------------------------------------------
+e_object_element(Num) when Num > 0 ->
+ [Last|T] = e_object_element2(Num),
+ [Last-128|T];
+e_object_element(0) -> [0].
+
+e_object_element2(Num) when Num > 0 ->
+ Byte = (Num rem 128),
+ [128+Byte | e_object_element2((Num-Byte) div 128)];
+e_object_element2(0) -> [].
+
+enc_integer_tag(Val) when Val >= 0 -> %% stdcase positive ints
+ Bytes = eint(Val,[]),
+ [2 | elength(length(Bytes))] ++ Bytes;
+
+enc_integer_tag(Val) -> %% It's a negative number
+ Bytes = enint(Val,[]),
+ [2 | elength(length(Bytes))] ++ Bytes.
+
+enc_integer_notag(Val) when Val >= 0 -> %% stdcase positive ints
+ eint(Val,[]);
+
+enc_integer_notag(Val) -> %% It's a negative number
+ enint(Val,[]).
+
+eint(0, [B|Acc]) when B < 128 ->
+ [B|Acc];
+eint(N, Acc) ->
+ eint(N bsr 8, [N band 16#ff| Acc]).
+
+enint(-1, [B1|T]) when B1 > 127 ->
+ [B1|T];
+enint(N, Acc) ->
+ enint(N bsr 8, [N band 16#ff|Acc]).
+
+enc_oct_str_tag(OStr) when is_list(OStr) ->
+ lists:append([4|elength(length(OStr))],OStr);
+enc_oct_str_tag(OBin) ->
+ [4 | elength(size(OBin))] ++ binary_to_list(OBin).
+
+
+enc_oct_str_notag(OStr) -> OStr.
+
+%%-----------------------------------------------------------------
+%% Always use definite form
+%%-----------------------------------------------------------------
+%% Short
+elength(L) when L < 127 ->
+ [L];
+
+%% 3 cases of long form
+elength(L) when L =< 16#FF ->
+ [2#10000001,L];
+
+elength(L) when L =< 16#FFFF ->
+ [2#10000010,(L bsr 8),(L band 16#FF)];
+
+elength(L) when L =< 16#7FFFFF ->
+ [2#10000011,(L bsr 16),((L band 16#FF00) bsr 8), (L band 16#FF)].
+
+
diff --git a/lib/snmp/src/misc/snmp_usm.erl b/lib/snmp/src/misc/snmp_usm.erl
new file mode 100644
index 0000000000..6d216e65d6
--- /dev/null
+++ b/lib/snmp/src/misc/snmp_usm.erl
@@ -0,0 +1,367 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2004-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%
+%%
+
+-module(snmp_usm).
+
+-export([passwd2localized_key/3, localize_key/3]).
+-export([auth_in/4, auth_out/4, set_msg_auth_params/3]).
+-export([des_encrypt/3, des_decrypt/3]).
+-export([aes_encrypt/3, aes_decrypt/5]).
+
+
+-define(SNMP_USE_V3, true).
+-include("snmp_types.hrl").
+-include("SNMP-USER-BASED-SM-MIB.hrl").
+-include("SNMP-USM-AES-MIB.hrl").
+
+-define(VMODULE,"USM").
+-include("snmp_verbosity.hrl").
+
+
+%%-----------------------------------------------------------------
+
+-define(twelwe_zeros, [0,0,0,0,0,0,0,0,0,0,0,0]).
+
+-define(i32(Int), (Int bsr 24) band 255, (Int bsr 16) band 255, (Int bsr 8) band 255, Int band 255).
+
+
+%%-----------------------------------------------------------------
+%% Func: passwd2localized_key/3
+%% Types: Alg = md5 | sha
+%% Passwd = string()
+%% EngineID = string()
+%% Purpose: Generates a key that can be used as an authentication
+%% or privacy key using MD5 och SHA. The key is
+%% localized for EngineID.
+%% The algorithm is described in appendix A.1 2) of
+%% rfc2274.
+%%-----------------------------------------------------------------
+passwd2localized_key(Alg, Passwd, EngineID) when length(Passwd) > 0 ->
+ Key = mk_digest(Alg, Passwd),
+ localize_key(Alg, Key, EngineID).
+
+
+%%-----------------------------------------------------------------
+%% Func: localize_key/3
+%% Types: Alg = md5 | sha
+%% Passwd = string()
+%% EngineID = string()
+%% Purpose: Localizes an unlocalized key for EngineID. See rfc2274
+%% section 2.6 for a definition of localized keys.
+%%-----------------------------------------------------------------
+localize_key(Alg, Key, EngineID) ->
+ Str = [Key, EngineID, Key],
+ binary_to_list(crypto:Alg(Str)).
+
+
+mk_digest(md5, Passwd) ->
+ mk_md5_digest(Passwd);
+mk_digest(sha, Passwd) ->
+ mk_sha_digest(Passwd).
+
+mk_md5_digest(Passwd) ->
+ Ctx = crypto:md5_init(),
+ Ctx2 = md5_loop(0, [], Ctx, Passwd, length(Passwd)),
+ crypto:md5_final(Ctx2).
+
+md5_loop(Count, Buf, Ctx, Passwd, PasswdLen) when Count < 1048576 ->
+ {Buf64, NBuf} = mk_buf64(length(Buf), Buf, Passwd, PasswdLen),
+ NCtx = crypto:md5_update(Ctx, Buf64),
+ md5_loop(Count+64, NBuf, NCtx, Passwd, PasswdLen);
+md5_loop(_Count, _Buf, Ctx, _Passwd, _PasswdLen) ->
+ Ctx.
+
+mk_sha_digest(Passwd) ->
+ Ctx = crypto:sha_init(),
+ Ctx2 = sha_loop(0, [], Ctx, Passwd, length(Passwd)),
+ crypto:sha_final(Ctx2).
+
+sha_loop(Count, Buf, Ctx, Passwd, PasswdLen) when Count < 1048576 ->
+ {Buf64, NBuf} = mk_buf64(length(Buf), Buf, Passwd, PasswdLen),
+ NCtx = crypto:sha_update(Ctx, Buf64),
+ sha_loop(Count+64, NBuf, NCtx, Passwd, PasswdLen);
+sha_loop(_Count, _Buf, Ctx, _Passwd, _PasswdLen) ->
+ Ctx.
+
+%% Create a 64 bytes long string, by repeating Passwd as many times
+%% as necessary. Output is the 64 byte string, and the rest of the
+%% last repetition of the Passwd. This is used as input in the next
+%% invocation.
+mk_buf64(BufLen, Buf, Passwd, PasswdLen) ->
+ case BufLen + PasswdLen of
+ TotLen when TotLen > 64 ->
+ {[Buf, lists:sublist(Passwd, 64-BufLen)],
+ lists:sublist(Passwd, 65-BufLen, PasswdLen)};
+ TotLen ->
+ mk_buf64(TotLen, [Buf, Passwd], Passwd, PasswdLen)
+ end.
+
+
+%%-----------------------------------------------------------------
+%% Auth and priv algorithms
+%%-----------------------------------------------------------------
+
+auth_in(usmHMACMD5AuthProtocol, AuthKey, AuthParams, Packet) ->
+ md5_auth_in(AuthKey, AuthParams, Packet);
+auth_in(?usmHMACMD5AuthProtocol, AuthKey, AuthParams, Packet) ->
+ md5_auth_in(AuthKey, AuthParams, Packet);
+auth_in(usmHMACSHAAuthProtocol, AuthKey, AuthParams, Packet) ->
+ sha_auth_in(AuthKey, AuthParams, Packet);
+auth_in(?usmHMACSHAAuthProtocol, AuthKey, AuthParams, Packet) ->
+ sha_auth_in(AuthKey, AuthParams, Packet).
+
+auth_out(usmNoAuthProtocol, _AuthKey, _Message, _UsmSecParams) -> % 3.1.3
+ error(unSupportedSecurityLevel);
+auth_out(?usmNoAuthProtocol, _AuthKey, _Message, _UsmSecParams) -> % 3.1.3
+ error(unSupportedSecurityLevel);
+auth_out(usmHMACMD5AuthProtocol, AuthKey, Message, UsmSecParams) ->
+ md5_auth_out(AuthKey, Message, UsmSecParams);
+auth_out(?usmHMACMD5AuthProtocol, AuthKey, Message, UsmSecParams) ->
+ md5_auth_out(AuthKey, Message, UsmSecParams);
+auth_out(usmHMACSHAAuthProtocol, AuthKey, Message, UsmSecParams) ->
+ sha_auth_out(AuthKey, Message, UsmSecParams);
+auth_out(?usmHMACSHAAuthProtocol, AuthKey, Message, UsmSecParams) ->
+ sha_auth_out(AuthKey, Message, UsmSecParams).
+
+md5_auth_out(AuthKey, Message, UsmSecParams) ->
+ %% 6.3.1.1
+ Message2 = set_msg_auth_params(Message, UsmSecParams, ?twelwe_zeros),
+ Packet = snmp_pdus:enc_message_only(Message2),
+ %% 6.3.1.2-4 is done by the crypto function
+ %% 6.3.1.4
+ MAC = binary_to_list(crypto:md5_mac_96(AuthKey, Packet)),
+ %% 6.3.1.5
+ set_msg_auth_params(Message, UsmSecParams, MAC).
+
+md5_auth_in(AuthKey, AuthParams, Packet) when length(AuthParams) == 12 ->
+ %% 6.3.2.3
+ Packet2 = patch_packet(binary_to_list(Packet)),
+ %% 6.3.2.5
+ MAC = binary_to_list(crypto:md5_mac_96(AuthKey, Packet2)),
+ %% 6.3.2.6
+%% ?vtrace("md5_auth_in -> entry with"
+%% "~n Packet2: ~w"
+%% "~n AuthKey: ~w"
+%% "~n AuthParams: ~w"
+%% "~n MAC: ~w", [Packet2, AuthKey, AuthParams, MAC]),
+ MAC == AuthParams;
+md5_auth_in(_AuthKey, _AuthParams, _Packet) ->
+ %% 6.3.2.1
+ ?vtrace("md5_auth_in -> entry with"
+ "~n _AuthKey: ~p"
+ "~n _AuthParams: ~p", [_AuthKey, _AuthParams]),
+ false.
+
+
+sha_auth_out(AuthKey, Message, UsmSecParams) ->
+ %% 7.3.1.1
+ Message2 = set_msg_auth_params(Message, UsmSecParams, ?twelwe_zeros),
+ Packet = snmp_pdus:enc_message_only(Message2),
+ %% 7.3.1.2-4 is done by the crypto function
+ %% 7.3.1.4
+ MAC = binary_to_list(crypto:sha_mac_96(AuthKey, Packet)),
+ %% 7.3.1.5
+ set_msg_auth_params(Message, UsmSecParams, MAC).
+
+sha_auth_in(AuthKey, AuthParams, Packet) when length(AuthParams) =:= 12 ->
+ %% 7.3.2.3
+ Packet2 = patch_packet(binary_to_list(Packet)),
+ %% 7.3.2.5
+ MAC = binary_to_list(crypto:sha_mac_96(AuthKey, Packet2)),
+ %% 7.3.2.6
+ MAC == AuthParams;
+sha_auth_in(_AuthKey, _AuthParams, _Packet) ->
+ %% 7.3.2.1
+ ?vtrace("sha_auth_in -> entry with"
+ "~n _AuthKey: ~p"
+ "~n _AuthParams: ~p", [_AuthKey, _AuthParams]),
+ false.
+
+
+des_encrypt(PrivKey, Data, SaltFun) ->
+ [A,B,C,D,E,F,G,H | PreIV] = PrivKey,
+ DesKey = [A,B,C,D,E,F,G,H],
+ Salt = SaltFun(),
+ IV = snmp_misc:str_xor(PreIV, Salt),
+ TailLen = (8 - (length(Data) rem 8)) rem 8,
+ Tail = mk_tail(TailLen),
+ EncData = crypto:des_cbc_encrypt(DesKey, IV, [Data,Tail]),
+ {ok, binary_to_list(EncData), Salt}.
+
+des_decrypt(PrivKey, MsgPrivParams, EncData)
+ when length(MsgPrivParams) =:= 8 ->
+ [A,B,C,D,E,F,G,H | PreIV] = PrivKey,
+ DesKey = [A,B,C,D,E,F,G,H],
+ Salt = MsgPrivParams,
+ IV = snmp_misc:str_xor(PreIV, Salt),
+ %% Whatabout errors here??? E.g. not a mulitple of 8!
+ Data = binary_to_list(crypto:des_cbc_decrypt(DesKey, IV, EncData)),
+ Data2 = snmp_pdus:strip_encrypted_scoped_pdu_data(Data),
+ {ok, Data2}.
+
+aes_encrypt(PrivKey, Data, SaltFun) ->
+ AesKey = PrivKey,
+ Salt = SaltFun(),
+ EngineBoots = snmp_framework_mib:get_engine_boots(),
+ EngineTime = snmp_framework_mib:get_engine_time(),
+ IV = [?i32(EngineBoots), ?i32(EngineTime) | Salt],
+ EncData = crypto:aes_cfb_128_encrypt(AesKey, IV, Data),
+ {ok, binary_to_list(EncData), Salt}.
+
+aes_decrypt(PrivKey, MsgPrivParams, EncData, EngineBoots, EngineTime)
+ when length(MsgPrivParams) == 8 ->
+ AesKey = PrivKey,
+ Salt = MsgPrivParams,
+ IV = [?i32(EngineBoots), ?i32(EngineTime) | Salt],
+ %% Whatabout errors here??? E.g. not a mulitple of 8!
+ Data = binary_to_list(crypto:aes_cfb_128_decrypt(AesKey, IV, EncData)),
+ Data2 = snmp_pdus:strip_encrypted_scoped_pdu_data(Data),
+ {ok, Data2}.
+
+
+%%-----------------------------------------------------------------
+%% Utility functions
+%%-----------------------------------------------------------------
+mk_tail(N) when N > 0 ->
+ [0 | mk_tail(N-1)];
+mk_tail(0) ->
+ [].
+
+set_msg_auth_params(Message, UsmSecParams, AuthParams) ->
+ NUsmSecParams =
+ UsmSecParams#usmSecurityParameters{msgAuthenticationParameters =
+ AuthParams},
+ SecBytes = snmp_pdus:enc_usm_security_parameters(NUsmSecParams),
+ VsnHdr = Message#message.vsn_hdr,
+ NVsnHdr = VsnHdr#v3_hdr{msgSecurityParameters = SecBytes},
+ Message#message{vsn_hdr = NVsnHdr}.
+
+
+%% Not very nice...
+%% This function patches the asn.1 encoded message. It changes the
+%% AuthenticationParameters to 12 zeros.
+%% NOTE: returns a deep list of bytes
+patch_packet([48 | T]) ->
+ %% Length for whole packet - 2 is tag for version
+ {Len1, [2 | T1]} = split_len(T),
+ %% Length for version - 48 is tag for header data
+ {Len2, [Vsn,48|T2]} = split_len(T1),
+ %% Length for header data
+ {Len3, T3} = split_len(T2),
+ [48,Len1,2,Len2,Vsn,48,Len3|pp2(dec_len(Len3),T3)].
+
+%% Skip HeaderData - 4 is tag for SecurityParameters
+pp2(0,[4|T]) ->
+ %% 48 is tag for UsmSecParams
+ {Len1,[48|T1]} = split_len(T),
+ %% 4 is tag for EngineID
+ {Len2,[4|T2]} = split_len(T1),
+ %% Len 3 is length for EngineID
+ {Len3,T3} = split_len(T2),
+ [4,Len1,48,Len2,4,Len3|pp3(dec_len(Len3),T3)];
+pp2(N,[H|T]) ->
+ [H|pp2(N-1,T)].
+
+%% Skip EngineID - 2 is tag for EngineBoots
+pp3(0,[2|T]) ->
+ {Len1,T1} = split_len(T),
+ [2,Len1|pp4(dec_len(Len1),T1)];
+pp3(N,[H|T]) ->
+ [H|pp3(N-1,T)].
+
+%% Skip EngineBoots - 2 is tag for EngineTime
+pp4(0,[2|T]) ->
+ {Len1,T1} = split_len(T),
+ [2,Len1|pp5(dec_len(Len1),T1)];
+pp4(N,[H|T]) ->
+ [H|pp4(N-1,T)].
+
+%% Skip EngineTime - 4 is tag for UserName
+pp5(0,[4|T]) ->
+ {Len1,T1} = split_len(T),
+ [4,Len1|pp6(dec_len(Len1),T1)];
+pp5(N,[H|T]) ->
+ [H|pp5(N-1,T)].
+
+%% Skip UserName - 4 is tag for AuthenticationParameters
+%% This is what we're looking for!
+pp6(0,[4|T]) ->
+ {Len1,[_,_,_,_,_,_,_,_,_,_,_,_|T1]} = split_len(T),
+ 12 = dec_len(Len1),
+ [4,Len1,?twelwe_zeros|T1];
+pp6(N,[H|T]) ->
+ [H|pp6(N-1,T)].
+
+
+%% Returns {LengthOctets, Rest}
+split_len([Hd|Tl]) ->
+ %% definite form
+ case is8set(Hd) of
+ 0 -> % Short form
+ {Hd,Tl};
+ 1 -> % Long form - at least one more octet
+ No = clear(Hd, 8),
+ {DigList,Rest} = head(No,Tl),
+ {[Hd | DigList], Rest}
+ end.
+
+dec_len(D) when is_integer(D) ->
+ D;
+dec_len([_LongOctet|T]) ->
+ dl(T).
+dl([D]) ->
+ D;
+dl([A,B]) ->
+ (A bsl 8) bor B;
+dl([A,B,C]) ->
+ (A bsl 16) bor (B bsl 8) bor C;
+dl([0 | T]) ->
+ dl(T).
+
+head(L,List) when length(List) == L -> {List,[]};
+head(L,List) ->
+ head(L,List,[]).
+
+head(0,L,Res) ->
+ {lists:reverse(Res),L};
+
+head(Int,[H|Tail],Res) ->
+ head(Int-1,Tail,[H|Res]).
+
+clear(Byte, 8) ->
+ Byte band 127.
+%% clear(Byte,Pos) when Pos < 9 ->
+%% Mask = bnot bset(0,Pos),
+%% Mask band Byte.
+
+%% bset(Byte, 8) ->
+%% Byte bor 2#10000000;
+%% bset(Byte, Pos) when (Pos < 9) ->
+%% Mask = 1 bsl (Pos-1),
+%% Byte bor Mask.
+
+is8set(Byte) ->
+ if
+ Byte > 127 -> 1;
+ true -> 0
+ end.
+
+error(Reason) ->
+ throw({error, Reason}).
+
diff --git a/lib/snmp/src/misc/snmp_verbosity.erl b/lib/snmp/src/misc/snmp_verbosity.erl
new file mode 100644
index 0000000000..85037ba2ae
--- /dev/null
+++ b/lib/snmp/src/misc/snmp_verbosity.erl
@@ -0,0 +1,161 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2000-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%
+%%
+
+-module(snmp_verbosity).
+
+-include_lib("stdlib/include/erl_compile.hrl").
+
+-export([print/4,print/5,printc/4,validate/1]).
+
+-export([process_args/2]).
+
+print(silence,_Severity,_Format,_Arguments) ->
+ ok;
+print(Verbosity,Severity,Format,Arguments) ->
+ print1(printable(Verbosity,Severity),Format,Arguments).
+
+
+print(silence,_Severity,_Module,_Format,_Arguments) ->
+ ok;
+print(Verbosity,Severity,Module,Format,Arguments) ->
+ print1(printable(Verbosity,Severity),Module,Format,Arguments).
+
+
+printc(silence,_Severity,_Format,_Arguments) ->
+ ok;
+printc(Verbosity,Severity,Format,Arguments) ->
+ print2(printable(Verbosity,Severity),Format,Arguments).
+
+
+print1(false,_Format,_Arguments) -> ok;
+print1(Verbosity,Format,Arguments) ->
+ V = image_of_verbosity(Verbosity),
+ S = image_of_sname(get(sname)),
+ A = process_args(Arguments, []),
+ (catch io:format("*** [~s] SNMP ~s ~s *** ~n"
+ " " ++ Format ++ "~n",
+ [timestamp(), S, V | A])).
+
+print1(false,_Module,_Format,_Arguments) -> ok;
+print1(Verbosity,Module,Format,Arguments) ->
+ V = image_of_verbosity(Verbosity),
+ S = image_of_sname(get(sname)),
+ A = process_args(Arguments, []),
+ (catch io:format("*** [~s] SNMP ~s ~s ~s *** ~n"
+ " " ++ Format ++ "~n",
+ [timestamp(), S, Module, V | A])).
+
+
+print2(false,_Format,_Arguments) -> ok;
+print2(_Verbosity,Format,Arguments) ->
+ A = process_args(Arguments, []),
+ (catch io:format(Format ++ "~n",A)).
+
+
+timestamp() ->
+ format_timestamp(now()).
+
+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).
+
+process_args([], Acc) ->
+ lists:reverse(Acc);
+process_args([{vapply, {M,F,A}}|T], Acc)
+ when is_atom(M) andalso is_atom(F) andalso is_list(A) ->
+ process_args(T, [(catch apply(M,F,A))|Acc]);
+process_args([H|T], Acc) ->
+ process_args(T, [H|Acc]).
+
+
+%% printable(Verbosity,Severity)
+printable(info,info) -> info;
+printable(log,info) -> info;
+printable(log,log) -> log;
+printable(debug,info) -> info;
+printable(debug,log) -> log;
+printable(debug,debug) -> debug;
+printable(trace,V) -> V;
+printable(_Verb,_Sev) -> false.
+
+
+image_of_verbosity(info) -> "INFO";
+image_of_verbosity(log) -> "LOG";
+image_of_verbosity(debug) -> "DEBUG";
+image_of_verbosity(trace) -> "TRACE";
+image_of_verbosity(_) -> "".
+
+%% ShortName
+image_of_sname(ma) -> "MASTER-AGENT";
+image_of_sname(maw) -> io_lib:format("MASTER-AGENT-worker(~p)",[self()]);
+image_of_sname(madis) -> io_lib:format("MASTER-AGENT-discovery_inform_sender(~p)",
+ [self()]);
+image_of_sname(mais) -> io_lib:format("MASTER-AGENT-inform_sender(~p)",
+ [self()]);
+image_of_sname(mats) -> io_lib:format("MASTER-AGENT-trap_sender(~p)",
+ [self()]);
+image_of_sname(maph) -> io_lib:format("MASTER-AGENT-pdu_handler(~p)",
+ [self()]);
+image_of_sname(sa) -> "SUB-AGENT";
+image_of_sname(saw) -> io_lib:format("SUB-AGENT-worker(~p)",[self()]);
+image_of_sname(sais) -> io_lib:format("SUB-AGENT-inform_sender(~p)",
+ [self()]);
+image_of_sname(sats) -> io_lib:format("SUB-AGENT-trap_sender(~p)",
+ [self()]);
+image_of_sname(saph) -> io_lib:format("SUB-AGENT-pdu_handler(~p)",
+ [self()]);
+image_of_sname(nif) -> "A-NET-IF";
+image_of_sname(ldb) -> "A-LOCAL-DB";
+image_of_sname(ns) -> "A-NOTE-STORE";
+image_of_sname(ss) -> "A-SYMBOLIC-STORE";
+image_of_sname(asup) -> "A-SUPERVISOR";
+image_of_sname(ms) -> "A-MIB-SERVER";
+image_of_sname(tcs) -> "A-TARGET-CACHE-SERVER";
+image_of_sname(conf) -> "A-CONF";
+
+image_of_sname(abs) -> "A-BKP";
+image_of_sname(albs) -> "A-LDB-BKP";
+image_of_sname(ambs) -> "A-MS-BKP";
+image_of_sname(asbs) -> "A-SS-BKP";
+image_of_sname(mcbs) -> "M-C-BKP";
+
+image_of_sname(mse) -> "M-SERVER";
+image_of_sname(msew) -> io_lib:format("M-SERVER-worker(~p)", [self()]);
+image_of_sname(mns) -> "M-NOTE-STORE";
+image_of_sname(mnif) -> "M-NET-IF";
+image_of_sname(mconf) -> "M-CONF";
+
+image_of_sname(mgr) -> "MGR";
+image_of_sname(mgr_misc) -> "MGR_MISC";
+
+image_of_sname(undefined) -> "";
+image_of_sname(V) -> lists:flatten(io_lib:format("~p",[V])).
+
+
+validate(info) -> info;
+validate(log) -> log;
+validate(debug) -> debug;
+validate(trace) -> trace;
+validate(_) -> silence.
+
diff --git a/lib/snmp/src/misc/snmp_verbosity.hrl b/lib/snmp/src/misc/snmp_verbosity.hrl
new file mode 100644
index 0000000000..934d32831f
--- /dev/null
+++ b/lib/snmp/src/misc/snmp_verbosity.hrl
@@ -0,0 +1,64 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2000-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%
+%%
+
+-ifndef(dont_use_verbosity).
+
+-define(vapply(M,F,A),{vapply, {M,F,A}}).
+
+-ifdef(VMODULE).
+
+-define(vinfo(F,A), snmp_verbosity:print(get(verbosity),info, ?VMODULE,F,A)).
+-define(vlog(F,A), snmp_verbosity:print(get(verbosity),log, ?VMODULE,F,A)).
+-define(vdebug(F,A),snmp_verbosity:print(get(verbosity),debug,?VMODULE,F,A)).
+-define(vtrace(F,A),snmp_verbosity:print(get(verbosity),trace,?VMODULE,F,A)).
+
+-else.
+
+-define(vinfo(F,A), snmp_verbosity:print(get(verbosity),info, F,A)).
+-define(vlog(F,A), snmp_verbosity:print(get(verbosity),log, F,A)).
+-define(vdebug(F,A),snmp_verbosity:print(get(verbosity),debug,F,A)).
+-define(vtrace(F,A),snmp_verbosity:print(get(verbosity),trace,F,A)).
+
+-endif.
+
+-define(vvalidate(V), snmp_verbosity:validate(V)).
+
+-define(vinfoc(F,A), snmp_verbosity:printc(get(verbosity),info, F,A)).
+-define(vlogc(F,A), snmp_verbosity:printc(get(verbosity),log, F,A)).
+-define(vdebugc(F,A),snmp_verbosity:printc(get(verbosity),debug,F,A)).
+-define(vtracec(F,A),snmp_verbosity:printc(get(verbosity),trace,F,A)).
+
+-else.
+
+-define(vvalidate(V),ok).
+
+-define(vinfo(F,A),ok).
+-define(vlog(F,A),ok).
+-define(vdebug(F,A),ok).
+-define(vtrace(F,A),ok).
+
+-define(vinfoc(F,A),ok).
+-define(vlogc(F,A),ok).
+-define(vdebugc(F,A),ok).
+-define(vtracec(F,A),ok).
+
+-endif.
+
+
+
diff --git a/lib/snmp/src/subdirs.mk b/lib/snmp/src/subdirs.mk
new file mode 100644
index 0000000000..1cbcd04b54
--- /dev/null
+++ b/lib/snmp/src/subdirs.mk
@@ -0,0 +1,22 @@
+#-*-makefile-*- ; force emacs to enter makefile-mode
+
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2003-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%
+
+SUB_DIRECTORIES = compile app misc agent manager
+# SUB_DIRECTORIES = compile app misc agent manager proxy
+
diff --git a/lib/snmp/subdirs.mk b/lib/snmp/subdirs.mk
new file mode 100644
index 0000000000..850d7d8284
--- /dev/null
+++ b/lib/snmp/subdirs.mk
@@ -0,0 +1,21 @@
+#-*-makefile-*- ; force emacs to enter makefile-mode
+
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2003-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%
+
+SUB_DIRECTORIES = src/compile mibs src examples priv/conf doc/src
+
diff --git a/lib/snmp/test/Makefile b/lib/snmp/test/Makefile
new file mode 100644
index 0000000000..86af2460f5
--- /dev/null
+++ b/lib/snmp/test/Makefile
@@ -0,0 +1,259 @@
+#-*-makefile-*- ; force emacs to enter makefile-mode
+
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 1997-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%
+
+include $(ERL_TOP)/make/target.mk
+include $(ERL_TOP)/make/$(TARGET)/otp.mk
+
+
+# ----------------------------------------------------
+# Application version
+# ----------------------------------------------------
+include ../vsn.mk
+
+VSN = $(SNMP_VSN)
+
+
+# ----------------------------------------------------
+# Target Specs
+# ----------------------------------------------------
+
+include modules.mk
+
+SNMP_ROOT = ..
+SNMP_SUITE = snmp_SUITE
+
+ERL_FILES = $(MODULES:%=%.erl)
+
+SNMP_TEST_DATA = snmp_test_data
+
+SNMP_MIB_DIR = $(SNMP_TEST_DATA)
+
+SNMP_BIN_TARGET_DIR = $(SNMP_TEST_DATA)
+
+MIB_SOURCE = $(MIB_FILES:%.mib=$(SNMP_MIB_DIR)/%.mib)
+
+MIB_TARGETS = \
+ $(MIB_FILES:%.mib=$(SNMP_BIN_TARGET_DIR)/%.bin) \
+ $(MIB_FILES:%.mib=$(SNMP_BIN_TARGET_DIR)/%.hrl)
+ERL_TARGETS = $(MODULES:%=$(EBIN)/%.$(EMULATOR))
+
+TEST_SERVER_TARGETS = $(TEST_SERVER_MODULES:%=$(EBIN)/%.$(EMULATOR))
+
+TARGET_FILES = $(ERL_TARGETS)
+
+SOURCE = $(ERL_FILES) $(HRL_FILES)
+
+# The script 'make_emakefile' only exist in R9 and later
+# So, if it does not exist, then use the old method
+# (compile the erl-files and install the beam-files)
+EMAKEFILE = Emakefile
+MAKE_EMAKE = $(wildcard $(ERL_TOP)/make/make_emakefile)
+
+ifeq ($(MAKE_EMAKE),)
+BUILDTARGET = $(TARGET_FILES)
+RELTEST_FILES = $(SPECS) $(SOURCE) $(TARGET_FILES)
+else
+BUILDTARGET = $(MIB_TARGETS) emakebuild
+RELTEST_FILES = $(EMAKEFILE) $(SPECS) $(SOURCE)
+endif
+
+COVER_SPEC_FILE = snmp.cover
+
+
+# ----------------------------------------------------
+# Release directory specification
+# ----------------------------------------------------
+RELSYSDIR = $(RELEASE_PATH)/snmp_test
+
+
+# ----------------------------------------------------
+# SNMP FLAGS
+# ----------------------------------------------------
+ifeq ($(SNMP_DEBUG),)
+ SNMP_DEBUG = d
+endif
+
+ifeq ($(SNMP_DEBUG),e)
+ SNMP_FLAGS += -Dsnmp_error
+endif
+ifeq ($(SNMP_DEBUG),l)
+ SNMP_FLAGS += -Dsnmp_log
+endif
+ifeq ($(SNMP_DEBUG),d)
+ SNMP_FLAGS += -Dsnmp_debug
+endif
+
+ifeq ($(DONT_USE_TS),true)
+ SNMP_FLAGS += -DDONT_USE_TEST_SERVER
+endif
+
+SNMP_MIB_FLAGS += -pa ../ebin +version
+
+ifneq ($(MIBS_VERBOSITY),)
+ SNMP_MIB_FLAGS += +'{verbosity,$(MIBS_VERBOSITY)}'
+endif
+
+ifeq ($(SNMP_DESC),true)
+ USE_DESCRIPTION = +'{description,true}'
+endif
+
+GROUP_CHECK = +'{group_check,false}'
+
+SNMP_MIB_FLAGS += $(GROUP_CHECK) $(USE_DESCRIPTION) -I$(SNMP_BIN_TARGET_DIR)
+
+ifndef SUITE
+SUITE = snmp_SUITE
+endif
+
+ESTOP = -s init stop
+
+ifeq ($(DONT_STOP),true)
+MAYBE_ESTOP =
+else
+MAYBE_ESTOP = $(ESTOP)
+endif
+
+ifeq ($(MERL),)
+MERL = erl
+endif
+
+ARGS += -noshell
+
+ifeq ($(DISABLE_TC_TIMEOUT),true)
+ARGS += -snmp_test_timeout
+endif
+
+
+# ----------------------------------------------------
+# FLAGS
+# ----------------------------------------------------
+EBIN = .
+
+ERL_COMPILE_FLAGS += -I../src \
+ -I$(ERL_TOP)/lib/test_server/include \
+ -I../include \
+ -Dsnmp_test_data=snmp_test_data \
+ -Dversion=\"$(VSN)$(PRE_VSN)\" \
+ +'{parse_transform,sys_pre_attributes}' \
+ +'{attribute,insert,app_vsn,$(APP_VSN)}' \
+ $(SNMP_FLAGS)
+
+ERL_SNMP_FLAGS = $(SNMP_MIB_FLAGS) \
+ -I../priv/mibs
+
+$(SNMP_BIN_TARGET_DIR)/%.bin: $(SNMP_MIB_DIR)/%.mib
+ $(ERLC) $(ERL_SNMP_FLAGS) -o $(SNMP_MIB_DIR) $<
+
+$(SNMP_BIN_TARGET_DIR)/%.hrl: $(SNMP_BIN_TARGET_DIR)/%.bin
+ $(ERLC) $(ERL_SNMP_FLAGS) -o $(SNMP_BIN_TARGET_DIR) $<
+
+
+# ----------------------------------------------------
+# Targets
+# ----------------------------------------------------
+
+tests debug opt: $(BUILDTARGET)
+
+.PHONY: emakebuild
+
+emakebuild: $(EMAKEFILE)
+
+targets: mib $(EMAKEFILE)
+ erl -make
+
+old_targets: $(TARGET_FILES) $(TEST_SERVER_TARGETS)
+
+$(EMAKEFILE): Makefile
+ $(MAKE_EMAKE) $(ERL_COMPILE_FLAGS) -o$(EBIN) '*_SUITE_make' > $(EMAKEFILE)
+ $(MAKE_EMAKE) $(ERL_COMPILE_FLAGS) -o$(EBIN) $(MODULES) >> $(EMAKEFILE)
+
+clean:
+ rm -f $(EMAKEFILE)
+ rm -f $(TARGET_FILES)
+ rm -f core
+
+docs:
+
+appup: snmp_appup_mgr.$(EMULATOR)
+
+mib: $(MIB_TARGETS)
+
+make: old_targets
+
+test: make
+ $(MERL) $(ARGS) -sname snmp_test $(ERL_PATH) \
+ -s snmp_test_server run $(SUITE) \
+ $(MAYBE_ESTOP)
+
+agent: make
+ $(MERL) $(ARGS) -sname snmp_agent_test $(ERL_PATH) \
+ -s snmp_test_server run snmp_agent_test \
+ $(MAYBE_ESTOP)
+
+manager: make
+ $(MERL) $(ARGS) -sname snmp_manager_test $(ERL_PATH) \
+ -s snmp_test_server run snmp_manager_test \
+ $(MAYBE_ESTOP)
+
+appup: make
+ $(MERL) $(ARGS) -sname snmp_appup_test $(ERL_PATH) \
+ -s snmp_test_server run snmp_appup_test \
+ $(MAYBE_ESTOP)
+
+
+# ----------------------------------------------------
+# Release Target
+# ----------------------------------------------------
+include $(ERL_TOP)/make/otp_release_targets.mk
+
+release_spec:
+
+release_tests_spec: opt
+ $(INSTALL_DIR) $(RELSYSDIR)
+ $(INSTALL_DATA) $(RELTEST_FILES) $(COVER_SPEC_FILE) $(RELSYSDIR)
+ chmod -f -R u+w $(RELSYSDIR)
+ tar cf - snmp_test_data | (cd $(RELSYSDIR); tar xf -)
+
+release_docs_spec:
+
+
+info:
+ @echo "SNMP_DEBUG = $(SNMP_DEBUG)"
+ @echo "SNMP_FLAGS = $(SNMP_FLAGS)"
+ @echo ""
+ @echo "SNMP_MIB_DIR = $(SNMP_MIB_DIR)"
+ @echo "MIB_SOURCE = $(MIB_SOURCE)"
+ @echo "MIB_TARGETS = $(MIB_TARGETS)"
+ @echo "SNMP_MIB_FLAGS = $(SNMP_MIB_FLAGS)"
+ @echo ""
+ @echo "ERL_COMPILE_FLAGS = $(ERL_COMPILE_FLAGS)"
+ @echo ""
+ @echo "RELSYSDIR = $(RELSYSDIR)"
+ @echo ""
+ @echo "SOURCE = $(SOURCE)"
+ @echo ""
+ @echo "TARGET_FILES = $(TARGET_FILES)"
+ @echo ""
+ @echo "EMAKEFILE = $(EMAKEFILE)"
+ @echo "MAKE_EMAKE = $(MAKE_EMAKE)"
+ @echo "BUILDTARGET = $(BUILDTARGET)"
+ @echo "RELTEST_FILES = $(RELTEST_FILES)"
+ @echo ""
+
+
diff --git a/lib/snmp/test/klas3.erl b/lib/snmp/test/klas3.erl
new file mode 100644
index 0000000000..a5ce2af8c5
--- /dev/null
+++ b/lib/snmp/test/klas3.erl
@@ -0,0 +1,162 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1997-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%
+%%
+
+-module(klas3).
+-compile(export_all).
+
+ftab(new) ->
+ mnesia:create_table([{name, friendsTable3},
+ {snmp, [{key, integer}]},
+ {attributes, [a1,a2]}]);
+
+ftab(delete) ->
+ ok.
+
+
+ftab(is_set_ok, [2], _Cols) ->
+% io:format("calling ftab is_set_ok - fail~n"),
+ {inconsistentValue, 2};
+ftab(is_set_ok, _, _Cols) ->
+% io:format("calling ftab is_set_ok - ok~n"),
+ {noError, 0};
+
+ftab(undo, [3], _Cols) ->
+% io:format("calling ftab undo - fail~n"),
+ {undoFailed, 2};
+
+ftab(undo, [1], _Cols) ->
+% io:format("calling ftab undo~n"),
+ {noError, 0};
+
+ftab(set, [4], _Cols) ->
+ {commitFailed, 2};
+
+ftab(Op, RowIndex, Cols) ->
+ snmp_generic:table_func(Op, RowIndex, Cols, {friendsTable3, mnesia}).
+
+
+fname(new) -> ok;
+fname(delete) -> ok;
+fname(get) ->
+ Str2 = (catch begin
+ case snmpa:current_request_id() of
+ {value, Int} when is_integer(Int) -> ok;
+ {value, _} -> throw("bad_int");
+ _ -> throw("bad_req")
+ end,
+ case snmpa:current_community() of
+ {value, Str} when is_list(Str) -> Str;
+ {value, _} -> throw("bad_str");
+ _ -> throw("bad_com")
+ end,
+ case snmpa:current_address() of
+ {value, {[_A,_B,_C,_D], E}} when is_integer(E) -> ok;
+ {value, _} -> throw("bad_ip");
+ _ -> throw("bad_adr")
+ end,
+ case snmpa:current_net_if_data() of
+ {value, []} -> ok;
+ {value, _} -> throw("bad_nil");
+ _ -> throw("bad_nid")
+ end,
+ "ok"
+ end),
+ {value, Str2}.
+
+fname(is_set_ok, "hoj") ->
+ inconsistentValue;
+fname(is_set_ok, "xfail") ->
+ i_know_this_is_wrong_it_should_be_user_error;
+fname(is_set_ok, _) ->
+% io:format("calling fname is_set_ok~n"),
+ noError;
+fname(set, "fel") -> commitFailed;
+fname(set, _) -> noError;
+fname(undo, "ufail") ->
+% io:format("calling fname undo - fail~n"),
+ undoFailed;
+fname(undo, _) ->
+% io:format("calling fname undo~n"),
+ noError.
+
+%% snmp_mgr:s([{[fStatus2, 1], 4}, {[fname2,0], "ok"}]). -> noError
+%% snmp_mgr:s([{[fStatus2, 1], 4}, {[fname2,0], "hoj"}]). -> {badValue, 2}
+%% snmp_mgr:s([{[fStatus2, 3], 4}, {[fname2,0], "hoj"}]). -> {genErr, 1}
+%% snmp_mgr:s([{[fStatus2, 4], 4}, {[fname2,0], "ok"}]). -> {genErr, 1}
+%% snmp_mgr:s([{[fStatus2, 4], 4}, {[fname2,0], "ufail"}]). -> {genErr, 1}
+%% snmp_mgr:s([{[fStatus2, 1], 4}, {[fname2,0], "xfail"}]). -> {genErr, 2}
+
+
+fname4(get) ->
+ {value, none}.
+
+
+ftab2(_) ->
+ ok.
+
+
+%% Following 2 clauses is for OTP-1222
+ftab2(is_set_ok, [1], _Cols) ->
+ % bad column - In: col 2 & 3
+ io:format("** Here comes Error Report is_set_ok bad column~n"),
+ {inconsistentValue, 1};
+ftab2(is_set_ok, _, _Cols) ->
+ {noError, 0};
+
+ftab2(set, [2], _Cols) ->
+ % bad column - In: col 2 & 3
+ io:format("** Here comes Error Report set bad column~n"),
+ {commitFailed, 4};
+ftab2(set, _, _Cols) ->
+ {noError, 0};
+
+%% Unfortunatly we can't force the undo - we don't know which var
+%% is tried first.
+%ftab2(undo, [3], Cols) ->
+% % bad column - In: col 2 & 3
+% io:format("** Here comes (no Error Report) undo bad column~n"),
+% {undoFailed, 5};
+%ftab2(undo, _, Cols) ->
+% {noError, 0};
+
+ftab2(get, [4], _Cols) ->
+ % bad return value
+ io:format("** Here comes Error Report get 1 bad return~n"),
+ [];
+ftab2(get, [5], _Cols) ->
+ % bad return value
+ io:format("** Here comes Error Report get 2 bad return~n"),
+ [{value, 1}];
+ftab2(get, [6], _Cols) ->
+ % bad return value
+ io:format("** Here comes Error Report get 3 bad return~n"),
+ [{value,1},{value,2},{value,3}];
+
+ftab2(get_next, [7], _Cols) ->
+ % bad return value
+ io:format("** Here comes Error Report get_next 1 bad return~n"),
+ [];
+ftab2(get_next, [8], _Cols) ->
+ % bad return value
+ io:format("** Here comes Error Report get_next 2 bad return~n"),
+ [endOfTable];
+ftab2(get_next, [9], _Cols) ->
+ % bad return value
+ io:format("** Here comes Error Report get_next 3 bad return~n"),
+ [{[1,5],1},{[2,5],3},{[2,6],3}].
diff --git a/lib/snmp/test/modules.mk b/lib/snmp/test/modules.mk
new file mode 100644
index 0000000000..ff848cad1b
--- /dev/null
+++ b/lib/snmp/test/modules.mk
@@ -0,0 +1,76 @@
+#-*-makefile-*- ; force emacs to enter makefile-mode
+
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 2004-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%
+
+SUITE_MODULES = \
+ snmp_SUITE \
+ snmp_app_test \
+ snmp_appup_test \
+ snmp_compiler_test \
+ snmp_conf_test \
+ snmp_log_test \
+ snmp_note_store_test \
+ snmp_pdus_test \
+ snmp_agent_mibs_test \
+ snmp_agent_nfilter_test \
+ snmp_agent_test \
+ snmp_agent_test_lib \
+ snmp_manager_config_test \
+ snmp_manager_user \
+ snmp_manager_user_old \
+ snmp_manager_user_test \
+ snmp_manager_user_test_lib \
+ snmp_manager_test
+
+TEST_UTIL_MODULES = \
+ snmp_test_lib \
+ snmp_test_manager \
+ snmp_test_mgr \
+ snmp_test_mgr_misc \
+ sa \
+ klas3 \
+ test1 \
+ test2
+
+TEST_SERVER_MODULES = \
+ snmp_test_server \
+ snmp_test_suite
+
+MODULES = \
+ $(TEST_UTIL_MODULES) \
+ $(SUITE_MODULES)
+
+HRL_FILES = snmp_test_lib.hrl
+
+MIB_FILES = \
+ OLD-SNMPEA-MIB.mib \
+ OLD-SNMPEA-MIB-v2.mib \
+ Klas1.mib \
+ Klas1-v2.mib \
+ Klas2.mib \
+ Klas3.mib \
+ Klas4.mib \
+ SA-MIB.mib \
+ EX1-MIB.mib \
+ TestTrap.mib \
+ TestTrapv2.mib \
+ Test1.mib \
+ Test2.mib
+
+SPECS = snmp.spec snmp.spec.vxworks
+
diff --git a/lib/snmp/test/sa.erl b/lib/snmp/test/sa.erl
new file mode 100644
index 0000000000..ad3ccce08f
--- /dev/null
+++ b/lib/snmp/test/sa.erl
@@ -0,0 +1,44 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1997-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%
+%%
+
+-module(sa).
+
+-compile(export_all).
+
+sa_bad_value(get) ->
+ {value, 3}.
+sa_bad_value(is_set_ok, 5) ->
+ badValue;
+sa_bad_value(is_set_ok, 6) ->
+ wrongValue.
+
+sa_gen_err(get) ->
+ {value, 4}.
+sa_gen_err(set, _NewVal) ->
+ genErr.
+
+sa_too_big(get) ->
+ {value, [67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67,67]}.
+
+
+sa_fel(get) ->
+ {value, undefined}.
+
+
+
diff --git a/lib/snmp/test/snmp.cover b/lib/snmp/test/snmp.cover
new file mode 100644
index 0000000000..027dce68c1
--- /dev/null
+++ b/lib/snmp/test/snmp.cover
@@ -0,0 +1,15 @@
+%% -*- erlang -*-
+{exclude,
+ [snmp_index,
+ snmpa_error_io,
+ snmpa_authentication_service,
+ snmpa_error_report,
+ snmpa_network_interface,
+ snmpa_network_interface_filter,
+ snmpa_notification_delivery_info_receiver,
+ snmpa_set_mechanism,
+ snmpm_network_interface,
+ snmpm_user
+ ]
+}.
+
diff --git a/lib/snmp/test/snmp.spec b/lib/snmp/test/snmp.spec
new file mode 100644
index 0000000000..0af52c139e
--- /dev/null
+++ b/lib/snmp/test/snmp.spec
@@ -0,0 +1 @@
+{topcase, {dir, "../snmp_test"}}.
diff --git a/lib/snmp/test/snmp.spec.vxworks b/lib/snmp/test/snmp.spec.vxworks
new file mode 100644
index 0000000000..654aa96d8c
--- /dev/null
+++ b/lib/snmp/test/snmp.spec.vxworks
@@ -0,0 +1,4 @@
+{topcase, {dir, "../snmp_test"}}.
+{skip, {snmp_SUITE, test_v3, "Requires crypto"}}.
+
+
diff --git a/lib/snmp/test/snmp_SUITE.erl b/lib/snmp/test/snmp_SUITE.erl
new file mode 100644
index 0000000000..f560e36663
--- /dev/null
+++ b/lib/snmp/test/snmp_SUITE.erl
@@ -0,0 +1,157 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1997-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%
+%%
+
+-module(snmp_SUITE).
+
+-export([all/1,
+ init_per_testcase/2, fin_per_testcase/2
+ ]).
+
+-export([app/1, compiler/1, misc/1, agent/1, manager/1]).
+
+-export([
+ app_test/1,
+ appup_test/1,
+ compiler_test/1,
+ conf_test/1,
+ pdus_test/1,
+ log_test/1,
+ note_store_test/1,
+ mibs_test/1,
+ nfilter_test/1,
+ agent_test/1,
+ manager_config_test/1,
+ manager_user_test/1,
+ manager_test/1
+ ]).
+
+%%
+%% -----
+%%
+
+init_per_testcase(_Case, Config) when is_list(Config) ->
+ Config.
+
+fin_per_testcase(_Case, Config) when is_list(Config) ->
+ Config.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Top test case
+
+all(doc) ->
+ ["Test suites for the snmp application.",
+ "There are eight different sub test-suites."];
+
+all(suite) ->
+ [
+ app,
+ compiler,
+ misc,
+ agent,
+ manager
+
+ ].
+
+app(suite) ->
+ [
+ app_test,
+ appup_test
+ ].
+
+compiler(suite) ->
+ [
+ compiler_test
+ ].
+
+misc(suite) ->
+ [
+ conf_test,
+ pdus_test,
+ log_test,
+ note_store_test
+ ].
+
+agent(suite) ->
+ [
+ mibs_test,
+ nfilter_test,
+ agent_test
+ ].
+
+manager(suite) ->
+ [
+ manager_config_test,
+ manager_user_test,
+ manager_test
+ ].
+
+
+app_test(suite) ->
+ [{snmp_app_test, all}].
+
+
+appup_test(suite) ->
+ [{snmp_appup_test, all}].
+
+
+compiler_test(suite) ->
+ [{snmp_compiler_test, all}].
+
+
+conf_test(suite) ->
+ [{snmp_conf_test, all}].
+
+
+pdus_test(suite) ->
+ [{snmp_pdus_test, all}].
+
+
+log_test(suite) ->
+ [{snmp_log_test, all}].
+
+
+note_store_test(suite) ->
+ [{snmp_note_store_test, all}].
+
+
+mibs_test(suite) ->
+ [{snmp_agent_mibs_test, all}].
+
+
+nfilter_test(suite) ->
+ [{snmp_agent_nfilter_test, all}].
+
+
+agent_test(suite) ->
+ [{snmp_agent_test, all}].
+
+
+manager_config_test(suite) ->
+ [{snmp_manager_config_test, all}].
+
+
+manager_user_test(suite) ->
+ [{snmp_manager_user_test, all}].
+
+
+manager_test(suite) ->
+ [{snmp_manager_test, all}].
+
+
diff --git a/lib/snmp/test/snmp_agent_bl_test.erl b/lib/snmp/test/snmp_agent_bl_test.erl
new file mode 100644
index 0000000000..4608d90201
--- /dev/null
+++ b/lib/snmp/test/snmp_agent_bl_test.erl
@@ -0,0 +1,5654 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2005-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%
+%%
+
+-module(snmp_agent_bl_test).
+
+%% TODO
+%% * Test fault-tolerance (kill master etc)
+%%
+
+% -include_lib("kernel/include/file.hrl").
+% -include("test_server.hrl").
+% -include("snmp_test_lib.hrl").
+% -define(SNMP_USE_V3, true).
+% -include_lib("snmp/include/snmp_types.hrl").
+
+%% -include_lib("snmp/include/SNMP-COMMUNITY-MIB.hrl").
+%% -include_lib("snmp/include/SNMP-VIEW-BASED-ACM-MIB.hrl").
+%% -include_lib("snmp/include/SNMP-USER-BASED-SM-MIB.hrl").
+
+
+% -define(klas1, [1,3,6,1,2,1,7]).
+% -define(klas2, [1,3,6,1,2,1,9]).
+% -define(klas3, [1,3,6,1,2,1,8,1]).
+% -define(klas4, [1,3,6,1,2,1,8,4]).
+% -define(sa, [1,3,6,1,4,1,193,2]).
+% -define(system, [1,3,6,1,2,1,1]).
+% -define(snmp, [1,3,6,1,2,1,11]).
+% -define(snmpTraps, [1,3,6,1,6,3,1,1,5]).
+% -define(ericsson, [1,3,6,1,4,1,193]).
+% -define(testTrap, [1,3,6,1,2,1,15,0]).
+% -define(xDescr, [1,3,6,1,2,1,17,1]).
+% -define(xDescr2, [1,3,6,1,2,1,17,2]).
+
+% -define(active, 1).
+% -define(notInService, 2).
+% -define(notReady, 3).
+% -define(createAndGo, 4).
+% -define(createAndWait, 5).
+% -define(destroy, 6).
+
+% -define(TRAP_UDP, 5000).
+
+% -define(tooBigStr, "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").
+
+-define(str(X), snmp_pdus:bits_to_str(X)).
+
+-define(break(), begin io:format(user, "break at line ~w: pid: ~p\n",
+ [?LINE, self()]),
+ receive cont -> ok end
+ end).
+
+
+-import(snmp_test_mgr, [gn/1, g/1, s/1, gb/3]).
+-define(v1_2(V1,V2),
+ case get(vsn) of
+ v1 -> V1;
+ _ -> V2
+ end).
+
+-define(v1_2_3(V1,V2,V3),
+ case get(vsn) of
+ v1 -> V1;
+ v2 -> V2;
+ _ -> V3
+ end).
+
+all(suite) -> {req,
+ [mnesia, distribution,
+ {local_slave_nodes, 2}, {time, 360}],
+ [{conf, init_all, cases(), finish_all}]}.
+
+init_per_testcase(_Case, Config) when list(Config) ->
+ Dog = ?t:timetrap(?t:minutes(6)),
+ [{watchdog, Dog}|Config].
+
+fin_per_testcase(_Case, Config) when list(Config) ->
+ Dog = ?config(watchdog, Config),
+ ?t:timetrap_cancel(Dog),
+ Config.
+
+cases() ->
+ case ?OSTYPE() of
+ vxworks ->
+ %% No crypto app, so skip v3 testcases
+ [
+ app_info,
+ test_v1, test_v2, test_v1_v2,
+ test_multi_threaded,
+ mib_storage,
+ tickets];
+ _Else ->
+ [
+ app_info,
+ test_v1, test_v2, test_v1_v2, test_v3,
+ test_multi_threaded,
+ mib_storage,
+ tickets
+ ]
+ end.
+
+
+%%%-----------------------------------------------------------------
+%%% The test case structure is as follows:
+%%%
+%%% init_all - starts mnesia,
+%%%
+%%% init_v1 - starts agent
+%%% simple
+%%% big - e.g. starts/stops subagent, load/unloads mibs
+%%% init_mul
+%%% mul_get
+%%% mul_set
+%%% <etc>
+%%% finish_mul
+%%% <etc>
+%%% finish_v1
+%%%
+%%% init_v2 - starts agent
+%%% finish_v2
+%%%
+%%% init_bilingual - starts agent
+%%% finish_bilingual
+%%%
+%%% finish_all
+%%%
+%%% There is still one problem with these testsuites. If one test
+%%% fails, it may not be possible to run some other cases, as it
+%%% may have e.g. created some row or loaded some table, that it
+%%% didn't undo (since it failed).
+%%%-----------------------------------------------------------------
+
+init_all(Config0) when list(Config0) ->
+ ?LOG("init_all -> entry with"
+ "~n Config0: ~p",[Config0]),
+
+ %% --
+ %% Fix config:
+ %%
+
+ DataDir0 = ?config(data_dir, Config0),
+ DataDir1 = filename:split(filename:absname(DataDir0)),
+ [_|DataDir2] = lists:reverse(DataDir1),
+ DataDir3 = filename:join(lists:reverse(DataDir2) ++ [?snmp_test_data]),
+ Config1 = lists:keydelete(data_dir, 1, Config0),
+ Config = [{data_dir, DataDir3 ++ "/"}|Config1],
+
+ %% --
+ %% Start nodes
+ %%
+
+ ?line {ok, SaNode} = start_node(snmp_sa),
+ ?line {ok, MgrNode} = start_node(snmp_mgr),
+
+
+ %% --
+ %% Create necessary files
+ %%
+
+ Dir = ?config(priv_dir, Config),
+ ?DBG("init_all -> Dir ~p", [Dir]),
+
+ DataDir = ?config(data_dir, Config),
+ ?DBG("init_all -> DataDir ~p", [DataDir]),
+
+ file:make_dir(MgrDir = filename:join(Dir, "mgr_dir/")),
+ ?DBG("init_all -> MgrDir ~p", [MgrDir]),
+
+ file:make_dir(AgentDir = filename:join(Dir, "agent_dir/")),
+ ?DBG("init_all -> AgentDir ~p", [AgentDir]),
+
+ file:make_dir(SaDir = filename:join(Dir, "sa_dir/")),
+ ?DBG("init_all -> SaDir ~p", [SaDir]),
+
+
+ %% --
+ %% Start and initiate mnesia
+ %%
+
+ ?DBG("init_all -> load application mnesia", []),
+ ?line ok = application:load(mnesia),
+
+ ?DBG("init_all -> load application mnesia on node ~p", [SaNode]),
+ ?line ok = rpc:call(SaNode, application, load, [mnesia]),
+
+ ?DBG("init_all -> application mnesia: set_env dir",[]),
+ ?line application_controller:set_env(mnesia, dir,
+ filename:join(Dir, "Mnesia1")),
+
+ ?DBG("init_all -> application mnesia: set_env dir on node ~p",[SaNode]),
+ ?line rpc:call(SaNode, application_controller, set_env,
+ [mnesia, dir, filename:join(Dir, "Mnesia2")]),
+
+ ?DBG("init_all -> create mnesia schema",[]),
+ ?line ok = mnesia:create_schema([SaNode, node()]),
+
+ ?DBG("init_all -> start application mnesia",[]),
+ ?line ok = application:start(mnesia),
+
+ ?DBG("init_all -> start application mnesia on ~p",[SaNode]),
+ ?line ok = rpc:call(SaNode, application, start, [mnesia]),
+ Ip = ?LOCALHOST(),
+ [{snmp_sa, SaNode},
+ {snmp_mgr, MgrNode},
+ {agent_dir, AgentDir ++ "/"},
+ {mgr_dir, MgrDir ++ "/"},
+ {sa_dir, SaDir ++ "/"},
+ {mib_dir, DataDir},
+ {ip, Ip} |
+ Config].
+
+finish_all(Config) when list(Config) ->
+ SaNode = ?config(snmp_sa, Config),
+ MgrNode = ?config(snmp_mgr, Config),
+ stop_node(SaNode),
+ stop_node(MgrNode),
+ application:stop(mnesia).
+
+start_v1_agent(Config) when list(Config) ->
+ start_agent(Config, [v1]).
+
+start_v1_agent(Config,Opts) when list(Config), list(Opts) ->
+ start_agent(Config, [v1], Opts).
+
+start_v2_agent(Config) when list(Config) ->
+ start_agent(Config, [v2]).
+
+start_v3_agent(Config) when list(Config) ->
+ start_agent(Config, [v3]).
+
+start_bilingual_agent(Config) when list(Config) ->
+ start_agent(Config, [v1,v2]).
+
+start_multi_threaded_agent(Config) when list(Config) ->
+ start_agent(Config, [v2], [{snmp_multi_threaded, true}]).
+
+stop_agent(Config) when list(Config) ->
+ ?LOG("stop_agent -> entry with"
+ "~n Config: ~p",[Config]),
+
+ {Sup, Par} = ?config(snmp_sup, Config),
+ ?DBG("stop_agent -> attempt to stop (sup) ~p"
+ "~n Sup: ~p"
+ "~n Par: ~p",
+ [Sup,
+ (catch process_info(Sup)),
+ (catch process_info(Par))]),
+ stop_sup(Sup, Par),
+
+ {Sup2, Par2} = ?config(snmp_sub, Config),
+ ?DBG("stop_agent -> attempt to stop (sub) ~p"
+ "~n Sup2: ~p"
+ "~n Par2: ~p",
+ [Sup2,
+ (catch process_info(Sup2)),
+ (catch process_info(Par2))]),
+ stop_sup(Sup2, Par2),
+
+ ?DBG("stop_agent -> done - now cleanup config", []),
+ C1 = lists:keydelete(snmp_sup, 1, Config),
+ lists:keydelete(snmp_sub, 1, C1).
+
+
+stop_sup(Pid, _) when node(Pid) == node() ->
+ case (catch process_info(Pid)) of
+ PI when list(PI) ->
+ ?LOG("stop_sup -> attempt to stop ~p", [Pid]),
+ Ref = erlang:monitor(process, Pid),
+ exit(Pid, kill),
+ await_stopped(Pid, Ref);
+ {'EXIT', _Reason} ->
+ ?LOG("stop_sup -> ~p not running", [Pid]),
+ ok
+ end;
+stop_sup(Pid, _) ->
+ ?LOG("stop_sup -> attempt to stop ~p", [Pid]),
+ Ref = erlang:monitor(process, Pid),
+ ?LOG("stop_sup -> Ref: ~p", [Ref]),
+ %% Pid ! {'EXIT', Parent, shutdown}, % usch
+ exit(Pid, kill),
+ await_stopped(Pid, Ref).
+
+await_stopped(Pid, Ref) ->
+ receive
+ {'DOWN', Ref, process, Pid, _Reason} ->
+ ?DBG("received down message for ~p", [Pid]),
+ ok
+ after 10000 ->
+ ?INF("await_stopped -> timeout for ~p",[Pid]),
+ erlang:demonitor(Ref),
+ ?FAIL({failed_stop,Pid})
+ end.
+
+
+start_agent(Config, Vsn) ->
+ start_agent(Config, Vsn, []).
+start_agent(Config, Vsn, Opts) ->
+ ?LOG("start_agent -> entry (~p) with"
+ "~n Config: ~p"
+ "~n Vsn: ~p"
+ "~n Opts: ~p",[node(), Config, Vsn, Opts]),
+
+ ?line AgentDir = ?config(agent_dir, Config),
+ ?line SaNode = ?config(snmp_sa, Config),
+
+ snmp_app_env_init(vsn_init(Vsn) ++
+ [{audit_trail_log, read_write_log},
+ {audit_trail_log_dir, AgentDir},
+ {audit_trail_log_size, {10240, 10}},
+ {force_config_reload, false},
+ {snmp_agent_type, master},
+ {snmp_config_dir, AgentDir},
+ {snmp_db_dir, AgentDir},
+ {snmp_local_db_auto_repair, true},
+ {snmp_master_agent_verbosity, trace},
+ {snmp_supervisor_verbosity, trace},
+ {snmp_mibserver_verbosity, trace},
+ {snmp_symbolic_store_verbosity, trace},
+ {snmp_note_store_verbosity, trace},
+ {snmp_net_if_verbosity, trace}],
+ Opts),
+
+
+ process_flag(trap_exit,true),
+
+ {ok, AppSup} = snmp_app_sup:start_link(),
+ unlink(AppSup),
+ ?DBG("start_agent -> snmp app supervisor: ~p",[AppSup]),
+
+ ?DBG("start_agent -> start master agent (old style)",[]),
+ Sup = case (catch snmpa_app:start(normal)) of
+ {ok, S} ->
+ ?DBG("start_agent -> started, Sup: ~p",[S]),
+ S;
+
+ Else ->
+ ?DBG("start_agent -> unknown result: ~n~p",[Else]),
+ %% Get info about the apps we depend on
+ MnesiaInfo = mnesia_running(),
+ ?FAIL({start_failed,Else,MnesiaInfo})
+ end,
+
+ ?DBG("start_agent -> unlink from supervisor",[]),
+ ?line unlink(Sup),
+ ?line SaDir = ?config(sa_dir, Config),
+ ?DBG("start_agent -> (rpc) start sub on ~p",[SaNode]),
+ ?line {ok, Sub} = rpc:call(SaNode, ?MODULE, start_sub, [SaDir]),
+ ?DBG("start_agent -> done",[]),
+ ?line [{snmp_sup, {Sup, self()}}, {snmp_sub, Sub} | Config].
+
+
+vsn_init(Vsn) ->
+ vsn_init([v1,v2,v3], Vsn, []).
+
+vsn_init([], _Vsn, Acc) ->
+ Acc;
+vsn_init([V|Vsns], Vsn, Acc) ->
+ case lists:member(V, Vsn) of
+ true ->
+ vsn_init(Vsns, Vsn, [{V, true}|Acc]);
+ false ->
+ vsn_init(Vsns, Vsn, [{V, false}|Acc])
+ end.
+
+snmp_app_env_init(Env0, Opts) ->
+ ?DBG("snmp_app_env_init -> unload snmp",[]),
+ ?line application:unload(snmp),
+ ?DBG("snmp_app_env_init -> load snmp",[]),
+ ?line application:load(snmp),
+ ?DBG("snmp_app_env_init -> initiate (snmp) application env",[]),
+ F1 = fun({Key,Val} = New, Acc0) ->
+ ?DBG("snmp_app_env_init -> "
+ "updating setting ~p to ~p", [Key, Val]),
+ case lists:keyreplace(Key, 1, Acc0, New) of
+ Acc0 ->
+ [New|Acc0];
+ Acc ->
+ Acc
+ end
+ end,
+ Env = lists:foldr(F1, Env0, Opts),
+ ?DBG("snmp_app_env_init -> Env: ~p",[Env]),
+ F2 = fun({Key,Val}) ->
+ ?DBG("snmp_app_env_init -> setting ~p to ~p",[Key, Val]),
+ application_controller:set_env(snmp, Key, Val)
+ end,
+ lists:foreach(F2, Env).
+
+
+
+
+%% Test if application is running
+mnesia_running() -> ?IS_MNESIA_RUNNING().
+crypto_running() -> ?IS_CRYPTO_RUNNING().
+
+
+start_sub(Dir) ->
+ ?DBG("start_sub -> entry",[]),
+ Opts = [{db_dir, Dir},
+ {supervisor, [{verbosity, trace}]}],
+ %% BMK BMK
+% {ok, P} = snmp_supervisor:start_sub(Dir),
+ {ok, P} = snmpa_supervisor:start_sub_sup(Opts),
+ unlink(P),
+ {ok, {P, self()}}.
+
+create_tables(SaNode) ->
+ ?line {atomic, ok} = mnesia:create_table([{name, friendsTable2},
+ {ram_copies, [SaNode]},
+ {snmp, [{key, integer}]},
+ {attributes, [a1,a2,a3]}]),
+ ?line {atomic, ok} = mnesia:create_table([{name, kompissTable2},
+ {ram_copies, [SaNode]},
+ {snmp, [{key, integer}]},
+ {attributes, [a1,a2,a3]}]),
+ ?line {atomic, ok} = mnesia:create_table([{name, snmp_variables},
+ {attributes, [a1,a2]}]).
+
+delete_tables() ->
+ mnesia:delete_table(friendsTable2),
+ mnesia:delete_table(kompissTable2),
+ mnesia:delete_table(snmp_variables).
+
+%% Creation is done in runtime!
+delete_mib_storage_mnesia_tables() ->
+ mnesia:delete_table(snmpa_mib_data),
+ mnesia:delete_table(snmpa_mib_tree),
+ mnesia:delete_table(snmpa_symbolic_store).
+
+%%-----------------------------------------------------------------
+%% A test case is always one of:
+%% - v1 specific case
+%% - v2 specific case
+%% - v1 and v2 case
+%% All v1 specific cases are prefixed with v1_, and all v2 with
+%% v2_. E.g. v1_trap/v2_trap.
+%%
+%% All other cases are shared. However, the testserver uses the name
+%% of the case to generate a file for that case. The same case cannot
+%% be used in different configurations in the same suite. Therefore
+%% all these functions exists in two variants, the base function
+%% <base>, and a second version <base>_2. There may be several
+%% versions as well, <base>_N.
+%%-----------------------------------------------------------------
+mib_storage(suite) -> [
+ mib_storage_ets,
+ mib_storage_dets,
+ mib_storage_mnesia,
+ mib_storage_size_check_ets,
+ mib_storage_size_check_dets,
+ mib_storage_size_check_mnesia,
+ mib_storage_varm_dets,
+ mib_storage_varm_mnesia
+ ].
+
+mib_storage_ets(suite) -> {req, [], {conf, init_mib_storage_ets,
+ mib_storage_ets_cases(),
+ finish_mib_storage_ets}}.
+
+mib_storage_dets(suite) -> {req, [], {conf, init_mib_storage_dets,
+ mib_storage_dets_cases(),
+ finish_mib_storage_dets}}.
+
+mib_storage_mnesia(suite) -> {req, [], {conf, init_mib_storage_mnesia,
+ mib_storage_mnesia_cases(),
+ finish_mib_storage_mnesia}}.
+
+mib_storage_size_check_ets(suite) ->
+ {req, [], {conf,
+ init_size_check_mse,
+ mse_size_check_cases(),
+ finish_size_check_mse}}.
+
+mib_storage_size_check_dets(suite) ->
+ {req, [], {conf,
+ init_size_check_msd,
+ msd_size_check_cases(),
+ finish_size_check_msd}}.
+
+mib_storage_size_check_mnesia(suite) ->
+ {req, [], {conf,
+ init_size_check_msm,
+ msm_size_check_cases(),
+ finish_size_check_msm}}.
+
+mib_storage_varm_dets(suite) ->
+ {req, [], {conf,
+ init_varm_mib_storage_dets,
+ varm_mib_storage_dets_cases(),
+ finish_varm_mib_storage_dets}}.
+
+mib_storage_varm_mnesia(suite) ->
+ {req, [], {conf,
+ init_varm_mib_storage_mnesia,
+ varm_mib_storage_mnesia_cases(),
+ finish_varm_mib_storage_mnesia}}.
+
+mib_storage_ets_cases() ->
+ [
+ mse_simple,
+ mse_v1_processing,
+ mse_big,
+ mse_big2,
+ mse_loop_mib,
+ mse_api,
+ mse_sa_register,
+ mse_v1_trap,
+ mse_sa_error,
+ mse_next_across_sa,
+ mse_undo,
+ mse_standard_mib,
+ mse_community_mib,
+ mse_framework_mib,
+ mse_target_mib,
+ mse_notification_mib,
+ mse_view_based_acm_mib,
+ mse_sparse_table,
+ mse_me_of,
+ mse_mib_of].
+
+mib_storage_dets_cases() ->
+ [
+ msd_simple,
+ msd_v1_processing,
+ msd_big,
+ msd_big2,
+ msd_loop_mib,
+ msd_api,
+ msd_sa_register,
+ msd_v1_trap,
+ msd_sa_error,
+ msd_next_across_sa,
+ msd_undo,
+ msd_standard_mib,
+ msd_community_mib,
+ msd_framework_mib,
+ msd_target_mib,
+ msd_notification_mib,
+ msd_view_based_acm_mib,
+ msd_sparse_table,
+ msd_me_of,
+ msd_mib_of
+ ].
+
+mib_storage_mnesia_cases() ->
+ [
+ msm_simple,
+ msm_v1_processing,
+ msm_big,
+ msm_big2,
+ msm_loop_mib,
+ msm_api,
+ msm_sa_register,
+ msm_v1_trap,
+ msm_sa_error,
+ msm_next_across_sa,
+ msm_undo,
+ msm_standard_mib,
+ msm_community_mib,
+ msm_framework_mib,
+ msm_target_mib,
+ msm_notification_mib,
+ msm_view_based_acm_mib,
+ msm_sparse_table,
+ msm_me_of,
+ msm_mib_of
+ ].
+
+mse_size_check_cases() ->
+ [mse_size_check].
+
+msd_size_check_cases() ->
+ [msd_size_check].
+
+msm_size_check_cases() ->
+ [msm_size_check].
+
+varm_mib_storage_dets_cases() ->
+ [msd_varm_mib_start].
+
+varm_mib_storage_mnesia_cases() ->
+ [msm_varm_mib_start].
+
+init_mib_storage_ets(Config) when list(Config) ->
+ ?LOG("init_mib_storage_ets -> entry", []),
+ MibStorage = {snmp_mib_storage,ets},
+ init_ms(Config, [MibStorage]).
+
+init_mib_storage_dets(Config) when list(Config) ->
+ ?LOG("init_mib_storage_ets -> entry", []),
+ ?line AgentDir = ?GCONF(agent_dir, Config),
+ MibStorage = {snmp_mib_storage,{dets,AgentDir}},
+ init_ms(Config, [MibStorage]).
+
+init_mib_storage_mnesia(Config) when list(Config) ->
+ ?LOG("init_mib_storage_ets -> entry", []),
+ MibStorage = {snmp_mib_storage,{mnesia,[]}},
+ init_ms(Config, [MibStorage]).
+
+init_ms(Config, Opts) when list(Config) ->
+ ?LOG("init_mib_storage_ets -> entry", []),
+ ?line SaNode = ?GCONF(snmp_sa, Config),
+ ?line create_tables(SaNode),
+ ?line AgentDir = ?GCONF(agent_dir, Config),
+ ?line MgrDir = ?GCONF(mgr_dir, Config),
+ ?line Ip = ?GCONF(ip, Config),
+ ?line config([v1], MgrDir, AgentDir, tuple_to_list(Ip), tuple_to_list(Ip)),
+ MasterAgentVerbosity = {snmp_master_agent_verbosity, trace},
+ MibsVerbosity = {snmp_mibserver_verbosity, trace},
+ SymStoreVerbosity = {snmp_symbolic_store_verbosity, trace},
+ Opts1 = [MasterAgentVerbosity,MibsVerbosity,SymStoreVerbosity|Opts],
+ [{vsn, v1} | start_v1_agent(Config,Opts1)].
+
+init_size_check_mse(Config) when list(Config) ->
+ MibStorage = {snmp_mib_storage, ets},
+ init_size_check_ms(Config, [MibStorage]).
+
+init_size_check_msd(Config) when list(Config) ->
+ AgentDir = ?GCONF(agent_dir, Config),
+ MibStorage = {snmp_mib_storage, {dets, AgentDir}},
+ init_size_check_ms(Config, [MibStorage]).
+
+init_size_check_msm(Config) when list(Config) ->
+ MibStorage = {snmp_mib_storage, {mnesia,[]}},
+ init_size_check_ms(Config, [MibStorage]).
+
+init_size_check_ms(Config, Opts) when list(Config) ->
+ SaNode = ?GCONF(snmp_sa, Config),
+ %% We are using v3 here, so crypto must be supported or else...
+ case ?CRYPTO_START() of
+ ok ->
+ case ?CRYPTO_SUPPORT() of
+ {no, Reason} ->
+ ?SKIP({unsupported_encryption, Reason});
+ yes ->
+ ok
+ end;
+ {error, Reason} ->
+ ?SKIP({failed_starting_crypto, Reason})
+ end,
+ create_tables(SaNode),
+ AgentDir = ?GCONF(agent_dir, Config),
+ MgrDir = ?GCONF(mgr_dir, Config),
+ Ip = ?GCONF(ip, Config),
+ ?line ok =
+ config([v3], MgrDir, AgentDir, tuple_to_list(Ip), tuple_to_list(Ip)),
+ [{vsn, v3} | start_agent(Config, [v3], Opts)].
+
+init_varm_mib_storage_dets(Config) when list(Config) ->
+ ?LOG("init_varm_mib_storage_dets -> entry", []),
+ ?line SaNode = ?GCONF(snmp_sa, Config),
+ ?line create_tables(SaNode),
+ ?line AgentDir = ?GCONF(agent_dir, Config),
+ ?line MgrDir = ?GCONF(mgr_dir, Config),
+ ?line Ip = ?GCONF(ip, Config),
+ ?line config([v1], MgrDir, AgentDir, tuple_to_list(Ip), tuple_to_list(Ip)),
+ MibStorage = {snmp_mib_storage,{dets,AgentDir}},
+ MasterAgentVerbosity = {snmp_master_agent_verbosity, trace},
+ MibsVerbosity = {snmp_mibserver_verbosity, trace},
+ SymStoreVerbosity = {snmp_symbolic_store_verbosity, trace},
+ Opts = [MibStorage,MasterAgentVerbosity,MibsVerbosity,SymStoreVerbosity],
+ [{vsn, v1}, {agent_opts,Opts} | Config].
+
+init_varm_mib_storage_mnesia(Config) when list(Config) ->
+ ?LOG("init_varm_mib_storage_mnesia -> entry", []),
+ ?line SaNode = ?GCONF(snmp_sa, Config),
+ ?line create_tables(SaNode),
+ ?line AgentDir = ?GCONF(agent_dir, Config),
+ ?line MgrDir = ?GCONF(mgr_dir, Config),
+ ?line Ip = ?GCONF(ip, Config),
+ ?line config([v1], MgrDir, AgentDir, tuple_to_list(Ip), tuple_to_list(Ip)),
+ MibStorage = {snmp_mib_storage,{mnesia,[]}},
+ MasterAgentVerbosity = {snmp_master_agent_verbosity, trace},
+ MibsVerbosity = {snmp_mibserver_verbosity, trace},
+ SymStoreVerbosity = {snmp_symbolic_store_verbosity, trace},
+ Opts = [MibStorage,MasterAgentVerbosity,MibsVerbosity,SymStoreVerbosity],
+ [{vsn, v1}, {agent_opts,Opts} | Config].
+
+finish_mib_storage_ets(Config) when list(Config) ->
+ ?LOG("finish_mib_storage_ets -> entry", []),
+ delete_tables(),
+ C1 = stop_agent(Config),
+ delete_files(C1),
+ C2 = lists:keydelete(vsn, 1, C1),
+ lists:keydelete(agent_opts, 1, C2).
+
+finish_mib_storage_dets(Config) when list(Config) ->
+ ?LOG("finish_mib_storage_dets -> entry", []),
+ delete_tables(),
+ C1 = stop_agent(Config),
+ delete_files(C1),
+ C2 = lists:keydelete(vsn, 1, C1),
+ lists:keydelete(agent_opts, 1, C2).
+
+finish_mib_storage_mnesia(Config) when list(Config) ->
+ ?LOG("finish_mib_storage_mnesia -> entry", []),
+ delete_tables(),
+ delete_mib_storage_mnesia_tables(),
+ C1 = stop_agent(Config),
+ delete_files(C1),
+ C2 = lists:keydelete(vsn, 1, C1),
+ lists:keydelete(agent_opts, 1, C2).
+
+finish_varm_mib_storage_dets(Config) when list(Config) ->
+ ?LOG("finish_varm_mib_storage_dets -> entry", []),
+ delete_tables(),
+ %% C1 = stop_agent(Config), % In case something went wrong...
+ delete_files(Config),
+ C2 = lists:keydelete(vsn, 1, Config),
+ lists:keydelete(agent_opts, 1, C2).
+
+finish_varm_mib_storage_mnesia(Config) when list(Config) ->
+ ?LOG("finish_varm_mib_storage_mnesia -> entry", []),
+ delete_tables(),
+ delete_mib_storage_mnesia_tables(),
+ %% C1 = stop_agent(Config), % In case something went wrong...
+ delete_files(Config),
+ C2 = lists:keydelete(vsn, 1, Config),
+ lists:keydelete(agent_opts, 1, C2).
+
+finish_size_check_mse(Config) when list(Config) ->
+ finish_size_check_ms(Config).
+
+finish_size_check_msd(Config) when list(Config) ->
+ finish_size_check_ms(Config).
+
+finish_size_check_msm(Config) when list(Config) ->
+ finish_size_check_ms(Config).
+
+finish_size_check_ms(Config) when list(Config) ->
+ delete_tables(),
+ C1 = stop_agent(Config),
+ delete_files(C1),
+ lists:keydelete(vsn, 1, C1).
+
+
+%% These are just interface functions to fool the test server
+mse_simple(X) -> simple(X).
+mse_v1_processing(X) -> v1_processing(X).
+mse_big(X) -> big(X).
+mse_big2(X) -> big2(X).
+mse_loop_mib(X) -> loop_mib(X).
+mse_api(X) -> api(X).
+mse_sa_register(X) -> sa_register(X).
+mse_v1_trap(X) -> v1_trap(X).
+mse_sa_error(X) -> sa_error(X).
+mse_next_across_sa(X) -> next_across_sa(X).
+mse_undo(X) -> undo(X).
+mse_standard_mib(X) -> snmp_standard_mib(X).
+mse_community_mib(X) -> snmp_community_mib(X).
+mse_framework_mib(X) -> snmp_framework_mib(X).
+mse_target_mib(X) -> snmp_target_mib(X).
+mse_notification_mib(X) -> snmp_notification_mib(X).
+mse_view_based_acm_mib(X) -> snmp_view_based_acm_mib(X).
+mse_sparse_table(X) -> sparse_table(X).
+mse_me_of(X) -> ms_me_of(X).
+mse_mib_of(X) -> ms_mib_of(X).
+
+msd_simple(X) -> simple(X).
+msd_v1_processing(X) -> v1_processing(X).
+msd_big(X) -> big(X).
+msd_big2(X) -> big2(X).
+msd_loop_mib(X) -> loop_mib(X).
+msd_api(X) -> api(X).
+msd_sa_register(X) -> sa_register(X).
+msd_v1_trap(X) -> v1_trap(X).
+msd_sa_error(X) -> sa_error(X).
+msd_next_across_sa(X) -> next_across_sa(X).
+msd_undo(X) -> undo(X).
+msd_standard_mib(X) -> snmp_standard_mib(X).
+msd_community_mib(X) -> snmp_community_mib(X).
+msd_framework_mib(X) -> snmp_framework_mib(X).
+msd_target_mib(X) -> snmp_target_mib(X).
+msd_notification_mib(X) -> snmp_notification_mib(X).
+msd_view_based_acm_mib(X) -> snmp_view_based_acm_mib(X).
+msd_sparse_table(X) -> sparse_table(X).
+msd_me_of(X) -> ms_me_of(X).
+msd_mib_of(X) -> ms_mib_of(X).
+
+msm_simple(X) -> simple(X).
+msm_v1_processing(X) -> v1_processing(X).
+msm_big(X) -> big(X).
+msm_big2(X) -> big2(X).
+msm_loop_mib(X) -> loop_mib(X).
+msm_api(X) -> api(X).
+msm_sa_register(X) -> sa_register(X).
+msm_v1_trap(X) -> v1_trap(X).
+msm_sa_error(X) -> sa_error(X).
+msm_next_across_sa(X) -> next_across_sa(X).
+msm_undo(X) -> undo(X).
+msm_standard_mib(X) -> snmp_standard_mib(X).
+msm_community_mib(X) -> snmp_community_mib(X).
+msm_framework_mib(X) -> snmp_framework_mib(X).
+msm_target_mib(X) -> snmp_target_mib(X).
+msm_notification_mib(X) -> snmp_notification_mib(X).
+msm_view_based_acm_mib(X) -> snmp_view_based_acm_mib(X).
+msm_sparse_table(X) -> sparse_table(X).
+msm_me_of(X) -> ms_me_of(X).
+msm_mib_of(X) -> ms_mib_of(X).
+
+
+mse_size_check(X) -> p("mse_size_check..."), ms_size_check(X).
+msd_size_check(X) -> p("msd_size_check..."), ms_size_check(X).
+msm_size_check(X) -> p("msm_size_check..."), ms_size_check(X).
+
+msd_varm_mib_start(X) -> p("msd_varm_mib_start..."), varm_mib_start(X).
+msm_varm_mib_start(X) -> p("msm_varm_mib_start..."), varm_mib_start(X).
+
+ms_size_check(suite) -> [];
+ms_size_check(Config) when list(Config) ->
+ p("ms_size_check..."),
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?LOG("mib server size check...", []),
+
+ ?line load_master("Test2"),
+ ?line load_master("TestTrap"),
+ ?line load_master("TestTrapv2"),
+ ?line load_master_std("OTP-SNMPEA-MIB"),
+ ?line load_master_std("SNMP-COMMUNITY-MIB"),
+ ?line load_master_std("SNMP-FRAMEWORK-MIB"),
+ ?line load_master_std("SNMP-MPD-MIB"),
+ ?line load_master_std("SNMP-NOTIFICATION-MIB"),
+ ?line load_master_std("SNMP-TARGET-MIB"),
+ ?line load_master_std("SNMP-USER-BASED-SM-MIB"),
+ ?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"),
+ ?line load_master_std("SNMPv2-MIB"),
+ ?line load_master_std("SNMPv2-TM"),
+
+ ?SLEEP(2000),
+
+ ?line display_memory_usage(),
+
+ ?line unload_master("OTP-SNMPEA-MIB"),
+ ?line unload_master("SNMP-COMMUNITY-MIB"),
+ ?line unload_master("SNMP-FRAMEWORK-MIB"),
+ ?line unload_master("SNMP-MPD-MIB"),
+ ?line unload_master("SNMP-NOTIFICATION-MIB"),
+ ?line unload_master("SNMP-TARGET-MIB"),
+ ?line unload_master("SNMP-USER-BASED-SM-MIB"),
+ ?line unload_master("SNMP-VIEW-BASED-ACM-MIB"),
+ ?line unload_master("SNMPv2-MIB"),
+ ?line unload_master("SNMPv2-TM"),
+
+ ?line unload_master("TestTrapv2"),
+ ?line unload_master("TestTrap"),
+ ?line unload_master("Test2"),
+
+ ok.
+
+
+varm_mib_start(suite) -> [];
+varm_mib_start(Config) when list(Config) ->
+ p("varm_mib_start..."),
+ ?LOG("varm_mib_start -> entry", []),
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ %% Start the agent
+ Opts = ?GCONF(agent_opts, Config),
+ Config1 = start_v1_agent(Config, Opts),
+
+ %% Sleep some in order for the agent to start properly
+ ?DBG("varm_mib_start -> sleep some (before loading mobs)", []),
+ ?SLEEP(5000),
+
+ %% Load all the mibs
+ HardwiredMibs = loaded_mibs(),
+ ?DBG("varm_mib_start -> load all mibs", []),
+ ?line load_master_std("SNMP-COMMUNITY-MIB"),
+ ?line load_master_std("SNMP-FRAMEWORK-MIB"),
+ ?line load_master_std("SNMP-TARGET-MIB"),
+ ?line load_master_std("SNMP-NOTIFICATION-MIB"),
+
+ %% Unload the hardwired mibs
+ ?DBG("varm_mib_start -> sleep some (before unloading hardwired mibs)", []),
+ ?SLEEP(1000),
+ ?DBG("varm_mib_start -> unload (hardwired) mibs", []),
+ ?line unload_mibs(HardwiredMibs), %% unload hardwired
+
+ ?DBG("varm_mib_start -> sleep some (before stopping agent)", []),
+ ?SLEEP(1000),
+
+ %% Stop the agent (without deleting the stored files)
+ ?DBG("varm_mib_start -> stop the agent", []),
+ Config2 = stop_agent(Config1),
+
+ %% Sleep some in order for the agent to stop properly
+ ?DBG("varm_mib_start -> sleep some (before re-starting the agent)", []),
+ ?SLEEP(5000),
+
+ %% Start the agent (again)
+ ?DBG("varm_mib_start -> start the agent", []),
+ Config3 = start_v1_agent(Config2, Opts),
+
+ ?DBG("varm_mib_start -> sleep some (before starting tests)", []),
+ ?SLEEP(5000),
+
+ %% Perform the test(s)
+ ?DBG("varm_mib_start -> perform the tests", []),
+ try_test(snmp_community_mib),
+ try_test(snmp_framework_mib),
+ try_test(snmp_target_mib),
+ try_test(snmp_notification_mib),
+
+ %% Stop the agent (without deleting the stored files)
+ ?DBG("varm_mib_start -> stop the agent", []),
+ stop_agent(Config3),
+ ok.
+
+
+-define(snmpTrapCommunity_instance, [1,3,6,1,6,3,18,1,4,0]).
+-define(vacmViewSpinLock_instance, [1,3,6,1,6,3,16,1,5,1,0]).
+-define(usmStatsNotInTimeWindows_instance, [1,3,6,1,6,3,15,1,1,2,0]).
+
+ms_me_of(suite) -> [];
+ms_me_of(Config) when list(Config) ->
+ p("ms_me_of..."),
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ ?line load_master("Test2"),
+ ?line load_master("TestTrap"),
+ ?line load_master("TestTrapv2"),
+ ?line load_master_std("OTP-SNMPEA-MIB"),
+ ?line load_master_std("SNMP-COMMUNITY-MIB"),
+ ?line load_master_std("SNMP-FRAMEWORK-MIB"),
+ ?line load_master_std("SNMP-MPD-MIB"),
+ ?line load_master_std("SNMP-NOTIFICATION-MIB"),
+ ?line load_master_std("SNMP-TARGET-MIB"),
+ ?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"),
+
+ ?SLEEP(2000),
+
+ ?line display_memory_usage(),
+
+
+ ?DBG("ms_me_of -> find ~w from SNMP-COMMUNITY-MIB",
+ [?snmpTrapCommunity_instance]),
+ ?line ok = me_of(?snmpTrapCommunity_instance),
+
+ ?DBG("ms_me_of -> find ~w from SNMP-VIEW-BASED-ACM-MIB",
+ [?vacmViewSpinLock_instance]),
+ ?line ok = me_of(?vacmViewSpinLock_instance),
+
+ ?DBG("ms_me_of -> find ~w from SNMP-USER-BASED-SM-MIB",
+ [?usmStatsNotInTimeWindows_instance]),
+ ?line {error, _} = me_of(?usmStatsNotInTimeWindows_instance),
+
+
+ ?line unload_master("OTP-SNMPEA-MIB"),
+ ?line unload_master("SNMP-COMMUNITY-MIB"),
+ ?line unload_master("SNMP-FRAMEWORK-MIB"),
+ ?line unload_master("SNMP-MPD-MIB"),
+ ?line unload_master("SNMP-NOTIFICATION-MIB"),
+ ?line unload_master("SNMP-TARGET-MIB"),
+ ?line unload_master("SNMP-VIEW-BASED-ACM-MIB"),
+
+ ?line unload_master("TestTrapv2"),
+ ?line unload_master("TestTrap"),
+ ?line unload_master("Test2"),
+
+ ok.
+
+me_of(Oid) ->
+ case snmpa:me_of(Oid) of
+ {ok, #me{oid = Oid}} ->
+ ok;
+ {ok, #me{oid = OtherOid}} ->
+ case lists:reverse(Oid) of
+ [0|Rest] ->
+ case lists:reverse(Rest) of
+ OtherOid ->
+ ok;
+ AnotherOid ->
+ {error, {invalid_oid, Oid, AnotherOid}}
+ end;
+ _ ->
+ {error, {invalid_oid, Oid, OtherOid}}
+ end;
+ {error, Reason} ->
+ {error, Reason};
+ Else ->
+ {error, Else}
+ end.
+
+
+ms_mib_of(suite) -> [];
+ms_mib_of(Config) when list(Config) ->
+ p("ms_mib_of..."),
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ ?line load_master("Test2"),
+ ?line load_master("TestTrap"),
+ ?line load_master("TestTrapv2"),
+ ?line load_master_std("OTP-SNMPEA-MIB"),
+ ?line load_master_std("SNMP-COMMUNITY-MIB"),
+ ?line load_master_std("SNMP-FRAMEWORK-MIB"),
+ ?line load_master_std("SNMP-MPD-MIB"),
+ ?line load_master_std("SNMP-NOTIFICATION-MIB"),
+ ?line load_master_std("SNMP-TARGET-MIB"),
+ ?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"),
+
+ ?SLEEP(2000),
+
+ ?line display_memory_usage(),
+
+
+ ?DBG("ms_mib_of -> find ~w from SNMP-COMMUNITY-MIB",
+ [?snmpTrapCommunity_instance]),
+ ?line ok = mib_of(?snmpTrapCommunity_instance, 'SNMP-COMMUNITY-MIB'),
+
+ ?DBG("ms_mib_of -> find ~w from SNMP-VIEW-BASED-ACM-MIB",
+ [?vacmViewSpinLock_instance]),
+ ?line ok = mib_of(?vacmViewSpinLock_instance, 'SNMP-VIEW-BASED-ACM-MIB'),
+
+ ?DBG("ms_mib_of -> find ~w from SNMP-USER-BASED-SM-MIB",
+ [?usmStatsNotInTimeWindows_instance]),
+ ?line {error, _} = mib_of(?usmStatsNotInTimeWindows_instance,
+ 'SNMP-USER-BASED-SM-MIB'),
+
+
+ ?line unload_master("OTP-SNMPEA-MIB"),
+ ?line unload_master("SNMP-COMMUNITY-MIB"),
+ ?line unload_master("SNMP-FRAMEWORK-MIB"),
+ ?line unload_master("SNMP-MPD-MIB"),
+ ?line unload_master("SNMP-NOTIFICATION-MIB"),
+ ?line unload_master("SNMP-TARGET-MIB"),
+ ?line unload_master("SNMP-VIEW-BASED-ACM-MIB"),
+
+ ?line unload_master("TestTrapv2"),
+ ?line unload_master("TestTrap"),
+ ?line unload_master("Test2"),
+
+ ok.
+
+mib_of(Oid, ExpectedMibName) ->
+ ?DBG("mib_of -> entry with"
+ "~n Oid: ~p"
+ "~n ExpectedMibName: ~p", [Oid, ExpectedMibName]),
+ %% case snmpa:mib_of(Oid) of
+ MibOf = snmpa:mib_of(Oid),
+ ?DBG("mib_of -> MibOf: ~n~p", [MibOf]),
+ case MibOf of
+ {ok, ExpectedMibName} ->
+ ok;
+ {ok, OtherMibName} ->
+ {error, {invalid_mib, ExpectedMibName, OtherMibName}};
+ {error, Reason} ->
+ {error, Reason};
+ Else ->
+ ?DBG("mib_of -> Else: ~n~p", [Else]),
+ {error, Else}
+ end.
+
+
+app_info(suite) -> [];
+app_info(Config) when list(Config) ->
+ SnmpDir = app_dir(snmp),
+ SslDir = app_dir(ssl),
+ CryptoDir = app_dir(crypto),
+ Attr = snmp:module_info(attributes),
+ AppVsn =
+ case lists:keysearch(app_vsn, 1, Attr) of
+ {value, {app_vsn, V}} ->
+ V;
+ false ->
+ "undefined"
+ end,
+ io:format("Root dir: ~s~n"
+ "SNMP: Application dir: ~s~n"
+ " Application ver: ~s~n"
+ "SSL: Application dir: ~s~n"
+ "CRYPTO: Application dir: ~s~n",
+ [code:root_dir(), SnmpDir, AppVsn, SslDir, CryptoDir]),
+ ok.
+
+app_dir(App) ->
+ case code:lib_dir(App) of
+ D when list(D) ->
+ filename:basename(D);
+ {error, _Reason} ->
+ "undefined"
+ end.
+
+
+test_v1(suite) -> {req, [], {conf, init_v1, v1_cases(), finish_v1}}.
+
+%v1_cases() -> [loop_mib];
+v1_cases() ->
+ [simple,
+ db_notify_client,
+ v1_processing, big, big2, loop_mib,
+ api, subagent, mnesia, multiple_reqs,
+ sa_register, v1_trap, sa_error, next_across_sa, undo, reported_bugs,
+ standard_mibs, sparse_table, cnt_64,
+ opaque,
+ % opaque].
+
+ change_target_addr_config].
+
+init_v1(Config) when list(Config) ->
+ ?line SaNode = ?config(snmp_sa, Config),
+ ?line create_tables(SaNode),
+ ?line AgentDir = ?config(agent_dir, Config),
+ ?line MgrDir = ?config(mgr_dir, Config),
+ ?line Ip = ?config(ip, Config),
+ ?line config([v1], MgrDir, AgentDir, tuple_to_list(Ip), tuple_to_list(Ip)),
+ [{vsn, v1} | start_v1_agent(Config)].
+
+finish_v1(Config) when list(Config) ->
+ delete_tables(),
+ C1 = stop_agent(Config),
+ delete_files(C1),
+ lists:keydelete(vsn, 1, C1).
+
+test_v2(suite) -> {req, [], {conf, init_v2, v2_cases(), finish_v2}}.
+
+%v2_cases() -> [loop_mib_2];
+v2_cases() ->
+ [simple_2, v2_processing, big_2, big2_2, loop_mib_2,
+ api_2, subagent_2, mnesia_2,
+ multiple_reqs_2, sa_register_2, v2_trap, v2_inform, sa_error_2,
+ next_across_sa_2, undo_2, reported_bugs_2, standard_mibs_2,
+ v2_types, implied, sparse_table_2, cnt_64_2, opaque_2, v2_caps].
+
+init_v2(Config) when list(Config) ->
+ SaNode = ?config(snmp_sa, Config),
+ create_tables(SaNode),
+ AgentDir = ?config(agent_dir, Config),
+ MgrDir = ?config(mgr_dir, Config),
+ Ip = ?config(ip, Config),
+ config([v2], MgrDir, AgentDir, tuple_to_list(Ip), tuple_to_list(Ip)),
+ [{vsn, v2} | start_v2_agent(Config)].
+
+finish_v2(Config) when list(Config) ->
+ delete_tables(),
+ C1 = stop_agent(Config),
+ delete_files(C1),
+ lists:keydelete(vsn, 1, C1).
+
+test_v1_v2(suite) -> {req, [], {conf, init_v1_v2, v1_v2_cases(), finish_v1_v2}}.
+
+v1_v2_cases() ->
+ [simple_bi].
+
+init_v1_v2(Config) when list(Config) ->
+ SaNode = ?config(snmp_sa, Config),
+ create_tables(SaNode),
+ AgentDir = ?config(agent_dir, Config),
+ MgrDir = ?config(mgr_dir, Config),
+ Ip = ?config(ip, Config),
+ config([v1,v2], MgrDir, AgentDir, tuple_to_list(Ip), tuple_to_list(Ip)),
+ [{vsn, bilingual} | start_bilingual_agent(Config)].
+
+finish_v1_v2(Config) when list(Config) ->
+ delete_tables(),
+ C1 = stop_agent(Config),
+ delete_files(C1),
+ lists:keydelete(vsn, 1, C1).
+
+test_v3(suite) -> {req, [], {conf, init_v3, v3_cases(), finish_v3}}.
+
+%v3_cases() -> [loop_mib_3];
+v3_cases() ->
+ [simple_3, v3_processing,
+ big_3, big2_3, api_3, subagent_3, mnesia_3, loop_mib_3,
+ multiple_reqs_3, sa_register_3, v3_trap, v3_inform, sa_error_3,
+ next_across_sa_3, undo_3, reported_bugs_3, standard_mibs_3,
+ v3_security,
+ v2_types_3, implied_3, sparse_table_3, cnt_64_3, opaque_3, v2_caps_3].
+
+init_v3(Config) when list(Config) ->
+ %% Make sure crypto works, otherwise start_agent will fail
+ %% and we will be stuck with a bunch of mnesia tables for
+ %% the rest of this suite...
+ ?DBG("start_agent -> start crypto app",[]),
+ case os:type() of
+ vxworks ->
+ no_crypto;
+ _ ->
+ case ?CRYPTO_START() of
+ ok ->
+ case ?CRYPTO_SUPPORT() of
+ {no, Reason} ->
+ ?SKIP({unsupported_encryption, Reason});
+ yes ->
+ ok
+ end;
+ {error, Reason} ->
+ ?SKIP({failed_starting_crypto, Reason})
+ end
+ end,
+ SaNode = ?config(snmp_sa, Config),
+ create_tables(SaNode),
+ AgentDir = ?config(agent_dir, Config),
+ MgrDir = ?config(mgr_dir, Config),
+ Ip = ?config(ip, Config),
+ ?line ok = config([v3], MgrDir, AgentDir,
+ tuple_to_list(Ip), tuple_to_list(Ip)),
+ [{vsn, v3} | start_v3_agent(Config)].
+
+finish_v3(Config) when list(Config) ->
+ delete_tables(),
+ C1 = stop_agent(Config),
+ delete_files(C1),
+ lists:keydelete(vsn, 1, C1).
+
+test_multi_threaded(suite) -> {req, [], {conf, init_mt, mt_cases(), finish_mt}}.
+
+mt_cases() ->
+ [multi_threaded, mt_trap].
+
+init_mt(Config) when list(Config) ->
+ SaNode = ?config(snmp_sa, Config),
+ create_tables(SaNode),
+ AgentDir = ?config(agent_dir, Config),
+ MgrDir = ?config(mgr_dir, Config),
+ Ip = ?config(ip, Config),
+ ?line ok = config([v2], MgrDir, AgentDir, tuple_to_list(Ip), tuple_to_list(Ip)),
+ [{vsn, v2} | start_multi_threaded_agent(Config)].
+
+finish_mt(Config) when list(Config) ->
+ delete_tables(),
+ C1 = stop_agent(Config),
+ delete_files(C1),
+ lists:keydelete(vsn, 1, C1).
+
+%% This one *must* be run first in each case.
+init_case(Config) when list(Config) ->
+ ?DBG("init_case -> entry with"
+ "~n Config: ~p", [Config]),
+ SaNode = ?config(snmp_sa, Config),
+ MgrNode = ?config(snmp_mgr, Config),
+ MasterNode = node(),
+
+ SaHost = ?HOSTNAME(SaNode),
+ MgrHost = ?HOSTNAME(MgrNode),
+ MasterHost = ?HOSTNAME(MasterNode),
+ {ok, MasterIP} = snmp_misc:ip(MasterHost),
+ {ok, MIP} = snmp_misc:ip(MgrHost),
+ {ok, SIP} = snmp_misc:ip(SaHost),
+
+
+ put(mgr_node, MgrNode),
+ put(sa_node, SaNode),
+ put(master_node, MasterNode),
+ put(sa_host, SaHost),
+ put(mgr_host, MgrHost),
+ put(master_host, MasterHost),
+ put(mip, tuple_to_list(MIP)),
+ put(masterip , tuple_to_list(MasterIP)),
+ put(sip, tuple_to_list(SIP)),
+
+ MibDir = ?config(mib_dir, Config),
+ put(mib_dir, MibDir),
+ StdM = filename:join(code:priv_dir(snmp), "mibs") ++ "/",
+ put(std_mib_dir, StdM),
+
+ MgrDir = ?config(mgr_dir, Config),
+ put(mgr_dir, MgrDir),
+
+ put(vsn, ?config(vsn, Config)),
+ ?DBG("init_case -> exit with"
+ "~n MasterNode: ~p"
+ "~n SaNode: ~p"
+ "~n MgrNode: ~p"
+ "~n MibDir: ~p", [MasterNode, SaNode, MgrNode, MibDir]),
+ {SaNode, MgrNode, MibDir}.
+
+load_master(Mib) ->
+ ?DBG("load_master -> entry with"
+ "~n Mib: ~p", [Mib]),
+ snmpa:unload_mibs(snmp_master_agent, [Mib]), % Unload for safety
+ ok = snmpa:load_mibs(snmp_master_agent, [get(mib_dir) ++ Mib]).
+
+load_master_std(Mib) ->
+ ?DBG("load_master_std -> entry with"
+ "~n Mib: ~p", [Mib]),
+ snmpa:unload_mibs(snmp_master_agent, [Mib]), % Unload for safety
+ ok = snmpa:load_mibs(snmp_master_agent, [get(std_mib_dir) ++ Mib]).
+
+unload_master(Mib) ->
+ ?DBG("unload_master -> entry with"
+ "~n Mib: ~p", [Mib]),
+ ok = snmpa:unload_mibs(snmp_master_agent, [Mib]).
+
+loaded_mibs() ->
+ ?DBG("loaded_mibs -> entry",[]),
+ Info = snmpa:info(snmp_master_agent),
+ {value, {loaded_mibs, Mibs}} = lists:keysearch(loaded_mibs, 1, Info),
+ [atom_to_list(Mib) || {Mib,_,_} <- Mibs].
+
+unload_mibs(Mibs) ->
+ ?DBG("unload_mibs -> entry with"
+ "~n Mibs: ~p", [Mibs]),
+ ok = snmpa:unload_mibs(snmp_master_agent, Mibs).
+
+start_subagent(SaNode, RegTree, Mib) ->
+ ?DBG("start_subagent -> entry with"
+ "~n SaNode: ~p"
+ "~n RegTree: ~p"
+ "~n Mib: ~p", [SaNode, RegTree, Mib]),
+ MA = whereis(snmp_master_agent),
+ ?DBG("start_subagent -> MA: ~p", [MA]),
+ MibDir = get(mib_dir),
+ Mib1 = join(MibDir,Mib),
+ %% BMK BMK
+% case rpc:call(SaNode,snmp_supervisor,start_subagent,[MA,RegTree,[Mib1]]) of
+ case rpc:call(SaNode, snmpa_supervisor,
+ start_sub_agent, [MA, RegTree, [Mib1]]) of
+ {ok, SA} ->
+ ?DBG("start_subagent -> SA: ~p", [SA]),
+ {ok, SA};
+ Error ->
+ ?FAIL({subagent_start_failed, SaNode, Error, [MA, RegTree, Mib1]})
+ end.
+
+stop_subagent(SA) ->
+ ?DBG("stop_subagent -> entry with"
+ "~n SA: ~p", [SA]),
+ %% BNK BMK
+ %% rpc:call(node(SA), snmp_supervisor, stop_subagent, [SA]).
+ rpc:call(node(SA), snmpa_supervisor, stop_sub_agent, [SA]).
+
+%%-----------------------------------------------------------------
+%% This function takes care of the old OTP-SNMPEA-MIB.
+%% Unfortunately, the testcases were written to use the data in the
+%% internal tables, and these table are now obsolete and not used
+%% by the agent. Therefore, we emulate them by using
+%% OLD-SNMPEA-MIB, which uses the default impl. of all tables.
+%%
+%% These two rows must exist in intCommunityTable
+%% {[147,214,36,45], "public", 2, readWrite}.
+%% {[147,214,36,45], "standard trap", 2, read}.
+%% (But with the manager's IP address)
+%%
+%%-----------------------------------------------------------------
+init_old() ->
+ snmpa_local_db:table_create_row(intCommunityTable,
+ get(mip) ++ [6 | "public"],
+ {get(mip), "public", 2, 2}),
+ snmpa_local_db:table_create_row(intCommunityTable,
+ get(mip) ++ [13 | "standard trap"],
+ {get(mip), "standard trap", 2, 1}),
+ snmpa_local_db:variable_set(intAgentIpAddress, [127,0,0,1]).
+
+
+
+simple(suite) -> [];
+simple(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ try_test(simple_standard_test).
+
+simple_2(X) -> simple(X).
+
+simple_bi(suite) -> [];
+simple_bi(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ put(vsn, v1), % First, try v1 manager
+ try_test(simple_standard_test),
+
+ put(vsn, v2), % Then, try v2 manager
+ try_test(simple_standard_test).
+
+simple_3(X) ->
+ simple(X).
+
+big(suite) -> [];
+big(Config) when list(Config) ->
+ ?DBG("big -> entry", []),
+ {SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ p("Starting subagent..."),
+ ?line pong = net_adm:ping(SaNode),
+
+ ?line {ok, SA} = start_subagent(SaNode, ?klas1, "Klas1"),
+ ?DBG("big -> SA: ~p", [SA]),
+ ?line load_master("OLD-SNMPEA-MIB"),
+ ?line init_old(),
+ try_test(big_test),
+ ?line stop_subagent(SA),
+ ?line unload_master("OLD-SNMPEA-MIB").
+
+big_2(X) -> big(X).
+
+big_3(X) -> big(X).
+
+
+big2(suite) -> [];
+big2(Config) when list(Config) ->
+ %% This is exactly the same tests as 'big', but with the
+ %% v2 equivalent of the mibs.
+ {SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ p("Starting subagent..."),
+ ?line pong = net_adm:ping(SaNode),
+
+ ?line {ok, SA} = start_subagent(SaNode, ?klas1, "Klas1-v2"),
+ ?line load_master("OLD-SNMPEA-MIB-v2"),
+ ?line init_old(),
+ try_test(big_test),
+ ?line stop_subagent(SA),
+ ?line unload_master("OLD-SNMPEA-MIB-v2").
+
+big2_2(X) -> big2(X).
+
+big2_3(X) -> big2(X).
+
+
+multi_threaded(suite) -> [];
+multi_threaded(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ ?line load_master("Test1"),
+ try_test(multi_threaded_test),
+ ?line unload_master("Test1").
+
+mt_trap(suite) -> [];
+mt_trap(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ MA = whereis(snmp_master_agent),
+
+ ?line load_master("Test1"),
+ ?line load_master("TestTrapv2"),
+ try_test(mt_trap_test, [MA]),
+ ?line unload_master("TestTrapv2"),
+ ?line unload_master("Test1").
+
+v2_types(suite) -> [];
+v2_types(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ ?line load_master("Test1"),
+ try_test(types_v2_test),
+ ?line unload_master("Test1").
+
+v2_types_3(X) -> v2_types(X).
+
+
+implied(suite) -> [];
+implied(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ MA = whereis(snmp_master_agent),
+
+ ?line load_master("Test1"),
+ try_test(implied_test,[MA]),
+ ?line unload_master("Test1").
+
+implied_3(X) -> implied(X).
+
+
+sparse_table(suite) -> [];
+sparse_table(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ ?line load_master("Test1"),
+ try_test(sparse_table_test),
+ ?line unload_master("Test1").
+
+sparse_table_2(X) -> sparse_table(X).
+
+sparse_table_3(X) -> sparse_table(X).
+
+cnt_64(suite) -> [];
+cnt_64(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ MA = whereis(snmp_master_agent),
+
+ ?line load_master("Test1"),
+ try_test(cnt_64_test, [MA]),
+ ?line unload_master("Test1").
+
+cnt_64_2(X) -> cnt_64(X).
+
+cnt_64_3(X) -> cnt_64(X).
+
+opaque(suite) -> [];
+opaque(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ ?line load_master("Test1"),
+ try_test(opaque_test),
+ ?line unload_master("Test1").
+
+opaque_2(X) -> opaque(X).
+
+opaque_3(X) -> opaque(X).
+
+
+change_target_addr_config(suite) -> [];
+change_target_addr_config(Config) when list(Config) ->
+ p("Testing changing target address config..."),
+ ?LOG("change_target_addr_config -> entry",[]),
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ put(sname,snmp_suite),
+ put(verbosity,trace),
+
+ MA = whereis(snmp_master_agent),
+
+ ?LOG("change_target_addr_config -> load TestTrap",[]),
+ ?line load_master("TestTrap"),
+
+ ?LOG("change_target_addr_config -> set trace verbosity for local_db",[]),
+ ?line snmpa:verbosity(local_db,trace),
+
+ %% First send some traps that will arive att the original manager
+ ?LOG("change_target_addr_config -> send trap",[]),
+ try_test(ma_trap1, [MA]),
+
+ ?LOG("change_target_addr_config -> set silence verbosity for local_db",[]),
+ ?line snmpa:verbosity(local_db,silence),
+
+ %% Start new dummy listener
+ ?LOG("change_target_addr_config -> start dummy manager",[]),
+ ?line {ok,Pid,NewPort} = dummy_manager_start(MA),
+
+ %% Reconfigure
+ ?LOG("change_target_addr_config -> reconfigure",[]),
+ AgentDir = ?config(agent_dir, Config),
+ ?line rewrite_target_addr_conf(AgentDir, NewPort),
+ ?line snmp_target_mib:reconfigure(AgentDir),
+
+ %% Send the trap again
+ ?LOG("change_target_addr_config -> send trap again",[]),
+ catch dummy_manager_send_trap2(Pid),
+
+ ?LOG("change_target_addr_config -> await trap ack",[]),
+ catch dummy_manager_await_trap2_ack(),
+
+ ?LOG("change_target_addr_config -> stop dummy manager",[]),
+ ?line ok = dummy_manager_stop(Pid),
+
+ ?LOG("change_target_addr_config -> reset target address config",[]),
+ ?line reset_target_addr_conf(AgentDir),
+
+ ?LOG("change_target_addr_config -> unload TestTrap",[]),
+ ?line unload_master("TestTrap").
+
+
+dummy_manager_start(MA) ->
+ ?DBG("dummy_manager_start -> entry",[]),
+ Pid = spawn(get(mgr_node), ?MODULE,dummy_manager_init,[self(),MA]),
+ ?DBG("dummy_manager_start -> Pid: ~p",[Pid]),
+ await_dummy_manager_started(Pid).
+
+await_dummy_manager_started(Pid) ->
+ receive
+ {dummy_manager_started,Pid,Port} ->
+ ?DBG("dummy_manager_start -> acknowledge received with"
+ "~n Port: ~p",[Port]),
+ {ok,Pid,Port};
+ {'EXIT', Pid, Reason} ->
+ {error, Pid, Reason};
+ O ->
+ ?LOG("dummy_manager_start -> received unknown message:"
+ "~n ~p",[O]),
+ await_dummy_manager_started(Pid)
+ end.
+
+dummy_manager_stop(Pid) ->
+ ?DBG("dummy_manager_stop -> entry with Pid: ~p",[Pid]),
+ Pid ! stop,
+ receive
+ {dummy_manager_stopping, Pid} ->
+ ?DBG("dummy_manager_stop -> acknowledge received",[]),
+ ok
+ after 10000 ->
+ ?ERR("dummy_manager_stop -> timeout",[]),
+ timeout
+ end.
+
+dummy_manager_send_trap2(Pid) ->
+ ?DBG("dummy_manager_send_trap2 -> entry",[]),
+ Pid ! {send_trap,testTrap2}.
+
+dummy_manager_await_trap2_ack() ->
+ ?DBG("dummy_manager_await_trap2 -> entry",[]),
+ receive
+ {received_trap,Trap} ->
+ ?LOG("dummy_manager_await_trap2 -> received trap: ~p",[Trap]),
+ %% Note:
+ %% Without this sleep the v2_inform_i testcase failes! There
+ %% is no relation between these two test cases as far as I
+ %% able to figure out...
+ sleep(60000),
+ ok;
+ O ->
+ ?ERR("dummy_manager_await_trap2 -> unexpected message: ~p",[O]),
+ ok
+ after 10000 ->
+ ?ERR("dummy_manager_await_trap2 -> timeout",[]),
+ timeout
+ end.
+
+dummy_manager_init(Parent,MA) ->
+ ?DBG("dummy_manager_init -> entry with"
+ "~n Parent: ~p"
+ "~n MA: ~p",[Parent,MA]),
+ {ok,S} = gen_udp:open(0,[{recbuf,65535}]),
+ ?DBG("dummy_manager_init -> S: ~p",[S]),
+ {ok,Port} = inet:port(S),
+ ?DBG("dummy_manager_init -> Port: ~p",[Port]),
+ Parent ! {dummy_manager_started,self(),Port},
+ dummy_manager_loop(Parent,S,MA).
+
+dummy_manager_loop(P,S,MA) ->
+ ?LOG("dummy_manager_loop -> ready for receive",[]),
+ receive
+ {send_trap,Trap} ->
+ ?LOG("dummy_manager_loop -> received trap send request"
+ "~n Trap: ~p",[Trap]),
+ snmpa:send_trap(MA, Trap, "standard trap"),
+ dummy_manager_loop(P,S,MA);
+ {udp, _UdpId, Ip, UdpPort, Bytes} ->
+ ?LOG("dummy_manager_loop -> received upd message"
+ "~n from: ~p:~p"
+ "~n size: ~p",
+ [Ip, UdpPort, dummy_manager_message_sz(Bytes)]),
+ R = dummy_manager_handle_message(Bytes),
+ ?DBG("dummy_manager_loop -> R: ~p",[R]),
+ P ! R,
+ dummy_manager_loop(P,S,MA);
+ stop ->
+ ?DBG("dummy_manager_loop -> received stop request",[]),
+ P ! {dummy_manager_stopping, self()},
+ gen_udp:close(S),
+ exit(normal);
+ O ->
+ ?LOG("dummy_manager_loop -> received unknown message:"
+ "~n ~p",[O]),
+ dummy_manager_loop(P,S,MA)
+ end.
+
+dummy_manager_message_sz(B) when binary(B) ->
+ size(B);
+dummy_manager_message_sz(L) when list(L) ->
+ length(L);
+dummy_manager_message_sz(_) ->
+ undefined.
+
+dummy_manager_handle_message(Bytes) ->
+ case (catch snmp_pdus:dec_message(Bytes)) of
+ {'EXIT',Reason} ->
+ ?ERR("dummy_manager_handle_message -> "
+ "failed decoding message only:~n ~p",[Reason]),
+ {error,Reason};
+ M ->
+ ?DBG("dummy_manager_handle_message -> decoded message:"
+ "~n ~p",[M]),
+ {received_trap,M}
+ end.
+
+
+api(suite) -> [];
+api(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ ?line load_master("OLD-SNMPEA-MIB"),
+ ?line init_old(),
+ try_test(api_test, [node()]),
+ ?line unload_master("OLD-SNMPEA-MIB").
+
+api_2(X) -> api(X).
+
+api_3(X) -> api(X).
+
+
+subagent(suite) -> [];
+subagent(Config) when list(Config) ->
+ {SaNode, _MgrNode, MibDir} = init_case(Config),
+
+ ?line {ok, SA} = start_subagent(SaNode, ?klas1, "Klas1"),
+ try_test(load_test_sa),
+
+ p("Testing unregister subagent..."),
+ MA = whereis(snmp_master_agent),
+ rpc:call(SaNode, snmp, unregister_subagent, [MA, SA]),
+ try_test(unreg_test),
+
+ p("Loading previous subagent mib in master and testing..."),
+ ?line ok = snmpa:load_mibs(MA, [MibDir ++ "Klas1"]),
+ try_test(load_test),
+
+ p("Unloading previous subagent mib in master and testing..."),
+ ?line ok = snmpa:unload_mibs(MA, [MibDir ++ "Klas1"]),
+ try_test(unreg_test),
+ p("Testing register subagent..."),
+ rpc:call(SaNode, snmp, register_subagent,
+ [MA, ?klas1, SA]),
+ try_test(load_test_sa),
+
+ ?line stop_subagent(SA),
+ try_test(unreg_test).
+
+subagent_2(X) -> subagent(X).
+
+subagent_3(X) -> subagent(X).
+
+
+mnesia(suite) -> [];
+mnesia(Config) when list(Config) ->
+ {SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ p("Starting subagent with mnesia impl..."),
+ {ok, SA} = start_subagent(SaNode, ?klas2, "Klas2"),
+ ?line load_master("OLD-SNMPEA-MIB"),
+ ?line init_old(),
+
+ try_test(big_test_2),
+
+ p("Testing unregister subagent..."),
+ MA = whereis(snmp_master_agent),
+ rpc:call(SaNode, snmp, unregister_subagent, [MA, SA]),
+ try_test(unreg_test),
+ ?line unload_master("OLD-SNMPEA-MIB"),
+ ?line stop_subagent(SA).
+
+mnesia_2(X) -> mnesia(X).
+
+mnesia_3(X) -> mnesia(X).
+
+
+multiple_reqs(suite) ->
+ {req, [], {conf, init_mul, mul_cases(), finish_mul}}.
+
+mul_cases() ->
+ [mul_get, mul_get_err, mul_next, mul_next_err, mul_set_err].
+
+multiple_reqs_2(suite) ->
+ {req, [], {conf, init_mul, mul_cases_2(), finish_mul}}.
+
+multiple_reqs_3(_X) ->
+ {req, [], {conf, init_mul, mul_cases_3(), finish_mul}}.
+
+
+mul_cases_2() ->
+ [mul_get_2, mul_get_err_2, mul_next_2, mul_next_err_2, mul_set_err_2].
+
+
+mul_cases_3() ->
+ [mul_get_3, mul_get_err_3, mul_next_3, mul_next_err_3, mul_set_err_3].
+
+
+init_mul(Config) when list(Config) ->
+ {SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ ?line {ok, SA} = start_subagent(SaNode, ?klas1, "Klas1"),
+ ?line load_master("OLD-SNMPEA-MIB"),
+ ?line init_old(),
+ [{mul_sub, SA} | Config].
+
+finish_mul(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ SA = ?config(mul_sub, Config),
+
+ ?line unload_master("OLD-SNMPEA-MIB"),
+ ?line stop_subagent(SA),
+ lists:keydelete(mul_sub, 1, Config).
+
+mul_get(suite) -> [];
+mul_get(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ p("Testing multiple get..."),
+ try_test(do_mul_get).
+
+mul_get_2(X) -> mul_get(X).
+
+mul_get_3(X) -> mul_get(X).
+
+
+mul_get_err(suite) -> [];
+mul_get_err(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ p("Testing multiple get with error..."),
+ try_test(do_mul_get_err).
+
+mul_get_err_2(X) -> mul_get_err(X).
+
+mul_get_err_3(X) -> mul_get_err(X).
+
+
+mul_next(suite) -> [];
+mul_next(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ p("Testing multiple next..."),
+ try_test(do_mul_next).
+
+mul_next_2(X) -> mul_next(X).
+
+mul_next_3(X) -> mul_next(X).
+
+
+mul_next_err(suite) -> [];
+mul_next_err(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ p("Testing multiple next..."),
+ try_test(do_mul_next_err).
+
+mul_next_err_2(X) -> mul_next_err(X).
+
+mul_next_err_3(X) -> mul_next_err(X).
+
+
+mul_set(suite) -> [];
+mul_set(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ p("Testing multiple set..."),
+ try_test(do_mul_set).
+
+mul_set_2(X) -> mul_set(X).
+
+mul_set_3(X) -> mul_set(X).
+
+
+mul_set_err(suite) -> [];
+mul_set_err(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ p("Testing multiple set with error..."),
+ try_test(do_mul_set_err).
+
+mul_set_err_2(X) -> mul_set_err(X).
+
+mul_set_err_3(X) -> mul_set_err(X).
+
+
+sa_register(suite) -> [];
+sa_register(Config) when list(Config) ->
+ ?DBG("sa_register -> entry", []),
+ {SaNode, _MgrNode, MibDir} = init_case(Config),
+
+ ?DBG("sa_register -> start subagent", []),
+ ?line {ok, SA} = start_subagent(SaNode, ?klas1, "Klas1"),
+
+ ?DBG("sa_register -> unregister subagent", []),
+ p("Testing unregister subagent (2)..."),
+ MA = whereis(snmp_master_agent),
+ rpc:call(SaNode, snmp, unregister_subagent, [MA, ?klas1]),
+ try_test(unreg_test),
+
+ p("Loading SA-MIB..."),
+ ?DBG("sa_register -> unload mibs", []),
+ snmpa:unload_mibs(SA, [MibDir ++ "Klas1"]),
+ ?DBG("sa_register -> unload mibs", []),
+ snmpa:load_mibs(SA, [MibDir ++ "SA-MIB"]),
+ ?DBG("sa_register -> register subagent", []),
+ rpc:call(SaNode, snmp, register_subagent, [MA,?sa,SA]),
+ try_test(sa_mib),
+
+ ?DBG("sa_register -> stop subagent", []),
+ ?line stop_subagent(SA).
+
+sa_register_2(X) -> sa_register(X).
+
+sa_register_3(X) -> sa_register(X).
+
+
+v1_trap(suite) -> [];
+v1_trap(Config) when list(Config) ->
+ {SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ ?line {ok, SA} = start_subagent(SaNode, ?sa, "SA-MIB"),
+
+ p("Testing trap sending from master agent..."),
+ MA = whereis(snmp_master_agent),
+
+ ?line load_master("TestTrap"),
+ ?line load_master("TestTrapv2"),
+
+ try_test(ma_trap1, [MA]),
+ try_test(ma_trap2, [MA]),
+ try_test(ma_v2_2_v1_trap, [MA]),
+ try_test(ma_v2_2_v1_trap2, [MA]),
+
+ p("Testing trap sending from subagent..."),
+ try_test(sa_trap1, [SA]),
+ try_test(sa_trap2, [SA]),
+ try_test(sa_trap3, [SA]),
+
+ ?line unload_master("TestTrap"),
+ ?line unload_master("TestTrapv2"),
+
+ ?line stop_subagent(SA).
+
+v2_trap(suite) -> [];
+v2_trap(Config) when list(Config) ->
+ {SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ ?line {ok, SA} = start_subagent(SaNode, ?sa, "SA-MIB"),
+
+ p("Testing trap sending from master agent..."),
+ MA = whereis(snmp_master_agent),
+
+ ?line load_master("TestTrap"),
+ ?line load_master("TestTrapv2"),
+
+
+ try_test(ma_v2_trap1, [MA]),
+ try_test(ma_v2_trap2, [MA]),
+ try_test(ma_v1_2_v2_trap, [MA]),
+ try_test(ma_v1_2_v2_trap2, [MA]),
+
+ try_test(sa_mib),
+ p("Testing trap sending from subagent..."),
+ try_test(sa_v1_2_v2_trap1, [SA]),
+ try_test(sa_v1_2_v2_trap2, [SA]),
+ try_test(sa_v1_2_v2_trap3, [SA]),
+
+ ?line unload_master("TestTrap"),
+ ?line unload_master("TestTrapv2"),
+
+ ?line stop_subagent(SA).
+
+v3_trap(X) ->
+ v2_trap(X).
+
+v2_inform(suite) ->
+ {req, [], {conf, init_v2_inform, [v2_inform_i], finish_v2_inform}}.
+
+v3_inform(_X) ->
+ %% v2_inform(X).
+ {req, [], {conf, init_v3_inform, [v3_inform_i], finish_v3_inform}}.
+
+init_v2_inform(Config) when list(Config) ->
+ _Dir = ?config(agent_dir, Config),
+% snmp_internal_mib:configure(Dir),
+ Config.
+
+init_v3_inform(X) ->
+ init_v2_inform(X).
+
+finish_v2_inform(Config) when list(Config) ->
+ _Dir = ?config(agent_dir, Config),
+% snmp_internal_mib:configure(Dir),
+ Config.
+
+finish_v3_inform(X) ->
+ finish_v2_inform(X).
+
+
+
+v2_inform_i(suite) -> [];
+v2_inform_i(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ p("Testing inform sending from master agent... NOTE! This test\ntakes a "
+ "few minutes (5) to complete."),
+ MA = whereis(snmp_master_agent),
+
+ ?line load_master("TestTrap"),
+ ?line load_master("TestTrapv2"),
+
+ try_test(ma_v2_inform1, [MA]),
+
+ ?line unload_master("TestTrap"),
+ ?line unload_master("TestTrapv2").
+
+v3_inform_i(X) -> v2_inform_i(X).
+
+
+sa_error(suite) -> [];
+sa_error(Config) when list(Config) ->
+ {SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ ?line load_master("OLD-SNMPEA-MIB"),
+ ?line init_old(),
+ ?line {ok, SA} = start_subagent(SaNode, ?sa, "SA-MIB"),
+
+ p("Testing sa bad value (is_set_ok)..."),
+ try_test(sa_errs_bad_value),
+
+ p("Testing sa gen err (set)..."),
+ try_test(sa_errs_gen_err),
+
+ p("Testing too big..."),
+ try_test(sa_too_big),
+
+ ?line unload_master("OLD-SNMPEA-MIB"),
+ stop_subagent(SA).
+
+sa_error_2(X) -> sa_error(X).
+
+sa_error_3(X) -> sa_error(X).
+
+
+next_across_sa(suite) -> [];
+next_across_sa(Config) when list(Config) ->
+ {SaNode, _MgrNode, MibDir} = init_case(Config),
+ MA = whereis(snmp_master_agent),
+
+ ?line {ok, SA} = start_subagent(SaNode, ?sa, "SA-MIB"),
+
+ p("Loading another subagent mib..."),
+ ?line ok = snmpa:load_mibs(SA, [MibDir ++ "Klas1"]),
+
+ rpc:call(SaNode, snmp, register_subagent, [MA, ?klas1, SA]),
+ try_test(load_test_sa),
+
+ p("Testing next across subagent (endOfMibView from SA)..."),
+ try_test(next_across_sa),
+
+ p("Unloading mib"),
+ snmpa:unload_mibs(SA, [MibDir ++ "Klas1"]),
+ rpc:call(SaNode, snmp, unregister_subagent, [MA, ?klas1]),
+ try_test(unreg_test),
+
+ p("Starting another subagent"),
+ ?line {ok, SA2} = start_subagent(SaNode, ?klas1, "Klas1"),
+ p("Testing next across subagent (wrong prefix from SA)..."),
+ try_test(next_across_sa),
+
+ stop_subagent(SA),
+ stop_subagent(SA2).
+
+next_across_sa_2(X) -> next_across_sa(X).
+
+next_across_sa_3(X) -> next_across_sa(X).
+
+
+undo(suite) -> [];
+undo(Config) when list(Config) ->
+ {SaNode, _MgrNode, MibDir} = init_case(Config),
+ MA = whereis(snmp_master_agent),
+
+ ?line {ok, SA} = start_subagent(SaNode, ?sa, "SA-MIB"),
+
+ p("Testing undo phase at master agent..."),
+ ?line ok = snmpa:load_mibs(MA, [MibDir ++ "Klas3"]),
+ ?line ok = snmpa:load_mibs(MA, [MibDir ++ "Klas4"]),
+ try_test(undo_test),
+ try_test(api_test2),
+ ?line ok = snmpa:unload_mibs(MA, [MibDir ++ "Klas3"]),
+
+ p("Testing bad return values from instrum. funcs..."),
+ try_test(bad_return),
+
+ ?line ok = snmpa:unload_mibs(MA, [MibDir ++ "Klas4"]),
+
+ p("Testing undo phase at subagent..."),
+ ?line ok = snmpa:load_mibs(SA, [MibDir ++ "Klas3"]),
+ ?line ok = snmpa:load_mibs(SA, [MibDir ++ "Klas4"]),
+ ?line ok = snmpa:register_subagent(MA, ?klas3, SA),
+ ?line ok = snmpa:register_subagent(MA, ?klas4, SA),
+ try_test(undo_test),
+ try_test(api_test3),
+
+ p("Testing undo phase across master/subagents..."),
+ try_test(undo_test),
+ try_test(api_test3),
+ stop_subagent(SA).
+
+undo_2(X) -> undo(X).
+
+undo_3(X) -> undo(X).
+
+%% Req. Test2
+v1_processing(suite) -> [];
+v1_processing(Config) when list(Config) ->
+ ?DBG("v1_processing -> entry", []),
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ ?line load_master("Test2"),
+ try_test(v1_proc),
+ ?line unload_master("Test2").
+
+%% Req. Test2
+v2_processing(suite) -> [];
+v2_processing(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ ?line load_master("Test2"),
+ try_test(v2_proc),
+ ?line unload_master("Test2").
+
+%% Req. Test2
+v3_processing(suite) -> [];
+v3_processing(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ ?line load_master("Test2"),
+ try_test(v2_proc), % same as v2!
+ ?line unload_master("Test2").
+
+
+%% We'll try get/set/trap and inform for all the auth & priv protocols.
+%% For informs, the mgr is auth-engine. The agent has to sync. This is
+%% accomplished by the first inform sent. That one will generate a
+%% report, which makes it in sync. The notification-generating
+%% application times out, and send again. This time it'll work.
+v3_security(suite) -> [v3_crypto_basic, v3_md5_auth, v3_sha_auth, v3_des_priv].
+
+v3_crypto_basic(suite) -> [];
+v3_crypto_basic(_Config) ->
+ EID = [0,0,0,0,0,0,0,0,0,0,0,2],
+ %% From rfc2274 appendix A.3.1
+ ?line KMd5_1 = snmp:passwd2localized_key(md5, "maplesyrup", EID),
+ ?line [16#52,16#6f,16#5e,16#ed,16#9f,16#cc,16#e2,16#6f,
+ 16#89,16#64,16#c2,16#93,16#07,16#87,16#d8,16#2b] =
+ KMd5_1,
+ %% From rfc2274 appendix A.3.2
+ ?line KSHA_1 = snmp:passwd2localized_key(sha, "maplesyrup", EID),
+ ?line [16#66,16#95,16#fe,16#bc,16#92,16#88,16#e3,16#62,16#82,16#23,
+ 16#5f,16#c7,16#15,16#1f,16#12,16#84,16#97,16#b3,16#8f,16#3f] =
+ KSHA_1,
+ %% From rfc2274, appendix A.5.1
+ ?line KMd5_2 = snmp:passwd2localized_key(md5, "newsyrup", EID),
+ ?line [16#00,16#00,16#00,16#00,16#00,16#00,16#00,16#00,
+ 16#00,16#00,16#00,16#00,16#00,16#00,16#00,16#00,
+ 16#88,16#05,16#61,16#51,16#41,16#67,16#6c,16#c9,
+ 16#19,16#61,16#74,16#e7,16#42,16#a3,16#25,16#51] =
+ snmp_user_based_sm_mib:mk_key_change(md5, KMd5_1, KMd5_2, 16,
+ [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]),
+ %% From rfc2274, appendix A.5.2
+ ?line KSHA_2 = snmp:passwd2localized_key(sha, "newsyrup", EID),
+ ?line [16#00,16#00,16#00,16#00,16#00,16#00,16#00,16#00,
+ 16#00,16#00,16#00,16#00,16#00,16#00,16#00,16#00,
+ 16#00,16#00,16#00,16#00,16#9c,16#10,16#17,16#f4,
+ 16#fd,16#48,16#3d,16#2d,16#e8,16#d5,16#fa,16#db,
+ 16#f8,16#43,16#92,16#cb,16#06,16#45,16#70,16#51] =
+ snmp_user_based_sm_mib:mk_key_change(sha, KSHA_1, KSHA_2, 20,
+ [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]),
+ KSHA_1t = lists:sublist(KSHA_1, 16),
+ KSHA_2t = lists:sublist(KSHA_2, 16),
+ ?line [16#00,16#00,16#00,16#00,16#00,16#00,16#00,16#00,
+ 16#00,16#00,16#00,16#00,16#00,16#00,16#00,16#00,
+ 16#7e,16#f8,16#d8,16#a4,16#c9,16#cd,16#b2,16#6b,
+ 16#47,16#59,16#1c,16#d8,16#52,16#ff,16#88,16#b5] =
+ snmp_user_based_sm_mib:mk_key_change(sha, KSHA_1t, KSHA_2t, 16,
+ [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]),
+
+ %% Try with correct random
+ ?line Kc1 = snmp_user_based_sm_mib:mk_key_change(md5, KMd5_1, KMd5_2),
+ ?line KMd5_2 = snmp_user_based_sm_mib:extract_new_key(md5, KMd5_1, Kc1),
+ ?line Kc2 = snmp_user_based_sm_mib:mk_key_change(sha, KSHA_1, KSHA_2),
+ ?line KSHA_2 = snmp_user_based_sm_mib:extract_new_key(sha, KSHA_1, Kc2),
+ ok.
+
+
+
+v3_md5_auth(suite) -> [];
+v3_md5_auth(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ p("Testing MD5 authentication...takes a few seconds..."),
+
+ AgentDir = ?config(agent_dir, Config),
+ ?line rewrite_target_params_conf(AgentDir, "authMD5", authNoPriv),
+ ?line snmp_target_mib:reconfigure(AgentDir),
+
+ MA = whereis(snmp_master_agent),
+
+ ?line load_master("Test2"),
+ ?line load_master("TestTrap"),
+ ?line load_master("TestTrapv2"),
+
+ try_test(v3_sync, [[{v2_proc, []},
+ {ma_v2_trap1, [MA]},
+ {v3_inform_sync, [MA]}]],
+ [{sec_level, authNoPriv}, {user, "authMD5"}]),
+
+ ?line unload_master("TestTrapv2"),
+ ?line unload_master("TestTrap"),
+ ?line unload_master("Test2"),
+ ?line reset_target_params_conf(AgentDir).
+
+v3_sha_auth(suite) -> [];
+v3_sha_auth(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ p("Testing SHA authentication...takes a few seconds..."),
+
+ AgentDir = ?config(agent_dir, Config),
+ ?line rewrite_target_params_conf(AgentDir, "authSHA", authNoPriv),
+ ?line snmp_target_mib:reconfigure(AgentDir),
+
+ MA = whereis(snmp_master_agent),
+
+ ?line load_master("Test2"),
+ ?line load_master("TestTrap"),
+ ?line load_master("TestTrapv2"),
+
+ try_test(v3_sync, [[{v2_proc, []},
+ {ma_v2_trap1, [MA]},
+ {v3_inform_sync, [MA]}]],
+ [{sec_level, authNoPriv}, {user, "authSHA"}]),
+
+ ?line unload_master("TestTrapv2"),
+ ?line unload_master("TestTrap"),
+ ?line unload_master("Test2"),
+ ?line reset_target_params_conf(AgentDir).
+
+v3_des_priv(suite) -> [];
+v3_des_priv(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ p("Testing DES encryption...takes a few seconds..."),
+
+ AgentDir = ?config(agent_dir, Config),
+ ?line rewrite_target_params_conf(AgentDir, "privDES", authPriv),
+ ?line snmp_target_mib:reconfigure(AgentDir),
+
+ MA = whereis(snmp_master_agent),
+
+ ?line load_master("Test2"),
+ ?line load_master("TestTrap"),
+ ?line load_master("TestTrapv2"),
+
+ try_test(v3_sync, [[{v2_proc, []},
+ {ma_v2_trap1, [MA]},
+ {v3_inform_sync, [MA]}]],
+ [{sec_level, authPriv}, {user, "privDES"}]),
+
+ ?line unload_master("TestTrapv2"),
+ ?line unload_master("TestTrap"),
+ ?line unload_master("Test2"),
+ ?line reset_target_params_conf(AgentDir).
+
+%% -define(usmStatsNotInTimeWindows_instance, [1,3,6,1,6,3,15,1,1,2,0]).
+
+%% Make sure mgr is in sync with agent
+v3_sync(Funcs) ->
+ ?DBG("v3_sync -> entry with Funcs: ~p",[Funcs]),
+ g([[sysDescr, 0]]),
+ expect(432, report, [{?usmStatsNotInTimeWindows_instance, any}]),
+ g([[sysDescr, 0]]),
+ expect(433, [{[sysDescr,0], any}]),
+ lists:foreach(fun({Func, Args}) -> apply(?MODULE, Func, Args) end, Funcs).
+
+v3_inform_sync(MA) ->
+ ?DBG("v3_sync -> entry with MA: ~p => Send notification",[MA]),
+ ?line snmpa:send_notification(MA, testTrapv22, no_receiver,
+ "standard inform", []),
+ %% Make sure agent is in sync with mgr...
+ ?DBG("v3_sync -> wait some time: ",[]),
+ sleep(20000), % more than 1500*10 in target_addr.conf
+ ?DBG("v3_sync -> await response",[]),
+ ?line expect(1, {inform, true},
+ [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?system ++ [0,1]}]).
+
+
+v2_caps(suite) -> [];
+v2_caps(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ try_test(v2_caps_i, [node()]).
+
+v2_caps_3(X) -> v2_caps(X).
+
+
+v2_caps_i(Node) ->
+ ?line Idx = rpc:call(Node, snmp, add_agent_caps, [[1,2,3,4,5], "test cap"]),
+ g([[sysORID, Idx], [sysORDescr, Idx]]),
+ ?line expect(1, [{[sysORID, Idx], [1,2,3,4,5]},
+ {[sysORDescr, Idx], "test cap"}]),
+ ?line rpc:call(Node, snmp, del_agent_caps, [Idx]),
+ g([[sysORID, Idx]]),
+ ?line expect(2, [{[sysORID, Idx], noSuchInstance}]).
+
+
+%% Req. Test2
+v1_proc() ->
+ ?DBG("v1_proc -> entry", []),
+ %% According to RFC1157.
+ %% Template: <Section>:<list no>
+ v1_get_p(),
+ v1_get_next_p(),
+ v1_set_p().
+
+
+v1_get_p() ->
+ %% 4.1.2:1
+ g([[test2]]),
+ ?line expect(10, noSuchName, 1, [{[test2], 'NULL'}]),
+ g([[tDescr]]),
+ ?line expect(11, noSuchName, 1, [{[tDescr], 'NULL'}]),
+ g([[tDescr2,0]]),
+ ?line expect(12, noSuchName, 1, [{[tDescr2,0], 'NULL'}]),
+ g([[tDescr3,0]]),
+ ?line expect(131, noSuchName, 1, [{[tDescr3,0], 'NULL'}]),
+ g([[tDescr4,0]]),
+ ?line expect(132, noSuchName, 1, [{[tDescr4,0], 'NULL'}]),
+ g([[sysDescr, 0], [tDescr,0]]), % Outside mibview
+ ?line expect(14, noSuchName, 2, [{[sysDescr, 0], 'NULL'},
+ {[tDescr,0], 'NULL'}]),
+ g([[sysDescr,3]]),
+ ?line expect(15, noSuchName, 1, [{[sysDescr, 3], 'NULL'}]),
+
+ %% 4.1.2:2
+ g([[tTable]]),
+ ?line expect(20, noSuchName, 1, [{[tTable], 'NULL'}]),
+ g([[tEntry]]),
+ ?line expect(21, noSuchName, 1, [{[tEntry], 'NULL'}]),
+
+ %% 4.1.2:3
+ g([[tTooBig, 0]]),
+ ?line expect(30, tooBig, 0, [{[tTooBig, 0], 'NULL'}]),
+
+ %% 4.1.2:4
+ g([[tGenErr1, 0]]),
+ ?line expect(40, genErr, 1, [{[tGenErr1, 0], 'NULL'}]),
+ g([[tGenErr2, 0]]),
+ ?line expect(41, genErr, 1, [{[tGenErr2, 0], 'NULL'}]),
+ g([[sysDescr, 0], [tGenErr3, 0]]),
+ ?line expect(42, genErr, 2, [{[sysDescr, 0], 'NULL'},
+ {[tGenErr3, 0], 'NULL'}]).
+
+
+v1_get_next_p() ->
+ %% 4.1.3:1
+ gn([[1,3,7,1]]),
+ ?line expect(10, noSuchName, 1, [{[1,3,7,1], 'NULL'}]),
+ gn([[tDescr2]]),
+ ?line expect(11, tooBig, 0, any),
+
+ %% 4.1.3:2
+ gn([[tTooBig]]),
+ io:format("We currently don't handle tooBig correct!!!\n"),
+% ?line expect(20, tooBig, 0, [{[tTooBig], 'NULL'}]),
+ ?line expect(20, tooBig, 0, any),
+
+ %% 4.1.3:3
+ gn([[tGenErr1]]),
+% ?line expect(40, genErr, 1, [{[tGenErr1], 'NULL'}]),
+ ?line expect(40, genErr, 1, any),
+ gn([[tGenErr2]]),
+% ?line expect(41, genErr, 1, [{[tGenErr2], 'NULL'}]),
+ ?line expect(41, genErr, 1, any),
+ gn([[sysDescr], [tGenErr3]]),
+% ?line expect(42, genErr, 2, [{[sysDescr], 'NULL'},
+% {[tGenErr3], 'NULL'}]).
+ ?line expect(42, genErr, 2, any).
+
+v1_set_p() ->
+ %% 4.1.5:1
+ s([{[1,3,7,0], i, 4}]),
+ ?line expect(10, noSuchName, 1, [{[1,3,7,0], 4}]),
+ s([{[tDescr,0], s, "outside mibview"}]),
+ ?line expect(11, noSuchName, 1, [{[tDescr,0], "outside mibview"}]),
+ s([{[tDescr3,0], s, "read-only"}]),
+ ?line expect(12, noSuchName, 1, [{[tDescr3,0], "read-only"}]),
+ s([{[tDescr3], s, "noSuchObject"}]),
+ ?line expect(13, noSuchName, 1, [{[tDescr3], "noSuchObject"}]),
+ s([{[tDescr3,1], s, "noSuchInstance"}]),
+ ?line expect(14, noSuchName, 1, [{[tDescr3,1], "noSuchInstance"}]),
+ s([{[tDescr2,0], s, "inconsistentName"}]),
+ ?line expect(15, noSuchName, 1, [{[tDescr2,0], "inconsistentName"}]),
+
+ %% 4.1.5:2
+ s([{[tDescr2, 0], i, 4}]),
+ ?line expect(20, badValue, 1, [{[tDescr2, 0], 4}]),
+ s([{[tDescr2, 0], s, "badValue"}]),
+ ?line expect(21, badValue, 1, [{[tDescr2, 0], "badValue"}]),
+
+ %% 4.1.5:3
+ %% The standard is quite incorrect here. The resp pdu was too big. In
+ %% the resp pdu, we have the original vbs. In the tooBig pdu we still
+ %% have to original vbs => the tooBig pdu is too big as well!!! It
+ %% may not get it to the manager, unless the agent uses 'NULL' instead
+ %% of the std-like original value.
+ s([{[tTooBig, 0], s, ?tooBigStr}]),
+ %% according to std:
+% ?line expect(30, tooBig, 0, [{[tTooBig, 0], ?tooBigStr}]),
+ ?line expect(30, tooBig, 0, [{[tTooBig, 0], 'NULL'}]),
+
+ %% 4.1.5:4
+ s([{[tDescr2, 0], s, "is_set_ok_fail"}]),
+ ?line expect(40, genErr, 1, [{[tDescr2, 0], "is_set_ok_fail"}]),
+ s([{[tDescr2, 0], s, "commit_fail"}]),
+ ?line expect(41, genErr, 1, [{[tDescr2, 0], "commit_fail"}]).
+
+%% Req. Test2
+v2_proc() ->
+ %% According to RFC1905.
+ %% Template: <Section>:<list no>
+ ?DBG("v2_proc -> entry",[]),
+ v2_get_p(),
+ v2_get_next_p(),
+ v2_get_bulk_p(),
+ v2_set_p().
+
+v2_get_p() ->
+ %% 4.2.1:2
+ ?DBG("v2_get_p -> entry",[]),
+ g([[test2]]),
+ ?line expect(10, [{[test2], noSuchObject}]),
+ g([[tDescr]]),
+ ?line expect(11, [{[tDescr], noSuchObject}]),
+ g([[tDescr4,0]]),
+ ?line expect(12, [{[tDescr4,0], noSuchObject}]),
+ g([[sysDescr, 0], [tDescr,0]]), % Outside mibview
+ ?line expect(13, [{[sysDescr,0], "Erlang SNMP agent"},
+ {[tDescr,0], noSuchObject}]),
+ g([[tTable]]),
+ ?line expect(14, [{[tTable], noSuchObject}]),
+ g([[tEntry]]),
+ ?line expect(15, [{[tEntry], noSuchObject}]),
+
+ %% 4.2.1:3
+ g([[tDescr2,0]]), %% instrum ret noSuchName!!!
+ ?line expect(20, [{[tDescr2,0], noSuchInstance}]),
+ g([[tDescr3,0]]),
+ ?line expect(21, [{[tDescr3,0], noSuchInstance}]),
+ g([[sysDescr,3]]),
+ ?line expect(22, [{[sysDescr, 3], noSuchInstance}]),
+ g([[tIndex,1]]),
+ ?line expect(23, [{[tIndex, 1], noSuchInstance}]),
+
+ %% 4.2.1 - any other error: genErr
+ g([[tGenErr1, 0]]),
+ ?line expect(30, genErr, 1, [{[tGenErr1, 0], 'NULL'}]),
+ g([[tGenErr2, 0]]),
+ ?line expect(31, genErr, 1, [{[tGenErr2, 0], 'NULL'}]),
+ g([[sysDescr, 0], [tGenErr3, 0]]),
+ ?line expect(32, genErr, 2, [{[sysDescr, 0], 'NULL'},
+ {[tGenErr3, 0], 'NULL'}]),
+
+ %% 4.2.1 - tooBig
+ g([[tTooBig, 0]]),
+ ?line expect(40, tooBig, 0, []).
+
+
+v2_get_next_p() ->
+ %% 4.2.2:2
+ ?DBG("v2_get_next_p -> entry",[]),
+ gn([[1,3,7,1]]),
+ ?line expect(10, [{[1,3,7,1], endOfMibView}]),
+ gn([[sysDescr], [1,3,7,1]]),
+ ?line expect(11, [{[sysDescr, 0], "Erlang SNMP agent"},
+ {[1,3,7,1], endOfMibView}]),
+ gn([[tCnt2, 1]]),
+ ?line expect(12, [{[tCnt2,2], 100}]),
+ gn([[tCnt2, 2]]),
+ ?line expect(12, [{[tCnt2,2], endOfMibView}]),
+
+ %% 4.2.2 - any other error: genErr
+ gn([[tGenErr1]]),
+ ?line expect(20, genErr, 1, [{[tGenErr1], 'NULL'}]),
+ gn([[tGenErr2]]),
+ ?line expect(21, genErr, 1, [{[tGenErr2], 'NULL'}]),
+ gn([[sysDescr], [tGenErr3]]),
+ ?line expect(22, genErr, 2, [{[sysDescr], 'NULL'},
+ {[tGenErr3], 'NULL'}]),
+
+ %% 4.2.2 - tooBig
+ gn([[tTooBig]]),
+ ?line expect(20, tooBig, 0, []).
+
+v2_get_bulk_p() ->
+ %% 4.2.3
+ ?DBG("v2_get_bulk_p -> entry",[]),
+ gb(1, 1, []),
+ ?line expect(10, []),
+ gb(-1, 1, []),
+ ?line expect(11, []),
+ gb(-1, -1, []),
+ ?line expect(12, []),
+ gb(-1, -1, []),
+ ?line expect(13, []),
+ gb(2, 0, [[sysDescr], [1,3,7,1]]),
+ ?line expect(14, [{[sysDescr, 0], "Erlang SNMP agent"},
+ {[1,3,7,1], endOfMibView}]),
+ gb(1, 2, [[sysDescr], [1,3,7,1]]),
+ ?line expect(15, [{[sysDescr, 0], "Erlang SNMP agent"},
+ {[1,3,7,1], endOfMibView}]),
+ gb(0, 2, [[sysDescr], [1,3,7,1]]),
+ ?line expect(16, [{[sysDescr, 0], "Erlang SNMP agent"},
+ {[1,3,7,1], endOfMibView},
+ {[sysObjectID, 0], [1,2,3]},
+ {[1,3,7,1], endOfMibView}]),
+
+ gb(2, 2, [[sysDescr], [1,3,7,1], [sysDescr], [1,3,7,1]]),
+ ?line expect(17, [{[sysDescr, 0], "Erlang SNMP agent"},
+ {[1,3,7,1], endOfMibView},
+ {[sysDescr, 0], "Erlang SNMP agent"},
+ {[1,3,7,1], endOfMibView},
+ {[sysObjectID, 0], [1,2,3]},
+ {[1,3,7,1], endOfMibView}]),
+
+ gb(1, 2, [[sysDescr], [sysDescr], [tTooBig]]),
+ ?line expect(18, [{[sysDescr, 0], "Erlang SNMP agent"},
+ {[sysDescr, 0], "Erlang SNMP agent"}]),
+
+ gb(1,12, [[tDescr2], [sysDescr]]), % next one after tDescr2 is tTooBig.
+ ?line expect(19, []),
+
+ gb(2,2, [[sysDescr], [sysObjectID], [tGenErr1], [sysDescr]]),
+ ?line expect(20, genErr, 3, [{[sysDescr], 'NULL'},
+ {[sysObjectID], 'NULL'},
+ {[tGenErr1], 'NULL'},
+ {[sysDescr], 'NULL'}]),
+ gb(0, 2, [[tCnt2, 1]]),
+ ?line expect(21, [{[tCnt2,2], 100},
+ {[tCnt2,2], endOfMibView}]).
+
+
+v2_set_p() ->
+ %% 4.2.5:1
+ ?DBG("v2_set_p -> entry",[]),
+ s([{[1,3,7,0], i, 4}]),
+ ?line expect(10, noAccess, 1, [{[1,3,7,0], 4}]),
+ s([{[tDescr,0], s, "outside mibview"}]),
+ ?line expect(11, noAccess, 1, [{[tDescr,0], "outside mibview"}]),
+
+ %% 4.2.5:2
+ s([{[1,3,6,1,0], s, "noSuchObject"}]),
+ ?line expect(20, notWritable, 1, [{[1,3,6,1,0], "noSuchObject"}]),
+
+ %% 4.2.5:3
+ s([{[tDescr2, 0], i, 4}]),
+ ?line expect(30, wrongType, 1, [{[tDescr2, 0], 4}]),
+ s([{[tDescr2, 0], s, "badValue"}]),
+ ?line expect(31, badValue, 1, [{[tDescr2, 0], "badValue"}]),
+
+ %% 4.2.5:4
+ s([{[tStr, 0], s, ""}]),
+ ?line expect(40, wrongLength, 1, [{[tStr, 0], ""}]),
+ s([{[tStr, 0], s, "12345"}]),
+ ?line expect(40, wrongLength, 1, [{[tStr, 0], "12345"}]),
+
+ %% 4.2.5:5 - N/A
+
+ %% 4.2.5:6
+ s([{[tInt1, 0], i, 0}]),
+ ?line expect(60, wrongValue, 1, [{[tInt1, 0], 0}]),
+ s([{[tInt1, 0], i, 5}]),
+ ?line expect(61, wrongValue, 1, [{[tInt1, 0], 5}]),
+ s([{[tInt2, 0], i, 0}]),
+ ?line expect(62, wrongValue, 1, [{[tInt2, 0], 0}]),
+ s([{[tInt2, 0], i, 5}]),
+ ?line expect(63, wrongValue, 1, [{[tInt2, 0], 5}]),
+ s([{[tInt3, 0], i, 5}]),
+ ?line expect(64, wrongValue, 1, [{[tInt3, 0], 5}]),
+
+ %% 4.2.5:7
+ s([{[tDescrX, 1, 1], s, "noCreation"}]),
+ ?line expect(70, noCreation, 1, [{[tDescrX, 1, 1], "noCreation"}]),
+
+ %% 4.2.5:8
+ s([{[tDescrX, 1, 2], s, "inconsistentName"}]),
+ ?line expect(80, inconsistentName, 1,
+ [{[tDescrX, 1, 2], "inconsistentName"}]),
+
+ %% 4.2.5:9
+ s([{[tCnt, 1, 2], i, 5}]),
+ ?line expect(90, notWritable, 1, [{[tCnt, 1, 2], 5}]),
+ s([{[tDescr3,0], s, "read-only"}]),
+ ?line expect(90, notWritable, 1, [{[tDescr3,0], "read-only"}]),
+
+ %% 4.2.5:10
+ s([{[tDescr2,0], s, "inconsistentValue"}]),
+ ?line expect(100, inconsistentValue, 1,
+ [{[tDescr2,0], "inconsistentValue"}]),
+
+ %% 4.2.5:11
+ s([{[tDescr2,0], s, "resourceUnavailable"}]),
+ ?line expect(110, resourceUnavailable, 1,
+ [{[tDescr2,0],"resourceUnavailable"}]),
+
+ %% 4.2.5:12
+ s([{[tDescr2, 0], s, "is_set_ok_fail"}]),
+ ?line expect(120, genErr, 1, [{[tDescr2, 0], "is_set_ok_fail"}]).
+
+ %% commitFailed and undoFailed is tested by the 'undo' case.
+
+
+%% Req. OLD-SNMPEA-MIB
+table_test() ->
+ io:format("Testing simple get, next and set on communityTable...~n"),
+%% {[147,214,36,45], "public", 2, readWrite}.
+%% {[147,214,36,45], "standard trap", 2, read}.
+ Key1c3 = [intCommunityViewIndex,get(mip),is("public")],
+ Key2c3 = [intCommunityViewIndex,get(mip),is("standard trap")],
+ Key1c4 = [intCommunityAccess,get(mip),is("public")],
+ EndKey = [intCommunityEntry,[9],get(mip),is("public")],
+ gn([[intCommunityEntry]]),
+ ?line expect(7, [{Key1c3, 2}]),
+ gn([[intCommunityTable]]),
+ ?line expect(71, [{Key1c3, 2}]),
+ gn([[community]]),
+ ?line expect(72, [{Key1c3, 2}]),
+ gn([[otpSnmpeaMIB]]),
+ ?line expect(73, [{Key1c3, 2}]),
+ gn([[ericsson]]),
+ ?line expect(74, [{Key1c3, 2}]),
+ gn([Key1c3]),
+ ?line expect(8, [{Key2c3, 2}]),
+ gn([Key2c3]),
+ ?line expect(9, [{Key1c4, 2}]),
+ gn([EndKey]),
+ AgentIp = [intAgentIpAddress,0],
+ ?line expect(10, [{AgentIp, any}]),
+ g([Key1c3]),
+ ?line expect(11, [{Key1c3, 2}]),
+ g([EndKey]),
+ ?line ?v1_2(expect(12, noSuchName, 1, any),
+ expect(12, [{EndKey, noSuchObject}])),
+
+ io:format("Testing row creation/deletion on communityTable...~n"),
+ NewKeyc3 = [intCommunityViewIndex,get(mip),is("test")],
+ NewKeyc4 = [intCommunityAccess,get(mip),is("test")],
+ NewKeyc5 = [intCommunityStatus,get(mip),is("test")],
+ s([{NewKeyc5, ?createAndGo}]),
+ ?line expect(14, ?v1_2(badValue, inconsistentValue), 1,any),
+ s([{NewKeyc5, ?createAndGo}, {NewKeyc3, 2}, {NewKeyc4, 2}]),
+ ?line expect(15, [{NewKeyc5, ?createAndGo},{NewKeyc3, 2}, {NewKeyc4, 2}]),
+ g([NewKeyc4]),
+ ?line expect(16, [{NewKeyc4, 2}]),
+ s([{NewKeyc5, ?destroy}]),
+ ?line expect(17, [{NewKeyc5, ?destroy}]),
+ s([{NewKeyc4, 2}]),
+ ?line expect(18, ?v1_2(noSuchName, inconsistentName), 1,[{NewKeyc4, 2}]),
+ s([{NewKeyc5, ?createAndWait}]),
+ ?line expect(19, [{NewKeyc5, ?createAndWait}]),
+ g([NewKeyc5]),
+ ?line expect(20, [{NewKeyc5, ?notReady}]),
+ s([{NewKeyc4, 2}]),
+ ?line expect(21, [{NewKeyc4, 2}]),
+ g([NewKeyc5]),
+ ?line expect(22, [{NewKeyc5, ?notReady}]),
+ s([{NewKeyc3, 2}]),
+ ?line expect(23, [{NewKeyc3, 2}]),
+ g([NewKeyc5]),
+ ?line expect(24, [{NewKeyc5, ?notInService}]),
+ s([{NewKeyc5, ?active}]),
+ ?line expect(25, [{NewKeyc5, ?active}]),
+ s([{NewKeyc5, ?destroy}]),
+ ?line expect(26, [{NewKeyc5, ?destroy}]),
+ s([{NewKeyc3, 3}]),
+ ?line expect(27, ?v1_2(noSuchName, inconsistentName), 1,[{NewKeyc3, 3}]),
+ otp_1128().
+
+%% Req. system group
+simple_standard_test() ->
+ ?DBG("simple_standard_test -> entry",[]),
+ gn([[1,1]]),
+ ?line expect(1, [{[sysDescr,0], "Erlang SNMP agent"}]),
+ gn([[1,3]]),
+ ?line expect(11, [{[sysDescr,0], "Erlang SNMP agent"}]),
+ gn([[1,3,6]]),
+ ?line expect(12, [{[sysDescr,0], "Erlang SNMP agent"}]),
+ gn([[1,3,6,1]]),
+ ?line expect(13, [{[sysDescr,0], "Erlang SNMP agent"}]),
+ gn([[1,3,6,1,2]]),
+ ?line expect(14, [{[sysDescr,0], "Erlang SNMP agent"}]),
+ gn([[1,3,6,1,2,1]]),
+ ?line expect(15, [{[sysDescr,0], "Erlang SNMP agent"}]),
+ gn([[1,3,6,1,2,1,1]]),
+ ?line expect(16, [{[sysDescr,0], "Erlang SNMP agent"}]),
+ gn([[sysDescr]]),
+ ?line expect(17, [{[sysDescr,0], "Erlang SNMP agent"}]),
+ g([[sysDescr,0]]),
+ ?line expect(2, [{[sysDescr,0], "Erlang SNMP agent"}]),
+ g([[sysDescr]]),
+ ?line ?v1_2(expect(3, noSuchName, 1, any),
+ expect(3, [{[sysDescr], noSuchObject}])),
+ g([[1,6,7,0]]),
+ ?line ?v1_2(expect(41, noSuchName, 1, any),
+ expect(3, [{[1,6,7,0], noSuchObject}])),
+ gn([[1,13]]),
+ ?line ?v1_2(expect(4, noSuchName,1, any),
+ expect(4, [{[1,13], endOfMibView}])),
+ s([{[sysLocation, 0], "new_value"}]),
+ ?line expect(5, [{[sysLocation, 0], "new_value"}]),
+ g([[sysLocation, 0]]),
+ ?line expect(6, [{[sysLocation, 0], "new_value"}]),
+ io:format("Testing noSuchName and badValue...~n"),
+ s([{[sysServices,0], 3}]),
+ ?line expect(61, ?v1_2(noSuchName, notWritable), 1, any),
+ s([{[sysLocation, 0], i, 3}]),
+ ?line expect(62, ?v1_2(badValue, wrongType), 1, any),
+ ?DBG("simple_standard_test -> done",[]),
+ ok.
+
+%% This is run in the agent node
+db_notify_client(suite) -> [];
+db_notify_client(Config) when list(Config) ->
+ {SaNode, MgrNode, MibDir} = init_case(Config),
+ ?DBG("~n\tSaNode: ~p~n\tMgrNode: ~p~n\tMibDir: ~p",
+ [SaNode,MgrNode,MibDir]),
+ snmpa_local_db:register_notify_client(self(),?MODULE),
+
+ %% This call (the manager) will issue to set operations, so
+ %% we expect to receive to notify(insert) calls.
+ try_test(db_notify_client_test),
+
+ ?DBG("await first notify",[]),
+ receive
+ {db_notify_test_reply,insert} -> ?DBG("first notify received",[]),ok
+ end,
+
+ ?DBG("await second notify",[]),
+ receive
+ {db_notify_test_reply,insert} -> ?DBG("second notify received",[]),ok
+ end,
+
+ snmpa_local_db:unregister_notify_client(self()).
+
+
+%% This is run in the manager node
+db_notify_client_test() ->
+ ?DBG("set first new sysLocation",[]),
+ s([{[sysLocation, 0], "new_value"}]),
+ ?line expect(5, [{[sysLocation, 0], "new_value"}]),
+
+ ?DBG("set second new sysLocation",[]),
+ s([{[sysLocation, 0], "new_value"}]),
+ ?line expect(5, [{[sysLocation, 0], "new_value"}]).
+
+notify(Pid,What) ->
+ ?DBG("notify(~p,~p) -> called",[Pid,What]),
+ Pid ! {db_notify_test_reply,What}.
+
+
+%% Req: system group, OLD-SNMPEA-MIB, Klas1
+big_test() ->
+ ?DBG("big_test -> testing simple next/get/set @ master agent...",[]),
+ simple_standard_test(),
+
+ ?DBG("big_test -> testing simple next/get/set @ subagent...",[]),
+ gn([[klas1]]),
+ ?line expect(1, [{[fname,0], ""}]),
+ g([[fname,0]]),
+ ?line expect(2, [{[fname,0], ""}]),
+ s([{[fname,0], s, "test set"}]),
+ ?line expect(3, [{[fname,0], "test set"}]),
+ g([[fname,0]]),
+ ?line expect(4, [{[fname,0], "test set"}]),
+
+ ?DBG("big_test -> "
+ "testing next from last instance in master to subagent...",[]),
+ gn([[?v1_2(sysServices, sysORLastChange),0]]),
+ ?line expect(5, [{[fname,0], "test set"}]),
+ gn([[1,1],
+ [?v1_2(sysServices, sysORLastChange),0]]),
+ ?line expect(51, [{[sysDescr,0], "Erlang SNMP agent"},
+ {[fname,0], "test set"}]),
+ s([{[fname,0], s, ""}]),
+ ?line expect(52, [{[fname,0], ""}]),
+
+ table_test(),
+
+ ?DBG("big_test -> adding one row in subagent table",[]),
+ _FTab = [friendsEntry],
+ s([{[friendsEntry, [2, 3]], s, "kompis3"},
+ {[friendsEntry, [3, 3]], i, ?createAndGo}]),
+ ?line expect(6, [{[friendsEntry, [2, 3]], "kompis3"},
+ {[friendsEntry, [3, 3]], ?createAndGo}]),
+ g([[friendsEntry, [2, 3]],
+ [friendsEntry, [3, 3]]]),
+ ?line expect(7, [{[friendsEntry, [2, 3]], "kompis3"},
+ {[friendsEntry, [3, 3]], ?active}]),
+ s([{[friendsEntry, [3, 3]], i, ?destroy}]),
+ ?line expect(8, [{[friendsEntry, [3, 3]], ?destroy}]),
+
+ otp_1131(),
+
+ ?DBG("big_test -> adding two rows in subagent table with special INDEX",
+ []),
+ s([{[kompissEntry, [1, 3]], s, "kompis3"},
+ {[kompissEntry, [2, 3]], i, ?createAndGo}]),
+ ?line expect(9, [{[kompissEntry, [1, 3]], "kompis3"},
+ {[kompissEntry, [2, 3]], ?createAndGo}]),
+ g([[kompissEntry, [1, 3]],
+ [kompissEntry, [2, 3]]]),
+ ?line expect(10, [{[kompissEntry, [1, 3]], "kompis3"},
+ {[kompissEntry, [2, 3]], ?active}]),
+ gn([[kompissEntry, [1]],
+ [kompissEntry, [2]]]),
+ ?line expect(11, [{[kompissEntry, [1, 3]], "kompis3"},
+ {[kompissEntry, [2, 3]], ?active}]),
+ s([{[kompissEntry, [1, 2]], s, "kompis3"},
+ {[kompissEntry, [2, 2]], i, ?createAndGo}]),
+ ?line expect(12, [{[kompissEntry, [1, 2]], "kompis3"},
+ {[kompissEntry, [2, 2]], ?createAndGo}]),
+ gn([[kompissEntry, [1, 1]],
+ [kompissEntry, [2, 1]]]),
+ ?line expect(13, [{[kompissEntry, [1, 2]], "kompis3"},
+ {[kompissEntry, [2, 2]], ?active}]),
+ s([{[kompissEntry, [2, 3]], i, ?destroy}]),
+ ?line expect(14, [{[kompissEntry, [2, 3]], ?destroy}]),
+ s([{[kompissEntry, [2, 2]], i, ?destroy}]),
+ ?line expect(15, [{[kompissEntry, [2, 2]], ?destroy}]),
+ ?DBG("big_test -> done",[]),
+ ok.
+
+%% Req. system group, Klas2, OLD-SNMPEA-MIB
+big_test_2() ->
+ p("Testing simple next/get/set @ master agent (2)..."),
+ simple_standard_test(),
+
+ p("Testing simple next/get/set @ subagent (2)..."),
+ gn([[klas2]]),
+ ?line expect(1, [{[fname2,0], ""}]),
+ g([[fname2,0]]),
+ ?line expect(2, [{[fname2,0], ""}]),
+ s([{[fname2,0], s, "test set"}]),
+ ?line expect(3, [{[fname2,0], "test set"}]),
+ g([[fname2,0]]),
+ ?line expect(4, [{[fname2,0], "test set"}]),
+
+ otp_1298(),
+
+ p("Testing next from last object in master to subagent (2)..."),
+ gn([[?v1_2(sysServices, sysORLastChange),0]]),
+ ?line expect(5, [{[fname2,0], "test set"}]),
+ gn([[1,1],
+ [?v1_2(sysServices, sysORLastChange),0]]),
+ ?line expect(51, [{[sysDescr,0], "Erlang SNMP agent"},
+ {[fname2,0], "test set"}]),
+
+ table_test(),
+
+ p("Adding one row in subagent table (2)"),
+ _FTab = [friendsEntry2],
+ s([{[friendsEntry2, [2, 3]], s, "kompis3"},
+ {[friendsEntry2, [3, 3]], i, ?createAndGo}]),
+ ?line expect(6, [{[friendsEntry2, [2, 3]], "kompis3"},
+ {[friendsEntry2, [3, 3]], ?createAndGo}]),
+ g([[friendsEntry2, [2, 3]],
+ [friendsEntry2, [3, 3]]]),
+ ?line expect(7, [{[friendsEntry2, [2, 3]], "kompis3"},
+ {[friendsEntry2, [3, 3]], ?active}]),
+ s([{[friendsEntry2, [3, 3]], i, ?destroy}]),
+ ?line expect(8, [{[friendsEntry2, [3, 3]], ?destroy}]),
+
+ p("Adding two rows in subagent table with special INDEX (2)"),
+ s([{[kompissEntry2, [1, 3]], s, "kompis3"},
+ {[kompissEntry2, [2, 3]], i, ?createAndGo}]),
+ ?line expect(9, [{[kompissEntry2, [1, 3]], "kompis3"},
+ {[kompissEntry2, [2, 3]], ?createAndGo}]),
+ g([[kompissEntry2, [1, 3]],
+ [kompissEntry2, [2, 3]]]),
+ ?line expect(10, [{[kompissEntry2, [1, 3]], "kompis3"},
+ {[kompissEntry2, [2, 3]], ?active}]),
+ gn([[kompissEntry2, [1]],
+ [kompissEntry2, [2]]]),
+ ?line expect(11, [{[kompissEntry2, [1, 3]], "kompis3"},
+ {[kompissEntry2, [2, 3]], ?active}]),
+ s([{[kompissEntry2, [1, 2]], s, "kompis3"},
+ {[kompissEntry2, [2, 2]], i, ?createAndGo}]),
+ ?line expect(12, [{[kompissEntry2, [1, 2]], "kompis3"},
+ {[kompissEntry2, [2, 2]], ?createAndGo}]),
+ gn([[kompissEntry2, [1, 1]],
+ [kompissEntry2, [2, 1]]]),
+ ?line expect(13, [{[kompissEntry2, [1, 2]], "kompis3"},
+ {[kompissEntry2, [2, 2]], ?active}]),
+ s([{[kompissEntry2, [2, 3]], i, ?destroy}]),
+ ?line expect(14, [{[kompissEntry2, [2, 3]], ?destroy}]),
+ s([{[kompissEntry2, [2, 2]], i, ?destroy}]),
+ ?line expect(15, [{[kompissEntry2, [2, 2]], ?destroy}]),
+ ok.
+
+%% Req. Test1
+multi_threaded_test() ->
+ p("Testing multi threaded agent..."),
+ g([[multiStr,0]]),
+ Pid = get_multi_pid(),
+ g([[sysUpTime,0]]),
+ ?line expect(1, [{[sysUpTime,0], any}]),
+ s([{[sysLocation, 0], s, "pelle"}]),
+ ?line expect(2, [{[sysLocation, 0], "pelle"}]),
+ Pid ! continue,
+ ?line expect(3, [{[multiStr,0], "ok"}]),
+
+ s([{[multiStr, 0], s, "block"}]),
+ Pid2 = get_multi_pid(),
+ g([[sysUpTime,0]]),
+ ?line expect(4, [{[sysUpTime,0], any}]),
+ g([[multiStr,0]]),
+ Pid3 = get_multi_pid(),
+ g([[sysUpTime,0]]),
+ ?line expect(5, [{[sysUpTime,0], any}]),
+ s([{[sysLocation, 0], s, "kalle"}]),
+ Pid3 ! continue,
+ ?line expect(6, [{[multiStr,0], "ok"}]),
+ Pid2 ! continue,
+ ?line expect(7, [{[multiStr,0], "block"}]),
+ ?line expect(8, [{[sysLocation,0], "kalle"}]).
+
+%% Req. Test1, TestTrapv2
+mt_trap_test(MA) ->
+ snmpa:send_trap(MA, testTrapv22, "standard trap"),
+ ?line expect(1, v2trap, [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?system ++ [0,1]}]),
+
+ snmpa:send_trap(MA, mtTrap, "standard trap"),
+ Pid = get_multi_pid(),
+ g([[sysUpTime,0]]),
+ ?line expect(2, [{[sysUpTime,0], any}]),
+ snmpa:send_trap(MA, testTrapv22, "standard trap"),
+ ?line expect(3, v2trap, [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?system ++ [0,1]}]),
+ Pid ! continue,
+ ?line expect(4, v2trap, [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?testTrap ++ [2]},
+ {[multiStr,0], "ok"}]).
+
+
+get_multi_pid() ->
+ get_multi_pid(10).
+get_multi_pid(0) ->
+ ?line ?FAIL(no_global_name);
+get_multi_pid(N) ->
+ sleep(1000),
+ case global:whereis_name(snmp_multi_tester) of
+ Pid when pid(Pid) -> Pid;
+ _ -> get_multi_pid(N-1)
+ end.
+
+%% Req. Test1
+types_v2_test() ->
+ p("Testing v2 types..."),
+
+ s([{[bits1,0], 2#10}]),
+ ?line expect(1, [{[bits1,0], ?str(2#10)}]),
+ g([[bits1,0]]),
+ ?line expect(2, [{[bits1,0], ?str(2#101)}]),
+
+ s([{[bits2,0], 2#11000000110}]),
+ ?line expect(3, [{[bits2,0], ?str(2#11000000110)}]),
+ g([[bits2,0]]),
+ ?line expect(4, [{[bits2,0], ?str(2#11000000110)}]),
+
+ g([[bits3,0]]),
+ ?line expect(50, genErr, 1, any),
+
+ g([[bits4,0]]),
+ ?line expect(51, genErr, 1, any),
+
+ s([{[bits1,0], s, [2#10]}]),
+ ?line expect(6, ?v1_2(badValue, wrongValue), 1, any),
+
+ s([{[bits2,0], 2#11001001101010011}]),
+ ?line expect(7, ?v1_2(badValue, wrongValue), 1, any).
+
+
+%% Req. Test1
+implied_test(MA) ->
+ ?LOG("implied_test -> start",[]),
+ p("Testing IMPLIED..."),
+
+ snmpa:verbosity(MA,trace),
+ snmpa:verbosity(MA,trace),
+
+ %% Create two rows, check that they are get-nexted in correct order.
+ Idx1 = "apa",
+ Idx2 = "qq",
+ ?DBG("implied_test -> (send) create row 1 '~s' in table 1",[Idx1]),
+ s([{[testStatus, Idx1], i, ?createAndGo}, {[testDescr, Idx1],s,"row 1"}]),
+ ?line expect(1, [{[testStatus, Idx1], ?createAndGo},
+ {[testDescr, Idx1], "row 1"}]),
+ ?DBG("implied_test -> (send) create row 2 '~s' in table 1",[Idx2]),
+ s([{[testStatus, Idx2], i, ?createAndGo}, {[testDescr, Idx2],s,"row 2"}]),
+ ?line expect(2, [{[testStatus, Idx2], ?createAndGo},
+ {[testDescr, Idx2], "row 2"}]),
+ ?DBG("implied_test -> get-next(testDescr)",[]),
+ gn([[testDescr]]),
+ ?line expect(3, [{[testDescr,Idx1], "row 1"}]),
+ ?DBG("implied_test -> get-next(testDescr) of row 1",[]),
+ gn([[testDescr,Idx1]]),
+ ?line expect(4, [{[testDescr,Idx2], "row 2"}]),
+
+ % Delete the rows
+ ?DBG("implied_test -> (send) delete row 1 '~s' from table 1",[Idx1]),
+ s([{[testStatus, Idx1], i, ?destroy}]),
+ ?line expect(5, [{[testStatus, Idx1], ?destroy}]),
+ ?DBG("implied_test -> (send) delete row 2 '~s' from table 1",[Idx2]),
+ s([{[testStatus, Idx2], i, ?destroy}]),
+ ?line expect(6, [{[testStatus, Idx2], ?destroy}]),
+
+ %% Try the same in other table
+ Idx3 = [1, "apa"],
+ Idx4 = [1, "qq"],
+ ?DBG("implied_test -> (send) create row 1 '~s' in table 2",[Idx3]),
+ s([{[testStatus2, Idx3], i, ?createAndGo}, {[testDescr2,Idx3],s,"row 1"}]),
+ ?line expect(1, [{[testStatus2, Idx3], ?createAndGo},
+ {[testDescr2, Idx3], "row 1"}]),
+ ?DBG("implied_test -> (send) create row 2 '~s' in table 2",[Idx4]),
+ s([{[testStatus2, Idx4], i, ?createAndGo}, {[testDescr2,Idx4],s,"row 2"}]),
+ ?line expect(2, [{[testStatus2, Idx4], ?createAndGo},
+ {[testDescr2, Idx4], "row 2"}]),
+ ?DBG("implied_test -> get-next(testDescr2)",[]),
+ gn([[testDescr2]]),
+ ?line expect(3, [{[testDescr2,Idx3], "row 1"}]),
+ ?DBG("implied_test -> get-next(testDescr2) of row 1",[]),
+ gn([[testDescr2,Idx3]]),
+ ?line expect(4, [{[testDescr2,Idx4], "row 2"}]),
+
+ % Delete the rows
+ ?DBG("implied_test -> (send) delete row 1 '~s' from table 2",[Idx3]),
+ s([{[testStatus2, Idx3], i, ?destroy}]),
+ ?line expect(5, [{[testStatus2, Idx3], ?destroy}]),
+ ?DBG("implied_test -> (send) delete row 2 '~s' from table 2",[Idx4]),
+ s([{[testStatus2, Idx4], i, ?destroy}]),
+ ?line expect(6, [{[testStatus2, Idx4], ?destroy}]),
+
+ snmpa:verbosity(MA,log),
+
+ ?LOG("implied_test -> done",[]).
+
+
+
+%% Req. Test1
+sparse_table_test() ->
+ p("Testing sparse table..."),
+
+ %% Create two rows, check that they are get-nexted in correct order.
+ Idx1 = 1,
+ Idx2 = 2,
+ s([{[sparseStatus, Idx1], i, ?createAndGo},
+ {[sparseDescr, Idx1], s, "row 1"}]),
+ ?line expect(1, [{[sparseStatus, Idx1], ?createAndGo},
+ {[sparseDescr, Idx1], "row 1"}]),
+ s([{[sparseStatus, Idx2], i, ?createAndGo},
+ {[sparseDescr, Idx2], s, "row 2"}]),
+ ?line expect(2, [{[sparseStatus, Idx2], ?createAndGo},
+ {[sparseDescr, Idx2], "row 2"}]),
+ ?v1_2(gn([[sparseIndex], [sparseDescr,Idx1], [sparseDescr,Idx2],
+ [sparseStatus,Idx1], [sparseStatus,Idx2]]),
+ gb(0,5,[[sparseIndex]])),
+ ?line expect(3, [{[sparseDescr,Idx1], "row 1"},
+ {[sparseDescr,Idx2], "row 2"},
+ {[sparseStatus,Idx1], ?active},
+ {[sparseStatus,Idx2], ?active},
+ {[sparseStr,0], "slut"}]),
+ % Delete the rows
+ s([{[sparseStatus, Idx1], i, ?destroy}]),
+ ?line expect(4, [{[sparseStatus, Idx1], ?destroy}]),
+ s([{[sparseStatus, Idx2], i, ?destroy}]),
+ ?line expect(5, [{[sparseStatus, Idx2], ?destroy}]).
+
+
+%% Req. Test1
+cnt_64_test(MA) ->
+ ?LOG("start cnt64 test (~p)",[MA]),
+ snmpa:verbosity(MA,trace),
+ ?LOG("start cnt64 test",[]),
+ p("Testing Counter64, and at the same time, RowStatus is not last column"),
+
+ ?DBG("get cnt64",[]),
+ g([[cnt64,0]]),
+ ?DBG("await response",[]),
+ ?line ?v1_2(expect(1, noSuchName, 1, any),
+ expect(1, [{[cnt64,0],18446744073709551615}])),
+ ?DBG("get-next cnt64",[]),
+ gn([[cnt64]]),
+ ?DBG("await response",[]),
+ ?line ?v1_2(expect(2, [{[cnt64Str,0], "after cnt64"}]),
+ expect(2, [{[cnt64,0],18446744073709551615}])),
+ ?DBG("send cntTrap",[]),
+ snmpa:send_trap(MA,cntTrap,"standard trap",[{sysContact,"pelle"},
+ {cnt64, 10},
+ {sysLocation, "here"}]),
+ ?DBG("await response",[]),
+ ?line ?v1_2(expect(3, trap, [test], 6, 1, [{[sysContact,0], "pelle"},
+ {[sysLocation,0], "here"}]),
+ expect(3, v2trap, [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?testTrap ++ [1]},
+ {[sysContact,0], "pelle"},
+ {[cnt64,0], 10},
+ {[sysLocation,0], "here"}])),
+
+ %% Create two rows, check that they are get-nexted in correct order.
+ Idx1 = 1,
+ Idx2 = 2,
+ ?DBG("create row (cntStatus): ~p",[Idx1]),
+ s([{[cntStatus, Idx1], i, ?createAndGo}]),
+ ?DBG("await response",[]),
+ ?line expect(1, [{[cntStatus, Idx1], ?createAndGo}]),
+ ?DBG("create row (cntStatus): ~p",[Idx2]),
+ s([{[cntStatus, Idx2], i, ?createAndGo}]),
+ ?DBG("await response",[]),
+ ?line expect(2, [{[cntStatus, Idx2], ?createAndGo}]),
+
+ ?DBG("get-next (cntIndex)",[]),
+ gn([[cntIndex]]),
+ ?DBG("await response",[]),
+ ?line ?v1_2(expect(3, [{[cntStatus,Idx1], ?active}]),
+ expect(3, [{[cntCnt,Idx1], 0}])),
+ % Delete the rows
+ ?DBG("delete row (cntStatus): ~p",[Idx1]),
+ s([{[cntStatus, Idx1], i, ?destroy}]),
+ ?DBG("await response",[]),
+ ?line expect(4, [{[cntStatus, Idx1], ?destroy}]),
+ ?DBG("delete row (cntStatus): ~p",[Idx2]),
+ s([{[cntStatus, Idx2], i, ?destroy}]),
+ ?DBG("await response",[]),
+ ?line expect(5, [{[cntStatus, Idx2], ?destroy}]),
+ catch snmpa:verbosity(MA,log),
+ ?DBG("done",[]),
+ ok.
+
+%% Req. Test1
+opaque_test() ->
+ p("Testing Opaque datatype..."),
+ g([[opaqueObj,0]]),
+ ?line expect(1, [{[opaqueObj,0], "opaque-data"}]).
+
+%% Req. OLD-SNMPEA-MIB
+api_test(MaNode) ->
+ ?line {value, OID} = rpc:call(MaNode, snmp, name_to_oid,
+ [intAgentIpAddress]),
+ ?line {value, intAgentIpAddress} = rpc:call(MaNode, snmp,
+ oid_to_name, [OID]),
+ ?line false = rpc:call(MaNode, snmp, name_to_oid, [intAgentIpAddres]),
+ ?line false = rpc:call(MaNode, snmp, oid_to_name,
+ [[1,5,32,3,54,3,3,34,4]]),
+ ?line {value, 2} = rpc:call(MaNode, snmp, enum_to_int,
+ [intViewType, excluded]),
+ ?line {value, excluded} = rpc:call(MaNode, snmp, int_to_enum,
+ [intViewType, 2]),
+ ?line false = rpc:call(MaNode, snmp, enum_to_int, [intViewType, exclude]),
+ ?line false = rpc:call(MaNode, snmp, enum_to_int,
+ [intAgentIpAddress, exclude]),
+ ?line false = rpc:call(MaNode, snmp, enum_to_int,
+ [intAgentIpAddre, exclude]),
+ ?line false = rpc:call(MaNode, snmp, int_to_enum, [intViewType, 3]),
+ ?line false = rpc:call(MaNode, snmp, int_to_enum, [intAgentIpAddress, 2]),
+ ?line false = rpc:call(MaNode, snmp, int_to_enum, [intAgentIpAddre, 2]),
+ ?line {value, active} = rpc:call(MaNode, snmp,
+ int_to_enum, ['RowStatus', ?active]),
+ ?line {value, ?destroy} = rpc:call(MaNode, snmp,
+ enum_to_int, ['RowStatus', destroy]),
+ ?line false = rpc:call(MaNode, snmp,
+ enum_to_int, ['RowStatus', xxxdestroy]),
+ ?line false = rpc:call(MaNode, snmp,
+ enum_to_int, ['xxRowStatus', destroy]),
+ ?line false = rpc:call(MaNode, snmp, int_to_enum, ['RowStatus', 25]),
+ ?line false = rpc:call(MaNode, snmp, int_to_enum, ['xxRowStatus', 1]),
+ ?line case snmp:date_and_time() of
+ List when list(List), length(List) == 8 -> ok;
+ List when list(List), length(List) == 11 -> ok
+ end.
+
+%% Req. Klas3
+api_test2() ->
+ g([[fname3,0]]),
+ ?line expect(1, [{[fname3,0], "ok"}]),
+ g([[fname4,0]]),
+ ?line expect(2, [{[fname4,0], 1}]).
+
+api_test3() ->
+ g([[fname3,0]]),
+ ?line expect(1, [{[fname3,0], "ok"}]).
+
+
+unreg_test() ->
+ gn([[?v1_2(sysServices, sysORLastChange),0]]),
+ ?line expect(1, [{[snmpInPkts, 0], any}]).
+
+load_test() ->
+ gn([[?v1_2(sysServices, sysORLastChange),0]]),
+ ?line expect(1, [{[fname,0], ""}]).
+
+%% Req. Klas1
+load_test_sa() ->
+ gn([[?v1_2(sysServices,sysORLastChange), 0]]),
+ ?line expect(1, [{[fname,0], any}]).
+
+%% Req. system group, Klas1, OLD-SNMPEA-MIB
+do_mul_get() ->
+ Key1c3 = [intCommunityEntry,[3],get(mip),is("public")],
+ Key1c4 = [intCommunityEntry,[4],get(mip),is("public")],
+ s([{[fname,0], s, "test set"}]),
+ ?line expect(3, [{[fname,0], "test set"}]),
+ g([[sysDescr,0], Key1c4, [fname,0],Key1c3,
+ [sysName,0]]),
+ ?line expect(1, [{[sysDescr,0], "Erlang SNMP agent"},
+ {Key1c4, 2},
+ {[fname,0], "test set"},
+ {Key1c3, 2},
+ {[sysName,0], "test"}]),
+ g([[1,3,7,1], Key1c4, [sysDescr,0], [1,3,7,2], Key1c3, [sysDescr,0]]),
+ ?line ?v1_2(expect(2, noSuchName, [1,4], any),
+ expect(2, [{[1,3,7,1], noSuchObject},
+ {Key1c4, 2},
+ {[sysDescr,0], "Erlang SNMP agent"},
+ {[1,3,7,2], noSuchObject},
+ {Key1c3, 2},
+ {[sysDescr,0], "Erlang SNMP agent"}])).
+
+%% Req. v1, system group, Klas1, OLD-SNMPEA-MIB, *ej* Klas3.
+do_mul_get_err() ->
+ Key1c3 = [intCommunityEntry,[3],get(mip),is("public")],
+ Key1c4 = [intCommunityEntry,[4],get(mip),is("public")],
+ s([{[fname,0], s, "test set"}]),
+ ?line expect(3, [{[fname,0], "test set"}]),
+ g([[sysDescr,0],Key1c4,[fname,0], Key1c3, [sysName,2]]),
+ ?line ?v1_2(expect(1, noSuchName, 5, any),
+ expect(1, [{[sysDescr,0], "Erlang SNMP agent"},
+ {Key1c4, 2},
+ {[fname,0], "test set"},
+ {Key1c3, 2},
+ {[sysName,2], noSuchInstance}])),
+ g([[sysDescr,0],Key1c4,[fname3,0], Key1c3, [sysName,1]]),
+ ?line ?v1_2(expect(1, noSuchName, [3,5], any),
+ expect(1, [{[sysDescr,0], "Erlang SNMP agent"},
+ {Key1c4, 2},
+ {[fname3,0], noSuchObject},
+ {Key1c3, 2},
+ {[sysName,1], noSuchInstance}])).
+
+
+%% Req. system group, Klas1, OLD-SNMPEA-MIB
+do_mul_next() ->
+ Key1c3s = [intCommunityEntry,[3],get(mip),is("publi")],
+ Key1c4s = [intCommunityEntry,[4],get(mip),is("publi")],
+ Key1c3 = [intCommunityEntry,[3],get(mip),is("public")],
+ Key1c4 = [intCommunityEntry,[4],get(mip),is("public")],
+ s([{[fname,0], s, "test set"}]),
+ ?line expect(3, [{[fname,0], "test set"}]),
+ gn([[sysDescr], Key1c4s, [fname],Key1c3s,[sysName]]),
+ ?line expect(1, [{[sysDescr,0], "Erlang SNMP agent"},
+ {Key1c4, 2}, {[fname,0], "test set"},
+ {Key1c3, 2}, {[sysName,0], "test"}]).
+
+%% Req. system group, Klas1, OLD-SNMPEA-MIB
+do_mul_next_err() ->
+ Key1c3s = [intCommunityEntry,[3],get(mip),is("publi")],
+ Key1c4s = [intCommunityEntry,[4],get(mip),is("publi")],
+ Key1c3 = [intCommunityEntry,[3],get(mip),is("public")],
+ Key1c4 = [intCommunityEntry,[4],get(mip),is("public")],
+ s([{[fname,0], s, "test set"}]),
+ ?line expect(3, [{[fname,0], "test set"}]),
+ gn([[sysDescr], Key1c4s, [1,3,6,999], [fname],[1,3,90], Key1c3s,[sysName]]),
+ ?line ?v1_2(expect(1, noSuchName, [3,5], any),
+ expect(1, [{[sysDescr,0], "Erlang SNMP agent"},
+ {Key1c4, 2},
+ {[1,3,6,999], endOfMibView},
+ {[fname,0], "test set"},
+ {[1,3,90], endOfMibView},
+ {Key1c3, 2},
+ {[sysName,0], "test"}])).
+
+
+%% Req. system group, Klas1, OLD-SNMPEA-MIB
+do_mul_set() ->
+ p("Adding one row in subagent table, and one in master table"),
+ NewKeyc3 = [intCommunityEntry,[3],get(mip),is("test")],
+ NewKeyc4 = [intCommunityEntry,[4],get(mip),is("test")],
+ NewKeyc5 = [intCommunityEntry,[5],get(mip),is("test")],
+ s([{[friendsEntry, [2, 3]], "kompis3"},
+ {NewKeyc3, 2},
+ {[sysLocation,0], "new_value"},
+ {NewKeyc5, ?createAndGo},
+ {NewKeyc4, 2},
+ {[friendsEntry, [3, 3]], ?createAndGo}]),
+ ?line expect(1, [{[friendsEntry, [2, 3]], "kompis3"},
+ {NewKeyc3, 2},
+ {[sysLocation,0], "new_value"},
+ {NewKeyc5, ?createAndGo},
+ {NewKeyc4, 2},
+ {[friendsEntry, [3, 3]], ?createAndGo}]),
+ g([[friendsEntry, [2, 3]],
+ [sysLocation,0],
+ [friendsEntry, [3, 3]]]),
+ ?line expect(2, [{[friendsEntry, [2, 3]], "kompis3"},
+ {[sysLocation,0], "new_value"},
+ {[friendsEntry, [3, 3]], ?active}]),
+ g([NewKeyc4]),
+ ?line expect(3, [{NewKeyc4, 2}]),
+ s([{[friendsEntry, [3, 3]], ?destroy},
+ {NewKeyc5, ?destroy}]),
+ ?line expect(4, [{[friendsEntry, [3, 3]], ?destroy},
+ {NewKeyc5, ?destroy}]).
+
+%% Req. system group, Klas1, OLD-SNMPEA-MIB
+do_mul_set_err() ->
+ NewKeyc3 = [intCommunityEntry,[3],get(mip),is("test")],
+ NewKeyc4 = [intCommunityEntry,[4],get(mip),is("test")],
+ NewKeyc5 = [intCommunityEntry,[5],get(mip),is("test")],
+ p("Adding one row in subagent table, and one in master table"),
+ s([{[friendsEntry, [2, 3]], s, "kompis3"},
+ {NewKeyc3, 2},
+ {[sysUpTime,0], 45}, % sysUpTime (readOnly)
+ {NewKeyc5, ?createAndGo},
+ {NewKeyc4, 2},
+ {[friendsEntry, [3, 3]], ?createAndGo}]),
+ ?line expect(1, ?v1_2(noSuchName, notWritable), 3, any),
+ g([[friendsEntry, [2, 3]]]),
+ ?line ?v1_2(expect(2, noSuchName, 1, any),
+ expect(2, [{[friendsEntry, [2,3]], noSuchInstance}])),
+ g([NewKeyc4]),
+ ?line ?v1_2(expect(3, noSuchName, 1, any),
+ expect(3, [{NewKeyc4, noSuchInstance}])).
+
+%% Req. SA-MIB
+sa_mib() ->
+ g([[sa, [2,0]]]),
+ ?line expect(1, [{[sa, [2,0]], 3}]),
+ s([{[sa, [1,0]], s, "sa_test"}]),
+ ?line expect(2, [{[sa, [1,0]], "sa_test"}]).
+
+ma_trap1(MA) ->
+ snmpa:send_trap(MA, testTrap2, "standard trap"),
+ ?line expect(1, trap, [system], 6, 1, [{[system, [4,0]],
+ "{mbj,eklas}@erlang.ericsson.se"}]),
+ snmpa:send_trap(MA, testTrap1, "standard trap"),
+ ?line expect(2, trap, [1,2,3] , 1, 0, [{[system, [4,0]],
+ "{mbj,eklas}@erlang.ericsson.se"}]).
+
+ma_trap2(MA) ->
+ snmpa:send_trap(MA,testTrap2,"standard trap",[{sysContact,"pelle"}]),
+ ?line expect(3, trap, [system], 6, 1, [{[system, [4,0]], "pelle"}]).
+
+ma_v2_2_v1_trap(MA) ->
+ snmpa:send_trap(MA,testTrapv22,"standard trap",[{sysContact,"pelle"}]),
+ ?line expect(3, trap, [system], 6, 1, [{[system, [4,0]], "pelle"}]).
+
+ma_v2_2_v1_trap2(MA) ->
+ snmpa:send_trap(MA,linkUp,"standard trap",[{ifIndex, [1], 1},
+ {ifAdminStatus, [1], 1},
+ {ifOperStatus, [1], 2}]),
+ ?line expect(3, trap, [1,2,3], 3, 0, [{[ifIndex, 1], 1},
+ {[ifAdminStatus, 1], 1},
+ {[ifOperStatus, 1], 2}]).
+
+sa_trap1(SA) ->
+ snmpa:send_trap(SA, saTrap, "standard trap"),
+ ?line expect(4, trap, [ericsson], 6, 1, [{[system, [4,0]],
+ "{mbj,eklas}@erlang.ericsson.se"},
+ {[sa, [1,0]], "sa_test"}]).
+
+sa_trap2(SA) ->
+ snmpa:send_trap(SA, saTrap, "standard trap",[{sysContact,"pelle"}]),
+ ?line expect(5, trap, [ericsson], 6, 1, [{[system, [4,0]],
+ "pelle"},
+ {[sa, [1,0]], "sa_test"}]).
+
+sa_trap3(SA) ->
+ snmpa:send_trap(SA, saTrap2, "standard trap",
+ [{intViewSubtree, [4], [1,2,3,4]}]),
+ ?line expect(6, trap, [ericsson], 6, 2, [{[system, [4,0]],
+ "{mbj,eklas}@erlang.ericsson.se"},
+ {[sa, [1,0]], "sa_test"},
+ {[intViewSubtree,4],[1,2,3,4]}]).
+
+ma_v2_trap1(MA) ->
+ ?DBG("ma_v2_traps -> entry with MA = ~p => "
+ "send standard trap: testTrapv22",[MA]),
+ snmpa:send_trap(MA, testTrapv22, "standard trap"),
+ ?line expect(1, v2trap, [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?system ++ [0,1]}]),
+ ?DBG("ma_v2_traps -> send standard trap: testTrapv21",[]),
+ snmpa:send_trap(MA, testTrapv21, "standard trap"),
+ ?line expect(2, v2trap, [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?snmp ++ [1]}]).
+
+ma_v2_trap2(MA) ->
+ snmpa:send_trap(MA,testTrapv22,"standard trap",[{sysContact,"pelle"}]),
+ ?line expect(3, v2trap, [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?system ++ [0,1]},
+ {[system, [4,0]], "pelle"}]).
+
+%% Note: This test case takes a while... actually a couple of minutes.
+ma_v2_inform1(MA) ->
+ ?DBG("ma_v2_inform -> entry with MA = ~p => "
+ "send notification: testTrapv22",[MA]),
+ ?line snmpa:send_notification(MA, testTrapv22, no_receiver, "standard inform", []),
+ ?line expect(1, {inform, true},
+ [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?system ++ [0,1]}]),
+
+ ?DBG("ma_v2_inform -> send notification: testTrapv22",[]),
+ snmpa:send_notification(MA, testTrapv22, {tag1, self()},
+ "standard inform", []),
+ ?line expect(1, {inform, true},
+ [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?system ++ [0,1]}]),
+ ?DBG("ma_v2_inform -> await targets",[]),
+ receive
+ {snmp_targets, tag1, [_]} ->
+ ok;
+ {snmp_targets, tag1, Addrs1} ->
+ ?line ?FAIL({bad_addrs, Addrs1})
+ after
+ 5000 ->
+ ?ERR("ma_v2_inform1 -> awaiting snmp_targets(tag1) timeout",[]),
+ ?line ?FAIL(nothing_at_all)
+ end,
+ ?DBG("ma_v2_inform -> await notification",[]),
+ receive
+ {snmp_notification, tag1, {got_response, _}} ->
+ ok;
+ {snmp_notification, tag1, {no_response, _}} ->
+ ?line ?FAIL(no_response)
+ after
+ 20000 ->
+ ?ERR("ma_v2_inform1 -> "
+ "awaiting snmp_notification(tag1) timeout",[]),
+ ?line ?FAIL(nothing_at_all)
+ end,
+
+ %%
+ %% -- The rest is possibly erroneous...
+ %%
+
+ ?DBG("ma_v2_inform -> send notification: testTrapv22",[]),
+ snmpa:send_notification(MA, testTrapv22, {tag2, self()},
+ "standard inform", []),
+ ?line expect(2, {inform, false},
+ [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?system ++ [0,1]}]),
+ ?DBG("ma_v2_inform -> await targets",[]),
+ receive
+ {snmp_targets, tag2, [_]} ->
+ ok;
+ {snmp_targets, tag2, Addrs2} ->
+ ?ERR("ma_v2_inform1 -> awaiting snmp_targets(tag2) timeout",[]),
+ ?line ?FAIL({bad_addrs, Addrs2})
+ after
+ 5000 ->
+ ?line ?FAIL(nothing_at_all)
+ end,
+ ?DBG("ma_v2_inform -> await notification",[]),
+ receive
+ {snmp_notification, tag2, {got_response, _}} ->
+ ?line ?FAIL(got_response);
+ {snmp_notification, tag2, {no_response, _}} ->
+ ok
+ after
+ 240000 ->
+ ?ERR("ma_v2_inform1 -> "
+ "awaiting snmp_notification(tag2) timeout",[]),
+ ?line ?FAIL(nothing_at_all)
+ end.
+
+
+ma_v1_2_v2_trap(MA) ->
+ snmpa:send_trap(MA,linkDown,"standard trap",[{ifIndex, [1], 1}]),
+ ?line expect(2, v2trap, [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?snmpTraps ++ [3]},
+ {[ifIndex, 1], 1},
+ {[snmpTrapEnterprise, 0], [1,2,3]}]).
+
+
+ma_v1_2_v2_trap2(MA) ->
+ snmpa:send_trap(MA,testTrap2,"standard trap",[{sysContact,"pelle"}]),
+ ?line expect(3, v2trap, [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?system ++ [0,1]},
+ {[system, [4,0]], "pelle"},
+ {[snmpTrapEnterprise, 0], ?system}]).
+
+
+sa_v1_2_v2_trap1(SA) ->
+ snmpa:send_trap(SA, saTrap, "standard trap"),
+ ?line expect(4, v2trap, [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?ericsson ++ [0, 1]},
+ {[system, [4,0]],
+ "{mbj,eklas}@erlang.ericsson.se"},
+ {[sa, [1,0]], "sa_test"},
+ {[snmpTrapEnterprise, 0], ?ericsson}]).
+
+sa_v1_2_v2_trap2(SA) ->
+ snmpa:send_trap(SA, saTrap, "standard trap",[{sysContact,"pelle"}]),
+ ?line expect(4, v2trap, [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?ericsson ++ [0, 1]},
+ {[system, [4,0]], "pelle"},
+ {[sa, [1,0]], "sa_test"},
+ {[snmpTrapEnterprise, 0], ?ericsson}]).
+
+
+sa_v1_2_v2_trap3(SA) ->
+ snmpa:send_trap(SA, saTrap2, "standard trap",
+ [{intViewSubtree, [4], [1,2,3,4]}]),
+ ?line expect(4, v2trap, [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?ericsson ++ [0, 2]},
+ {[system, [4,0]],
+ "{mbj,eklas}@erlang.ericsson.se"},
+ {[sa, [1,0]], "sa_test"},
+ {[intViewSubtree,4],[1,2,3,4]},
+ {[snmpTrapEnterprise, 0], ?ericsson}]).
+
+
+%% Req. SA-MIB, OLD-SNMPEA-MIB
+sa_errs_bad_value() ->
+ NewKeyc3 = [intCommunityEntry,[3],get(mip),is("test")],
+ NewKeyc4 = [intCommunityEntry,[4],get(mip),is("test")],
+ NewKeyc5 = [intCommunityEntry,[5],get(mip),is("test")],
+ s([{NewKeyc3, 2},
+ {[sa, [2,0]], 5}, % badValue (i is_set_ok)
+ {NewKeyc5, ?createAndGo},
+ {NewKeyc4, 2}]),
+ ?line expect(1, badValue, 2, any),
+ s([{NewKeyc3, 2},
+ {[sa, [2,0]], 6}, % wrongValue (i is_set_ok)
+ {NewKeyc5, ?createAndGo},
+ {NewKeyc4, 2}]),
+ ?line expect(1, ?v1_2(badValue, wrongValue), 2, any),
+ g([NewKeyc4]),
+ ?line ?v1_2(expect(2, noSuchName, 1, any),
+ expect(2, [{NewKeyc4, noSuchInstance}])).
+
+%% Req. SA-MIB, OLD-SNMPEA-MIB
+sa_errs_gen_err() ->
+ NewKeyc3 = [intCommunityEntry,[3],get(mip),is("test")],
+ NewKeyc4 = [intCommunityEntry,[4],get(mip),is("test")],
+ NewKeyc5 = [intCommunityEntry,[5],get(mip),is("test")],
+ s([{NewKeyc3, 2},{NewKeyc4, 2},
+ {NewKeyc5, ?createAndGo}, {[sa, [3,0]], 5}]),
+ ?line expect(1, genErr, 4, any),
+% The row might have been added; we don't know.
+% (as a matter of fact we do - it is added, because the agent
+% first sets its own vars, and then th SAs. Lets destroy it.
+ s([{NewKeyc5, ?destroy}]),
+ ?line expect(2, [{NewKeyc5, ?destroy}]).
+
+%% Req. SA-MIB, OLD-SNMPEA-MIB
+sa_too_big() ->
+ g([[sa, [4,0]]]),
+ ?line expect(1, tooBig).
+
+%% Req. Klas1, system group, snmp group (v1/v2)
+next_across_sa() ->
+ gn([[sysDescr],[klas1,5]]),
+ ?line expect(1, [{[sysDescr,0], "Erlang SNMP agent"},
+ {[snmpInPkts, 0], any}]).
+
+%% snmp_test_mgr:s([{[fStatus3, 1], 4}, {[fname3,0], "ok"}]). -> noError
+%% snmp_test_mgr:s([{[fStatus3, 1], 4}, {[fname3,0], "hoj"}]). -> {badValue, 2}
+%% snmp_test_mgr:s([{[fStatus3, 3], 4}, {[fname3,0], "hoj"}]). -> {genErr, 1}
+%% snmp_test_mgr:s([{[fStatus3, 4], 4}, {[fname3,0], "ok"}]). -> {genErr, 1}
+%% snmp_test_mgr:s([{[fStatus3, 4], 4}, {[fname3,0], "ufail"}]). -> {genErr, 1}
+%% snmp_test_mgr:s([{[fStatus3, 1], 4}, {[fname3,0], "xfail"}]). -> {genErr, 2}
+%% Req. Klas3, Klas4
+undo_test() ->
+ s([{[fStatus3, 1], 4}, {[fname3,0], "ok"}]),
+ ?line expect(1, [{[fStatus3, 1], 4}, {[fname3,0], "ok"}]),
+ s([{[fStatus3, 1], 4}, {[fname3,0], "hoj"}]),
+ ?line expect(2, ?v1_2(badValue, inconsistentValue), 2, any),
+ s([{[fStatus3, 3], 4}, {[fname3,0], "hoj"}]),
+ ?line expect(3, ?v1_2(genErr, undoFailed), 1, any),
+ s([{[fStatus3, 4], 4}, {[fname3,0], "ok"}]),
+ ?line expect(4, ?v1_2(genErr, commitFailed), 1, any),
+% unfortunatly we don't know if we'll get undoFailed or commitFailed.
+% it depends on which order the agent traverses the varbind list.
+% s([{[fStatus3, 4], 4}, {[fname3,0], "ufail"}]),
+% ?line expect(5, ?v1_2(genErr, undoFailed), 1, any),
+ s([{[fStatus3, 1], 4}, {[fname3,0], "xfail"}]),
+ ?line expect(6, genErr, 2, any).
+
+%% Req. Klas3, Klas4
+bad_return() ->
+ g([[fStatus4,4],
+ [fName4,4]]),
+ ?line expect(4, genErr, 2, any),
+ g([[fStatus4,5],
+ [fName4,5]]),
+ ?line expect(5, genErr, 1, any),
+ g([[fStatus4,6],
+ [fName4,6]]),
+ ?line expect(6, genErr, 2, any),
+ gn([[fStatus4,7],
+ [fName4,7]]),
+ ?line expect(7, genErr, 2, any),
+ gn([[fStatus4,8],
+ [fName4,8]]),
+ ?line expect(8, genErr, 1, any),
+ gn([[fStatus4,9],
+ [fName4,9]]),
+ ?line expect(9, genErr, 2, any).
+
+
+%%%-----------------------------------------------------------------
+%%% Test the implementation of standard mibs.
+%%% We should *at least* try to GET all variables, just to make
+%%% sure the instrumentation functions work.
+%%% Note that many of the functions in the standard mib is
+%%% already tested by the normal tests.
+%%%-----------------------------------------------------------------
+standard_mibs(suite) ->
+ [snmp_standard_mib, snmp_community_mib,
+ snmp_framework_mib,
+ snmp_target_mib, snmp_notification_mib,
+ snmp_view_based_acm_mib].
+
+standard_mibs_2(suite) ->
+ [snmpv2_mib_2, snmp_community_mib_2,
+ snmp_framework_mib_2,
+ snmp_target_mib_2, snmp_notification_mib_2,
+ snmp_view_based_acm_mib_2].
+
+standard_mibs_3(suite) ->
+ [snmpv2_mib_3,snmp_framework_mib_3, snmp_mpd_mib_3,
+ snmp_target_mib_3, snmp_notification_mib_3,
+ snmp_view_based_acm_mib_3, snmp_user_based_sm_mib_3].
+
+%%-----------------------------------------------------------------
+%% For this test, the agent is configured for v1.
+%% o Test the counters and control objects in SNMP-STANDARD-MIB
+%%-----------------------------------------------------------------
+snmp_standard_mib(suite) -> [];
+snmp_standard_mib(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?DBG("snmp_standard_mib -> std_mib_init", []),
+ try_test(std_mib_init),
+
+ ?DBG("snmp_standard_mib -> std_mib_a", []),
+ InBadVsns = try_test(std_mib_a),
+ put(vsn, v2),
+ ?DBG("snmp_standard_mib -> std_mib_read", []),
+ try_test(std_mib_read),
+ put(vsn, v1),
+
+ ?DBG("snmp_standard_mib -> std_mib_b (~w)", [InBadVsns]),
+ Bad = try_test(std_mib_b, [InBadVsns]),
+ ?DBG("snmp_standard_mib -> std_mib_read (community: 'bad community')", []),
+ try_test(std_mib_read, [], [{community, "bad community"}]),
+ ?DBG("snmp_standard_mib -> std_mib_write (community: 'public')", []),
+ try_test(std_mib_write, [], [{community, "public"}]),
+ ?DBG("snmp_standard_mib -> std_mib_asn_err", []),
+ try_test(std_mib_asn_err),
+ ?DBG("snmp_standard_mib -> std_mib_c (~w)", [Bad]),
+ try_test(std_mib_c, [Bad]),
+ ?DBG("snmp_standard_mib -> std_mib_a", []),
+ try_test(standard_mib_a),
+
+ ?DBG("snmp_standard_mib -> std_mib_finish", []),
+ try_test(std_mib_finish),
+ ?DBG("snmp_standard_mib -> std_mib_test_finish", []),
+ try_test(standard_mib_test_finish, [], [{community, "bad community"}]).
+
+%% Req. SNMP-STANDARD-MIB
+standard_mib_a() ->
+ ?line [OutPkts] = get_req(2, [[snmpOutPkts,0]]),
+ ?line [OutPkts2] = get_req(3, [[snmpOutPkts,0]]),
+ ?line OutPkts2 = OutPkts + 1,
+ %% There are some more counters we could test here, but it's not that
+ %% important, since they are removed from SNMPv2-MIB.
+ ok.
+
+%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB
+std_mib_init() ->
+ %% disable authentication failure traps. (otherwise w'd get many of
+ %% them - this is also a test to see that it works).
+ s([{[snmpEnableAuthenTraps,0], 2}]),
+ ?line expect(1, [{[snmpEnableAuthenTraps, 0], 2}]).
+
+%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB
+std_mib_finish() ->
+ %% enable again
+ s([{[snmpEnableAuthenTraps,0], 1}]),
+ ?line expect(1, [{[snmpEnableAuthenTraps, 0], 1}]).
+
+%% Req. SNMP-STANDARD-MIB
+standard_mib_test_finish() ->
+ %% force a authenticationFailure
+ std_mib_write(),
+ %% check that we got a trap
+ ?line expect(2, trap, [1,2,3], 4, 0, []).
+
+%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB
+std_mib_read() ->
+ ?DBG("std_mib_read -> entry", []),
+ g([[sysUpTime,0]]), % try a bad <something>; msg dropped, no reply
+ ?DBG("std_mib_read -> await timeout (i.e. no reply)", []),
+ ?line expect(1, timeout). % make sure we don't get a trap!
+
+
+%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB
+std_mib_write() ->
+ ?DBG("std_mib_write -> entry", []),
+ s([{[sysLocation, 0], "new_value"}]).
+
+%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB
+std_mib_asn_err() ->
+ snmp_test_mgr:send_bytes([48,99,67,12,0,0,0,0,0,0,5]).
+
+%%-----------------------------------------------------------------
+%% For this test, the agent is configured for v2 and v3.
+%% o Test the counters and control objects in SNMPv2-MIB
+%%-----------------------------------------------------------------
+snmpv2_mib_2(suite) -> [];
+snmpv2_mib_2(Config) when list(Config) ->
+ ?LOG("snmpv2_mib_2 -> start",[]),
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ ?DBG("snmpv2_mib_2 -> standard mib init",[]),
+ try_test(std_mib_init),
+
+ ?DBG("snmpv2_mib_2 -> get number of (so far) bad versions",[]),
+ InBadVsns = try_test(std_mib_a),
+
+ ?DBG("snmpv2_mib_2 -> make a bad version read",[]),
+ put(vsn, v1),
+ try_test(std_mib_read),
+
+ ?DBG("snmpv2_mib_2 -> bad version read",[]),
+ put(vsn, v2),
+ Bad = try_test(std_mib_b, [InBadVsns]),
+
+ ?DBG("snmpv2_mib_2 -> read with bad community",[]),
+ try_test(std_mib_read, [], [{community, "bad community"}]),
+
+ ?DBG("snmpv2_mib_2 -> write with public community",[]),
+ try_test(std_mib_write, [], [{community, "public"}]),
+
+ ?DBG("snmpv2_mib_2 -> asn err",[]),
+ try_test(std_mib_asn_err),
+
+ ?DBG("snmpv2_mib_2 -> check counters",[]),
+ try_test(std_mib_c, [Bad]),
+
+ ?DBG("snmpv2_mib_2 -> get som counters",[]),
+ try_test(snmpv2_mib_a),
+
+ ?DBG("snmpv2_mib_2 -> enable auth traps, and await some",[]),
+ try_test(std_mib_finish),
+
+ ?DBG("snmpv2_mib_2 -> force auth failure, and await trap, "
+ "then disable auth traps",[]),
+ try_test(snmpv2_mib_test_finish, [], [{community, "bad community"}]),
+
+ ?LOG("snmpv2_mib_2 -> done",[]).
+
+%% Req. SNMPv2-MIB
+snmpv2_mib_3(suite) -> [];
+snmpv2_mib_3(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ InBadVsns = try_test(std_mib_a),
+ put(vsn, v1),
+ try_test(std_mib_read),
+ put(vsn, v3),
+ _Bad = try_test(std_mib_b, [InBadVsns]),
+ try_test(snmpv2_mib_a),
+
+ try_test(std_mib_finish).
+
+-define(authenticationFailure, [1,3,6,1,6,3,1,1,5,5]).
+
+%% Req. SNMPv2-MIB
+snmpv2_mib_test_finish() ->
+ %% force a authenticationFailure
+ ?DBG("ma_v2_inform -> write to std mib",[]),
+ std_mib_write(),
+
+ %% check that we got a trap
+ ?DBG("ma_v2_inform -> await trap",[]),
+ ?line expect(2, v2trap, [{[sysUpTime,0], any},
+ {[snmpTrapOID,0], ?authenticationFailure}]),
+
+ %% and the the inform
+ ?DBG("ma_v2_inform -> await inform",[]),
+ ?line expect(2, {inform,true}, [{[sysUpTime,0], any},
+ {[snmpTrapOID,0],?authenticationFailure}]).
+
+%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB
+std_mib_a() ->
+ ?line [InPkts] = get_req(2, [[snmpInPkts,0]]),
+ ?line [InPkts2] = get_req(3, [[snmpInPkts,0]]),
+ ?line InPkts2 = InPkts + 1,
+
+ ?line [InBadVsns] = get_req(4, [[snmpInBadVersions,0]]),
+ InBadVsns.
+
+%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB
+std_mib_b(InBadVsns) ->
+ ?line [InBadVsns2] = get_req(1, [[snmpInBadVersions,0]]),
+ ?line InBadVsns2 = InBadVsns + 1,
+ ?line [InPkts] = get_req(2, [[snmpInPkts,0]]),
+ ?line [InPkts2] = get_req(3, [[snmpInPkts,0]]),
+ ?line InPkts2 = InPkts + 1,
+ ?line [InBadCommunityNames, InBadCommunityUses, InASNErrs] =
+ get_req(4, [[snmpInBadCommunityNames,0],
+ [snmpInBadCommunityUses,0],
+ [snmpInASNParseErrs, 0]]),
+ {InBadCommunityNames, InBadCommunityUses, InASNErrs}.
+
+%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB
+std_mib_c({InBadCommunityNames, InBadCommunityUses, InASNErrs}) ->
+ ?line [InBadCommunityNames2, InBadCommunityUses2, InASNErrs2] =
+ get_req(1, [[snmpInBadCommunityNames,0],
+ [snmpInBadCommunityUses,0],
+ [snmpInASNParseErrs, 0]]),
+ ?line InBadCommunityNames2 = InBadCommunityNames + 1,
+ ?line InBadCommunityUses2 = InBadCommunityUses + 1,
+ ?line InASNErrs2 = InASNErrs + 1.
+
+%% Req. SNMPv2-MIB
+snmpv2_mib_a() ->
+ ?line [SetSerial] = get_req(2, [[snmpSetSerialNo,0]]),
+ s([{[snmpSetSerialNo,0], SetSerial}, {[sysLocation, 0], "val2"}]),
+ ?line expect(3, [{[snmpSetSerialNo,0], SetSerial},
+ {[sysLocation, 0], "val2"}]),
+ s([{[sysLocation, 0], "val3"}, {[snmpSetSerialNo,0], SetSerial}]),
+ ?line expect(4, inconsistentValue, 2,
+ [{[sysLocation, 0], "val3"},
+ {[snmpSetSerialNo,0], SetSerial}]),
+ ?line ["val2"] = get_req(5, [[sysLocation,0]]).
+
+
+%%-----------------------------------------------------------------
+%% o Bad community uses/name is tested already
+%% in SNMPv2-MIB and STANDARD-MIB.
+%% o Test add/deletion of rows.
+%%-----------------------------------------------------------------
+snmp_community_mib(suite) -> [];
+snmp_community_mib(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?line load_master_std("SNMP-COMMUNITY-MIB"),
+ try_test(snmp_community_mib),
+ ?line unload_master("SNMP-COMMUNITY-MIB").
+
+snmp_community_mib_2(X) -> snmp_community_mib(X).
+
+%% Req. SNMP-COMMUNITY-MIB
+snmp_community_mib() ->
+ ?INF("NOT YET IMPLEMENTED", []),
+ nyi.
+
+%%-----------------------------------------------------------------
+%% o Test engine boots / time
+%%-----------------------------------------------------------------
+snmp_framework_mib(suite) -> [];
+snmp_framework_mib(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?line load_master_std("SNMP-FRAMEWORK-MIB"),
+ try_test(snmp_framework_mib),
+ ?line unload_master("SNMP-FRAMEWORK-MIB").
+
+snmp_framework_mib_2(X) -> snmp_framework_mib(X).
+
+snmp_framework_mib_3(suite) -> [];
+snmp_framework_mib_3(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ try_test(snmp_framework_mib).
+
+
+%% Req. SNMP-FRAMEWORK-MIB
+snmp_framework_mib() ->
+ ?line ["agentEngine"] = get_req(1, [[snmpEngineID,0]]),
+ ?line [EngineTime] = get_req(2, [[snmpEngineTime,0]]),
+ sleep(5000),
+ ?line [EngineTime2] = get_req(3, [[snmpEngineTime,0]]),
+ if
+ EngineTime+7 < EngineTime2 ->
+ ?line ?FAIL({too_large_diff, EngineTime, EngineTime2});
+ EngineTime+4 > EngineTime2 ->
+ ?line ?FAIL({too_large_diff, EngineTime, EngineTime2});
+ true -> ok
+ end,
+ ?line case get_req(4, [[snmpEngineBoots,0]]) of
+ [Boots] when integer(Boots) -> ok;
+ Else -> ?FAIL(Else)
+ end,
+ ok.
+
+%%-----------------------------------------------------------------
+%% o Test the counters
+%%-----------------------------------------------------------------
+snmp_mpd_mib_3(suite) -> [];
+snmp_mpd_mib_3(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ UnknownPDUHs = try_test(snmp_mpd_mib_a),
+ try_test(snmp_mpd_mib_b, [], [{context_engine_id, "bad engine"}]),
+ try_test(snmp_mpd_mib_c, [UnknownPDUHs]).
+
+
+%% Req. SNMP-MPD-MIB
+snmp_mpd_mib_a() ->
+ ?line [UnknownSecs, InvalidMsgs] =
+ get_req(1, [[snmpUnknownSecurityModels,0],
+ [snmpInvalidMsgs,0]]),
+ Pdu = #pdu{type = 'get-request',
+ request_id = 23,
+ error_status = noError,
+ error_index = 0,
+ varbinds = []},
+ SPdu = #scopedPdu{contextEngineID = "agentEngine",
+ contextName = "",
+ data = Pdu},
+ ?line SPDUBytes = snmp_pdus:enc_scoped_pdu(SPdu),
+ V3Hdr1 = #v3_hdr{msgID = 21,
+ msgMaxSize = 484,
+ msgFlags = [7],
+ msgSecurityModel = 23, % bad sec model
+ msgSecurityParameters = []},
+ V3Hdr2 = #v3_hdr{msgID = 21,
+ msgMaxSize = 484,
+ msgFlags = [6], % bad flag combination
+ msgSecurityModel = 3,
+ msgSecurityParameters = []},
+ Message1 = #message{version = 'version-3', vsn_hdr = V3Hdr1,
+ data = SPDUBytes},
+ Message2 = #message{version = 'version-3', vsn_hdr = V3Hdr2,
+ data = SPDUBytes},
+ ?line MsgBytes1 = snmp_pdus:enc_message_only(Message1),
+ ?line MsgBytes2 = snmp_pdus:enc_message_only(Message2),
+ snmp_test_mgr:send_bytes(MsgBytes1),
+ snmp_test_mgr:send_bytes(MsgBytes2),
+
+ ?line [UnknownSecs2, InvalidMsgs2, UnknownPDUHs] =
+ get_req(1, [[snmpUnknownSecurityModels,0],
+ [snmpInvalidMsgs,0],
+ [snmpUnknownPDUHandlers, 0]]),
+ ?line UnknownSecs2 = UnknownSecs + 1,
+ ?line InvalidMsgs2 = InvalidMsgs + 1,
+ UnknownPDUHs.
+
+-define(snmpUnknownPDUHandlers_instance, [1,3,6,1,6,3,11,2,1,3,0]).
+snmp_mpd_mib_b() ->
+ g([[sysUpTime,0]]),
+ ?line expect(1, report, [{?snmpUnknownPDUHandlers_instance, any}]).
+
+
+snmp_mpd_mib_c(UnknownPDUHs) ->
+ ?line [UnknownPDUHs2] = get_req(1, [[snmpUnknownPDUHandlers, 0]]),
+ ?line UnknownPDUHs2 = UnknownPDUHs + 1.
+
+
+snmp_target_mib(suite) -> [];
+snmp_target_mib(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?line load_master_std("SNMP-TARGET-MIB"),
+ try_test(snmp_target_mib),
+ ?line unload_master("SNMP-TARGET-MIB").
+
+snmp_target_mib_2(X) -> snmp_target_mib(X).
+
+snmp_target_mib_3(X) -> snmp_target_mib(X).
+
+snmp_target_mib() ->
+ ?INF("NOT YET IMPLEMENTED", []),
+ nyi.
+
+snmp_notification_mib(suite) -> [];
+snmp_notification_mib(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?line load_master_std("SNMP-NOTIFICATION-MIB"),
+ try_test(snmp_notification_mib),
+ ?line unload_master("SNMP-NOTIFICATION-MIB").
+
+snmp_notification_mib_2(X) -> snmp_notification_mib(X).
+
+snmp_notification_mib_3(X) -> snmp_notification_mib(X).
+
+snmp_notification_mib() ->
+ ?INF("NOT YET IMPLEMENTED", []),
+ nyi.
+
+%%-----------------------------------------------------------------
+%% o add/delete views and try them
+%% o try boundaries
+%%-----------------------------------------------------------------
+snmp_view_based_acm_mib(suite) -> [];
+snmp_view_based_acm_mib(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"),
+ ?line load_master("Test2"),
+ snmp_view_based_acm_mib(),
+ ?line unload_master("Test2"),
+ ?line unload_master("SNMP-VIEW-BASED-ACM-MIB").
+
+snmp_view_based_acm_mib_2(X) -> snmp_view_based_acm_mib(X).
+
+snmp_view_based_acm_mib_3(X) -> snmp_view_based_acm_mib(X).
+
+snmp_view_based_acm_mib() ->
+ snmpa:verbosity(net_if,trace),
+ snmpa:verbosity(master_agent,trace),
+ ?LOG("start snmp_view_based_acm_mib test",[]),
+ %% The user "no-rights" is present in USM, and is mapped to security
+ %% name 'no-rights", which is not present in VACM.
+ %% So, we'll add rights for it, try them and delete them.
+ %% We'll give "no-rights" write access to tDescr.0 and read access
+ %% to tDescr2.0
+ %% These are the options we'll use to the mgr
+ Opts = [{user, "no-rights"}, {community, "no-rights"}],
+ %% Find the valid secmodel, and one invalid secmodel.
+ {SecMod, InvSecMod} =
+ case get(vsn) of
+ v1 -> {?SEC_V1, ?SEC_V2C};
+ v2 -> {?SEC_V2C, ?SEC_USM};
+ v3 -> {?SEC_USM, ?SEC_V1}
+ end,
+ ?DBG("assign rights for 'no-rights'",[]),
+ ?line try_test(use_no_rights, [], Opts),
+
+ %% Now, add a mapping from "no-rights" -> "no-rights-group"
+ GRow1Status = [vacmSecurityToGroupStatus,[SecMod, 9,"no-rights"]],
+ GRow1 =
+ [{[vacmGroupName, [SecMod, 9,"no-rights"]], "no-rights-group"},
+ {GRow1Status, ?createAndGo}],
+ ?DBG("set '~p'",[GRow1]),
+ ?line try_test(do_set, [GRow1]),
+
+ ?DBG("assign rights for 'no-rights'",[]),
+ ?line try_test(use_no_rights, [], Opts),
+
+ %% Create a mapping for another sec model, and make sure it dosn't
+ %% give us access
+ GRow2Status = [vacmSecurityToGroupStatus,[InvSecMod, 9,"no-rights"]],
+ GRow2 = [{[vacmGroupName, [InvSecMod, 9, "no-rights"]], "initial"},
+ {GRow2Status, ?createAndGo}],
+
+ ?DBG("set '~p'",[GRow2]),
+ ?line try_test(do_set, [GRow2]),
+
+ ?DBG("assign rights for 'no-rights'",[]),
+ ?line try_test(use_no_rights, [], Opts),
+
+ %% Delete that row
+ ?line try_test(del_row, [GRow2Status]),
+
+ RVName = "rv_name",
+ WVName = "wv_name",
+
+ %% Access row
+ ARow1Idx = [15 | "no-rights-group"] ++ [0, ?SEC_ANY, 1],
+ ARow1Status = [vacmAccessStatus, ARow1Idx],
+ ARow1 = [{[vacmAccessContextMatch, ARow1Idx], 1},
+ {[vacmAccessReadViewName, ARow1Idx], RVName},
+ {[vacmAccessWriteViewName, ARow1Idx], WVName},
+ {ARow1Status, ?createAndGo}],
+
+ %% This access row would give acces, if InvSecMod was valid.
+ ARow2Idx = [15 | "no-rights-group"] ++ [0, InvSecMod, 1],
+ ARow2Status = [vacmAccessStatus, ARow2Idx],
+ ARow2 = [{[vacmAccessContextMatch, ARow2Idx], 1},
+ {[vacmAccessReadViewName, ARow2Idx], "internet"},
+ {[vacmAccessWriteViewName, ARow2Idx], "internet"},
+ {ARow2Status, ?createAndGo}],
+
+ ?line try_test(do_set, [ARow2]),
+
+ ?line try_test(use_no_rights, [], Opts),
+
+ %% Delete that row
+ ?line try_test(del_row, [ARow2Status]),
+
+
+ %% Add valid row
+ ?line try_test(do_set, [ARow1]),
+
+ ?line try_test(use_no_rights, [], Opts),
+
+ %% Create the view family
+ VRow1Idx = mk_ln(RVName) ++ mk_ln(?xDescr), % object access
+ VRow2Idx = mk_ln(RVName) ++ mk_ln(?xDescr2 ++ [0]), % instance access
+ VRow3Idx = mk_ln(WVName) ++ mk_ln(?xDescr), % object access
+ VRow4Idx = mk_ln(WVName) ++ mk_ln(?xDescr ++ [0]), % instance access
+ VRow1Status = [vacmViewTreeFamilyStatus, VRow1Idx],
+ VRow2Status = [vacmViewTreeFamilyStatus, VRow2Idx],
+ VRow3Status = [vacmViewTreeFamilyStatus, VRow3Idx],
+ VRow4Status = [vacmViewTreeFamilyStatus, VRow4Idx],
+
+ ?line try_test(add_row, [VRow1Status]),
+ ?line try_test(add_row, [VRow2Status]),
+ ?line try_test(add_row, [VRow3Status]),
+
+ %% We're supposed to have access now...
+ ?line try_test(use_rights, [], Opts),
+
+ %% Change Row3 to Row4
+ ?line try_test(del_row, [VRow3Status]),
+ ?line try_test(add_row, [VRow4Status]),
+
+ %% We should still have access...
+ ?line try_test(use_rights, [], Opts),
+
+ %% Delete rows
+ ?line try_test(del_row, [GRow1Status]),
+
+ ?line try_test(use_no_rights, [], Opts),
+
+ %% Delete rest of rows
+ ?line try_test(del_row, [ARow1Status]),
+ ?line try_test(del_row, [VRow1Status]),
+ ?line try_test(del_row, [VRow2Status]),
+ ?line try_test(del_row, [VRow4Status]),
+
+ ?line try_test(use_no_rights, [], Opts),
+ snmpa:verbosity(master_agent,log).
+
+do_set(Row) ->
+ s(Row),
+ expect(1, Row).
+
+add_row(RowStatus) ->
+ s([{RowStatus, ?createAndGo}]),
+ expect(1, [{RowStatus, ?createAndGo}]).
+
+del_row(RowStatus) ->
+ s([{RowStatus, ?destroy}]),
+ expect(1, [{RowStatus, ?destroy}]).
+
+
+
+use_no_rights() ->
+ g([[xDescr,0]]),
+ ?v1_2_3(expect(11, noSuchName, 1, any),
+ expect(12, [{[xDescr,0], noSuchObject}]),
+ expect(13, authorizationError, 1, any)),
+ g([[xDescr2,0]]),
+ ?v1_2_3(expect(21, noSuchName, 1, any),
+ expect(22, [{[xDescr2,0], noSuchObject}]),
+ expect(23, authorizationError, 1, any)),
+ gn([[xDescr]]),
+ ?v1_2_3(expect(31, noSuchName, 1, any),
+ expect(32, [{[xDescr], endOfMibView}]),
+ expect(33, authorizationError, 1, any)),
+ s([{[xDescr,0], "tryit"}]),
+ ?v1_2_3(expect(41, noSuchName, 1, any),
+ expect(42, noAccess, 1, any),
+ expect(43, authorizationError, 1, any)).
+
+
+use_rights() ->
+ g([[xDescr,0]]),
+ expect(1, [{[xDescr,0], any}]),
+ g([[xDescr2,0]]),
+ expect(2, [{[xDescr2,0], any}]),
+ s([{[xDescr,0], "tryit"}]),
+ expect(3, noError, 0, any),
+ g([[xDescr,0]]),
+ expect(4, [{[xDescr,0], "tryit"}]).
+
+mk_ln(X) ->
+ [length(X) | X].
+
+%%-----------------------------------------------------------------
+%% o add/delete users and try them
+%% o test all secLevels
+%% o test all combinations of protocols
+%% o try bad ops; check counters
+%%-----------------------------------------------------------------
+snmp_user_based_sm_mib_3(suite) -> [];
+snmp_user_based_sm_mib_3(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ _AgentDir = ?config(agent_dir, Config),
+ ?line load_master_std("SNMP-USER-BASED-SM-MIB"),
+
+ %% The newUser used here already has VACM access.
+
+ %% Add a new user in the simplest way; just createAndGo
+ try_test(v3_sync, [[{usm_add_user1, []}]],
+ [{sec_level, authPriv}, {user, "privDES"}]),
+
+ %% Try to use the new user
+ ?line load_master("Test2"),
+ try_test(v3_sync, [[{usm_use_user, []}]],
+ [{sec_level, authPriv}, {user, "newUser"}]),
+ ?line unload_master("Test2"),
+
+ ShaKey1 = snmp:passwd2localized_key(sha, "new sha password", "agentEngine"),
+ DesKey1 = lists:sublist(ShaKey1, 16),
+
+ %% Change the new user's keys - 1
+ try_test(v3_sync, [[{usm_key_change1, [ShaKey1, DesKey1]}]],
+ [{sec_level, authPriv}, {user, "newUser"}]),
+
+ %% Try to use the new keys
+ MgrDir = ?config(mgr_dir, Config),
+ ?line rewrite_usm_mgr(MgrDir, ShaKey1, DesKey1),
+ ?line load_master("Test2"),
+ try_test(v3_sync, [[{usm_use_user, []}]],
+ [{sec_level, authPriv}, {user, "newUser"}]),
+ ?line unload_master("Test2"),
+
+ ShaKey2 = snmp:passwd2localized_key(sha, "newer password", "agentEngine"),
+ DesKey2 = lists:sublist(ShaKey2, 16),
+
+ %% Change the new user's keys - 2
+ ?line try_test(v3_sync,
+ [[{usm_key_change2, [ShaKey1, DesKey1, ShaKey2, DesKey2]}]],
+ [{sec_level, authPriv}, {user, "newUser"}]),
+
+ %% Try to use the new keys
+ reset_usm_mgr(MgrDir),
+ ?line rewrite_usm_mgr(MgrDir, ShaKey2, DesKey2),
+ ?line load_master("Test2"),
+ ?line try_test(v3_sync, [[{usm_use_user, []}]],
+ [{sec_level, authPriv}, {user, "newUser"}]),
+ ?line unload_master("Test2"),
+ reset_usm_mgr(MgrDir),
+
+ %% Change the new user's keys - 3
+ ?line try_test(v3_sync,
+ [[{usm_key_change3, [ShaKey2, DesKey2, ShaKey1, DesKey1]}]],
+ [{sec_level, authPriv}, {user, "privDES"}]),
+
+ %% Try to use the new keys
+ ?line rewrite_usm_mgr(MgrDir, ShaKey1, DesKey1),
+ ?line load_master("Test2"),
+ try_test(v3_sync, [[{usm_use_user, []}]],
+ [{sec_level, authPriv}, {user, "newUser"}]),
+ ?line unload_master("Test2"),
+ reset_usm_mgr(MgrDir),
+
+ %% Try some read requests
+ ?line try_test(v3_sync, [[{usm_read, []}]],
+ [{sec_level, authPriv}, {user, "privDES"}]),
+
+ %% Delete the new user
+ ?line try_test(v3_sync, [[{usm_del_user, []}]],
+ [{sec_level, authPriv}, {user, "privDES"}]),
+
+ %% Try some bad requests
+ ?line try_test(v3_sync, [[{usm_bad, []}]],
+ [{sec_level, authPriv}, {user, "privDES"}]),
+
+ ?line unload_master("SNMP-USER-BASED-SM-MIB").
+
+-define(usmUserSecurityName, [1,3,6,1,6,3,15,1,2,2,1,3]).
+
+usm_add_user1() ->
+ NewRowIndex = [11,"agentEngine", 7, "newUser"],
+ RowPointer = ?usmUserSecurityName ++ [11|"agentEngine"] ++ [7|"privDES"],
+ Vbs1 = [{[usmUserCloneFrom, NewRowIndex], RowPointer},
+ {[usmUserStatus, NewRowIndex], ?createAndGo}],
+ ?line s(Vbs1),
+ ?line expect(1, Vbs1),
+ ok.
+
+usm_use_user() ->
+ v2_proc().
+
+
+%% Change own public keys
+usm_key_change1(ShaKey, DesKey) ->
+ NewRowIndex = [11,"agentEngine", 7, "newUser"],
+ ShaKeyChange = snmp_user_based_sm_mib:mk_key_change(sha,
+ "passwd_shaxxxxxxxxxx",
+ ShaKey),
+ DesKeyChange = snmp_user_based_sm_mib:mk_key_change(sha,
+ "passwd_desxxxxxx",
+ DesKey),
+ Vbs1 = [{[usmUserAuthKeyChange, NewRowIndex], ShaKeyChange},
+ {[usmUserPrivKeyChange, NewRowIndex], DesKeyChange}],
+ s(Vbs1),
+ ?line expect(1, Vbs1).
+
+%% Change own private keys
+usm_key_change2(OldShaKey, OldDesKey, ShaKey, DesKey) ->
+ NewRowIndex = [11,"agentEngine", 7, "newUser"],
+ ShaKeyChange = snmp_user_based_sm_mib:mk_key_change(sha,
+ OldShaKey,
+ ShaKey),
+ DesKeyChange = snmp_user_based_sm_mib:mk_key_change(sha,
+ OldDesKey,
+ DesKey),
+ Vbs1 = [{[usmUserOwnAuthKeyChange, NewRowIndex], ShaKeyChange},
+ {[usmUserOwnPrivKeyChange, NewRowIndex], DesKeyChange}],
+ s(Vbs1),
+ ?line expect(1, Vbs1).
+
+%% Change other's public keys
+usm_key_change3(OldShaKey, OldDesKey, ShaKey, DesKey) ->
+ NewRowIndex = [11,"agentEngine", 7, "newUser"],
+ ShaKeyChange = snmp_user_based_sm_mib:mk_key_change(sha,
+ OldShaKey,
+ ShaKey),
+ DesKeyChange = snmp_user_based_sm_mib:mk_key_change(sha,
+ OldDesKey,
+ DesKey),
+ Vbs1 = [{[usmUserOwnAuthKeyChange, NewRowIndex], ShaKeyChange}],
+ s(Vbs1),
+ ?line expect(1, noAccess, 1, any),
+ Vbs2 = [{[usmUserOwnPrivKeyChange, NewRowIndex], DesKeyChange}],
+ s(Vbs2),
+ ?line expect(2, noAccess, 1, any),
+
+
+ Vbs3 = [{[usmUserAuthKeyChange, NewRowIndex], ShaKeyChange},
+ {[usmUserPrivKeyChange, NewRowIndex], DesKeyChange}],
+ s(Vbs3),
+ ?line expect(1, Vbs3).
+
+usm_read() ->
+ NewRowIndex = [11,"agentEngine", 7, "newUser"],
+ ?line g([[usmUserSecurityName, NewRowIndex],
+ [usmUserCloneFrom, NewRowIndex],
+ [usmUserAuthKeyChange, NewRowIndex],
+ [usmUserOwnAuthKeyChange, NewRowIndex],
+ [usmUserPrivKeyChange, NewRowIndex],
+ [usmUserOwnPrivKeyChange, NewRowIndex]]),
+ ?line expect(1,
+ [{[usmUserSecurityName, NewRowIndex], "newUser"},
+ {[usmUserCloneFrom, NewRowIndex], [0,0]},
+ {[usmUserAuthKeyChange, NewRowIndex], ""},
+ {[usmUserOwnAuthKeyChange, NewRowIndex], ""},
+ {[usmUserPrivKeyChange, NewRowIndex], ""},
+ {[usmUserOwnPrivKeyChange, NewRowIndex], ""}]),
+ ok.
+
+
+
+usm_del_user() ->
+ NewRowIndex = [11,"agentEngine", 7, "newUser"],
+ Vbs1 = [{[usmUserStatus, NewRowIndex], ?destroy}],
+ ?line s(Vbs1),
+ ?line expect(1, Vbs1),
+ ok.
+
+-define(usmUserCloneFrom, [1,3,6,1,6,3,15,1,2,2,1,4]).
+
+-define(usmNoAuthProtocol, [1,3,6,1,6,3,10,1,1,1]).
+
+-define(usmHMACMD5AuthProtocol, [1,3,6,1,6,3,10,1,1,2]).
+
+-define(usmHMACSHAAuthProtocol, [1,3,6,1,6,3,10,1,1,3]).
+
+-define(usmNoPrivProtocol, [1,3,6,1,6,3,10,1,2,1]).
+
+-define(usmDESPrivProtocol, [1,3,6,1,6,3,10,1,2,2]).
+
+usm_bad() ->
+ NewRowIndex = [11,"agentEngine", 7, "newUser"],
+ RowPointer1 = ?usmUserSecurityName ++ [11|"agentEngine"] ++ [7|"privDOS"],
+ Vbs1 = [{[usmUserCloneFrom, NewRowIndex], RowPointer1},
+ {[usmUserStatus, NewRowIndex], ?createAndGo}],
+ ?line s(Vbs1),
+ ?line expect(1, inconsistentName, 1, any),
+
+ RowPointer2 = ?usmUserCloneFrom ++ [11|"agentEngine"] ++ [7|"privDES"],
+ Vbs2 = [{[usmUserCloneFrom, NewRowIndex], RowPointer2},
+ {[usmUserStatus, NewRowIndex], ?createAndGo}],
+ ?line s(Vbs2),
+ ?line expect(2, wrongValue, 1, any),
+
+ RowPointer3 = ?usmUserSecurityName ++ [11|"agentEngine"] ++ [7|"privDES"],
+ Vbs3 = [{[usmUserCloneFrom, NewRowIndex], RowPointer3},
+ {[usmUserStatus, NewRowIndex], ?createAndGo}],
+ ?line s(Vbs3),
+ ?line expect(3, Vbs3),
+ ?line s([{[usmUserAuthProtocol, NewRowIndex], ?usmNoAuthProtocol}]),
+ ?line expect(4, inconsistentValue, 1, any),
+ ?line s([{[usmUserAuthProtocol, NewRowIndex], ?usmHMACMD5AuthProtocol}]),
+ ?line expect(5, inconsistentValue, 1, any),
+ ?line s([{[usmUserAuthProtocol, NewRowIndex], ?usmDESPrivProtocol}]),
+ ?line expect(6, wrongValue, 1, any),
+ ?line s([{[usmUserPrivProtocol, NewRowIndex], ?usmHMACSHAAuthProtocol}]),
+ ?line expect(7, wrongValue, 1, any),
+
+ Vbs4 = [{[usmUserStatus, NewRowIndex], ?destroy}],
+ ?line s(Vbs4),
+ ?line expect(1, Vbs4),
+
+ ok.
+
+
+%%-----------------------------------------------------------------
+%% Loop through entire MIB, to make sure that all instrum. funcs
+%% works.
+%% Load all std mibs that are not loaded by default.
+%%-----------------------------------------------------------------
+loop_mib(suite) -> [];
+loop_mib(Config) when list(Config) ->
+ ?LOG("loop_mib -> initiate case",[]),
+ %% snmpa:verbosity(master_agent,debug),
+ %% snmpa:verbosity(mib_server,info),
+ {SaNode, MgrNode, MibDir} = init_case(Config),
+ ?DBG("loop_mib -> ~n"
+ "\tSaNode: ~p~n"
+ "\tMgrNode: ~p~n"
+ "\tMibDir: ~p",[SaNode, MgrNode, MibDir]),
+ ?DBG("loop_mib -> load mib SNMP-COMMUNITY-MIB",[]),
+ ?line load_master_std("SNMP-COMMUNITY-MIB"),
+ ?DBG("loop_mib -> load mib SNMP-MPD-MIB",[]),
+ ?line load_master_std("SNMP-MPD-MIB"),
+ ?DBG("loop_mib -> load mib SNMP-TARGET-MIB",[]),
+ ?line load_master_std("SNMP-TARGET-MIB"),
+ ?DBG("loop_mib -> load mib SNMP-NOTIFICATION-MIB",[]),
+ ?line load_master_std("SNMP-NOTIFICATION-MIB"),
+ ?DBG("loop_mib -> load mib SNMP-FRAMEWORK-MIB",[]),
+ ?line load_master_std("SNMP-FRAMEWORK-MIB"),
+ ?DBG("loop_mib -> load mib SNMP-VIEW-BASED-ACM-MIB",[]),
+ ?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"),
+ ?DBG("loop_mib -> try",[]),
+ try_test(loop_mib_1),
+ ?DBG("loop_mib -> unload mib SNMP-COMMUNITY-MIB",[]),
+ ?line unload_master("SNMP-COMMUNITY-MIB"),
+ ?DBG("loop_mib -> unload mib SNMP-MPD-MIB",[]),
+ ?line unload_master("SNMP-MPD-MIB"),
+ ?DBG("loop_mib -> unload mib SNMP-TARGET-MIB",[]),
+ ?line unload_master("SNMP-TARGET-MIB"),
+ ?DBG("loop_mib -> unload mib SNMP-NOTIFICATION-MIB",[]),
+ ?line unload_master("SNMP-NOTIFICATION-MIB"),
+ ?DBG("loop_mib -> unload mib SNMP-FRAMEWORK-MIB",[]),
+ ?line unload_master("SNMP-FRAMEWORK-MIB"),
+ ?DBG("loop_mib -> unload mib SNMP-VIEW-BASED-ACM-MIB",[]),
+ ?line unload_master("SNMP-VIEW-BASED-ACM-MIB"),
+ %% snmpa:verbosity(master_agent,log),
+ %% snmpa:verbosity(mib_server,silence),
+ ?LOG("loop_mib -> done",[]).
+
+
+loop_mib_2(suite) -> [];
+loop_mib_2(Config) when list(Config) ->
+ ?LOG("loop_mib_2 -> initiate case",[]),
+ {SaNode, MgrNode, MibDir} = init_case(Config),
+ ?DBG("loop_mib_2 -> ~n"
+ "\tSaNode: ~p~n"
+ "\tMgrNode: ~p~n"
+ "\tMibDir: ~p",[SaNode, MgrNode, MibDir]),
+ ?DBG("loop_mib_2 -> load mibs",[]),
+ ?line load_master_std("SNMP-COMMUNITY-MIB"),
+ ?line load_master_std("SNMP-MPD-MIB"),
+ ?line load_master_std("SNMP-TARGET-MIB"),
+ ?line load_master_std("SNMP-NOTIFICATION-MIB"),
+ ?line load_master_std("SNMP-FRAMEWORK-MIB"),
+ ?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"),
+ try_test(loop_mib_2),
+ ?DBG("loop_mib_2 -> unload mibs",[]),
+ ?line unload_master("SNMP-COMMUNITY-MIB"),
+ ?line unload_master("SNMP-MPD-MIB"),
+ ?line unload_master("SNMP-TARGET-MIB"),
+ ?line unload_master("SNMP-NOTIFICATION-MIB"),
+ ?line unload_master("SNMP-FRAMEWORK-MIB"),
+ ?line unload_master("SNMP-VIEW-BASED-ACM-MIB"),
+ ?LOG("loop_mib_2 -> done",[]).
+
+
+loop_mib_3(suite) -> [];
+loop_mib_3(Config) when list(Config) ->
+ ?LOG("loop_mib_3 -> initiate case",[]),
+ {SaNode, MgrNode, MibDir} = init_case(Config),
+ ?DBG("loop_mib_3 -> ~n"
+ "\tSaNode: ~p~n"
+ "\tMgrNode: ~p~n"
+ "\tMibDir: ~p",[SaNode, MgrNode, MibDir]),
+ ?DBG("loop_mib_3 -> load mibs",[]),
+ ?line load_master_std("SNMP-TARGET-MIB"),
+ ?line load_master_std("SNMP-NOTIFICATION-MIB"),
+ ?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"),
+ ?line load_master_std("SNMP-USER-BASED-SM-MIB"),
+ try_test(loop_mib_2),
+ ?DBG("loop_mib_3 -> unload mibs",[]),
+ ?line unload_master("SNMP-TARGET-MIB"),
+ ?line unload_master("SNMP-NOTIFICATION-MIB"),
+ ?line unload_master("SNMP-VIEW-BASED-ACM-MIB"),
+ ?line unload_master("SNMP-USER-BASED-SM-MIB"),
+ ?LOG("loop_mib_3 -> done",[]).
+
+
+%% Req. As many mibs all possible
+loop_mib_1() ->
+ ?DBG("loop_mib_1 -> entry",[]),
+ N = loop_it_1([1,1], 0),
+ io:format(user, "found ~w varibles\n", [N]),
+ ?line N = if N < 100 -> 100;
+ true -> N
+ end.
+
+
+loop_it_1(Oid, N) ->
+ ?DBG("loop_it_1 -> entry with~n"
+ "\tOid: ~p~n"
+ "\tN: ~p",[Oid,N]),
+ case get_next_req([Oid]) of
+ #pdu{type='get-response', error_status=noError, error_index=0,
+ varbinds=[#varbind{oid = NOid,value = Value}]} when NOid > Oid ->
+ ?DBG("loop_it_1 -> ~n"
+ "\tNOid: ~p~n"
+ "\tValue: ~p",[NOid,Value]),
+ ?line [Value2] = get_req(1, [NOid]), % must not be same
+ ?DBG("loop_it_1 -> ~n"
+ "\tValue2: ~p",[Value2]),
+ loop_it_1(NOid, N+1);
+ #pdu{type='get-response', error_status=noSuchName, error_index=1,
+ varbinds=[_]} ->
+ ?DBG("loop_it_1 -> done",[]),
+ N;
+
+ #pdu{type = Type, error_status = Err, error_index = Idx,
+ varbinds = Vbs} ->
+ exit({unexpected_pdu, ?LINE, Type, Err, Idx, Vbs})
+ end.
+
+%% Req. As many mibs all possible
+loop_mib_2() ->
+ ?DBG("loop_mib_1 -> entry",[]),
+ N = loop_it_2([1,1], 0),
+ io:format(user, "found ~w varibles\n", [N]),
+ ?line N = if N < 100 -> 100;
+ true -> N
+ end.
+
+
+loop_it_2(Oid, N) ->
+ ?DBG("loop_it_2 -> entry with~n"
+ "\tOid: ~p~n"
+ "\tN: ~p",[Oid,N]),
+ case get_next_req([Oid]) of
+ #pdu{type='get-response', error_status=noError, error_index=0,
+ varbinds=[#varbind{oid = NOid, value = endOfMibView}]} ->
+ ?DBG("loop_it_2 -> ~n"
+ "\tNOid: ~p",[NOid]),
+ N;
+ #pdu{type='get-response', error_status=noError, error_index=0,
+ varbinds=[#varbind{oid = NOid,value = Value}]} when NOid > Oid ->
+ ?DBG("loop_it_2 -> ~n"
+ "\tNOid: ~p~n"
+ "\tValue: ~p",[NOid,Value]),
+ ?line [Value2] = get_req(1, [NOid]), % must not be same
+ ?DBG("loop_it_2 -> ~n"
+ "\tValue2: ~p",[Value2]),
+ loop_it_2(NOid, N+1)
+ end.
+
+
+%%%-----------------------------------------------------------------
+%%% Testing of reported bugs and other tickets.
+%%%-----------------------------------------------------------------
+
+reported_bugs(suite) ->
+ [otp_1128, otp_1129, otp_1131, otp_1162,
+ otp_1222, otp_1298, otp_1331, otp_1338,
+ otp_1342, otp_2776, otp_2979, otp_3187, otp_3725].
+
+reported_bugs_2(suite) ->
+ [otp_1128_2, otp_1129_2, otp_1131_2, otp_1162_2,
+ otp_1222_2, otp_1298_2, otp_1331_2, otp_1338_2,
+ otp_1342_2, otp_2776_2, otp_2979_2, otp_3187_2].
+
+reported_bugs_3(suite) ->
+ [otp_1128_3, otp_1129_3, otp_1131_3, otp_1162_3,
+ otp_1222_3, otp_1298_3, otp_1331_3, otp_1338_3,
+ otp_1342_3, otp_2776_3, otp_2979_3, otp_3187_3,
+ otp_3542].
+
+
+%% These are (ticket) test cases where the initiation has to be done
+%% individually.
+tickets(suite) ->
+ [otp_4394].
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-1128
+%% Slogan: Bug in handling of createAndWait set-requests.
+%%-----------------------------------------------------------------
+otp_1128(suite) -> [];
+otp_1128(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?line load_master("OLD-SNMPEA-MIB"),
+ ?line init_old(),
+ try_test(otp_1128),
+ ?line unload_master("OLD-SNMPEA-MIB").
+
+otp_1128_2(X) -> otp_1128(X).
+
+otp_1128_3(X) -> otp_1128(X).
+
+otp_1128() ->
+ io:format("Testing bug reported in ticket OTP-1128...~n"),
+
+ NewKeyc3 = [intCommunityViewIndex,get(mip),is("test")],
+ NewKeyc4 = [intCommunityAccess,get(mip),is("test")],
+ NewKeyc5 = [intCommunityStatus,get(mip),is("test")],
+
+ s([{NewKeyc5, ?createAndWait}, {NewKeyc4, 2}]),
+ ?line expect(28, [{NewKeyc5, ?createAndWait}, {NewKeyc4, 2}]),
+ g([NewKeyc5]),
+ ?line expect(29, [{NewKeyc5, ?notReady}]),
+ s([{NewKeyc5, ?active}, {NewKeyc3, 2}]),
+ ?line expect(30, [{NewKeyc5, ?active}, {NewKeyc3, 2}]),
+ g([NewKeyc5]),
+ ?line expect(31, [{NewKeyc5, ?active}]),
+ s([{NewKeyc5, ?destroy}]),
+ ?line expect(32, [{NewKeyc5, ?destroy}]).
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-1129, OTP-1169
+%% Slogan: snmpa:int_to_enum crashes on bad oids
+%%-----------------------------------------------------------------
+otp_1129(suite) -> [];
+otp_1129(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?line load_master("Klas3"),
+ try_test(otp_1129_i, [node()]),
+ ?line unload_master("Klas3").
+
+otp_1129_2(X) -> otp_1129(X).
+
+otp_1129_3(X) -> otp_1129(X).
+
+otp_1129_i(MaNode) ->
+ io:format("Testing bug reported in ticket OTP-1129...~n"),
+ false = rpc:call(MaNode, snmp, int_to_enum, [iso, 1]),
+ false = rpc:call(MaNode, snmp, int_to_enum, [isox, 1]).
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-1131
+%% Slogan: Agent crashes / erlang node halts if RowIndex in a
+%% setrequest is of bad type, e.g. an INDEX {INTEGER},
+%% and RowIdenx [3,2].
+%%-----------------------------------------------------------------
+otp_1131(suite) -> [];
+otp_1131(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?line load_master("Klas1"),
+ try_test(otp_1131),
+ ?line unload_master("Klas1").
+
+otp_1131_2(X) -> otp_1131(X).
+
+otp_1131_3(X) -> otp_1131(X).
+
+otp_1131() ->
+ io:format("Testing bug reported in ticket OTP-1131...~n"),
+ s([{[friendsEntry, [2, 3, 1]], s, "kompis3"},
+ {[friendsEntry, [3, 3, 1]], i, ?createAndGo}]),
+ ?line expect(1, ?v1_2(noSuchName, noCreation), 2, any).
+
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-1162
+%% Slogan: snmp_agent can't handle wrongValue from instrum.func
+%%-----------------------------------------------------------------
+otp_1162(suite) -> [];
+otp_1162(Config) when list(Config) ->
+ {SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?line {ok, SA} = start_subagent(SaNode, ?sa, "SA-MIB"),
+ try_test(otp_1162),
+ stop_subagent(SA).
+
+otp_1162_2(X) -> otp_1162(X).
+
+otp_1162_3(X) -> otp_1162(X).
+
+otp_1162() ->
+ s([{[sa, [2,0]], 6}]), % wrongValue (i is_set_ok)
+ ?line expect(1, ?v1_2(badValue, wrongValue), 1, any).
+
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-1222
+%% Slogan: snmp agent crash if faulty index is returned from instrum
+%%-----------------------------------------------------------------
+otp_1222(suite) -> [];
+otp_1222(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?line load_master("Klas3"),
+ ?line load_master("Klas4"),
+ try_test(otp_1222),
+ ?line unload_master("Klas3"),
+ ?line unload_master("Klas4").
+
+otp_1222_2(X) -> otp_1222(X).
+
+otp_1222_3(X) -> otp_1222(X).
+
+otp_1222() ->
+ io:format("Testing bug reported in ticket OTP-1222...~n"),
+ s([{[fStatus4,1], 4}, {[fName4,1], 1}]),
+ ?line expect(1, genErr, 0, any),
+ s([{[fStatus4,2], 4}, {[fName4,2], 1}]),
+ ?line expect(2, genErr, 0, any).
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-1298
+%% Slogan: Negative INTEGER values are treated as positive.
+%%-----------------------------------------------------------------
+otp_1298(suite) -> [];
+otp_1298(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?line load_master("Klas2"),
+ try_test(otp_1298),
+ ?line unload_master("Klas2").
+
+otp_1298_2(X) -> otp_1298(X).
+
+otp_1298_3(X) -> otp_1298(X).
+
+otp_1298() ->
+ io:format("Testing bug reported in ticket OTP-1298...~n"),
+ s([{[fint,0], -1}]),
+ ?line expect(1298, [{[fint,0], -1}]).
+
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-1331
+%% Slogan: snmp_generic should return noError when deleting non-ex row
+%%-----------------------------------------------------------------
+otp_1331(suite) -> [];
+otp_1331(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?line load_master("OLD-SNMPEA-MIB"),
+ ?line init_old(),
+ try_test(otp_1331),
+ ?line unload_master("OLD-SNMPEA-MIB").
+
+otp_1331_2(X) -> otp_1331(X).
+
+otp_1331_3(X) -> otp_1331(X).
+
+otp_1331() ->
+ NewKeyc5 = [intCommunityStatus,[127,32,0,0],is("test")],
+ s([{NewKeyc5, ?destroy}]),
+ ?line expect(1, [{NewKeyc5, ?destroy}]).
+
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-1338
+%% Slogan: snmp bug in initialisation of default values for mnesia tabs
+%%-----------------------------------------------------------------
+otp_1338(suite) -> [];
+otp_1338(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?line load_master("Klas2"),
+ try_test(otp_1338),
+ ?line unload_master("Klas2").
+
+otp_1338_2(X) -> otp_1338(X).
+
+otp_1338_3(X) -> otp_1338(X).
+
+otp_1338() ->
+ s([{[kStatus2, 7], i, ?createAndGo}]),
+ ?line expect(1, [{[kStatus2, 7], ?createAndGo}]),
+ g([[kName2, 7]]),
+ ?line expect(2, [{[kName2, 7], "JJJ"}]).
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-1342
+%% Slogan: default impl of snmp table can't handle bad index access,
+%% Set when INDEX is read-write gets into an infinite loop!
+%%-----------------------------------------------------------------
+otp_1342(suite) -> [];
+otp_1342(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?line load_master("Klas4"),
+ try_test(otp_1342),
+ ?line unload_master("Klas4").
+
+otp_1342_2(X) -> otp_1342(X).
+
+otp_1342_3(X) -> otp_1342(X).
+
+otp_1342() ->
+ s([{[fIndex5, 1], i, 1},
+ {[fName5, 1], i, 3},
+ {[fStatus5, 1], i, ?createAndGo}]),
+ ?line expect(1, ?v1_2(noSuchName, noCreation), 3, any).
+
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-1366
+%% Slogan: snmp traps not sent to all managers
+%% Note: NYI! We need a way to tell the test server that we need
+%% mgrs on two different machines.
+%%-----------------------------------------------------------------
+otp_1366(suite) -> [];
+otp_1366(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?line load_master("OLD-SNMPEA-MIB"),
+ ?line init_old(),
+ try_test(otp_1366),
+ ?line unload_master("OLD-SNMPEA-MIB").
+
+otp_1366_2(X) -> otp_1366(X).
+
+otp_1366_3(X) -> otp_1366(X).
+
+otp_1366() ->
+ ?INF("NOT YET IMPLEMENTED", []),
+ 'NYI'.
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-2776
+%% Slogan: snmp:validate_date_and_time() fails when time is 00:00
+%%-----------------------------------------------------------------
+otp_2776(suite) -> [];
+otp_2776(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ try_test(otp_2776).
+
+otp_2776_2(X) -> otp_2776(X).
+
+otp_2776_3(X) -> otp_2776(X).
+
+otp_2776() ->
+ io:format("Testing bug reported in ticket OTP-2776...~n"),
+
+ Dt01_valid = [19,98,9,1,1,0,23,0,43,0,0],
+ Dt02_valid = [19,98,9,1,0,0,0,0,43,0,0], % This is what is fixed: 00:00
+ Dt03_valid = [19,98,2,28,1,0,23,0,43,0,0],
+ Dt04_invalid = [19,98,2,29,1,0,23,0,43,0,0],
+ Dt05_valid = [19,96,2,29,1,0,23,0,43,0,0],
+ Dt06_valid = [20,0,2,29,1,0,23,0,43,0,0],
+ Dt07_invalid = [19,96,2,30,1,0,23,0,43,0,0], % This is also fixed: 30/2
+ Dt08_valid = [19,98,4,30,1,0,23,0,43,0,0],
+ Dt09_invalid = [19,98,4,31,1,0,23,0,43,0,0], % This is also fixed: 31/4
+ Dt10_invalid = [],
+ Dt11_invalid = [kalle,hobbe],
+ L = [{ 1, true, Dt01_valid},
+ { 2, true, Dt02_valid},
+ { 3, true, Dt03_valid},
+ { 4, false, Dt04_invalid},
+ { 5, true, Dt05_valid},
+ { 6, true, Dt06_valid},
+ { 7, false, Dt07_invalid},
+ { 8, true, Dt08_valid},
+ { 9, false, Dt09_invalid},
+ {10, false, Dt10_invalid},
+ {11, false, Dt11_invalid}],
+
+ ?line ok = validate_dat(L).
+
+
+validate_dat(L) -> validate_dat(L,[]).
+
+validate_dat([],V) ->
+ Fun = fun({_,X}) -> case X of
+ ok -> false;
+ _ -> true
+ end
+ end,
+ validate_dat1( lists:reverse( lists:filter(Fun,V) ) );
+validate_dat([{Id,E,Dat}|T],V) ->
+ validate_dat(T,[validate_dat2(Id,E,Dat) | V]).
+
+validate_dat1([]) -> ok;
+validate_dat1(L) -> {error,L}.
+
+validate_dat2(Id, E, Dat) ->
+ Res = case {E,snmp:validate_date_and_time(Dat)} of
+ {E,E} -> ok;
+ {E,A} -> {E,A}
+ end,
+ {Id, Res}.
+
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-2979
+%% Slogan: get-next on more than 1 column in an empty table
+%% returns bad response.
+%%-----------------------------------------------------------------
+otp_2979(suite) -> [];
+otp_2979(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?line load_master("Test1"),
+ ?line init_old(),
+ try_test(otp_2979),
+ ?line unload_master("Test1").
+
+otp_2979_2(X) -> otp_2979(X).
+
+otp_2979_3(X) -> otp_2979(X).
+
+otp_2979() ->
+ gn([[sparseDescr], [sparseStatus]]),
+ ?line expect(1, [{[sparseStr,0], "slut"},
+ {[sparseStr,0], "slut"}]).
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-3187
+%% Slogan: get-next on vacmAccessTable for colums > 5 returns
+%% endOfTable - should return value.
+%%-----------------------------------------------------------------
+otp_3187(suite) -> [];
+otp_3187(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"),
+ otp_3187(),
+ ?line unload_master("SNMP-VIEW-BASED-ACM-MIB").
+
+otp_3187_2(X) -> otp_3187(X).
+
+otp_3187_3(X) -> otp_3187(X).
+
+otp_3187() ->
+ ?line Elements =
+ snmp_view_based_acm_mib:vacmAccessTable(get_next,[],[4,5,6]),
+ lists:foreach(fun(E) ->
+ ?line if E == endOfTable ->
+ ?FAIL(endOfTable);
+ true -> ok
+ end
+ end, Elements).
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-3542
+%% Slogan:
+%%-----------------------------------------------------------------
+otp_3542(suite) -> [];
+otp_3542(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ try_test(otp_3542).
+
+otp_3542() ->
+ io:format("SNMP v3 discovery...~n"),
+ ?line Res = snmp_test_mgr:d(),
+ io:format("SNMP v3 discovery result: ~p~n",[Res]).
+
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-3725
+%% Slogan: Slow response time on snmpa:int_to_enum
+%%-----------------------------------------------------------------
+otp_3725(suite) -> [];
+otp_3725(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ ?line load_master("OLD-SNMPEA-MIB"),
+ ?line init_old(),
+ try_test(otp_3725_test, [node()]),
+ ?line unload_master("OLD-SNMPEA-MIB").
+
+%% Req. OLD-SNMPEA-MIB
+otp_3725_test(MaNode) ->
+ io:format("Testing feature requested in ticket OTP-3725...~n"),
+ ?line rpc:call(MaNode,snmpa,verbosity,[symbolic_store,trace]),
+ ?line Db = rpc:call(MaNode,snmp,get_symbolic_store_db,[]),
+ ?DBG("otp_3725_test -> Db = ~p",[Db]),
+
+ ?line {value, OID} = rpc:call(MaNode, snmp, name_to_oid,
+ [Db, intAgentIpAddress]),
+ ?DBG("otp_3725_test -> name_to_oid for ~p: ~p",[intAgentIpAddress,OID]),
+ ?line {value, intAgentIpAddress} = rpc:call(MaNode, snmp, oid_to_name,
+ [Db,OID]),
+ ?DBG("otp_3725_test -> oid_to_name for ~p: ~p",[OID,intAgentIpAddress]),
+ ?line false = rpc:call(MaNode, snmp, name_to_oid, [Db, intAgentIpAddres]),
+ ?line false = rpc:call(MaNode, snmp, oid_to_name,
+ [Db, [1,5,32,3,54,3,3,34,4]]),
+ ?line {value, 2} = rpc:call(MaNode, snmp, enum_to_int,
+ [Db, intViewType, excluded]),
+ ?line {value, excluded} = rpc:call(MaNode, snmp, int_to_enum,
+ [Db, intViewType, 2]),
+ ?line false = rpc:call(MaNode, snmp, enum_to_int,
+ [Db, intViewType, exclude]),
+ ?line false = rpc:call(MaNode, snmp, enum_to_int,
+ [Db, intAgentIpAddress, exclude]),
+ ?line false = rpc:call(MaNode, snmp, enum_to_int,
+ [Db, intAgentIpAddre, exclude]),
+ ?line false = rpc:call(MaNode, snmp, int_to_enum, [Db, intViewType, 3]),
+ ?line false = rpc:call(MaNode, snmp, int_to_enum,
+ [Db, intAgentIpAddress, 2]),
+ ?line false = rpc:call(MaNode, snmp, int_to_enum,
+ [Db, intAgentIpAddre, 2]),
+ ?line {value, active} = rpc:call(MaNode, snmp, int_to_enum,
+ [Db, 'RowStatus', ?active]),
+ ?line {value, ?destroy} = rpc:call(MaNode, snmp, enum_to_int,
+ [Db, 'RowStatus', destroy]),
+ ?line false = rpc:call(MaNode, snmp, enum_to_int,
+ [Db, 'RowStatus', xxxdestroy]),
+ ?line false = rpc:call(MaNode, snmp, enum_to_int,
+ [Db, 'xxRowStatus', destroy]),
+ ?line false = rpc:call(MaNode, snmp, int_to_enum, [Db, 'RowStatus', 25]),
+ ?line false = rpc:call(MaNode, snmp, int_to_enum, [Db, 'xxRowStatus', 1]),
+ ok.
+
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-4394
+%% Slogan: Target mib tag list check invalid
+%%-----------------------------------------------------------------
+
+
+otp_4394(suite) -> {req, [], {conf,
+ init_otp_4394,
+ [otp_4394_test],
+ finish_otp_4394}}.
+
+init_otp_4394(Config) when list(Config) ->
+ ?DBG("init_otp_4394 -> entry with"
+ "~n Config: ~p", [Config]),
+ ?line AgentDir = ?config(agent_dir, Config),
+ ?line MgrDir = ?config(mgr_dir, Config),
+ ?line Ip = ?config(ip, Config),
+ ?line otp_4394_config(AgentDir, MgrDir, Ip),
+ MasterAgentVerbosity = {master_agent_verbosity, trace},
+ NetIfVerbosity = {net_if_verbosity, trace},
+ Opts = [MasterAgentVerbosity,NetIfVerbosity],
+ [{vsn, v1} | start_v1_agent(Config,Opts)].
+
+otp_4394_config(AgentDir, MgrDir, Ip0) ->
+ ?DBG("otp_4394_config -> entry with"
+ "~n AgentDir: ~p"
+ "~n MgrDir: ~p"
+ "~n Ip0: ~p", [AgentDir, MgrDir, Ip0]),
+ Vsn = [v1],
+ Ip = tuple_to_list(Ip0),
+ ?line snmp_config:write_agent_snmp_files(AgentDir, Vsn, Ip,
+ ?TRAP_UDP, Ip, 4000,
+ "OTP-4394 test"),
+ ?line case update_usm(Vsn, AgentDir) of
+ true ->
+ ?line copy_file(filename:join(AgentDir, "usm.conf"),
+ filename:join(MgrDir, "usm.conf")),
+ ?line update_usm_mgr(Vsn, MgrDir);
+ false ->
+ ?line ok
+ end,
+ C1 = {"a", "all-rights", "initial", "", "pc"},
+ C2 = {"c", "secret", "secret_name", "", "secret_tag"},
+ ?line write_community_conf(AgentDir, [C1, C2]),
+ ?line update_vacm(Vsn, AgentDir),
+ Ta1 = {"shelob v1",
+ [134,138,177,177], 5000, 1500, 3, %% Anv�nd Ip och modda
+ "pc1",
+ "target_v1", "",
+ %% [255,255,255,255,0,0],
+ [],
+ 2048},
+ Ta2 = {"bifur v1",
+ [134,138,177,75], 5000, 1500, 3, %% Anv�nd Ip
+ "pc2",
+ "target_v1", "",
+ %% [255,255,255,255,0,0],
+ [], 2048},
+ ?line write_target_addr_conf(AgentDir, [Ta1, Ta2]),
+ ?line write_target_params_conf(AgentDir, Vsn),
+ ?line write_notify_conf(AgentDir),
+ ok.
+
+
+
+finish_otp_4394(Config) when list(Config) ->
+ ?DBG("finish_otp_4394 -> entry", []),
+ C1 = stop_agent(Config),
+ delete_files(C1),
+ erase(mgr_node),
+ lists:keydelete(vsn, 1, C1).
+
+otp_4394_test(suite) -> [];
+otp_4394_test(Config) ->
+ ?DBG("otp_4394_test -> entry", []),
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ try_test(otp_4394_test1),
+ ?DBG("otp_4394_test -> done", []),
+ ok.
+
+otp_4394_test1() ->
+ ?DBG("otp_4394_test1 -> entry", []),
+ gn([[1,1]]),
+ Res =
+ case snmp_test_mgr:expect(1, [{[sysDescr,0], "Erlang SNMP agent"}]) of
+ %% {error, 1, {"?",[]}, {"~w",[timeout]}}
+ {error, 1, _, {_, [timeout]}} ->
+ ?DBG("otp_4394_test1 -> expected result: timeout", []),
+ ok;
+ Else ->
+ Else
+ end,
+ ?DBG("otp_4394_test1 -> done with: ~p", [Res]),
+ Res.
+
+
+%%%--------------------------------------------------
+%%% Used to test the standard mib with our
+%%% configuration.
+%%%--------------------------------------------------
+run(F, A, Opts) ->
+ M = get(mib_dir),
+ Dir = get(mgr_dir),
+ User = snmp_misc:get_option(user, Opts, "all-rights"),
+ SecLevel = snmp_misc:get_option(sec_level, Opts, noAuthNoPriv),
+ EngineID = snmp_misc:get_option(engine_id, Opts, "agentEngine"),
+ CtxEngineID = snmp_misc:get_option(context_engine_id, Opts, EngineID),
+ Community = snmp_misc:get_option(community, Opts, "all-rights"),
+ ?DBG("run -> start crypto app",[]),
+ Crypto = case os:type() of
+ vxworks ->
+ no_crypto;
+ _ ->
+ ?CRYPTO_START()
+ end,
+ ?DBG("run -> Crypto: ~p",[Crypto]),
+ catch snmp_test_mgr:stop(), % If we had a running mgr from a failed case
+ StdM = filename:join(code:priv_dir(snmp), "mibs") ++ "/",
+ ?DBG("run -> config:~n"
+ "\tM: ~p~n"
+ "\tDir: ~p~n"
+ "\tUser: ~p~n"
+ "\tSecLevel: ~p~n"
+ "\tEngineID: ~p~n"
+ "\tCtxEngineID: ~p~n"
+ "\tCommunity: ~p~n"
+ "\tStdM: ~p",
+ [M,Dir,User,SecLevel,EngineID,CtxEngineID,Community,StdM]),
+ case snmp_test_mgr:start([%% {agent, snmp_test_lib:hostname()},
+ {packet_server_debug,true},
+ {debug,true},
+ {agent, get(master_host)},
+ {agent_udp, 4000},
+ {trap_udp, 5000},
+ {recbuf,65535},
+ quiet,
+ get(vsn),
+ {community, Community},
+ {user, User},
+ {sec_level, SecLevel},
+ {engine_id, EngineID},
+ {context_engine_id, CtxEngineID},
+ {dir, Dir},
+ {mibs, mibs(StdM, M)}]) of
+ {ok, _Pid} ->
+ Res = apply(?MODULE, F, A),
+ catch snmp_test_mgr:stop(),
+ Res;
+ Err ->
+ io:format("Error starting manager: ~p\n", [Err]),
+ catch snmp_test_mgr:stop(),
+ ?line exit({mgr_start, Err})
+ end.
+
+
+mibs(StdMibDir,MibDir) ->
+ [join(StdMibDir, ?v1_2("STANDARD-MIB.bin", "SNMPv2-MIB.bin")),
+ join(MibDir, "OLD-SNMPEA-MIB.bin"),
+ join(StdMibDir, "SNMP-FRAMEWORK-MIB"),
+ join(StdMibDir, "SNMP-MPD-MIB"),
+ join(StdMibDir, "SNMP-VIEW-BASED-ACM-MIB"),
+ join(StdMibDir, "SNMP-USER-BASED-SM-MIB"),
+ join(StdMibDir, "SNMP-TARGET-MIB"),
+ join(StdMibDir, "SNMP-NOTIFICATION-MIB"),
+ join(MibDir, "Klas1.bin"),
+ join(MibDir, "Klas2.bin"),
+ join(MibDir, "Klas3.bin"),
+ join(MibDir, "Klas4.bin"),
+ join(MibDir, "SA-MIB.bin"),
+ join(MibDir, "TestTrap.bin"),
+ join(MibDir, "Test1.bin"),
+ join(MibDir, "Test2.bin"),
+ join(MibDir, "TestTrapv2.bin")].
+
+join(D,F) ->
+ filename:join(D,F).
+
+%% string used in index
+is(S) -> [length(S) | S].
+
+try_test(Func) ->
+ call(get(mgr_node), ?MODULE, run, [Func, [], []]).
+
+try_test(Func, A) ->
+ call(get(mgr_node), ?MODULE, run, [Func, A, []]).
+
+try_test(Func, A, Opts) ->
+ call(get(mgr_node), ?MODULE, run, [Func, A, Opts]).
+
+call(N,M,F,A) ->
+ ?DBG("call -> entry with~n"
+ " N: ~p~n"
+ " M: ~p~n"
+ " F: ~p~n"
+ " A: ~p~n"
+ " when~n"
+ " get(): ~p",
+ [N,M,F,A,get()]),
+ spawn(N, ?MODULE, wait, [self(),get(),M,F,A]),
+ receive
+ {done, {'EXIT', Rn}, Loc} ->
+ ?DBG("call -> returned ~p",[{done, {'EXIT', Rn}, Loc}]),
+ put(test_server_loc, Loc),
+ exit(Rn);
+ {done, Ret, Zed} ->
+ ?DBG("call -> returned ~p~n",[{done, Ret, Zed}]),
+ Ret
+ end.
+
+wait(From, Env, M, F, A) ->
+ ?DBG("wait -> entry with ~n"
+ "\tFrom: ~p~n"
+ "\tEnv: ~p",[From,Env]),
+ lists:foreach(fun({K,V}) -> put(K,V) end, Env),
+ Rn = (catch apply(M, F, A)),
+ ?DBG("wait -> Rn: ~n~p", [Rn]),
+ From ! {done, Rn, get(test_server_loc)},
+ exit(Rn).
+
+expect(A,B) -> ok = snmp_test_mgr:expect(A,B).
+expect(A,B,C) -> ok = snmp_test_mgr:expect(A,B,C).
+expect(A,B,C,D) -> ok = snmp_test_mgr:expect(A,B,C,D).
+expect(A,B,C,D,E,F) -> ok = snmp_test_mgr:expect(A,B,C,D,E,F).
+
+get_req(Id, Vars) ->
+ ?DBG("get_req -> entry with~n"
+ "\tId: ~p~n"
+ "\tVars: ~p",[Id,Vars]),
+ g(Vars),
+ ?DBG("get_req -> await response",[]),
+ {ok, Val} = snmp_test_mgr:get_response(Id, Vars),
+ ?DBG("get_req -> response: ~p",[Val]),
+ Val.
+
+get_next_req(Vars) ->
+ ?DBG("get_next_req -> entry with Vars '~p', send request",[Vars]),
+ gn(Vars),
+ ?DBG("get_next_req -> await response",[]),
+ Response = snmp_test_mgr:receive_response(),
+ ?DBG("get_next_req -> response: ~p",[Response]),
+ Response.
+
+
+
+start_node(Name) ->
+ ?LOG("start_node -> entry with Name: ~p",[Name]),
+ M = list_to_atom(?HOSTNAME(node())),
+ ?DBG("start_node -> M: ~p",[M]),
+ Pa = filename:dirname(code:which(?MODULE)),
+ ?DBG("start_node -> Pa: ~p",[Pa]),
+
+ Args = case init:get_argument('CC_TEST') of
+ {ok, [[]]} ->
+ " -pa /clearcase/otp/libraries/snmp/ebin ";
+ {ok, [[Path]]} ->
+ " -pa " ++ Path;
+ error ->
+ ""
+ end,
+ %% Do not use start_link!!! (the proc that calls this one is tmp)
+ ?DBG("start_node -> Args: ~p~n",[Args]),
+ A = Args ++ " -pa " ++ Pa,
+ case (catch ?START_NODE(Name, A)) of
+ {ok, Node} ->
+ %% Tell the test_server to not clean up things it never started.
+ ?DBG("start_node -> Node: ~p",[Node]),
+ {ok, Node};
+ Else ->
+ ?ERR("start_node -> failed with(other): Else: ~p",[Else]),
+ ?line ?FAIL(Else)
+ end.
+
+
+stop_node(Node) ->
+ ?LOG("stop_node -> Node: ~p",[Node]),
+ rpc:cast(Node, erlang, halt, []).
+
+p(X) ->
+ io:format(user, X++"\n", []).
+
+sleep(X) ->
+ receive
+ after
+ X -> ok
+ end.
+
+%%%-----------------------------------------------------------------
+%%% Configuration
+%%%-----------------------------------------------------------------
+config(Vsns, MgrDir, AgentDir, MIp, AIp) ->
+ ?line snmp_config:write_agent_snmp_files(AgentDir, Vsns, MIp,
+ ?TRAP_UDP, AIp, 4000,
+ "test"),
+ ?line case update_usm(Vsns, AgentDir) of
+ true ->
+ ?line copy_file(filename:join(AgentDir, "usm.conf"),
+ filename:join(MgrDir, "usm.conf")),
+ ?line update_usm_mgr(Vsns, MgrDir);
+ false ->
+ ?line ok
+ end,
+ ?line update_community(Vsns, AgentDir),
+ ?line update_vacm(Vsns, AgentDir),
+ ?line write_target_addr_conf(AgentDir, MIp, ?TRAP_UDP, Vsns),
+ ?line write_target_params_conf(AgentDir, Vsns),
+ ?line write_notify_conf(AgentDir),
+ ok.
+
+delete_files(Config) ->
+ Dir = ?config(agent_dir, Config),
+ {ok, List} = file:list_dir(Dir),
+ lists:foreach(fun(FName) -> file:delete(filename:join(Dir, FName)) end,
+ List).
+
+update_usm(Vsns, Dir) ->
+ case lists:member(v3, Vsns) of
+ true ->
+ {ok, Fid} = file:open(filename:join(Dir,"usm.conf"),[read,write]),
+ file:position(Fid, eof),
+ ok = io:format(Fid, "{\"agentEngine\", \"all-rights\", "
+ "\"all-rights\", zeroDotZero, "
+ "usmNoAuthProtocol, \"\", \"\", "
+ "usmNoPrivProtocol, \"\", \"\", \"\", "
+ "\"\", \"\"}.\n", []),
+ ok = io:format(Fid, "{\"agentEngine\", \"no-rights\", "
+ "\"no-rights\", zeroDotZero, "
+ "usmNoAuthProtocol, \"\", \"\", "
+ "usmNoPrivProtocol, \"\", \"\", \"\", "
+ "\"\", \"\"}.\n", []),
+ ok = io:format(Fid, "{\"agentEngine\", \"authMD5\", "
+ "\"authMD5\", zeroDotZero, "
+ "usmHMACMD5AuthProtocol, \"\", \"\", "
+ "usmNoPrivProtocol, \"\", \"\", \"\", "
+ "\"passwd_md5xxxxxx\", \"\"}.\n", []),
+ ok = io:format(Fid, "{\"agentEngine\", \"authSHA\", "
+ "\"authSHA\", zeroDotZero, "
+ "usmHMACSHAAuthProtocol, \"\", \"\", "
+ "usmNoPrivProtocol, \"\", \"\", \"\", "
+ "\"passwd_shaxxxxxxxxxx\", \"\"}.\n", []),
+ ok = io:format(Fid, "{\"agentEngine\", \"privDES\", "
+ "\"privDES\", zeroDotZero, "
+ "usmHMACSHAAuthProtocol, \"\", \"\", "
+ "usmDESPrivProtocol, \"\", \"\", \"\", "
+ "\"passwd_shaxxxxxxxxxx\", \"passwd_desxxxxxx\"}.\n",
+ []),
+ ok = io:format(Fid, "{\"mgrEngine\", \"all-rights\", "
+ "\"all-rights\", zeroDotZero, "
+ "usmNoAuthProtocol, \"\", \"\", "
+ "usmNoPrivProtocol, \"\", \"\", \"\", "
+ "\"\", \"\"}.\n", []),
+ ok = io:format(Fid, "{\"mgrEngine\", \"no-rights\", "
+ "\"no-rights\", zeroDotZero, "
+ "usmNoAuthProtocol, \"\", \"\", "
+ "usmNoPrivProtocol, \"\", \"\", \"\", "
+ "\"\", \"\"}.\n", []),
+ ok = io:format(Fid, "{\"mgrEngine\", \"authMD5\", "
+ "\"authMD5\", zeroDotZero, "
+ "usmHMACMD5AuthProtocol, \"\", \"\", "
+ "usmNoPrivProtocol, \"\", \"\", \"\", "
+ "\"passwd_md5xxxxxx\", \"\"}.\n", []),
+ ok = io:format(Fid, "{\"mgrEngine\", \"authSHA\", "
+ "\"authSHA\", zeroDotZero, "
+ "usmHMACSHAAuthProtocol, \"\", \"\", "
+ "usmNoPrivProtocol, \"\", \"\", \"\", "
+ "\"passwd_shaxxxxxxxxxx\", \"\"}.\n", []),
+ ok = io:format(Fid, "{\"mgrEngine\", \"privDES\", "
+ "\"privDES\", zeroDotZero, "
+ "usmHMACSHAAuthProtocol, \"\", \"\", "
+ "usmDESPrivProtocol, \"\", \"\", \"\", "
+ "\"passwd_shaxxxxxxxxxx\", \"passwd_desxxxxxx\"}.\n",
+ []),
+ file:close(Fid),
+ true;
+ false ->
+ false
+ end.
+
+update_usm_mgr(Vsns, Dir) ->
+ case lists:member(v3, Vsns) of
+ true ->
+ {ok, Fid} = file:open(filename:join(Dir,"usm.conf"),[read,write]),
+ file:position(Fid, eof),
+ ok = io:format(Fid, "{\"agentEngine\", \"newUser\", "
+ "\"newUser\", zeroDotZero, "
+ "usmHMACSHAAuthProtocol, \"\", \"\", "
+ "usmDESPrivProtocol, \"\", \"\", \"\", "
+ "\"passwd_shaxxxxxxxxxx\", \"passwd_desxxxxxx\"}.\n",
+ []),
+ ok = io:format(Fid, "{\"mgrEngine\", \"newUser\", "
+ "\"newUser\", zeroDotZero, "
+ "usmHMACSHAAuthProtocol, \"\", \"\", "
+ "usmDESPrivProtocol, \"\", \"\", \"\", "
+ "\"passwd_shaxxxxxxxxxx\", \"passwd_desxxxxxx\"}.\n",
+ []),
+ file:close(Fid),
+ true;
+ false ->
+ false
+ end.
+
+rewrite_usm_mgr(Dir, ShaKey, DesKey) ->
+ ?line ok = file:rename(filename:join(Dir,"usm.conf"),
+ filename:join(Dir,"usm.old")),
+ ?line {ok, Fid} = file:open(filename:join(Dir,"usm.conf"),write),
+ ok = io:format(Fid, "{\"agentEngine\", \"newUser\", "
+ "\"newUser\", zeroDotZero, "
+ "usmHMACSHAAuthProtocol, \"\", \"\", "
+ "usmDESPrivProtocol, \"\", \"\", \"\", "
+ "\"~s\", \"~s\"}.\n",
+ [ShaKey, DesKey]),
+ ok = io:format(Fid, "{\"mgrEngine\", \"newUser\", "
+ "\"newUser\", zeroDotZero, "
+ "usmHMACSHAAuthProtocol, \"\", \"\", "
+ "usmDESPrivProtocol, \"\", \"\", \"\", "
+ "\"~s\", \"~s\"}.\n",
+ [ShaKey, DesKey]),
+ file:close(Fid).
+
+reset_usm_mgr(Dir) ->
+ ?line ok = file:rename(filename:join(Dir,"usm.old"),
+ filename:join(Dir,"usm.conf")).
+
+
+update_community([v3], _Dir) -> ok;
+update_community(_, Dir) ->
+ {ok, Fid} = file:open(filename:join(Dir,"community.conf"),[read,write]),
+ file:position(Fid, eof),
+ ok=io:format(Fid,"{\"no-rights\",\"no-rights\",\"no-rights\",\"\",\"\"}.\n",
+ []),
+ file:close(Fid).
+
+
+-define(tDescr_instance, [1,3,6,1,2,1,16,1,0]).
+update_vacm(_Vsn, Dir) ->
+ {ok, Fid} = file:open(filename:join(Dir,"vacm.conf"),[read,write]),
+ file:position(Fid, eof),
+ ok=io:format(Fid,"{vacmSecurityToGroup,usm,\"authMD5\",\"initial\"}.\n",[]),
+ ok=io:format(Fid,"{vacmSecurityToGroup,usm,\"authSHA\",\"initial\"}.\n",[]),
+ ok=io:format(Fid,"{vacmSecurityToGroup,usm,\"privDES\",\"initial\"}.\n",[]),
+ ok=io:format(Fid,"{vacmSecurityToGroup,usm,\"newUser\",\"initial\"}.\n",[]),
+ ok = io:format(Fid, "{vacmViewTreeFamily, \"internet\", "
+ "~w, excluded, null}.\n", [?tDescr_instance]),
+ file:close(Fid).
+
+
+vacm_ver(v1) -> v1;
+vacm_ver(v2) -> v2c;
+vacm_ver(v3) -> usm.
+
+
+write_community_conf(Dir, Confs) ->
+ {ok, Fid} = file:open(filename:join(Dir,"community.conf"),write),
+ ok = write_community_conf1(Fid, Confs),
+ file:close(Fid).
+
+write_community_conf1(_, []) ->
+ ok;
+write_community_conf1(Fid, [{ComIdx, ComName, SecName, CtxName, TransTag}|Confs]) ->
+ ok = io:format(Fid, "{\"~s\", \"~s\", \"~s\", \"~s\", \"~s\"}.~n",
+ [ComIdx, ComName, SecName, CtxName, TransTag]),
+ write_community_conf1(Fid, Confs).
+
+
+write_target_addr_conf(Dir, Confs) ->
+ {ok, Fid} = file:open(filename:join(Dir,"target_addr.conf"),write),
+ ok = write_target_addr_conf1(Fid, Confs),
+ file:close(Fid).
+
+
+write_target_addr_conf1(_, []) ->
+ ok;
+write_target_addr_conf1(Fid,
+ [{Name, Ip, Port, Timeout, Retry, TagList, ParamName,
+ EngineId, TMask, MaxMsgSz}|Confs]) ->
+ ok = io:format(Fid, "{\"~s\", ~w, ~w, ~w, ~w, \"~s\", \"~s\", \"~s\", ~w, ~w}.~n",
+ [Name, Ip, Port, Timeout, Retry, TagList, ParamName,
+ EngineId, TMask, MaxMsgSz]),
+ write_target_addr_conf1(Fid, Confs).
+
+write_target_addr_conf(Dir, ManagerIp, UDP, Vsns) ->
+ {ok, Fid} = file:open(filename:join(Dir,"target_addr.conf"),write),
+ lists:foreach(fun(Vsn) ->
+ ok = io:format(Fid,
+ "{\"~s\", ~w, ~w, 1500, 3, "
+ "\"std_trap\", \"~s\"}.~n",
+ [mk_ip(ManagerIp, Vsn),
+ ManagerIp, UDP, mk_param(Vsn)]),
+ case Vsn of
+ v1 -> ok;
+ v2 ->
+ ok = io:format(Fid,
+ "{\"~s.2\",~w,~w,1500,3, "
+ "\"std_inform\", \"~s\"}.~n",
+ [mk_ip(ManagerIp, Vsn),
+ ManagerIp, UDP,
+ mk_param(Vsn)]);
+ v3 ->
+ ok = io:format(Fid,
+ "{\"~s.3\",~w,~w,1500,3, "
+ "\"std_inform\", \"~s\", "
+ "\"mgrEngine\", [], 1024}.~n",
+ [mk_ip(ManagerIp, Vsn),
+ ManagerIp, UDP,
+ mk_param(Vsn)])
+ end
+ end,
+ Vsns),
+ file:close(Fid).
+
+mk_param(v1) -> "target_v1";
+mk_param(v2) -> "target_v2";
+mk_param(v3) -> "target_v3".
+
+mk_ip([A,B,C,D], Vsn) ->
+ io_lib:format("~w.~w.~w.~w ~w", [A,B,C,D,Vsn]).
+
+
+rewrite_target_addr_conf(Dir,NewPort) ->
+ TAFile = filename:join(Dir, "target_addr.conf"),
+ ?DBG("rewrite_target_addr_conf -> read target file info of address config file",[]),
+ case file:read_file_info(TAFile) of
+ {ok, _} -> ok;
+ {error, R} -> ?ERR("failure reading file info of "
+ "target address config file: ~p",[R]),
+ ok
+ end,
+
+ ?line [TrapAddr|Addrs] =
+ snmp_conf:read(TAFile,fun(R) -> rewrite_target_addr_conf1(R) end),
+
+ ?DBG("rewrite_target_addr_conf -> TrapAddr: ~p",[TrapAddr]),
+
+ NewAddrs = [rewrite_target_addr_conf2(NewPort,TrapAddr)|Addrs],
+
+ ?DBG("rewrite_target_addr_conf -> NewAddrs: ~p",[NewAddrs]),
+
+ ?line ok = file:rename(filename:join(Dir,"target_addr.conf"),
+ filename:join(Dir,"target_addr.old")),
+ ?line {ok, Fid} = file:open(filename:join(Dir,"target_addr.conf"),write),
+
+ ?line ok = rewrite_target_addr_conf3(Fid,NewAddrs),
+
+ file:close(Fid).
+
+rewrite_target_addr_conf1(O) ->
+ {ok,O}.
+
+rewrite_target_addr_conf2(NewPort,{Name,Ip,_Port,Timeout,Retry,
+ "std_trap",EngineId}) ->
+ ?LOG("rewrite_target_addr_conf2 -> entry with std_trap",[]),
+ {Name,Ip,NewPort,Timeout,Retry,"std_trap",EngineId};
+rewrite_target_addr_conf2(_NewPort,O) ->
+ ?LOG("rewrite_target_addr_conf2 -> entry with "
+ "~n O: ~p",[O]),
+ O.
+
+
+rewrite_target_addr_conf3(_,[]) -> ok;
+rewrite_target_addr_conf3(Fid,[{Name,Ip,Port,Timeout,Retry,
+ ParamName,EngineId}|T]) ->
+ ?LOG("rewrite_target_addr_conf3 -> write(1) ~s",[ParamName]),
+ io:format(Fid,
+ "{\"~s\", " % Name
+ "~p, " % Ip
+ "~p, " % Port
+ "~p, " % Timeout
+ "~p, " % Retry
+ "\"~s\", " % ParamsName
+ "\"~s\"}.", % EngineId
+ [Name,Ip,Port,Timeout,Retry,ParamName,EngineId]),
+ rewrite_target_addr_conf3(Fid,T);
+rewrite_target_addr_conf3(Fid,[{Name,Ip,Port,Timeout,Retry,TagList,
+ ParamName,EngineId,TMask,MMS}|T]) ->
+ ?LOG("rewrite_target_addr_conf3 -> write(2) ~s",[ParamName]),
+ io:format(Fid,
+ "{\"~s\", " % Name
+ "~p, " % Ip
+ "~p, " % Port
+ "~p, " % Timeout
+ "~p, " % Retry
+ "\"~s\", " % TagList
+ "\"~s\", " % ParamsName
+ "\"~s\"," % EngineId
+ "~p, " % TMask
+ "~p}.", % MMS
+ [Name,Ip,Port,Timeout,Retry,TagList,ParamName,
+ EngineId,TMask,MMS]),
+ rewrite_target_addr_conf3(Fid,T).
+
+reset_target_addr_conf(Dir) ->
+ ?line ok = file:rename(filename:join(Dir,"target_addr.old"),
+ filename:join(Dir,"target_addr.conf")).
+
+write_target_params_conf(Dir, Vsns) ->
+ {ok, Fid} = file:open(filename:join(Dir,"target_params.conf"),write),
+ lists:foreach(fun(Vsn) ->
+ MP = if Vsn == v1 -> v1;
+ Vsn == v2 -> v2c;
+ Vsn == v3 -> v3
+ end,
+ SM = if Vsn == v1 -> v1;
+ Vsn == v2 -> v2c;
+ Vsn == v3 -> usm
+ end,
+ ok = io:format(Fid, "{\"target_~w\", ~w, ~w, "
+ "\"all-rights\", noAuthNoPriv}.~n",
+ [Vsn, MP, SM])
+ end,
+ Vsns),
+ file:close(Fid).
+
+rewrite_target_params_conf(Dir, SecName, SecLevel) ->
+ ?line ok = file:rename(filename:join(Dir,"target_params.conf"),
+ filename:join(Dir,"target_params.old")),
+ ?line {ok, Fid} = file:open(filename:join(Dir,"target_params.conf"),write),
+ ?line ok = io:format(Fid, "{\"target_v3\", v3, usm, \"~s\", ~w}.~n",
+ [SecName, SecLevel]),
+ file:close(Fid).
+
+reset_target_params_conf(Dir) ->
+ ?line ok = file:rename(filename:join(Dir,"target_params.old"),
+ filename:join(Dir,"target_params.conf")).
+
+write_notify_conf(Dir) ->
+ {ok, Fid} = file:open(filename:join(Dir,"notify.conf"),write),
+ ok = io:format(Fid, "{\"standard trap\", \"std_trap\", trap}.~n", []),
+ ok = io:format(Fid, "{\"standard inform\", \"std_inform\",inform}.~n", []),
+ file:close(Fid).
+
+ver_to_trap_str([v1]) -> "v1";
+ver_to_trap_str([v2]) -> "v2";
+% default is to use the latest snmp version
+ver_to_trap_str([v1,v2]) -> "v2".
+
+
+
+write_view_conf(Dir) ->
+ {ok, Fid} = file:open(a(Dir,"view.conf"),write),
+ ok = io:format(Fid, "{2, [1,3,6], included, null}.~n", []),
+ ok = io:format(Fid, "{2, ~w, excluded, null}.~n", [?tDescr_instance]),
+ file:close(Fid).
+
+a(A,B) -> lists:append(A,B).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+copy_file(From, To) ->
+ {ok, Bin} = file:read_file(From),
+ ok = file:write_file(To, Bin).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+display_memory_usage() ->
+ Info = snmpa:info(snmp_master_agent),
+ TreeSize = lists_key1search(tree_size_bytes, Info),
+ ProcMem = lists_key1search(process_memory, Info),
+ MibDbSize = lists_key1search([db_memory,mib], Info),
+ NodeDbSize = lists_key1search([db_memory,node], Info),
+ TreeDbSize = lists_key1search([db_memory,tree], Info),
+ ?INF("Memory usage: "
+ "~n Tree size: ~p"
+ "~n Process memory size: ~p"
+ "~n Mib db size: ~p"
+ "~n Node db size: ~p"
+ "~n Tree db size: ~p",
+ [TreeSize, ProcMem, MibDbSize, NodeDbSize, TreeDbSize]).
+
+lists_key1search([], Res) ->
+ Res;
+lists_key1search([Key|Keys], List) when atom(Key), list(List) ->
+ case lists:keysearch(Key, 1, List) of
+ {value, {Key, Val}} ->
+ lists_key1search(Keys, Val);
+ false ->
+ undefined
+ end;
+lists_key1search(Key, List) when atom(Key) ->
+ case lists:keysearch(Key, 1, List) of
+ {value, {Key, Val}} ->
+ Val;
+ false ->
+ undefined
+ end.
+
+
+regs() ->
+ lists:sort(registered()).
diff --git a/lib/snmp/test/snmp_agent_mibs_test.erl b/lib/snmp/test/snmp_agent_mibs_test.erl
new file mode 100644
index 0000000000..5f1ff53a79
--- /dev/null
+++ b/lib/snmp/test/snmp_agent_mibs_test.erl
@@ -0,0 +1,721 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2003-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%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose:
+%%----------------------------------------------------------------------
+-module(snmp_agent_mibs_test).
+
+%%----------------------------------------------------------------------
+%% Include files
+%%----------------------------------------------------------------------
+-include("test_server.hrl").
+-include("snmp_test_lib.hrl").
+-include_lib("snmp/include/snmp_types.hrl").
+-include_lib("snmp/include/SNMP-COMMUNITY-MIB.hrl").
+-include_lib("snmp/include/SNMP-VIEW-BASED-ACM-MIB.hrl").
+-include_lib("snmp/include/SNMP-USER-BASED-SM-MIB.hrl").
+-include("snmp_test_data/Test2.hrl").
+
+
+%%----------------------------------------------------------------------
+%% External exports
+%%----------------------------------------------------------------------
+-export([
+ all/1,
+ init_per_testcase/2, fin_per_testcase/2,
+ init_all/1, finish_all/1,
+
+ start_and_stop/1,
+ size_check/1,
+ size_check_ets/1,
+ size_check_dets/1,
+ size_check_mnesia/1,
+ load_unload/1,
+ me_lookup/1,
+ which_mib/1,
+ cache_test/1
+
+ ]).
+
+%%----------------------------------------------------------------------
+%% Internal exports
+%%----------------------------------------------------------------------
+-export([
+ ]).
+
+%%----------------------------------------------------------------------
+%% Macros
+%%----------------------------------------------------------------------
+
+%%----------------------------------------------------------------------
+%% Records
+%%----------------------------------------------------------------------
+
+%%======================================================================
+%% External functions
+%%======================================================================
+
+init_per_testcase(size_check_dets, Config) when is_list(Config) ->
+ Dir = ?config(priv_dir, Config),
+ DetsDir = join(Dir, "dets_dir/"),
+ ?line ok = file:make_dir(DetsDir),
+ [{dets_dir, DetsDir}|Config];
+init_per_testcase(size_check_mnesia, Config) when is_list(Config) ->
+ Dir = ?config(priv_dir, Config),
+ MnesiaDir = join(Dir, "mnesia_dir/"),
+ ?line ok = file:make_dir(MnesiaDir),
+ mnesia_start([{dir, MnesiaDir}]),
+ [{mnesia_dir, MnesiaDir}|Config];
+init_per_testcase(cache_test, Config) when is_list(Config) ->
+ Min = timer:minutes(5),
+ Timeout =
+ case lists:keysearch(tc_timeout, 1, Config) of
+ {value, {tc_timeout, TcTimeout}} when TcTimeout < Min ->
+ Min;
+ {value, {tc_timeout, TcTimeout}} ->
+ TcTimeout;
+ _ ->
+ Min
+ end,
+ Dog = test_server:timetrap(Timeout),
+ [{watchdog, Dog} | Config];
+init_per_testcase(_Case, Config) when is_list(Config) ->
+ Config.
+
+fin_per_testcase(size_check_dets, Config) when is_list(Config) ->
+ Dir = ?config(dets_dir, Config),
+ ?line ok = ?DEL_DIR(Dir),
+ lists:keydelete(dets_dir, 1, Config);
+fin_per_testcase(size_check_mnesia, Config) when is_list(Config) ->
+ mnesia_stop(),
+ Dir = ?config(mnesia_dir, Config),
+ ?line ok = ?DEL_DIR(Dir),
+ lists:keydelete(mnesia_dir, 1, Config);
+fin_per_testcase(cache_test, Config) when is_list(Config) ->
+ Dog = ?config(watchdog, Config),
+ test_server:timetrap_cancel(Dog),
+ Config;
+fin_per_testcase(_Case, Config) when is_list(Config) ->
+ Config.
+
+
+%%======================================================================
+%% Test case definitions
+%%======================================================================
+
+all(suite) ->
+ {conf, init_all, cases(), finish_all}.
+
+cases() ->
+ [
+ start_and_stop,
+ load_unload,
+ size_check,
+ me_lookup,
+ which_mib,
+ cache_test
+ ].
+
+init_all(Config) when is_list(Config) ->
+ %% Data dir points wrong
+ DataDir0 = ?config(data_dir, Config),
+ DataDir1 = filename:split(filename:absname(DataDir0)),
+ [_|DataDir2] = lists:reverse(DataDir1),
+ DataDir = filename:join(lists:reverse(DataDir2) ++ [?snmp_test_data]),
+ [{snmp_data_dir, DataDir ++ "/"}|Config].
+
+finish_all(Config) when is_list(Config) ->
+ lists:keydelete(snmp_data_dir, 1, Config).
+
+
+%%======================================================================
+%% Test functions
+%%======================================================================
+
+start_and_stop(suite) -> [];
+start_and_stop(Config) when is_list(Config) ->
+ Prio = normal,
+ Verbosity = trace,
+
+ ?line sym_start(Prio, Verbosity),
+ ?line MibsPid = mibs_start(Prio, Verbosity),
+
+ ?line mibs_info(MibsPid),
+
+ ?line mibs_stop(MibsPid),
+ ?line sym_stop(),
+
+ ok.
+
+
+%% ---------------------------------------------------------------------
+
+load_unload(suite) -> [];
+load_unload(Config) when is_list(Config) ->
+ Prio = normal,
+ Verbosity = log,
+ %% MibStorage = ets,
+ MibDir = ?config(snmp_data_dir, Config),
+
+ ?DBG("load_unload -> start symbolic store", []),
+ ?line sym_start(Prio, Verbosity),
+
+ ?DBG("load_unload -> start mib server", []),
+ ?line MibsPid = mibs_start(Prio, Verbosity),
+
+ ?DBG("load_unload -> load one not already loaded mib", []),
+ ?line ok = verify_loaded_mibs(MibsPid, MibDir, []),
+ ?line ok = load_mibs(MibsPid, MibDir, ["Test2"]),
+ ?line ok = verify_loaded_mibs(MibsPid, MibDir, ["Test2"]),
+
+ ?DBG("load_unload -> load one already loaded mib", []),
+ ?line {error, _} = load_mibs(MibsPid, MibDir, ["Test2"]),
+
+ ?DBG("load_unload -> load 2 not already loaded mibs", []),
+ ?line ok = load_mibs(MibsPid, MibDir, ["TestTrap", "TestTrapv2"]),
+ ?line ok = verify_loaded_mibs(MibsPid, MibDir,
+ ["Test2", "TestTrap", "TestTrapv2"]),
+
+ ?DBG("load_unload -> unload one loaded mib", []),
+ ?line ok = unload_mibs(MibsPid, ["Test2"]),
+ ?line ok = verify_loaded_mibs(MibsPid, MibDir, ["TestTrap", "TestTrapv2"]),
+
+ ?DBG("load_unload -> try unload two loaded mibs and one not loaded", []),
+ ?line {error, _} = unload_mibs(MibsPid, ["TestTrap","Test2","TestTrapv2"]),
+ ?line ok = verify_loaded_mibs(MibsPid, MibDir, ["TestTrapv2"]),
+
+ ?DBG("load_unload -> unload the remaining loaded mib", []),
+ ?line ok = unload_mibs(MibsPid, ["TestTrapv2"]),
+ ?line ok = verify_loaded_mibs(MibsPid, MibDir, []),
+
+ ?DBG("load_unload -> stop mib server", []),
+ ?line mibs_stop(MibsPid),
+
+ ?DBG("load_unload -> stop symbolic store", []),
+ ?line sym_stop(),
+
+ ok.
+
+
+%% ---------------------------------------------------------------------
+
+size_check(suite) ->
+ [
+ size_check_ets,
+ size_check_dets,
+ size_check_mnesia
+ ].
+
+size_check_ets(suite) ->
+ [];
+size_check_ets(Config) when is_list(Config) ->
+ do_size_check([{mib_storage, ets}|Config]).
+
+size_check_dets(suite) ->
+ [];
+size_check_dets(Config) when is_list(Config) ->
+ Dir = ?config(dets_dir, Config),
+ do_size_check([{mib_storage, {dets, Dir}}|Config]).
+
+size_check_mnesia(suite) ->
+ [];
+size_check_mnesia(Config) when is_list(Config) ->
+ do_size_check([{mib_storage, {mnesia, [node()]}}|Config]).
+
+do_size_check(Config) ->
+ ?DBG("do_size_check -> start", []),
+ Prio = normal,
+ Verbosity = trace,
+
+ MibStorage = ?config(mib_storage, Config),
+ ?DBG("do_size_check -> MibStorage: ~p", [MibStorage]),
+ MibDir = ?config(snmp_data_dir, Config),
+ StdMibDir = filename:join(code:priv_dir(snmp), "mibs") ++ "/",
+
+ ?DBG("do_size_check -> start symbolic store", []),
+ ?line sym_start(Prio, MibStorage, Verbosity),
+ ?DBG("do_size_check -> start mib server", []),
+ ?line MibsPid = mibs_start(Prio, MibStorage, Verbosity),
+
+ Mibs = ["Test2", "TestTrap", "TestTrapv2"],
+ StdMibs = ["OTP-SNMPEA-MIB",
+ "SNMP-COMMUNITY-MIB",
+ "SNMP-FRAMEWORK-MIB",
+ "SNMP-MPD-MIB",
+ "SNMP-NOTIFICATION-MIB",
+ "SNMP-TARGET-MIB",
+ "SNMP-USER-BASED-SM-MIB",
+ "SNMP-VIEW-BASED-ACM-MIB",
+ "SNMPv2-MIB",
+ "SNMPv2-TC",
+ "SNMPv2-TM"],
+
+ ?DBG("do_size_check -> load mibs", []),
+ ?line load_mibs(MibsPid, MibDir, Mibs),
+ ?DBG("do_size_check -> load std mibs", []),
+ ?line load_mibs(MibsPid, StdMibDir, StdMibs),
+
+ ?SLEEP(2000),
+ ?DBG("do_size_check -> display mem usage", []),
+ ?line display_memory_usage(MibsPid),
+
+ ?DBG("do_size_check -> unload std mibs", []),
+ ?line unload_mibs(MibsPid, StdMibs),
+ ?DBG("do_size_check -> unload mibs", []),
+ ?line unload_mibs(MibsPid, Mibs),
+
+ ?DBG("do_size_check -> stop mib server", []),
+ ?line mibs_stop(MibsPid),
+ ?DBG("do_size_check -> stop symbolic store", []),
+ ?line sym_stop(),
+
+ ?DBG("do_size_check -> done", []),
+ ok.
+
+
+%% ---------------------------------------------------------------------
+
+me_lookup(suite) -> [];
+me_lookup(Config) when is_list(Config) ->
+ Prio = normal,
+ Verbosity = trace,
+ %% MibStorage = ets,
+ MibDir = ?config(snmp_data_dir, Config),
+ StdMibDir = filename:join(code:priv_dir(snmp), "mibs") ++ "/",
+ Mibs = ["Test2", "TestTrap", "TestTrapv2"],
+ StdMibs = ["OTP-SNMPEA-MIB",
+ "SNMP-COMMUNITY-MIB",
+ "SNMP-FRAMEWORK-MIB",
+ "SNMP-MPD-MIB",
+ "SNMP-NOTIFICATION-MIB",
+ "SNMP-TARGET-MIB",
+ %% "SNMP-USER-BASED-SM-MIB",
+ "SNMP-VIEW-BASED-ACM-MIB",
+ "SNMPv2-MIB",
+ "SNMPv2-TC",
+ "SNMPv2-TM"],
+
+ ?DBG("me_lookup -> start symbolic store", []),
+ ?line sym_start(Prio, Verbosity),
+
+ ?DBG("me_lookup -> start mib server", []),
+ ?line MibsPid = mibs_start(Prio, Verbosity),
+
+ ?DBG("me_lookup -> load mibs", []),
+ ?line load_mibs(MibsPid, MibDir, Mibs),
+ ?DBG("me_lookup -> load std mibs", []),
+ ?line load_mibs(MibsPid, StdMibDir, StdMibs),
+
+ ?DBG("me_lookup -> find ~w from SNMP-COMMUNITY-MIB",
+ [?snmpTrapCommunity_instance]),
+ ?line ok = me_lookup(MibsPid, ?snmpTrapCommunity_instance),
+
+ ?DBG("me_lookup -> find ~w from SNMP-VIEW-BASED-ACM-MIB",
+ [?vacmViewSpinLock_instance]),
+ ?line ok = me_lookup(MibsPid, ?vacmViewSpinLock_instance),
+
+ ?DBG("me_lookup -> find ~w from SNMP-USER-BASED-SM-MIB",
+ [?usmStatsNotInTimeWindows_instance]),
+ ?line {error, _} = me_lookup(MibsPid, ?usmStatsNotInTimeWindows_instance),
+
+ ?DBG("me_lookup -> stop mib server", []),
+ ?line mibs_stop(MibsPid),
+
+ ?DBG("me_lookup -> stop symbolic store", []),
+ ?line sym_stop(),
+
+ ok.
+
+
+%% ---------------------------------------------------------------------
+
+which_mib(suite) -> [];
+which_mib(Config) when is_list(Config) ->
+ Prio = normal,
+ Verbosity = trace,
+ %% MibStorage = ets,
+ MibDir = ?config(snmp_data_dir, Config),
+ StdMibDir = filename:join(code:priv_dir(snmp), "mibs") ++ "/",
+ Mibs = ["Test2", "TestTrap", "TestTrapv2"],
+ StdMibs = ["OTP-SNMPEA-MIB",
+ "SNMP-COMMUNITY-MIB",
+ "SNMP-FRAMEWORK-MIB",
+ "SNMP-MPD-MIB",
+ "SNMP-NOTIFICATION-MIB",
+ "SNMP-TARGET-MIB",
+ %% "SNMP-USER-BASED-SM-MIB",
+ "SNMP-VIEW-BASED-ACM-MIB",
+ "SNMPv2-MIB",
+ "SNMPv2-TC",
+ "SNMPv2-TM"],
+
+ ?DBG("which_mib -> start symbolic store", []),
+ ?line sym_start(Prio, Verbosity),
+
+ ?DBG("which_mib -> start mib server", []),
+ ?line MibsPid = mibs_start(Prio, Verbosity),
+
+ ?DBG("which_mib -> load mibs", []),
+ ?line load_mibs(MibsPid, MibDir, Mibs),
+ ?DBG("which_mib -> load std mibs", []),
+ ?line load_mibs(MibsPid, StdMibDir, StdMibs),
+
+ ?DBG("which_mib -> find ~w from SNMP-COMMUNITY-MIB",
+ [?snmpTrapCommunity_instance]),
+ ?line ok = which_mib(MibsPid, ?snmpTrapCommunity_instance,
+ "SNMP-COMMUNITY-MIB"),
+
+ ?DBG("which_mib -> find ~w from SNMP-VIEW-BASED-ACM-MIB",
+ [?vacmViewSpinLock_instance]),
+ ?line ok = which_mib(MibsPid, ?vacmViewSpinLock_instance,
+ "SNMP-VIEW-BASED-ACM-MIB"),
+
+ ?DBG("which_mib -> find ~w from SNMP-USER-BASED-SM-MIB (not loaded)",
+ [?usmStatsNotInTimeWindows_instance]),
+ ?line {error, _} = which_mib(MibsPid, ?usmStatsNotInTimeWindows_instance,
+ "SNMP-USER-BASED-SM-MIB"),
+
+ ?DBG("which_mib -> stop mib server", []),
+ ?line mibs_stop(MibsPid),
+
+ ?DBG("which_mib -> stop symbolic store", []),
+ ?line sym_stop(),
+
+ ok.
+
+
+%% ---------------------------------------------------------------------
+
+cache_test(suite) -> [];
+cache_test(Config) when is_list(Config) ->
+ ?DBG("cache_test -> start", []),
+ Prio = normal,
+ Verbosity = trace,
+ MibStorage = ets,
+ MibDir = ?config(snmp_data_dir, Config),
+ StdMibDir = filename:join(code:priv_dir(snmp), "mibs") ++ "/",
+ Mibs = ["Test2", "TestTrap", "TestTrapv2"],
+ StdMibs = ["OTP-SNMPEA-MIB",
+ "SNMP-COMMUNITY-MIB",
+ "SNMP-FRAMEWORK-MIB",
+ "SNMP-MPD-MIB",
+ "SNMP-NOTIFICATION-MIB",
+ "SNMP-TARGET-MIB",
+ %% "SNMP-USER-BASED-SM-MIB",
+ "SNMP-VIEW-BASED-ACM-MIB",
+ "SNMPv2-MIB",
+ "SNMPv2-TC",
+ "SNMPv2-TM"],
+
+ ?DBG("cache_test -> start symbolic store", []),
+ ?line sym_start(Prio, MibStorage, Verbosity),
+
+ ?DBG("cache_test -> start mib server", []),
+ GcLimit = 2,
+ Age = timer:seconds(10),
+ CacheOpts = [{autogc, false}, {age, Age}, {gclimit, GcLimit}],
+ ?line MibsPid = mibs_start(Prio, MibStorage, [], Verbosity, CacheOpts),
+
+ ?DBG("cache_test -> load mibs", []),
+ ?line load_mibs(MibsPid, MibDir, Mibs),
+ ?DBG("cache_test -> load std mibs", []),
+ ?line load_mibs(MibsPid, StdMibDir, StdMibs),
+
+ ?DBG("cache_test -> do a simple walk to populate the cache", []),
+ ?line ok = walk(MibsPid),
+
+ {ok, Sz1} = snmpa_mib:which_cache_size(MibsPid),
+ ?DBG("cache_test -> Size1: ~p", [Sz1]),
+
+ ?DBG("cache_test -> sleep 5 secs", []),
+ ?SLEEP(timer:seconds(5)),
+
+ ?DBG("cache_test -> perform gc, expect nothing", []),
+ {ok, 0} = snmpa_mib:gc_cache(MibsPid),
+
+ ?DBG("cache_test -> sleep 10 secs", []),
+ ?SLEEP(timer:seconds(10)),
+
+ ?DBG("cache_test -> perform gc, expect GcLimit", []),
+ GcLimit1 = GcLimit + 1,
+ {ok, GcLimit1} = snmpa_mib:gc_cache(MibsPid, Age, GcLimit1),
+
+ Sz2 = Sz1 - GcLimit1,
+ {ok, Sz2} = snmpa_mib:which_cache_size(MibsPid),
+ ?DBG("cache_test -> Size2: ~p", [Sz2]),
+
+ ?DBG("cache_test -> enable cache autogc", []),
+ ?line ok = snmpa_mib:enable_cache_autogc(MibsPid),
+
+ ?DBG("cache_test -> wait 65 seconds to allow gc to happen", []),
+ ?SLEEP(timer:seconds(65)),
+ Sz3 = Sz2 - GcLimit,
+ {ok, Sz3} = snmpa_mib:which_cache_size(MibsPid),
+ ?DBG("cache_test -> Size3: ~p", [Sz3]),
+
+ ?DBG("cache_test -> "
+ "wait 2 minutes to allow gc to happen, expect empty cache", []),
+ ?SLEEP(timer:minutes(2)),
+ {ok, 0} = snmpa_mib:which_cache_size(MibsPid),
+
+ ?DBG("cache_test -> stop mib server", []),
+ ?line mibs_stop(MibsPid),
+
+ ?DBG("cache_test -> stop symbolic store", []),
+ ?line sym_stop(),
+ ok.
+
+walk(MibsPid) ->
+ MibView = snmpa_acm:get_root_mib_view(),
+ do_walk(MibsPid, ?snmpTrapCommunity_instance, MibView),
+ do_walk(MibsPid, ?vacmViewSpinLock_instance, MibView),
+ do_walk(MibsPid, ?usmStatsNotInTimeWindows_instance, MibView),
+ do_walk(MibsPid, ?tDescr_instance, MibView).
+
+
+do_walk(MibsPid, Oid, MibView) ->
+ io:format("do_walk -> entry with"
+ "~n Oid: ~p"
+ "~n", [Oid]),
+ case snmpa_mib:next(MibsPid, Oid, MibView) of
+ {table, _, _, #me{oid = Oid}} ->
+ ok;
+ {table, _, _, #me{oid = Next}} ->
+ do_walk(MibsPid, Next, MibView);
+ {variable, #me{oid = Oid}, _} ->
+ ok;
+ {variable, #me{oid = Next}, _} ->
+ do_walk(MibsPid, Next, MibView)
+ end.
+
+
+%%======================================================================
+%% Internal functions
+%%======================================================================
+
+%% -- Mnesia functions
+
+mnesia_start(Opts) ->
+ mnesia_start(Opts, [node()]).
+
+mnesia_start(Opts, Nodes) ->
+ ?DBG("mnesia_start -> load mnesia", []),
+ ?line ok = application:load(mnesia),
+ F = fun({Key, Val}) ->
+ ?DBG("mnesia_start -> set mnesia env: ~n~p -> ~p", [Key,Val]),
+ ?line application_controller:set_env(mnesia, Key, Val)
+ end,
+ lists:foreach(F, Opts),
+ ?DBG("mnesia_start -> create mnesia schema on ~p", [Nodes]),
+ ?line ok = mnesia:create_schema(Nodes),
+ ?DBG("mnesia_start -> start mnesia", []),
+ ?line ok = application:start(mnesia),
+ ok.
+
+mnesia_stop() ->
+ ?DBG("mnesia_stop -> stop mnesia", []),
+ application:stop(mnesia),
+ ?DBG("mnesia_stop -> unload mnesia", []),
+ application:unload(mnesia),
+ ok.
+
+%% - Symbolic Store mini interface
+
+sym_start(Prio, Verbosity) ->
+ sym_start(Prio, ets, Verbosity).
+
+sym_start(Prio, MibStorage, Verbosity) ->
+ Opts = [{mib_storage, MibStorage}, {verbosity,Verbosity}],
+ {ok, _Pid} = snmpa_symbolic_store:start_link(Prio, Opts),
+ ok.
+
+sym_stop() ->
+ ok = snmpa_symbolic_store:stop().
+
+sym_info() ->
+ snmpa_symbolic_store:info().
+
+
+%% -- MIB server mini interface
+
+mibs_start(Prio, Verbosity) when is_atom(Prio) andalso is_atom(Verbosity) ->
+ mibs_start(Prio, ets, [], Verbosity).
+
+mibs_start(Prio, MibStorage, Verbosity)
+ when is_atom(Prio) andalso is_atom(Verbosity) ->
+ mibs_start(Prio, MibStorage, [], Verbosity).
+
+mibs_start(Prio, MibStorage, Mibs, Verbosity)
+ when is_atom(Prio) andalso
+ is_list(Mibs) andalso
+ is_atom(Verbosity) ->
+ mibs_start(Prio, MibStorage, Mibs, Verbosity, []).
+
+mibs_start(Prio, MibStorage, Mibs, Verbosity, CacheOpts)
+ when is_atom(Prio) andalso
+ is_list(Mibs) andalso
+ is_atom(Verbosity) andalso
+ is_list(CacheOpts) ->
+ Opts = [{mib_storage, MibStorage},
+ {verbosity, Verbosity},
+ {cache, CacheOpts}],
+ {ok, Pid} = snmpa_mib:start_link(Prio, Mibs, Opts),
+ Pid.
+
+mibs_stop(Pid) ->
+ ok = snmpa_mib:stop(Pid).
+
+mibs_info(Pid) ->
+ snmpa_mib:info(Pid).
+
+load_mibs(Pid, Dir, Mibs0) ->
+ Mibs = [join(Dir, Mib) || Mib <- Mibs0],
+ snmpa_mib:load_mibs(Pid, Mibs).
+
+unload_mibs(Pid, Mibs) ->
+ snmpa_mib:unload_mibs(Pid, Mibs).
+
+verify_loaded_mibs(Pid, Dir, ExpectedMibs0) ->
+ ExpectedMibs = [join(Dir, Mib) || Mib <- ExpectedMibs0],
+ case snmpa_mib:info(Pid, loaded_mibs) of
+ ExpectedMibs ->
+ ok;
+ LoadedMibs0 ->
+ ?DBG("verify_loaded_mibs -> LoadedMibs0: ~p", [LoadedMibs0]),
+ LoadedMibs = [filename:rootname(FN, ".bin") || FN <- LoadedMibs0],
+ ?DBG("verify_loaded_mibs -> LoadedMibs: ~p", [LoadedMibs]),
+ ExpNotLoadedMibs = ExpectedMibs -- LoadedMibs,
+ LoadedNotExpMibs = LoadedMibs -- ExpectedMibs,
+ ?DBG("verify_loaded_mibs -> "
+ "~n ExpNotLoadedMibs: ~p"
+ "~n LoadedNotExpMibs: ~p",
+ [ExpNotLoadedMibs, LoadedNotExpMibs]),
+ case ExpNotLoadedMibs of
+ [] ->
+ case LoadedNotExpMibs of
+ [] ->
+ ok;
+ _ ->
+ {error, {unexpected_loaded_mibs, LoadedNotExpMibs}}
+ end;
+ _ ->
+ case LoadedNotExpMibs of
+ [] ->
+ {error, {not_loaded_mibs, ExpNotLoadedMibs}};
+ _ ->
+ {error, {unexpected_mibs,
+ ExpNotLoadedMibs, LoadedNotExpMibs}}
+ end
+ end
+
+ end.
+
+me_lookup(Pid, Oid) ->
+ case snmpa_mib:lookup(Pid, Oid) of
+ {variable, #me{oid = Oid}} ->
+ ok;
+ {variable, #me{oid = OtherOid}} ->
+ case lists:reverse(Oid) of
+ [0|Rest] ->
+ case lists:reverse(Rest) of
+ OtherOid ->
+ ok;
+ AnotherOid ->
+ {error, {invalid_oid, Oid, AnotherOid}}
+ end;
+ _ ->
+ {error, {invalid_oid, Oid, OtherOid}}
+ end;
+ {table_column, _ME, _TableEntryOid} ->
+ ok;
+ {subagent, SubAgentPid, _SANextOid} ->
+ {error, {subagent, SubAgentPid}};
+ {false, Reason} ->
+ {error, Reason};
+ Else ->
+ {error, Else}
+ end.
+
+
+which_mib(Pid, Oid, Mib1) ->
+ case snmpa_mib:which_mib(Pid, Oid) of
+ {ok, Mib2} when is_atom(Mib2) ->
+ Mib3 = atom_to_list(Mib2),
+ which_mib(Mib1, Mib3);
+ {ok, Mib2} ->
+ which_mib(Mib1, Mib2);
+ {error, Reason} ->
+ {error, Reason};
+ Else ->
+ {error, Else}
+ end.
+
+which_mib(M, M) ->
+ ok;
+which_mib(M1, M2) ->
+ {error, {invalid_mib, M1, M2}}.
+
+
+%% --
+
+display_memory_usage(MibsPid) ->
+ SymInfo = sym_info(),
+ SymProcSize = key1search(process_memory, SymInfo),
+ DbSize = key1search(db_memory, SymInfo),
+ MibsInfo = mibs_info(MibsPid),
+ TreeSize = key1search(tree_size_bytes, MibsInfo),
+ MibsProcMem = key1search(process_memory, MibsInfo),
+ MibDbSize = key1search([db_memory,mib], MibsInfo),
+ NodeDbSize = key1search([db_memory,node], MibsInfo),
+ TreeDbSize = key1search([db_memory,tree], MibsInfo),
+ ?INF("Symbolic store memory usage: "
+ "~n Process memory size: ~p"
+ "~n Db size: ~p"
+ "~n"
+ "~nMib server memory usage: "
+ "~n Tree size: ~p"
+ "~n Process memory size: ~p"
+ "~n Mib db size: ~p"
+ "~n Node db size: ~p"
+ "~n Tree db size: ~p"
+ "~n",
+ [SymProcSize, DbSize,
+ TreeSize, MibsProcMem, MibDbSize, NodeDbSize, TreeDbSize]).
+
+key1search([], Res) ->
+ Res;
+key1search([Key|Keys], List) when is_atom(Key) andalso is_list(List) ->
+ case lists:keysearch(Key, 1, List) of
+ {value, {Key, Val}} ->
+ key1search(Keys, Val);
+ false ->
+ undefined
+ end;
+key1search(Key, List) when is_atom(Key) ->
+ case lists:keysearch(Key, 1, List) of
+ {value, {Key, Val}} ->
+ Val;
+ false ->
+ undefined
+ end.
+
+join(Dir, File) ->
+ filename:join(Dir, File).
diff --git a/lib/snmp/test/snmp_agent_ms_test.erl b/lib/snmp/test/snmp_agent_ms_test.erl
new file mode 100644
index 0000000000..3a3a790e6a
--- /dev/null
+++ b/lib/snmp/test/snmp_agent_ms_test.erl
@@ -0,0 +1,5657 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2005-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%
+%%
+
+-module(snmp_agent_ms_test).
+
+%% TODO
+%% * Test fault-tolerance (kill master etc)
+%%
+
+-compile(export_all).
+
+-define(application, snmp).
+
+-include_lib("kernel/include/file.hrl").
+-include("test_server.hrl").
+-include("snmp_test_lib.hrl").
+-define(SNMP_USE_V3, true).
+-include_lib("snmp/include/snmp_types.hrl").
+%% -include_lib("snmp/include/SNMP-COMMUNITY-MIB.hrl").
+%% -include_lib("snmp/include/SNMP-VIEW-BASED-ACM-MIB.hrl").
+%% -include_lib("snmp/include/SNMP-USER-BASED-SM-MIB.hrl").
+
+
+-define(klas1, [1,3,6,1,2,1,7]).
+-define(klas2, [1,3,6,1,2,1,9]).
+-define(klas3, [1,3,6,1,2,1,8,1]).
+-define(klas4, [1,3,6,1,2,1,8,4]).
+-define(sa, [1,3,6,1,4,1,193,2]).
+-define(system, [1,3,6,1,2,1,1]).
+-define(snmp, [1,3,6,1,2,1,11]).
+-define(snmpTraps, [1,3,6,1,6,3,1,1,5]).
+-define(ericsson, [1,3,6,1,4,1,193]).
+-define(testTrap, [1,3,6,1,2,1,15,0]).
+-define(xDescr, [1,3,6,1,2,1,17,1]).
+-define(xDescr2, [1,3,6,1,2,1,17,2]).
+
+-define(active, 1).
+-define(notInService, 2).
+-define(notReady, 3).
+-define(createAndGo, 4).
+-define(createAndWait, 5).
+-define(destroy, 6).
+
+-define(TRAP_UDP, 5000).
+
+-define(tooBigStr, "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").
+
+-define(str(X), snmp_pdus:bits_to_str(X)).
+
+-define(break(), begin io:format(user, "break at line ~w: pid: ~p\n",
+ [?LINE, self()]),
+ receive cont -> ok end
+ end).
+
+
+-import(snmp_test_mgr, [gn/1, g/1, s/1, gb/3]).
+-define(v1_2(V1,V2),
+ case get(vsn) of
+ v1 -> V1;
+ _ -> V2
+ end).
+
+-define(v1_2_3(V1,V2,V3),
+ case get(vsn) of
+ v1 -> V1;
+ v2 -> V2;
+ _ -> V3
+ end).
+
+all(suite) -> {req,
+ [mnesia, distribution,
+ {local_slave_nodes, 2}, {time, 360}],
+ [{conf, init_all, cases(), finish_all}]}.
+
+init_per_testcase(_Case, Config) when list(Config) ->
+ Dog = ?t:timetrap(?t:minutes(6)),
+ [{watchdog, Dog}|Config].
+
+fin_per_testcase(_Case, Config) when list(Config) ->
+ Dog = ?config(watchdog, Config),
+ ?t:timetrap_cancel(Dog),
+ Config.
+
+cases() ->
+ case ?OSTYPE() of
+ vxworks ->
+ %% No crypto app, so skip v3 testcases
+ [
+ app_info,
+ test_v1, test_v2, test_v1_v2,
+ test_multi_threaded,
+ mib_storage,
+ tickets];
+ _Else ->
+ [
+ app_info,
+ test_v1, test_v2, test_v1_v2, test_v3,
+ test_multi_threaded,
+ mib_storage,
+ tickets
+ ]
+ end.
+
+
+%%%-----------------------------------------------------------------
+%%% The test case structure is as follows:
+%%%
+%%% init_all - starts mnesia,
+%%%
+%%% init_v1 - starts agent
+%%% simple
+%%% big - e.g. starts/stops subagent, load/unloads mibs
+%%% init_mul
+%%% mul_get
+%%% mul_set
+%%% <etc>
+%%% finish_mul
+%%% <etc>
+%%% finish_v1
+%%%
+%%% init_v2 - starts agent
+%%% finish_v2
+%%%
+%%% init_bilingual - starts agent
+%%% finish_bilingual
+%%%
+%%% finish_all
+%%%
+%%% There is still one problem with these testsuites. If one test
+%%% fails, it may not be possible to run some other cases, as it
+%%% may have e.g. created some row or loaded some table, that it
+%%% didn't undo (since it failed).
+%%%-----------------------------------------------------------------
+
+init_all(Config0) when list(Config0) ->
+ ?LOG("init_all -> entry with"
+ "~n Config0: ~p",[Config0]),
+
+ %% --
+ %% Fix config:
+ %%
+
+ DataDir0 = ?config(data_dir, Config0),
+ DataDir1 = filename:split(filename:absname(DataDir0)),
+ [_|DataDir2] = lists:reverse(DataDir1),
+ DataDir3 = filename:join(lists:reverse(DataDir2) ++ [?snmp_test_data]),
+ Config1 = lists:keydelete(data_dir, 1, Config0),
+ Config = [{data_dir, DataDir3 ++ "/"}|Config1],
+
+ %% --
+ %% Start nodes
+ %%
+
+ ?line {ok, SaNode} = start_node(snmp_sa),
+ ?line {ok, MgrNode} = start_node(snmp_mgr),
+
+
+ %% --
+ %% Create necessary files
+ %%
+
+ Dir = ?config(priv_dir, Config),
+ ?DBG("init_all -> Dir ~p", [Dir]),
+
+ DataDir = ?config(data_dir, Config),
+ ?DBG("init_all -> DataDir ~p", [DataDir]),
+
+ file:make_dir(MgrDir = filename:join(Dir, "mgr_dir/")),
+ ?DBG("init_all -> MgrDir ~p", [MgrDir]),
+
+ file:make_dir(AgentDir = filename:join(Dir, "agent_dir/")),
+ ?DBG("init_all -> AgentDir ~p", [AgentDir]),
+
+ file:make_dir(SaDir = filename:join(Dir, "sa_dir/")),
+ ?DBG("init_all -> SaDir ~p", [SaDir]),
+
+
+ %% --
+ %% Start and initiate mnesia
+ %%
+
+ ?DBG("init_all -> load application mnesia", []),
+ ?line ok = application:load(mnesia),
+
+ ?DBG("init_all -> load application mnesia on node ~p", [SaNode]),
+ ?line ok = rpc:call(SaNode, application, load, [mnesia]),
+
+ ?DBG("init_all -> application mnesia: set_env dir",[]),
+ ?line application_controller:set_env(mnesia, dir,
+ filename:join(Dir, "Mnesia1")),
+
+ ?DBG("init_all -> application mnesia: set_env dir on node ~p",[SaNode]),
+ ?line rpc:call(SaNode, application_controller, set_env,
+ [mnesia, dir, filename:join(Dir, "Mnesia2")]),
+
+ ?DBG("init_all -> create mnesia schema",[]),
+ ?line ok = mnesia:create_schema([SaNode, node()]),
+
+ ?DBG("init_all -> start application mnesia",[]),
+ ?line ok = application:start(mnesia),
+
+ ?DBG("init_all -> start application mnesia on ~p",[SaNode]),
+ ?line ok = rpc:call(SaNode, application, start, [mnesia]),
+ Ip = ?LOCALHOST(),
+ [{snmp_sa, SaNode},
+ {snmp_mgr, MgrNode},
+ {agent_dir, AgentDir ++ "/"},
+ {mgr_dir, MgrDir ++ "/"},
+ {sa_dir, SaDir ++ "/"},
+ {mib_dir, DataDir},
+ {ip, Ip} |
+ Config].
+
+finish_all(Config) when list(Config) ->
+ SaNode = ?config(snmp_sa, Config),
+ MgrNode = ?config(snmp_mgr, Config),
+ stop_node(SaNode),
+ stop_node(MgrNode),
+ application:stop(mnesia).
+
+start_v1_agent(Config) when list(Config) ->
+ start_agent(Config, [v1]).
+
+start_v1_agent(Config,Opts) when list(Config), list(Opts) ->
+ start_agent(Config, [v1], Opts).
+
+start_v2_agent(Config) when list(Config) ->
+ start_agent(Config, [v2]).
+
+start_v3_agent(Config) when list(Config) ->
+ start_agent(Config, [v3]).
+
+start_bilingual_agent(Config) when list(Config) ->
+ start_agent(Config, [v1,v2]).
+
+start_multi_threaded_agent(Config) when list(Config) ->
+ start_agent(Config, [v2], [{snmp_multi_threaded, true}]).
+
+stop_agent(Config) when list(Config) ->
+ ?LOG("stop_agent -> entry with"
+ "~n Config: ~p",[Config]),
+
+ {Sup, Par} = ?config(snmp_sup, Config),
+ ?DBG("stop_agent -> attempt to stop (sup) ~p"
+ "~n Sup: ~p"
+ "~n Par: ~p",
+ [Sup,
+ (catch process_info(Sup)),
+ (catch process_info(Par))]),
+ stop_sup(Sup, Par),
+
+ {Sup2, Par2} = ?config(snmp_sub, Config),
+ ?DBG("stop_agent -> attempt to stop (sub) ~p"
+ "~n Sup2: ~p"
+ "~n Par2: ~p",
+ [Sup2,
+ (catch process_info(Sup2)),
+ (catch process_info(Par2))]),
+ stop_sup(Sup2, Par2),
+
+ ?DBG("stop_agent -> done - now cleanup config", []),
+ C1 = lists:keydelete(snmp_sup, 1, Config),
+ lists:keydelete(snmp_sub, 1, C1).
+
+
+stop_sup(Pid, _) when node(Pid) == node() ->
+ case (catch process_info(Pid)) of
+ PI when list(PI) ->
+ ?LOG("stop_sup -> attempt to stop ~p", [Pid]),
+ Ref = erlang:monitor(process, Pid),
+ exit(Pid, kill),
+ await_stopped(Pid, Ref);
+ {'EXIT', _Reason} ->
+ ?LOG("stop_sup -> ~p not running", [Pid]),
+ ok
+ end;
+stop_sup(Pid, _) ->
+ ?LOG("stop_sup -> attempt to stop ~p", [Pid]),
+ Ref = erlang:monitor(process, Pid),
+ ?LOG("stop_sup -> Ref: ~p", [Ref]),
+ %% Pid ! {'EXIT', Parent, shutdown}, % usch
+ exit(Pid, kill),
+ await_stopped(Pid, Ref).
+
+await_stopped(Pid, Ref) ->
+ receive
+ {'DOWN', Ref, process, Pid, _Reason} ->
+ ?DBG("received down message for ~p", [Pid]),
+ ok
+ after 10000 ->
+ ?INF("await_stopped -> timeout for ~p",[Pid]),
+ erlang:demonitor(Ref),
+ ?FAIL({failed_stop,Pid})
+ end.
+
+
+start_agent(Config, Vsn) ->
+ start_agent(Config, Vsn, []).
+start_agent(Config, Vsn, Opts) ->
+ ?LOG("start_agent -> entry (~p) with"
+ "~n Config: ~p"
+ "~n Vsn: ~p"
+ "~n Opts: ~p",[node(), Config, Vsn, Opts]),
+
+ ?line AgentDir = ?config(agent_dir, Config),
+ ?line SaNode = ?config(snmp_sa, Config),
+
+ snmp_app_env_init(vsn_init(Vsn) ++
+ [{audit_trail_log, read_write_log},
+ {audit_trail_log_dir, AgentDir},
+ {audit_trail_log_size, {10240, 10}},
+ {force_config_reload, false},
+ {snmp_agent_type, master},
+ {snmp_config_dir, AgentDir},
+ {snmp_db_dir, AgentDir},
+ {snmp_local_db_auto_repair, true},
+ {snmp_master_agent_verbosity, trace},
+ {snmp_supervisor_verbosity, trace},
+ {snmp_mibserver_verbosity, trace},
+ {snmp_symbolic_store_verbosity, trace},
+ {snmp_note_store_verbosity, trace},
+ {snmp_net_if_verbosity, trace}],
+ Opts),
+
+
+ process_flag(trap_exit,true),
+
+ {ok, AppSup} = snmp_app_sup:start_link(),
+ unlink(AppSup),
+ ?DBG("start_agent -> snmp app supervisor: ~p",[AppSup]),
+
+ ?DBG("start_agent -> start master agent (old style)",[]),
+ Sup = case (catch snmpa_app:start(normal)) of
+ {ok, S} ->
+ ?DBG("start_agent -> started, Sup: ~p",[S]),
+ S;
+
+ Else ->
+ ?DBG("start_agent -> unknown result: ~n~p",[Else]),
+ %% Get info about the apps we depend on
+ MnesiaInfo = mnesia_running(),
+ ?FAIL({start_failed,Else,MnesiaInfo})
+ end,
+
+ ?DBG("start_agent -> unlink from supervisor",[]),
+ ?line unlink(Sup),
+ ?line SaDir = ?config(sa_dir, Config),
+ ?DBG("start_agent -> (rpc) start sub on ~p",[SaNode]),
+ ?line {ok, Sub} = rpc:call(SaNode, ?MODULE, start_sub, [SaDir]),
+ ?DBG("start_agent -> done",[]),
+ ?line [{snmp_sup, {Sup, self()}}, {snmp_sub, Sub} | Config].
+
+
+vsn_init(Vsn) ->
+ vsn_init([v1,v2,v3], Vsn, []).
+
+vsn_init([], _Vsn, Acc) ->
+ Acc;
+vsn_init([V|Vsns], Vsn, Acc) ->
+ case lists:member(V, Vsn) of
+ true ->
+ vsn_init(Vsns, Vsn, [{V, true}|Acc]);
+ false ->
+ vsn_init(Vsns, Vsn, [{V, false}|Acc])
+ end.
+
+snmp_app_env_init(Env0, Opts) ->
+ ?DBG("snmp_app_env_init -> unload snmp",[]),
+ ?line application:unload(snmp),
+ ?DBG("snmp_app_env_init -> load snmp",[]),
+ ?line application:load(snmp),
+ ?DBG("snmp_app_env_init -> initiate (snmp) application env",[]),
+ F1 = fun({Key,Val} = New, Acc0) ->
+ ?DBG("snmp_app_env_init -> "
+ "updating setting ~p to ~p", [Key, Val]),
+ case lists:keyreplace(Key, 1, Acc0, New) of
+ Acc0 ->
+ [New|Acc0];
+ Acc ->
+ Acc
+ end
+ end,
+ Env = lists:foldr(F1, Env0, Opts),
+ ?DBG("snmp_app_env_init -> Env: ~p",[Env]),
+ F2 = fun({Key,Val}) ->
+ ?DBG("snmp_app_env_init -> setting ~p to ~p",[Key, Val]),
+ application_controller:set_env(snmp, Key, Val)
+ end,
+ lists:foreach(F2, Env).
+
+
+
+
+%% Test if application is running
+mnesia_running() -> ?IS_MNESIA_RUNNING().
+crypto_running() -> ?IS_CRYPTO_RUNNING().
+
+
+start_sub(Dir) ->
+ ?DBG("start_sub -> entry",[]),
+ Opts = [{db_dir, Dir},
+ {supervisor, [{verbosity, trace}]}],
+ %% BMK BMK
+% {ok, P} = snmp_supervisor:start_sub(Dir),
+ {ok, P} = snmpa_supervisor:start_sub_sup(Opts),
+ unlink(P),
+ {ok, {P, self()}}.
+
+create_tables(SaNode) ->
+ ?line {atomic, ok} = mnesia:create_table([{name, friendsTable2},
+ {ram_copies, [SaNode]},
+ {snmp, [{key, integer}]},
+ {attributes, [a1,a2,a3]}]),
+ ?line {atomic, ok} = mnesia:create_table([{name, kompissTable2},
+ {ram_copies, [SaNode]},
+ {snmp, [{key, integer}]},
+ {attributes, [a1,a2,a3]}]),
+ ?line {atomic, ok} = mnesia:create_table([{name, snmp_variables},
+ {attributes, [a1,a2]}]).
+
+delete_tables() ->
+ mnesia:delete_table(friendsTable2),
+ mnesia:delete_table(kompissTable2),
+ mnesia:delete_table(snmp_variables).
+
+%% Creation is done in runtime!
+delete_mib_storage_mnesia_tables() ->
+ mnesia:delete_table(snmpa_mib_data),
+ mnesia:delete_table(snmpa_mib_tree),
+ mnesia:delete_table(snmpa_symbolic_store).
+
+%%-----------------------------------------------------------------
+%% A test case is always one of:
+%% - v1 specific case
+%% - v2 specific case
+%% - v1 and v2 case
+%% All v1 specific cases are prefixed with v1_, and all v2 with
+%% v2_. E.g. v1_trap/v2_trap.
+%%
+%% All other cases are shared. However, the testserver uses the name
+%% of the case to generate a file for that case. The same case cannot
+%% be used in different configurations in the same suite. Therefore
+%% all these functions exists in two variants, the base function
+%% <base>, and a second version <base>_2. There may be several
+%% versions as well, <base>_N.
+%%-----------------------------------------------------------------
+mib_storage(suite) -> [
+ mib_storage_ets,
+ mib_storage_dets,
+ mib_storage_mnesia,
+ mib_storage_size_check_ets,
+ mib_storage_size_check_dets,
+ mib_storage_size_check_mnesia,
+ mib_storage_varm_dets,
+ mib_storage_varm_mnesia
+ ].
+
+mib_storage_ets(suite) -> {req, [], {conf, init_mib_storage_ets,
+ mib_storage_ets_cases(),
+ finish_mib_storage_ets}}.
+
+mib_storage_dets(suite) -> {req, [], {conf, init_mib_storage_dets,
+ mib_storage_dets_cases(),
+ finish_mib_storage_dets}}.
+
+mib_storage_mnesia(suite) -> {req, [], {conf, init_mib_storage_mnesia,
+ mib_storage_mnesia_cases(),
+ finish_mib_storage_mnesia}}.
+
+mib_storage_size_check_ets(suite) ->
+ {req, [], {conf,
+ init_size_check_mse,
+ mse_size_check_cases(),
+ finish_size_check_mse}}.
+
+mib_storage_size_check_dets(suite) ->
+ {req, [], {conf,
+ init_size_check_msd,
+ msd_size_check_cases(),
+ finish_size_check_msd}}.
+
+mib_storage_size_check_mnesia(suite) ->
+ {req, [], {conf,
+ init_size_check_msm,
+ msm_size_check_cases(),
+ finish_size_check_msm}}.
+
+mib_storage_varm_dets(suite) ->
+ {req, [], {conf,
+ init_varm_mib_storage_dets,
+ varm_mib_storage_dets_cases(),
+ finish_varm_mib_storage_dets}}.
+
+mib_storage_varm_mnesia(suite) ->
+ {req, [], {conf,
+ init_varm_mib_storage_mnesia,
+ varm_mib_storage_mnesia_cases(),
+ finish_varm_mib_storage_mnesia}}.
+
+mib_storage_ets_cases() ->
+ [
+ mse_simple,
+ mse_v1_processing,
+ mse_big,
+ mse_big2,
+ mse_loop_mib,
+ mse_api,
+ mse_sa_register,
+ mse_v1_trap,
+ mse_sa_error,
+ mse_next_across_sa,
+ mse_undo,
+ mse_standard_mib,
+ mse_community_mib,
+ mse_framework_mib,
+ mse_target_mib,
+ mse_notification_mib,
+ mse_view_based_acm_mib,
+ mse_sparse_table,
+ mse_me_of,
+ mse_mib_of].
+
+mib_storage_dets_cases() ->
+ [
+ msd_simple,
+ msd_v1_processing,
+ msd_big,
+ msd_big2,
+ msd_loop_mib,
+ msd_api,
+ msd_sa_register,
+ msd_v1_trap,
+ msd_sa_error,
+ msd_next_across_sa,
+ msd_undo,
+ msd_standard_mib,
+ msd_community_mib,
+ msd_framework_mib,
+ msd_target_mib,
+ msd_notification_mib,
+ msd_view_based_acm_mib,
+ msd_sparse_table,
+ msd_me_of,
+ msd_mib_of
+ ].
+
+mib_storage_mnesia_cases() ->
+ [
+ msm_simple,
+ msm_v1_processing,
+ msm_big,
+ msm_big2,
+ msm_loop_mib,
+ msm_api,
+ msm_sa_register,
+ msm_v1_trap,
+ msm_sa_error,
+ msm_next_across_sa,
+ msm_undo,
+ msm_standard_mib,
+ msm_community_mib,
+ msm_framework_mib,
+ msm_target_mib,
+ msm_notification_mib,
+ msm_view_based_acm_mib,
+ msm_sparse_table,
+ msm_me_of,
+ msm_mib_of
+ ].
+
+mse_size_check_cases() ->
+ [mse_size_check].
+
+msd_size_check_cases() ->
+ [msd_size_check].
+
+msm_size_check_cases() ->
+ [msm_size_check].
+
+varm_mib_storage_dets_cases() ->
+ [msd_varm_mib_start].
+
+varm_mib_storage_mnesia_cases() ->
+ [msm_varm_mib_start].
+
+init_mib_storage_ets(Config) when list(Config) ->
+ ?LOG("init_mib_storage_ets -> entry", []),
+ MibStorage = {snmp_mib_storage,ets},
+ init_ms(Config, [MibStorage]).
+
+init_mib_storage_dets(Config) when list(Config) ->
+ ?LOG("init_mib_storage_ets -> entry", []),
+ ?line AgentDir = ?GCONF(agent_dir, Config),
+ MibStorage = {snmp_mib_storage,{dets,AgentDir}},
+ init_ms(Config, [MibStorage]).
+
+init_mib_storage_mnesia(Config) when list(Config) ->
+ ?LOG("init_mib_storage_ets -> entry", []),
+ MibStorage = {snmp_mib_storage,{mnesia,[]}},
+ init_ms(Config, [MibStorage]).
+
+init_ms(Config, Opts) when list(Config) ->
+ ?LOG("init_mib_storage_ets -> entry", []),
+ ?line SaNode = ?GCONF(snmp_sa, Config),
+ ?line create_tables(SaNode),
+ ?line AgentDir = ?GCONF(agent_dir, Config),
+ ?line MgrDir = ?GCONF(mgr_dir, Config),
+ ?line Ip = ?GCONF(ip, Config),
+ ?line config([v1], MgrDir, AgentDir, tuple_to_list(Ip), tuple_to_list(Ip)),
+ MasterAgentVerbosity = {snmp_master_agent_verbosity, trace},
+ MibsVerbosity = {snmp_mibserver_verbosity, trace},
+ SymStoreVerbosity = {snmp_symbolic_store_verbosity, trace},
+ Opts1 = [MasterAgentVerbosity,MibsVerbosity,SymStoreVerbosity|Opts],
+ [{vsn, v1} | start_v1_agent(Config,Opts1)].
+
+init_size_check_mse(Config) when list(Config) ->
+ MibStorage = {snmp_mib_storage, ets},
+ init_size_check_ms(Config, [MibStorage]).
+
+init_size_check_msd(Config) when list(Config) ->
+ AgentDir = ?GCONF(agent_dir, Config),
+ MibStorage = {snmp_mib_storage, {dets, AgentDir}},
+ init_size_check_ms(Config, [MibStorage]).
+
+init_size_check_msm(Config) when list(Config) ->
+ MibStorage = {snmp_mib_storage, {mnesia,[]}},
+ init_size_check_ms(Config, [MibStorage]).
+
+init_size_check_ms(Config, Opts) when list(Config) ->
+ SaNode = ?GCONF(snmp_sa, Config),
+ %% We are using v3 here, so crypto must be supported or else...
+ case ?CRYPTO_START() of
+ ok ->
+ case ?CRYPTO_SUPPORT() of
+ {no, Reason} ->
+ ?SKIP({unsupported_encryption, Reason});
+ yes ->
+ ok
+ end;
+ {error, Reason} ->
+ ?SKIP({failed_starting_crypto, Reason})
+ end,
+ create_tables(SaNode),
+ AgentDir = ?GCONF(agent_dir, Config),
+ MgrDir = ?GCONF(mgr_dir, Config),
+ Ip = ?GCONF(ip, Config),
+ ?line ok =
+ config([v3], MgrDir, AgentDir, tuple_to_list(Ip), tuple_to_list(Ip)),
+ [{vsn, v3} | start_agent(Config, [v3], Opts)].
+
+init_varm_mib_storage_dets(Config) when list(Config) ->
+ ?LOG("init_varm_mib_storage_dets -> entry", []),
+ ?line SaNode = ?GCONF(snmp_sa, Config),
+ ?line create_tables(SaNode),
+ ?line AgentDir = ?GCONF(agent_dir, Config),
+ ?line MgrDir = ?GCONF(mgr_dir, Config),
+ ?line Ip = ?GCONF(ip, Config),
+ ?line config([v1], MgrDir, AgentDir, tuple_to_list(Ip), tuple_to_list(Ip)),
+ MibStorage = {snmp_mib_storage,{dets,AgentDir}},
+ MasterAgentVerbosity = {snmp_master_agent_verbosity, trace},
+ MibsVerbosity = {snmp_mibserver_verbosity, trace},
+ SymStoreVerbosity = {snmp_symbolic_store_verbosity, trace},
+ Opts = [MibStorage,MasterAgentVerbosity,MibsVerbosity,SymStoreVerbosity],
+ [{vsn, v1}, {agent_opts,Opts} | Config].
+
+init_varm_mib_storage_mnesia(Config) when list(Config) ->
+ ?LOG("init_varm_mib_storage_mnesia -> entry", []),
+ ?line SaNode = ?GCONF(snmp_sa, Config),
+ ?line create_tables(SaNode),
+ ?line AgentDir = ?GCONF(agent_dir, Config),
+ ?line MgrDir = ?GCONF(mgr_dir, Config),
+ ?line Ip = ?GCONF(ip, Config),
+ ?line config([v1], MgrDir, AgentDir, tuple_to_list(Ip), tuple_to_list(Ip)),
+ MibStorage = {snmp_mib_storage,{mnesia,[]}},
+ MasterAgentVerbosity = {snmp_master_agent_verbosity, trace},
+ MibsVerbosity = {snmp_mibserver_verbosity, trace},
+ SymStoreVerbosity = {snmp_symbolic_store_verbosity, trace},
+ Opts = [MibStorage,MasterAgentVerbosity,MibsVerbosity,SymStoreVerbosity],
+ [{vsn, v1}, {agent_opts,Opts} | Config].
+
+finish_mib_storage_ets(Config) when list(Config) ->
+ ?LOG("finish_mib_storage_ets -> entry", []),
+ delete_tables(),
+ C1 = stop_agent(Config),
+ delete_files(C1),
+ C2 = lists:keydelete(vsn, 1, C1),
+ lists:keydelete(agent_opts, 1, C2).
+
+finish_mib_storage_dets(Config) when list(Config) ->
+ ?LOG("finish_mib_storage_dets -> entry", []),
+ delete_tables(),
+ C1 = stop_agent(Config),
+ delete_files(C1),
+ C2 = lists:keydelete(vsn, 1, C1),
+ lists:keydelete(agent_opts, 1, C2).
+
+finish_mib_storage_mnesia(Config) when list(Config) ->
+ ?LOG("finish_mib_storage_mnesia -> entry", []),
+ delete_tables(),
+ delete_mib_storage_mnesia_tables(),
+ C1 = stop_agent(Config),
+ delete_files(C1),
+ C2 = lists:keydelete(vsn, 1, C1),
+ lists:keydelete(agent_opts, 1, C2).
+
+finish_varm_mib_storage_dets(Config) when list(Config) ->
+ ?LOG("finish_varm_mib_storage_dets -> entry", []),
+ delete_tables(),
+ %% C1 = stop_agent(Config), % In case something went wrong...
+ delete_files(Config),
+ C2 = lists:keydelete(vsn, 1, Config),
+ lists:keydelete(agent_opts, 1, C2).
+
+finish_varm_mib_storage_mnesia(Config) when list(Config) ->
+ ?LOG("finish_varm_mib_storage_mnesia -> entry", []),
+ delete_tables(),
+ delete_mib_storage_mnesia_tables(),
+ %% C1 = stop_agent(Config), % In case something went wrong...
+ delete_files(Config),
+ C2 = lists:keydelete(vsn, 1, Config),
+ lists:keydelete(agent_opts, 1, C2).
+
+finish_size_check_mse(Config) when list(Config) ->
+ finish_size_check_ms(Config).
+
+finish_size_check_msd(Config) when list(Config) ->
+ finish_size_check_ms(Config).
+
+finish_size_check_msm(Config) when list(Config) ->
+ finish_size_check_ms(Config).
+
+finish_size_check_ms(Config) when list(Config) ->
+ delete_tables(),
+ C1 = stop_agent(Config),
+ delete_files(C1),
+ lists:keydelete(vsn, 1, C1).
+
+
+%% These are just interface functions to fool the test server
+mse_simple(X) -> simple(X).
+mse_v1_processing(X) -> v1_processing(X).
+mse_big(X) -> big(X).
+mse_big2(X) -> big2(X).
+mse_loop_mib(X) -> loop_mib(X).
+mse_api(X) -> api(X).
+mse_sa_register(X) -> sa_register(X).
+mse_v1_trap(X) -> v1_trap(X).
+mse_sa_error(X) -> sa_error(X).
+mse_next_across_sa(X) -> next_across_sa(X).
+mse_undo(X) -> undo(X).
+mse_standard_mib(X) -> snmp_standard_mib(X).
+mse_community_mib(X) -> snmp_community_mib(X).
+mse_framework_mib(X) -> snmp_framework_mib(X).
+mse_target_mib(X) -> snmp_target_mib(X).
+mse_notification_mib(X) -> snmp_notification_mib(X).
+mse_view_based_acm_mib(X) -> snmp_view_based_acm_mib(X).
+mse_sparse_table(X) -> sparse_table(X).
+mse_me_of(X) -> ms_me_of(X).
+mse_mib_of(X) -> ms_mib_of(X).
+
+msd_simple(X) -> simple(X).
+msd_v1_processing(X) -> v1_processing(X).
+msd_big(X) -> big(X).
+msd_big2(X) -> big2(X).
+msd_loop_mib(X) -> loop_mib(X).
+msd_api(X) -> api(X).
+msd_sa_register(X) -> sa_register(X).
+msd_v1_trap(X) -> v1_trap(X).
+msd_sa_error(X) -> sa_error(X).
+msd_next_across_sa(X) -> next_across_sa(X).
+msd_undo(X) -> undo(X).
+msd_standard_mib(X) -> snmp_standard_mib(X).
+msd_community_mib(X) -> snmp_community_mib(X).
+msd_framework_mib(X) -> snmp_framework_mib(X).
+msd_target_mib(X) -> snmp_target_mib(X).
+msd_notification_mib(X) -> snmp_notification_mib(X).
+msd_view_based_acm_mib(X) -> snmp_view_based_acm_mib(X).
+msd_sparse_table(X) -> sparse_table(X).
+msd_me_of(X) -> ms_me_of(X).
+msd_mib_of(X) -> ms_mib_of(X).
+
+msm_simple(X) -> simple(X).
+msm_v1_processing(X) -> v1_processing(X).
+msm_big(X) -> big(X).
+msm_big2(X) -> big2(X).
+msm_loop_mib(X) -> loop_mib(X).
+msm_api(X) -> api(X).
+msm_sa_register(X) -> sa_register(X).
+msm_v1_trap(X) -> v1_trap(X).
+msm_sa_error(X) -> sa_error(X).
+msm_next_across_sa(X) -> next_across_sa(X).
+msm_undo(X) -> undo(X).
+msm_standard_mib(X) -> snmp_standard_mib(X).
+msm_community_mib(X) -> snmp_community_mib(X).
+msm_framework_mib(X) -> snmp_framework_mib(X).
+msm_target_mib(X) -> snmp_target_mib(X).
+msm_notification_mib(X) -> snmp_notification_mib(X).
+msm_view_based_acm_mib(X) -> snmp_view_based_acm_mib(X).
+msm_sparse_table(X) -> sparse_table(X).
+msm_me_of(X) -> ms_me_of(X).
+msm_mib_of(X) -> ms_mib_of(X).
+
+
+mse_size_check(X) -> p("mse_size_check..."), ms_size_check(X).
+msd_size_check(X) -> p("msd_size_check..."), ms_size_check(X).
+msm_size_check(X) -> p("msm_size_check..."), ms_size_check(X).
+
+msd_varm_mib_start(X) -> p("msd_varm_mib_start..."), varm_mib_start(X).
+msm_varm_mib_start(X) -> p("msm_varm_mib_start..."), varm_mib_start(X).
+
+ms_size_check(suite) -> [];
+ms_size_check(Config) when list(Config) ->
+ p("ms_size_check..."),
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?LOG("mib server size check...", []),
+
+ ?line load_master("Test2"),
+ ?line load_master("TestTrap"),
+ ?line load_master("TestTrapv2"),
+ ?line load_master_std("OTP-SNMPEA-MIB"),
+ ?line load_master_std("SNMP-COMMUNITY-MIB"),
+ ?line load_master_std("SNMP-FRAMEWORK-MIB"),
+ ?line load_master_std("SNMP-MPD-MIB"),
+ ?line load_master_std("SNMP-NOTIFICATION-MIB"),
+ ?line load_master_std("SNMP-TARGET-MIB"),
+ ?line load_master_std("SNMP-USER-BASED-SM-MIB"),
+ ?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"),
+ ?line load_master_std("SNMPv2-MIB"),
+ ?line load_master_std("SNMPv2-TM"),
+
+ ?SLEEP(2000),
+
+ ?line display_memory_usage(),
+
+ ?line unload_master("OTP-SNMPEA-MIB"),
+ ?line unload_master("SNMP-COMMUNITY-MIB"),
+ ?line unload_master("SNMP-FRAMEWORK-MIB"),
+ ?line unload_master("SNMP-MPD-MIB"),
+ ?line unload_master("SNMP-NOTIFICATION-MIB"),
+ ?line unload_master("SNMP-TARGET-MIB"),
+ ?line unload_master("SNMP-USER-BASED-SM-MIB"),
+ ?line unload_master("SNMP-VIEW-BASED-ACM-MIB"),
+ ?line unload_master("SNMPv2-MIB"),
+ ?line unload_master("SNMPv2-TM"),
+
+ ?line unload_master("TestTrapv2"),
+ ?line unload_master("TestTrap"),
+ ?line unload_master("Test2"),
+
+ ok.
+
+
+varm_mib_start(suite) -> [];
+varm_mib_start(Config) when list(Config) ->
+ p("varm_mib_start..."),
+ ?LOG("varm_mib_start -> entry", []),
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ %% Start the agent
+ Opts = ?GCONF(agent_opts, Config),
+ Config1 = start_v1_agent(Config, Opts),
+
+ %% Sleep some in order for the agent to start properly
+ ?DBG("varm_mib_start -> sleep some (before loading mobs)", []),
+ ?SLEEP(5000),
+
+ %% Load all the mibs
+ HardwiredMibs = loaded_mibs(),
+ ?DBG("varm_mib_start -> load all mibs", []),
+ ?line load_master_std("SNMP-COMMUNITY-MIB"),
+ ?line load_master_std("SNMP-FRAMEWORK-MIB"),
+ ?line load_master_std("SNMP-TARGET-MIB"),
+ ?line load_master_std("SNMP-NOTIFICATION-MIB"),
+
+ %% Unload the hardwired mibs
+ ?DBG("varm_mib_start -> sleep some (before unloading hardwired mibs)", []),
+ ?SLEEP(1000),
+ ?DBG("varm_mib_start -> unload (hardwired) mibs", []),
+ ?line unload_mibs(HardwiredMibs), %% unload hardwired
+
+ ?DBG("varm_mib_start -> sleep some (before stopping agent)", []),
+ ?SLEEP(1000),
+
+ %% Stop the agent (without deleting the stored files)
+ ?DBG("varm_mib_start -> stop the agent", []),
+ Config2 = stop_agent(Config1),
+
+ %% Sleep some in order for the agent to stop properly
+ ?DBG("varm_mib_start -> sleep some (before re-starting the agent)", []),
+ ?SLEEP(5000),
+
+ %% Start the agent (again)
+ ?DBG("varm_mib_start -> start the agent", []),
+ Config3 = start_v1_agent(Config2, Opts),
+
+ ?DBG("varm_mib_start -> sleep some (before starting tests)", []),
+ ?SLEEP(5000),
+
+ %% Perform the test(s)
+ ?DBG("varm_mib_start -> perform the tests", []),
+ try_test(snmp_community_mib),
+ try_test(snmp_framework_mib),
+ try_test(snmp_target_mib),
+ try_test(snmp_notification_mib),
+
+ %% Stop the agent (without deleting the stored files)
+ ?DBG("varm_mib_start -> stop the agent", []),
+ stop_agent(Config3),
+ ok.
+
+
+-define(snmpTrapCommunity_instance, [1,3,6,1,6,3,18,1,4,0]).
+-define(vacmViewSpinLock_instance, [1,3,6,1,6,3,16,1,5,1,0]).
+-define(usmStatsNotInTimeWindows_instance, [1,3,6,1,6,3,15,1,1,2,0]).
+
+ms_me_of(suite) -> [];
+ms_me_of(Config) when list(Config) ->
+ p("ms_me_of..."),
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ ?line load_master("Test2"),
+ ?line load_master("TestTrap"),
+ ?line load_master("TestTrapv2"),
+ ?line load_master_std("OTP-SNMPEA-MIB"),
+ ?line load_master_std("SNMP-COMMUNITY-MIB"),
+ ?line load_master_std("SNMP-FRAMEWORK-MIB"),
+ ?line load_master_std("SNMP-MPD-MIB"),
+ ?line load_master_std("SNMP-NOTIFICATION-MIB"),
+ ?line load_master_std("SNMP-TARGET-MIB"),
+ ?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"),
+
+ ?SLEEP(2000),
+
+ ?line display_memory_usage(),
+
+
+ ?DBG("ms_me_of -> find ~w from SNMP-COMMUNITY-MIB",
+ [?snmpTrapCommunity_instance]),
+ ?line ok = me_of(?snmpTrapCommunity_instance),
+
+ ?DBG("ms_me_of -> find ~w from SNMP-VIEW-BASED-ACM-MIB",
+ [?vacmViewSpinLock_instance]),
+ ?line ok = me_of(?vacmViewSpinLock_instance),
+
+ ?DBG("ms_me_of -> find ~w from SNMP-USER-BASED-SM-MIB",
+ [?usmStatsNotInTimeWindows_instance]),
+ ?line {error, _} = me_of(?usmStatsNotInTimeWindows_instance),
+
+
+ ?line unload_master("OTP-SNMPEA-MIB"),
+ ?line unload_master("SNMP-COMMUNITY-MIB"),
+ ?line unload_master("SNMP-FRAMEWORK-MIB"),
+ ?line unload_master("SNMP-MPD-MIB"),
+ ?line unload_master("SNMP-NOTIFICATION-MIB"),
+ ?line unload_master("SNMP-TARGET-MIB"),
+ ?line unload_master("SNMP-VIEW-BASED-ACM-MIB"),
+
+ ?line unload_master("TestTrapv2"),
+ ?line unload_master("TestTrap"),
+ ?line unload_master("Test2"),
+
+ ok.
+
+me_of(Oid) ->
+ case snmpa:me_of(Oid) of
+ {ok, #me{oid = Oid}} ->
+ ok;
+ {ok, #me{oid = OtherOid}} ->
+ case lists:reverse(Oid) of
+ [0|Rest] ->
+ case lists:reverse(Rest) of
+ OtherOid ->
+ ok;
+ AnotherOid ->
+ {error, {invalid_oid, Oid, AnotherOid}}
+ end;
+ _ ->
+ {error, {invalid_oid, Oid, OtherOid}}
+ end;
+ {error, Reason} ->
+ {error, Reason};
+ Else ->
+ {error, Else}
+ end.
+
+
+ms_mib_of(suite) -> [];
+ms_mib_of(Config) when list(Config) ->
+ p("ms_mib_of..."),
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ ?line load_master("Test2"),
+ ?line load_master("TestTrap"),
+ ?line load_master("TestTrapv2"),
+ ?line load_master_std("OTP-SNMPEA-MIB"),
+ ?line load_master_std("SNMP-COMMUNITY-MIB"),
+ ?line load_master_std("SNMP-FRAMEWORK-MIB"),
+ ?line load_master_std("SNMP-MPD-MIB"),
+ ?line load_master_std("SNMP-NOTIFICATION-MIB"),
+ ?line load_master_std("SNMP-TARGET-MIB"),
+ ?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"),
+
+ ?SLEEP(2000),
+
+ ?line display_memory_usage(),
+
+
+ ?DBG("ms_mib_of -> find ~w from SNMP-COMMUNITY-MIB",
+ [?snmpTrapCommunity_instance]),
+ ?line ok = mib_of(?snmpTrapCommunity_instance, 'SNMP-COMMUNITY-MIB'),
+
+ ?DBG("ms_mib_of -> find ~w from SNMP-VIEW-BASED-ACM-MIB",
+ [?vacmViewSpinLock_instance]),
+ ?line ok = mib_of(?vacmViewSpinLock_instance, 'SNMP-VIEW-BASED-ACM-MIB'),
+
+ ?DBG("ms_mib_of -> find ~w from SNMP-USER-BASED-SM-MIB",
+ [?usmStatsNotInTimeWindows_instance]),
+ ?line {error, _} = mib_of(?usmStatsNotInTimeWindows_instance,
+ 'SNMP-USER-BASED-SM-MIB'),
+
+
+ ?line unload_master("OTP-SNMPEA-MIB"),
+ ?line unload_master("SNMP-COMMUNITY-MIB"),
+ ?line unload_master("SNMP-FRAMEWORK-MIB"),
+ ?line unload_master("SNMP-MPD-MIB"),
+ ?line unload_master("SNMP-NOTIFICATION-MIB"),
+ ?line unload_master("SNMP-TARGET-MIB"),
+ ?line unload_master("SNMP-VIEW-BASED-ACM-MIB"),
+
+ ?line unload_master("TestTrapv2"),
+ ?line unload_master("TestTrap"),
+ ?line unload_master("Test2"),
+
+ ok.
+
+mib_of(Oid, ExpectedMibName) ->
+ ?DBG("mib_of -> entry with"
+ "~n Oid: ~p"
+ "~n ExpectedMibName: ~p", [Oid, ExpectedMibName]),
+ %% case snmpa:mib_of(Oid) of
+ MibOf = snmpa:mib_of(Oid),
+ ?DBG("mib_of -> MibOf: ~n~p", [MibOf]),
+ case MibOf of
+ {ok, ExpectedMibName} ->
+ ok;
+ {ok, OtherMibName} ->
+ {error, {invalid_mib, ExpectedMibName, OtherMibName}};
+ {error, Reason} ->
+ {error, Reason};
+ Else ->
+ ?DBG("mib_of -> Else: ~n~p", [Else]),
+ {error, Else}
+ end.
+
+
+app_info(suite) -> [];
+app_info(Config) when list(Config) ->
+ SnmpDir = app_dir(snmp),
+ SslDir = app_dir(ssl),
+ CryptoDir = app_dir(crypto),
+ Attr = snmp:module_info(attributes),
+ AppVsn =
+ case lists:keysearch(app_vsn, 1, Attr) of
+ {value, {app_vsn, V}} ->
+ V;
+ false ->
+ "undefined"
+ end,
+ io:format("Root dir: ~s~n"
+ "SNMP: Application dir: ~s~n"
+ " Application ver: ~s~n"
+ "SSL: Application dir: ~s~n"
+ "CRYPTO: Application dir: ~s~n",
+ [code:root_dir(), SnmpDir, AppVsn, SslDir, CryptoDir]),
+ ok.
+
+app_dir(App) ->
+ case code:lib_dir(App) of
+ D when list(D) ->
+ filename:basename(D);
+ {error, _Reason} ->
+ "undefined"
+ end.
+
+
+test_v1(suite) -> {req, [], {conf, init_v1, v1_cases(), finish_v1}}.
+
+%v1_cases() -> [loop_mib];
+v1_cases() ->
+ [simple,
+ db_notify_client,
+ v1_processing, big, big2, loop_mib,
+ api, subagent, mnesia, multiple_reqs,
+ sa_register, v1_trap, sa_error, next_across_sa, undo, reported_bugs,
+ standard_mibs, sparse_table, cnt_64,
+ opaque,
+ % opaque].
+
+ change_target_addr_config].
+
+init_v1(Config) when list(Config) ->
+ ?line SaNode = ?config(snmp_sa, Config),
+ ?line create_tables(SaNode),
+ ?line AgentDir = ?config(agent_dir, Config),
+ ?line MgrDir = ?config(mgr_dir, Config),
+ ?line Ip = ?config(ip, Config),
+ ?line config([v1], MgrDir, AgentDir, tuple_to_list(Ip), tuple_to_list(Ip)),
+ [{vsn, v1} | start_v1_agent(Config)].
+
+finish_v1(Config) when list(Config) ->
+ delete_tables(),
+ C1 = stop_agent(Config),
+ delete_files(C1),
+ lists:keydelete(vsn, 1, C1).
+
+test_v2(suite) -> {req, [], {conf, init_v2, v2_cases(), finish_v2}}.
+
+%v2_cases() -> [loop_mib_2];
+v2_cases() ->
+ [simple_2, v2_processing, big_2, big2_2, loop_mib_2,
+ api_2, subagent_2, mnesia_2,
+ multiple_reqs_2, sa_register_2, v2_trap, v2_inform, sa_error_2,
+ next_across_sa_2, undo_2, reported_bugs_2, standard_mibs_2,
+ v2_types, implied, sparse_table_2, cnt_64_2, opaque_2, v2_caps].
+
+init_v2(Config) when list(Config) ->
+ SaNode = ?config(snmp_sa, Config),
+ create_tables(SaNode),
+ AgentDir = ?config(agent_dir, Config),
+ MgrDir = ?config(mgr_dir, Config),
+ Ip = ?config(ip, Config),
+ config([v2], MgrDir, AgentDir, tuple_to_list(Ip), tuple_to_list(Ip)),
+ [{vsn, v2} | start_v2_agent(Config)].
+
+finish_v2(Config) when list(Config) ->
+ delete_tables(),
+ C1 = stop_agent(Config),
+ delete_files(C1),
+ lists:keydelete(vsn, 1, C1).
+
+test_v1_v2(suite) -> {req, [], {conf, init_v1_v2, v1_v2_cases(), finish_v1_v2}}.
+
+v1_v2_cases() ->
+ [simple_bi].
+
+init_v1_v2(Config) when list(Config) ->
+ SaNode = ?config(snmp_sa, Config),
+ create_tables(SaNode),
+ AgentDir = ?config(agent_dir, Config),
+ MgrDir = ?config(mgr_dir, Config),
+ Ip = ?config(ip, Config),
+ config([v1,v2], MgrDir, AgentDir, tuple_to_list(Ip), tuple_to_list(Ip)),
+ [{vsn, bilingual} | start_bilingual_agent(Config)].
+
+finish_v1_v2(Config) when list(Config) ->
+ delete_tables(),
+ C1 = stop_agent(Config),
+ delete_files(C1),
+ lists:keydelete(vsn, 1, C1).
+
+test_v3(suite) -> {req, [], {conf, init_v3, v3_cases(), finish_v3}}.
+
+%v3_cases() -> [loop_mib_3];
+v3_cases() ->
+ [simple_3, v3_processing,
+ big_3, big2_3, api_3, subagent_3, mnesia_3, loop_mib_3,
+ multiple_reqs_3, sa_register_3, v3_trap, v3_inform, sa_error_3,
+ next_across_sa_3, undo_3, reported_bugs_3, standard_mibs_3,
+ v3_security,
+ v2_types_3, implied_3, sparse_table_3, cnt_64_3, opaque_3, v2_caps_3].
+
+init_v3(Config) when list(Config) ->
+ %% Make sure crypto works, otherwise start_agent will fail
+ %% and we will be stuck with a bunch of mnesia tables for
+ %% the rest of this suite...
+ ?DBG("start_agent -> start crypto app",[]),
+ case os:type() of
+ vxworks ->
+ no_crypto;
+ _ ->
+ case ?CRYPTO_START() of
+ ok ->
+ case ?CRYPTO_SUPPORT() of
+ {no, Reason} ->
+ ?SKIP({unsupported_encryption, Reason});
+ yes ->
+ ok
+ end;
+ {error, Reason} ->
+ ?SKIP({failed_starting_crypto, Reason})
+ end
+ end,
+ SaNode = ?config(snmp_sa, Config),
+ create_tables(SaNode),
+ AgentDir = ?config(agent_dir, Config),
+ MgrDir = ?config(mgr_dir, Config),
+ Ip = ?config(ip, Config),
+ ?line ok = config([v3], MgrDir, AgentDir,
+ tuple_to_list(Ip), tuple_to_list(Ip)),
+ [{vsn, v3} | start_v3_agent(Config)].
+
+finish_v3(Config) when list(Config) ->
+ delete_tables(),
+ C1 = stop_agent(Config),
+ delete_files(C1),
+ lists:keydelete(vsn, 1, C1).
+
+test_multi_threaded(suite) -> {req, [], {conf, init_mt, mt_cases(), finish_mt}}.
+
+mt_cases() ->
+ [multi_threaded, mt_trap].
+
+init_mt(Config) when list(Config) ->
+ SaNode = ?config(snmp_sa, Config),
+ create_tables(SaNode),
+ AgentDir = ?config(agent_dir, Config),
+ MgrDir = ?config(mgr_dir, Config),
+ Ip = ?config(ip, Config),
+ ?line ok = config([v2], MgrDir, AgentDir, tuple_to_list(Ip), tuple_to_list(Ip)),
+ [{vsn, v2} | start_multi_threaded_agent(Config)].
+
+finish_mt(Config) when list(Config) ->
+ delete_tables(),
+ C1 = stop_agent(Config),
+ delete_files(C1),
+ lists:keydelete(vsn, 1, C1).
+
+%% This one *must* be run first in each case.
+init_case(Config) when list(Config) ->
+ ?DBG("init_case -> entry with"
+ "~n Config: ~p", [Config]),
+ SaNode = ?config(snmp_sa, Config),
+ MgrNode = ?config(snmp_mgr, Config),
+ MasterNode = node(),
+
+ SaHost = ?HOSTNAME(SaNode),
+ MgrHost = ?HOSTNAME(MgrNode),
+ MasterHost = ?HOSTNAME(MasterNode),
+ {ok, MasterIP} = snmp_misc:ip(MasterHost),
+ {ok, MIP} = snmp_misc:ip(MgrHost),
+ {ok, SIP} = snmp_misc:ip(SaHost),
+
+
+ put(mgr_node, MgrNode),
+ put(sa_node, SaNode),
+ put(master_node, MasterNode),
+ put(sa_host, SaHost),
+ put(mgr_host, MgrHost),
+ put(master_host, MasterHost),
+ put(mip, tuple_to_list(MIP)),
+ put(masterip , tuple_to_list(MasterIP)),
+ put(sip, tuple_to_list(SIP)),
+
+ MibDir = ?config(mib_dir, Config),
+ put(mib_dir, MibDir),
+ StdM = filename:join(code:priv_dir(snmp), "mibs") ++ "/",
+ put(std_mib_dir, StdM),
+
+ MgrDir = ?config(mgr_dir, Config),
+ put(mgr_dir, MgrDir),
+
+ put(vsn, ?config(vsn, Config)),
+ ?DBG("init_case -> exit with"
+ "~n MasterNode: ~p"
+ "~n SaNode: ~p"
+ "~n MgrNode: ~p"
+ "~n MibDir: ~p", [MasterNode, SaNode, MgrNode, MibDir]),
+ {SaNode, MgrNode, MibDir}.
+
+load_master(Mib) ->
+ ?DBG("load_master -> entry with"
+ "~n Mib: ~p", [Mib]),
+ snmpa:unload_mibs(snmp_master_agent, [Mib]), % Unload for safety
+ ok = snmpa:load_mibs(snmp_master_agent, [get(mib_dir) ++ Mib]).
+
+load_master_std(Mib) ->
+ ?DBG("load_master_std -> entry with"
+ "~n Mib: ~p", [Mib]),
+ snmpa:unload_mibs(snmp_master_agent, [Mib]), % Unload for safety
+ ok = snmpa:load_mibs(snmp_master_agent, [get(std_mib_dir) ++ Mib]).
+
+unload_master(Mib) ->
+ ?DBG("unload_master -> entry with"
+ "~n Mib: ~p", [Mib]),
+ ok = snmpa:unload_mibs(snmp_master_agent, [Mib]).
+
+loaded_mibs() ->
+ ?DBG("loaded_mibs -> entry",[]),
+ Info = snmpa:info(snmp_master_agent),
+ {value, {loaded_mibs, Mibs}} = lists:keysearch(loaded_mibs, 1, Info),
+ [atom_to_list(Mib) || {Mib,_,_} <- Mibs].
+
+unload_mibs(Mibs) ->
+ ?DBG("unload_mibs -> entry with"
+ "~n Mibs: ~p", [Mibs]),
+ ok = snmpa:unload_mibs(snmp_master_agent, Mibs).
+
+start_subagent(SaNode, RegTree, Mib) ->
+ ?DBG("start_subagent -> entry with"
+ "~n SaNode: ~p"
+ "~n RegTree: ~p"
+ "~n Mib: ~p", [SaNode, RegTree, Mib]),
+ MA = whereis(snmp_master_agent),
+ ?DBG("start_subagent -> MA: ~p", [MA]),
+ MibDir = get(mib_dir),
+ Mib1 = join(MibDir,Mib),
+ %% BMK BMK
+% case rpc:call(SaNode,snmp_supervisor,start_subagent,[MA,RegTree,[Mib1]]) of
+ case rpc:call(SaNode, snmpa_supervisor,
+ start_sub_agent, [MA, RegTree, [Mib1]]) of
+ {ok, SA} ->
+ ?DBG("start_subagent -> SA: ~p", [SA]),
+ {ok, SA};
+ Error ->
+ ?FAIL({subagent_start_failed, SaNode, Error, [MA, RegTree, Mib1]})
+ end.
+
+stop_subagent(SA) ->
+ ?DBG("stop_subagent -> entry with"
+ "~n SA: ~p", [SA]),
+ %% BNK BMK
+ %% rpc:call(node(SA), snmp_supervisor, stop_subagent, [SA]).
+ rpc:call(node(SA), snmpa_supervisor, stop_sub_agent, [SA]).
+
+%%-----------------------------------------------------------------
+%% This function takes care of the old OTP-SNMPEA-MIB.
+%% Unfortunately, the testcases were written to use the data in the
+%% internal tables, and these table are now obsolete and not used
+%% by the agent. Therefore, we emulate them by using
+%% OLD-SNMPEA-MIB, which uses the default impl. of all tables.
+%%
+%% These two rows must exist in intCommunityTable
+%% {[147,214,36,45], "public", 2, readWrite}.
+%% {[147,214,36,45], "standard trap", 2, read}.
+%% (But with the manager's IP address)
+%%
+%%-----------------------------------------------------------------
+init_old() ->
+ snmpa_local_db:table_create_row(intCommunityTable,
+ get(mip) ++ [6 | "public"],
+ {get(mip), "public", 2, 2}),
+ snmpa_local_db:table_create_row(intCommunityTable,
+ get(mip) ++ [13 | "standard trap"],
+ {get(mip), "standard trap", 2, 1}),
+ snmpa_local_db:variable_set(intAgentIpAddress, [127,0,0,1]).
+
+
+
+simple(suite) -> [];
+simple(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ try_test(simple_standard_test).
+
+simple_2(X) -> simple(X).
+
+simple_bi(suite) -> [];
+simple_bi(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ put(vsn, v1), % First, try v1 manager
+ try_test(simple_standard_test),
+
+ put(vsn, v2), % Then, try v2 manager
+ try_test(simple_standard_test).
+
+simple_3(X) ->
+ simple(X).
+
+big(suite) -> [];
+big(Config) when list(Config) ->
+ ?DBG("big -> entry", []),
+ {SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ p("Starting subagent..."),
+ ?line pong = net_adm:ping(SaNode),
+
+ ?line {ok, SA} = start_subagent(SaNode, ?klas1, "Klas1"),
+ ?DBG("big -> SA: ~p", [SA]),
+ ?line load_master("OLD-SNMPEA-MIB"),
+ ?line init_old(),
+ try_test(big_test),
+ ?line stop_subagent(SA),
+ ?line unload_master("OLD-SNMPEA-MIB").
+
+big_2(X) -> big(X).
+
+big_3(X) -> big(X).
+
+
+big2(suite) -> [];
+big2(Config) when list(Config) ->
+ %% This is exactly the same tests as 'big', but with the
+ %% v2 equivalent of the mibs.
+ {SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ p("Starting subagent..."),
+ ?line pong = net_adm:ping(SaNode),
+
+ ?line {ok, SA} = start_subagent(SaNode, ?klas1, "Klas1-v2"),
+ ?line load_master("OLD-SNMPEA-MIB-v2"),
+ ?line init_old(),
+ try_test(big_test),
+ ?line stop_subagent(SA),
+ ?line unload_master("OLD-SNMPEA-MIB-v2").
+
+big2_2(X) -> big2(X).
+
+big2_3(X) -> big2(X).
+
+
+multi_threaded(suite) -> [];
+multi_threaded(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ ?line load_master("Test1"),
+ try_test(multi_threaded_test),
+ ?line unload_master("Test1").
+
+mt_trap(suite) -> [];
+mt_trap(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ MA = whereis(snmp_master_agent),
+
+ ?line load_master("Test1"),
+ ?line load_master("TestTrapv2"),
+ try_test(mt_trap_test, [MA]),
+ ?line unload_master("TestTrapv2"),
+ ?line unload_master("Test1").
+
+v2_types(suite) -> [];
+v2_types(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ ?line load_master("Test1"),
+ try_test(types_v2_test),
+ ?line unload_master("Test1").
+
+v2_types_3(X) -> v2_types(X).
+
+
+implied(suite) -> [];
+implied(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ MA = whereis(snmp_master_agent),
+
+ ?line load_master("Test1"),
+ try_test(implied_test,[MA]),
+ ?line unload_master("Test1").
+
+implied_3(X) -> implied(X).
+
+
+sparse_table(suite) -> [];
+sparse_table(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ ?line load_master("Test1"),
+ try_test(sparse_table_test),
+ ?line unload_master("Test1").
+
+sparse_table_2(X) -> sparse_table(X).
+
+sparse_table_3(X) -> sparse_table(X).
+
+cnt_64(suite) -> [];
+cnt_64(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ MA = whereis(snmp_master_agent),
+
+ ?line load_master("Test1"),
+ try_test(cnt_64_test, [MA]),
+ ?line unload_master("Test1").
+
+cnt_64_2(X) -> cnt_64(X).
+
+cnt_64_3(X) -> cnt_64(X).
+
+opaque(suite) -> [];
+opaque(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ ?line load_master("Test1"),
+ try_test(opaque_test),
+ ?line unload_master("Test1").
+
+opaque_2(X) -> opaque(X).
+
+opaque_3(X) -> opaque(X).
+
+
+change_target_addr_config(suite) -> [];
+change_target_addr_config(Config) when list(Config) ->
+ p("Testing changing target address config..."),
+ ?LOG("change_target_addr_config -> entry",[]),
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ put(sname,snmp_suite),
+ put(verbosity,trace),
+
+ MA = whereis(snmp_master_agent),
+
+ ?LOG("change_target_addr_config -> load TestTrap",[]),
+ ?line load_master("TestTrap"),
+
+ ?LOG("change_target_addr_config -> set trace verbosity for local_db",[]),
+ ?line snmpa:verbosity(local_db,trace),
+
+ %% First send some traps that will arive att the original manager
+ ?LOG("change_target_addr_config -> send trap",[]),
+ try_test(ma_trap1, [MA]),
+
+ ?LOG("change_target_addr_config -> set silence verbosity for local_db",[]),
+ ?line snmpa:verbosity(local_db,silence),
+
+ %% Start new dummy listener
+ ?LOG("change_target_addr_config -> start dummy manager",[]),
+ ?line {ok,Pid,NewPort} = dummy_manager_start(MA),
+
+ %% Reconfigure
+ ?LOG("change_target_addr_config -> reconfigure",[]),
+ AgentDir = ?config(agent_dir, Config),
+ ?line rewrite_target_addr_conf(AgentDir, NewPort),
+ ?line snmp_target_mib:reconfigure(AgentDir),
+
+ %% Send the trap again
+ ?LOG("change_target_addr_config -> send trap again",[]),
+ catch dummy_manager_send_trap2(Pid),
+
+ ?LOG("change_target_addr_config -> await trap ack",[]),
+ catch dummy_manager_await_trap2_ack(),
+
+ ?LOG("change_target_addr_config -> stop dummy manager",[]),
+ ?line ok = dummy_manager_stop(Pid),
+
+ ?LOG("change_target_addr_config -> reset target address config",[]),
+ ?line reset_target_addr_conf(AgentDir),
+
+ ?LOG("change_target_addr_config -> unload TestTrap",[]),
+ ?line unload_master("TestTrap").
+
+
+dummy_manager_start(MA) ->
+ ?DBG("dummy_manager_start -> entry",[]),
+ Pid = spawn(get(mgr_node), ?MODULE,dummy_manager_init,[self(),MA]),
+ ?DBG("dummy_manager_start -> Pid: ~p",[Pid]),
+ await_dummy_manager_started(Pid).
+
+await_dummy_manager_started(Pid) ->
+ receive
+ {dummy_manager_started,Pid,Port} ->
+ ?DBG("dummy_manager_start -> acknowledge received with"
+ "~n Port: ~p",[Port]),
+ {ok,Pid,Port};
+ {'EXIT', Pid, Reason} ->
+ {error, Pid, Reason};
+ O ->
+ ?LOG("dummy_manager_start -> received unknown message:"
+ "~n ~p",[O]),
+ await_dummy_manager_started(Pid)
+ end.
+
+dummy_manager_stop(Pid) ->
+ ?DBG("dummy_manager_stop -> entry with Pid: ~p",[Pid]),
+ Pid ! stop,
+ receive
+ {dummy_manager_stopping, Pid} ->
+ ?DBG("dummy_manager_stop -> acknowledge received",[]),
+ ok
+ after 10000 ->
+ ?ERR("dummy_manager_stop -> timeout",[]),
+ timeout
+ end.
+
+dummy_manager_send_trap2(Pid) ->
+ ?DBG("dummy_manager_send_trap2 -> entry",[]),
+ Pid ! {send_trap,testTrap2}.
+
+dummy_manager_await_trap2_ack() ->
+ ?DBG("dummy_manager_await_trap2 -> entry",[]),
+ receive
+ {received_trap,Trap} ->
+ ?LOG("dummy_manager_await_trap2 -> received trap: ~p",[Trap]),
+ %% Note:
+ %% Without this sleep the v2_inform_i testcase failes! There
+ %% is no relation between these two test cases as far as I
+ %% able to figure out...
+ sleep(60000),
+ ok;
+ O ->
+ ?ERR("dummy_manager_await_trap2 -> unexpected message: ~p",[O]),
+ ok
+ after 10000 ->
+ ?ERR("dummy_manager_await_trap2 -> timeout",[]),
+ timeout
+ end.
+
+dummy_manager_init(Parent,MA) ->
+ ?DBG("dummy_manager_init -> entry with"
+ "~n Parent: ~p"
+ "~n MA: ~p",[Parent,MA]),
+ {ok,S} = gen_udp:open(0,[{recbuf,65535}]),
+ ?DBG("dummy_manager_init -> S: ~p",[S]),
+ {ok,Port} = inet:port(S),
+ ?DBG("dummy_manager_init -> Port: ~p",[Port]),
+ Parent ! {dummy_manager_started,self(),Port},
+ dummy_manager_loop(Parent,S,MA).
+
+dummy_manager_loop(P,S,MA) ->
+ ?LOG("dummy_manager_loop -> ready for receive",[]),
+ receive
+ {send_trap,Trap} ->
+ ?LOG("dummy_manager_loop -> received trap send request"
+ "~n Trap: ~p",[Trap]),
+ snmpa:send_trap(MA, Trap, "standard trap"),
+ dummy_manager_loop(P,S,MA);
+ {udp, _UdpId, Ip, UdpPort, Bytes} ->
+ ?LOG("dummy_manager_loop -> received upd message"
+ "~n from: ~p:~p"
+ "~n size: ~p",
+ [Ip, UdpPort, dummy_manager_message_sz(Bytes)]),
+ R = dummy_manager_handle_message(Bytes),
+ ?DBG("dummy_manager_loop -> R: ~p",[R]),
+ P ! R,
+ dummy_manager_loop(P,S,MA);
+ stop ->
+ ?DBG("dummy_manager_loop -> received stop request",[]),
+ P ! {dummy_manager_stopping, self()},
+ gen_udp:close(S),
+ exit(normal);
+ O ->
+ ?LOG("dummy_manager_loop -> received unknown message:"
+ "~n ~p",[O]),
+ dummy_manager_loop(P,S,MA)
+ end.
+
+dummy_manager_message_sz(B) when binary(B) ->
+ size(B);
+dummy_manager_message_sz(L) when list(L) ->
+ length(L);
+dummy_manager_message_sz(_) ->
+ undefined.
+
+dummy_manager_handle_message(Bytes) ->
+ case (catch snmp_pdus:dec_message(Bytes)) of
+ {'EXIT',Reason} ->
+ ?ERR("dummy_manager_handle_message -> "
+ "failed decoding message only:~n ~p",[Reason]),
+ {error,Reason};
+ M ->
+ ?DBG("dummy_manager_handle_message -> decoded message:"
+ "~n ~p",[M]),
+ {received_trap,M}
+ end.
+
+
+api(suite) -> [];
+api(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ ?line load_master("OLD-SNMPEA-MIB"),
+ ?line init_old(),
+ try_test(api_test, [node()]),
+ ?line unload_master("OLD-SNMPEA-MIB").
+
+api_2(X) -> api(X).
+
+api_3(X) -> api(X).
+
+
+subagent(suite) -> [];
+subagent(Config) when list(Config) ->
+ {SaNode, _MgrNode, MibDir} = init_case(Config),
+
+ ?line {ok, SA} = start_subagent(SaNode, ?klas1, "Klas1"),
+ try_test(load_test_sa),
+
+ p("Testing unregister subagent..."),
+ MA = whereis(snmp_master_agent),
+ rpc:call(SaNode, snmp, unregister_subagent, [MA, SA]),
+ try_test(unreg_test),
+
+ p("Loading previous subagent mib in master and testing..."),
+ ?line ok = snmpa:load_mibs(MA, [MibDir ++ "Klas1"]),
+ try_test(load_test),
+
+ p("Unloading previous subagent mib in master and testing..."),
+ ?line ok = snmpa:unload_mibs(MA, [MibDir ++ "Klas1"]),
+ try_test(unreg_test),
+ p("Testing register subagent..."),
+ rpc:call(SaNode, snmp, register_subagent,
+ [MA, ?klas1, SA]),
+ try_test(load_test_sa),
+
+ ?line stop_subagent(SA),
+ try_test(unreg_test).
+
+subagent_2(X) -> subagent(X).
+
+subagent_3(X) -> subagent(X).
+
+
+mnesia(suite) -> [];
+mnesia(Config) when list(Config) ->
+ {SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ p("Starting subagent with mnesia impl..."),
+ {ok, SA} = start_subagent(SaNode, ?klas2, "Klas2"),
+ ?line load_master("OLD-SNMPEA-MIB"),
+ ?line init_old(),
+
+ try_test(big_test_2),
+
+ p("Testing unregister subagent..."),
+ MA = whereis(snmp_master_agent),
+ rpc:call(SaNode, snmp, unregister_subagent, [MA, SA]),
+ try_test(unreg_test),
+ ?line unload_master("OLD-SNMPEA-MIB"),
+ ?line stop_subagent(SA).
+
+mnesia_2(X) -> mnesia(X).
+
+mnesia_3(X) -> mnesia(X).
+
+
+multiple_reqs(suite) ->
+ {req, [], {conf, init_mul, mul_cases(), finish_mul}}.
+
+mul_cases() ->
+ [mul_get, mul_get_err, mul_next, mul_next_err, mul_set_err].
+
+multiple_reqs_2(suite) ->
+ {req, [], {conf, init_mul, mul_cases_2(), finish_mul}}.
+
+multiple_reqs_3(_X) ->
+ {req, [], {conf, init_mul, mul_cases_3(), finish_mul}}.
+
+
+mul_cases_2() ->
+ [mul_get_2, mul_get_err_2, mul_next_2, mul_next_err_2, mul_set_err_2].
+
+
+mul_cases_3() ->
+ [mul_get_3, mul_get_err_3, mul_next_3, mul_next_err_3, mul_set_err_3].
+
+
+init_mul(Config) when list(Config) ->
+ {SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ ?line {ok, SA} = start_subagent(SaNode, ?klas1, "Klas1"),
+ ?line load_master("OLD-SNMPEA-MIB"),
+ ?line init_old(),
+ [{mul_sub, SA} | Config].
+
+finish_mul(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ SA = ?config(mul_sub, Config),
+
+ ?line unload_master("OLD-SNMPEA-MIB"),
+ ?line stop_subagent(SA),
+ lists:keydelete(mul_sub, 1, Config).
+
+mul_get(suite) -> [];
+mul_get(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ p("Testing multiple get..."),
+ try_test(do_mul_get).
+
+mul_get_2(X) -> mul_get(X).
+
+mul_get_3(X) -> mul_get(X).
+
+
+mul_get_err(suite) -> [];
+mul_get_err(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ p("Testing multiple get with error..."),
+ try_test(do_mul_get_err).
+
+mul_get_err_2(X) -> mul_get_err(X).
+
+mul_get_err_3(X) -> mul_get_err(X).
+
+
+mul_next(suite) -> [];
+mul_next(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ p("Testing multiple next..."),
+ try_test(do_mul_next).
+
+mul_next_2(X) -> mul_next(X).
+
+mul_next_3(X) -> mul_next(X).
+
+
+mul_next_err(suite) -> [];
+mul_next_err(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ p("Testing multiple next..."),
+ try_test(do_mul_next_err).
+
+mul_next_err_2(X) -> mul_next_err(X).
+
+mul_next_err_3(X) -> mul_next_err(X).
+
+
+mul_set(suite) -> [];
+mul_set(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ p("Testing multiple set..."),
+ try_test(do_mul_set).
+
+mul_set_2(X) -> mul_set(X).
+
+mul_set_3(X) -> mul_set(X).
+
+
+mul_set_err(suite) -> [];
+mul_set_err(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ p("Testing multiple set with error..."),
+ try_test(do_mul_set_err).
+
+mul_set_err_2(X) -> mul_set_err(X).
+
+mul_set_err_3(X) -> mul_set_err(X).
+
+
+sa_register(suite) -> [];
+sa_register(Config) when list(Config) ->
+ ?DBG("sa_register -> entry", []),
+ {SaNode, _MgrNode, MibDir} = init_case(Config),
+
+ ?DBG("sa_register -> start subagent", []),
+ ?line {ok, SA} = start_subagent(SaNode, ?klas1, "Klas1"),
+
+ ?DBG("sa_register -> unregister subagent", []),
+ p("Testing unregister subagent (2)..."),
+ MA = whereis(snmp_master_agent),
+ rpc:call(SaNode, snmp, unregister_subagent, [MA, ?klas1]),
+ try_test(unreg_test),
+
+ p("Loading SA-MIB..."),
+ ?DBG("sa_register -> unload mibs", []),
+ snmpa:unload_mibs(SA, [MibDir ++ "Klas1"]),
+ ?DBG("sa_register -> unload mibs", []),
+ snmpa:load_mibs(SA, [MibDir ++ "SA-MIB"]),
+ ?DBG("sa_register -> register subagent", []),
+ rpc:call(SaNode, snmp, register_subagent, [MA,?sa,SA]),
+ try_test(sa_mib),
+
+ ?DBG("sa_register -> stop subagent", []),
+ ?line stop_subagent(SA).
+
+sa_register_2(X) -> sa_register(X).
+
+sa_register_3(X) -> sa_register(X).
+
+
+v1_trap(suite) -> [];
+v1_trap(Config) when list(Config) ->
+ {SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ ?line {ok, SA} = start_subagent(SaNode, ?sa, "SA-MIB"),
+
+ p("Testing trap sending from master agent..."),
+ MA = whereis(snmp_master_agent),
+
+ ?line load_master("TestTrap"),
+ ?line load_master("TestTrapv2"),
+
+ try_test(ma_trap1, [MA]),
+ try_test(ma_trap2, [MA]),
+ try_test(ma_v2_2_v1_trap, [MA]),
+ try_test(ma_v2_2_v1_trap2, [MA]),
+
+ p("Testing trap sending from subagent..."),
+ try_test(sa_trap1, [SA]),
+ try_test(sa_trap2, [SA]),
+ try_test(sa_trap3, [SA]),
+
+ ?line unload_master("TestTrap"),
+ ?line unload_master("TestTrapv2"),
+
+ ?line stop_subagent(SA).
+
+v2_trap(suite) -> [];
+v2_trap(Config) when list(Config) ->
+ {SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ ?line {ok, SA} = start_subagent(SaNode, ?sa, "SA-MIB"),
+
+ p("Testing trap sending from master agent..."),
+ MA = whereis(snmp_master_agent),
+
+ ?line load_master("TestTrap"),
+ ?line load_master("TestTrapv2"),
+
+
+ try_test(ma_v2_trap1, [MA]),
+ try_test(ma_v2_trap2, [MA]),
+ try_test(ma_v1_2_v2_trap, [MA]),
+ try_test(ma_v1_2_v2_trap2, [MA]),
+
+ try_test(sa_mib),
+ p("Testing trap sending from subagent..."),
+ try_test(sa_v1_2_v2_trap1, [SA]),
+ try_test(sa_v1_2_v2_trap2, [SA]),
+ try_test(sa_v1_2_v2_trap3, [SA]),
+
+ ?line unload_master("TestTrap"),
+ ?line unload_master("TestTrapv2"),
+
+ ?line stop_subagent(SA).
+
+v3_trap(X) ->
+ v2_trap(X).
+
+v2_inform(suite) ->
+ {req, [], {conf, init_v2_inform, [v2_inform_i], finish_v2_inform}}.
+
+v3_inform(_X) ->
+ %% v2_inform(X).
+ {req, [], {conf, init_v3_inform, [v3_inform_i], finish_v3_inform}}.
+
+init_v2_inform(Config) when list(Config) ->
+ _Dir = ?config(agent_dir, Config),
+% snmp_internal_mib:configure(Dir),
+ Config.
+
+init_v3_inform(X) ->
+ init_v2_inform(X).
+
+finish_v2_inform(Config) when list(Config) ->
+ _Dir = ?config(agent_dir, Config),
+% snmp_internal_mib:configure(Dir),
+ Config.
+
+finish_v3_inform(X) ->
+ finish_v2_inform(X).
+
+
+
+v2_inform_i(suite) -> [];
+v2_inform_i(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ p("Testing inform sending from master agent... NOTE! This test\ntakes a "
+ "few minutes (5) to complete."),
+ MA = whereis(snmp_master_agent),
+
+ ?line load_master("TestTrap"),
+ ?line load_master("TestTrapv2"),
+
+ try_test(ma_v2_inform1, [MA]),
+
+ ?line unload_master("TestTrap"),
+ ?line unload_master("TestTrapv2").
+
+v3_inform_i(X) -> v2_inform_i(X).
+
+
+sa_error(suite) -> [];
+sa_error(Config) when list(Config) ->
+ {SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ ?line load_master("OLD-SNMPEA-MIB"),
+ ?line init_old(),
+ ?line {ok, SA} = start_subagent(SaNode, ?sa, "SA-MIB"),
+
+ p("Testing sa bad value (is_set_ok)..."),
+ try_test(sa_errs_bad_value),
+
+ p("Testing sa gen err (set)..."),
+ try_test(sa_errs_gen_err),
+
+ p("Testing too big..."),
+ try_test(sa_too_big),
+
+ ?line unload_master("OLD-SNMPEA-MIB"),
+ stop_subagent(SA).
+
+sa_error_2(X) -> sa_error(X).
+
+sa_error_3(X) -> sa_error(X).
+
+
+next_across_sa(suite) -> [];
+next_across_sa(Config) when list(Config) ->
+ {SaNode, _MgrNode, MibDir} = init_case(Config),
+ MA = whereis(snmp_master_agent),
+
+ ?line {ok, SA} = start_subagent(SaNode, ?sa, "SA-MIB"),
+
+ p("Loading another subagent mib..."),
+ ?line ok = snmpa:load_mibs(SA, [MibDir ++ "Klas1"]),
+
+ rpc:call(SaNode, snmp, register_subagent, [MA, ?klas1, SA]),
+ try_test(load_test_sa),
+
+ p("Testing next across subagent (endOfMibView from SA)..."),
+ try_test(next_across_sa),
+
+ p("Unloading mib"),
+ snmpa:unload_mibs(SA, [MibDir ++ "Klas1"]),
+ rpc:call(SaNode, snmp, unregister_subagent, [MA, ?klas1]),
+ try_test(unreg_test),
+
+ p("Starting another subagent"),
+ ?line {ok, SA2} = start_subagent(SaNode, ?klas1, "Klas1"),
+ p("Testing next across subagent (wrong prefix from SA)..."),
+ try_test(next_across_sa),
+
+ stop_subagent(SA),
+ stop_subagent(SA2).
+
+next_across_sa_2(X) -> next_across_sa(X).
+
+next_across_sa_3(X) -> next_across_sa(X).
+
+
+undo(suite) -> [];
+undo(Config) when list(Config) ->
+ {SaNode, _MgrNode, MibDir} = init_case(Config),
+ MA = whereis(snmp_master_agent),
+
+ ?line {ok, SA} = start_subagent(SaNode, ?sa, "SA-MIB"),
+
+ p("Testing undo phase at master agent..."),
+ ?line ok = snmpa:load_mibs(MA, [MibDir ++ "Klas3"]),
+ ?line ok = snmpa:load_mibs(MA, [MibDir ++ "Klas4"]),
+ try_test(undo_test),
+ try_test(api_test2),
+ ?line ok = snmpa:unload_mibs(MA, [MibDir ++ "Klas3"]),
+
+ p("Testing bad return values from instrum. funcs..."),
+ try_test(bad_return),
+
+ ?line ok = snmpa:unload_mibs(MA, [MibDir ++ "Klas4"]),
+
+ p("Testing undo phase at subagent..."),
+ ?line ok = snmpa:load_mibs(SA, [MibDir ++ "Klas3"]),
+ ?line ok = snmpa:load_mibs(SA, [MibDir ++ "Klas4"]),
+ ?line ok = snmpa:register_subagent(MA, ?klas3, SA),
+ ?line ok = snmpa:register_subagent(MA, ?klas4, SA),
+ try_test(undo_test),
+ try_test(api_test3),
+
+ p("Testing undo phase across master/subagents..."),
+ try_test(undo_test),
+ try_test(api_test3),
+ stop_subagent(SA).
+
+undo_2(X) -> undo(X).
+
+undo_3(X) -> undo(X).
+
+%% Req. Test2
+v1_processing(suite) -> [];
+v1_processing(Config) when list(Config) ->
+ ?DBG("v1_processing -> entry", []),
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ ?line load_master("Test2"),
+ try_test(v1_proc),
+ ?line unload_master("Test2").
+
+%% Req. Test2
+v2_processing(suite) -> [];
+v2_processing(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ ?line load_master("Test2"),
+ try_test(v2_proc),
+ ?line unload_master("Test2").
+
+%% Req. Test2
+v3_processing(suite) -> [];
+v3_processing(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ ?line load_master("Test2"),
+ try_test(v2_proc), % same as v2!
+ ?line unload_master("Test2").
+
+
+%% We'll try get/set/trap and inform for all the auth & priv protocols.
+%% For informs, the mgr is auth-engine. The agent has to sync. This is
+%% accomplished by the first inform sent. That one will generate a
+%% report, which makes it in sync. The notification-generating
+%% application times out, and send again. This time it'll work.
+v3_security(suite) -> [v3_crypto_basic, v3_md5_auth, v3_sha_auth, v3_des_priv].
+
+v3_crypto_basic(suite) -> [];
+v3_crypto_basic(_Config) ->
+ EID = [0,0,0,0,0,0,0,0,0,0,0,2],
+ %% From rfc2274 appendix A.3.1
+ ?line KMd5_1 = snmp:passwd2localized_key(md5, "maplesyrup", EID),
+ ?line [16#52,16#6f,16#5e,16#ed,16#9f,16#cc,16#e2,16#6f,
+ 16#89,16#64,16#c2,16#93,16#07,16#87,16#d8,16#2b] =
+ KMd5_1,
+ %% From rfc2274 appendix A.3.2
+ ?line KSHA_1 = snmp:passwd2localized_key(sha, "maplesyrup", EID),
+ ?line [16#66,16#95,16#fe,16#bc,16#92,16#88,16#e3,16#62,16#82,16#23,
+ 16#5f,16#c7,16#15,16#1f,16#12,16#84,16#97,16#b3,16#8f,16#3f] =
+ KSHA_1,
+ %% From rfc2274, appendix A.5.1
+ ?line KMd5_2 = snmp:passwd2localized_key(md5, "newsyrup", EID),
+ ?line [16#00,16#00,16#00,16#00,16#00,16#00,16#00,16#00,
+ 16#00,16#00,16#00,16#00,16#00,16#00,16#00,16#00,
+ 16#88,16#05,16#61,16#51,16#41,16#67,16#6c,16#c9,
+ 16#19,16#61,16#74,16#e7,16#42,16#a3,16#25,16#51] =
+ snmp_user_based_sm_mib:mk_key_change(md5, KMd5_1, KMd5_2, 16,
+ [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]),
+ %% From rfc2274, appendix A.5.2
+ ?line KSHA_2 = snmp:passwd2localized_key(sha, "newsyrup", EID),
+ ?line [16#00,16#00,16#00,16#00,16#00,16#00,16#00,16#00,
+ 16#00,16#00,16#00,16#00,16#00,16#00,16#00,16#00,
+ 16#00,16#00,16#00,16#00,16#9c,16#10,16#17,16#f4,
+ 16#fd,16#48,16#3d,16#2d,16#e8,16#d5,16#fa,16#db,
+ 16#f8,16#43,16#92,16#cb,16#06,16#45,16#70,16#51] =
+ snmp_user_based_sm_mib:mk_key_change(sha, KSHA_1, KSHA_2, 20,
+ [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]),
+ KSHA_1t = lists:sublist(KSHA_1, 16),
+ KSHA_2t = lists:sublist(KSHA_2, 16),
+ ?line [16#00,16#00,16#00,16#00,16#00,16#00,16#00,16#00,
+ 16#00,16#00,16#00,16#00,16#00,16#00,16#00,16#00,
+ 16#7e,16#f8,16#d8,16#a4,16#c9,16#cd,16#b2,16#6b,
+ 16#47,16#59,16#1c,16#d8,16#52,16#ff,16#88,16#b5] =
+ snmp_user_based_sm_mib:mk_key_change(sha, KSHA_1t, KSHA_2t, 16,
+ [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]),
+
+ %% Try with correct random
+ ?line Kc1 = snmp_user_based_sm_mib:mk_key_change(md5, KMd5_1, KMd5_2),
+ ?line KMd5_2 = snmp_user_based_sm_mib:extract_new_key(md5, KMd5_1, Kc1),
+ ?line Kc2 = snmp_user_based_sm_mib:mk_key_change(sha, KSHA_1, KSHA_2),
+ ?line KSHA_2 = snmp_user_based_sm_mib:extract_new_key(sha, KSHA_1, Kc2),
+ ok.
+
+
+
+v3_md5_auth(suite) -> [];
+v3_md5_auth(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ p("Testing MD5 authentication...takes a few seconds..."),
+
+ AgentDir = ?config(agent_dir, Config),
+ ?line rewrite_target_params_conf(AgentDir, "authMD5", authNoPriv),
+ ?line snmp_target_mib:reconfigure(AgentDir),
+
+ MA = whereis(snmp_master_agent),
+
+ ?line load_master("Test2"),
+ ?line load_master("TestTrap"),
+ ?line load_master("TestTrapv2"),
+
+ try_test(v3_sync, [[{v2_proc, []},
+ {ma_v2_trap1, [MA]},
+ {v3_inform_sync, [MA]}]],
+ [{sec_level, authNoPriv}, {user, "authMD5"}]),
+
+ ?line unload_master("TestTrapv2"),
+ ?line unload_master("TestTrap"),
+ ?line unload_master("Test2"),
+ ?line reset_target_params_conf(AgentDir).
+
+v3_sha_auth(suite) -> [];
+v3_sha_auth(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ p("Testing SHA authentication...takes a few seconds..."),
+
+ AgentDir = ?config(agent_dir, Config),
+ ?line rewrite_target_params_conf(AgentDir, "authSHA", authNoPriv),
+ ?line snmp_target_mib:reconfigure(AgentDir),
+
+ MA = whereis(snmp_master_agent),
+
+ ?line load_master("Test2"),
+ ?line load_master("TestTrap"),
+ ?line load_master("TestTrapv2"),
+
+ try_test(v3_sync, [[{v2_proc, []},
+ {ma_v2_trap1, [MA]},
+ {v3_inform_sync, [MA]}]],
+ [{sec_level, authNoPriv}, {user, "authSHA"}]),
+
+ ?line unload_master("TestTrapv2"),
+ ?line unload_master("TestTrap"),
+ ?line unload_master("Test2"),
+ ?line reset_target_params_conf(AgentDir).
+
+v3_des_priv(suite) -> [];
+v3_des_priv(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ p("Testing DES encryption...takes a few seconds..."),
+
+ AgentDir = ?config(agent_dir, Config),
+ ?line rewrite_target_params_conf(AgentDir, "privDES", authPriv),
+ ?line snmp_target_mib:reconfigure(AgentDir),
+
+ MA = whereis(snmp_master_agent),
+
+ ?line load_master("Test2"),
+ ?line load_master("TestTrap"),
+ ?line load_master("TestTrapv2"),
+
+ try_test(v3_sync, [[{v2_proc, []},
+ {ma_v2_trap1, [MA]},
+ {v3_inform_sync, [MA]}]],
+ [{sec_level, authPriv}, {user, "privDES"}]),
+
+ ?line unload_master("TestTrapv2"),
+ ?line unload_master("TestTrap"),
+ ?line unload_master("Test2"),
+ ?line reset_target_params_conf(AgentDir).
+
+%% -define(usmStatsNotInTimeWindows_instance, [1,3,6,1,6,3,15,1,1,2,0]).
+
+%% Make sure mgr is in sync with agent
+v3_sync(Funcs) ->
+ ?DBG("v3_sync -> entry with Funcs: ~p",[Funcs]),
+ g([[sysDescr, 0]]),
+ expect(432, report, [{?usmStatsNotInTimeWindows_instance, any}]),
+ g([[sysDescr, 0]]),
+ expect(433, [{[sysDescr,0], any}]),
+ lists:foreach(fun({Func, Args}) -> apply(?MODULE, Func, Args) end, Funcs).
+
+v3_inform_sync(MA) ->
+ ?DBG("v3_sync -> entry with MA: ~p => Send notification",[MA]),
+ ?line snmpa:send_notification(MA, testTrapv22, no_receiver,
+ "standard inform", []),
+ %% Make sure agent is in sync with mgr...
+ ?DBG("v3_sync -> wait some time: ",[]),
+ sleep(20000), % more than 1500*10 in target_addr.conf
+ ?DBG("v3_sync -> await response",[]),
+ ?line expect(1, {inform, true},
+ [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?system ++ [0,1]}]).
+
+
+v2_caps(suite) -> [];
+v2_caps(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ try_test(v2_caps_i, [node()]).
+
+v2_caps_3(X) -> v2_caps(X).
+
+
+v2_caps_i(Node) ->
+ ?line Idx = rpc:call(Node, snmp, add_agent_caps, [[1,2,3,4,5], "test cap"]),
+ g([[sysORID, Idx], [sysORDescr, Idx]]),
+ ?line expect(1, [{[sysORID, Idx], [1,2,3,4,5]},
+ {[sysORDescr, Idx], "test cap"}]),
+ ?line rpc:call(Node, snmp, del_agent_caps, [Idx]),
+ g([[sysORID, Idx]]),
+ ?line expect(2, [{[sysORID, Idx], noSuchInstance}]).
+
+
+%% Req. Test2
+v1_proc() ->
+ ?DBG("v1_proc -> entry", []),
+ %% According to RFC1157.
+ %% Template: <Section>:<list no>
+ v1_get_p(),
+ v1_get_next_p(),
+ v1_set_p().
+
+
+v1_get_p() ->
+ %% 4.1.2:1
+ g([[test2]]),
+ ?line expect(10, noSuchName, 1, [{[test2], 'NULL'}]),
+ g([[tDescr]]),
+ ?line expect(11, noSuchName, 1, [{[tDescr], 'NULL'}]),
+ g([[tDescr2,0]]),
+ ?line expect(12, noSuchName, 1, [{[tDescr2,0], 'NULL'}]),
+ g([[tDescr3,0]]),
+ ?line expect(131, noSuchName, 1, [{[tDescr3,0], 'NULL'}]),
+ g([[tDescr4,0]]),
+ ?line expect(132, noSuchName, 1, [{[tDescr4,0], 'NULL'}]),
+ g([[sysDescr, 0], [tDescr,0]]), % Outside mibview
+ ?line expect(14, noSuchName, 2, [{[sysDescr, 0], 'NULL'},
+ {[tDescr,0], 'NULL'}]),
+ g([[sysDescr,3]]),
+ ?line expect(15, noSuchName, 1, [{[sysDescr, 3], 'NULL'}]),
+
+ %% 4.1.2:2
+ g([[tTable]]),
+ ?line expect(20, noSuchName, 1, [{[tTable], 'NULL'}]),
+ g([[tEntry]]),
+ ?line expect(21, noSuchName, 1, [{[tEntry], 'NULL'}]),
+
+ %% 4.1.2:3
+ g([[tTooBig, 0]]),
+ ?line expect(30, tooBig, 0, [{[tTooBig, 0], 'NULL'}]),
+
+ %% 4.1.2:4
+ g([[tGenErr1, 0]]),
+ ?line expect(40, genErr, 1, [{[tGenErr1, 0], 'NULL'}]),
+ g([[tGenErr2, 0]]),
+ ?line expect(41, genErr, 1, [{[tGenErr2, 0], 'NULL'}]),
+ g([[sysDescr, 0], [tGenErr3, 0]]),
+ ?line expect(42, genErr, 2, [{[sysDescr, 0], 'NULL'},
+ {[tGenErr3, 0], 'NULL'}]).
+
+
+v1_get_next_p() ->
+ %% 4.1.3:1
+ gn([[1,3,7,1]]),
+ ?line expect(10, noSuchName, 1, [{[1,3,7,1], 'NULL'}]),
+ gn([[tDescr2]]),
+ ?line expect(11, tooBig, 0, any),
+
+ %% 4.1.3:2
+ gn([[tTooBig]]),
+ io:format("We currently don't handle tooBig correct!!!\n"),
+% ?line expect(20, tooBig, 0, [{[tTooBig], 'NULL'}]),
+ ?line expect(20, tooBig, 0, any),
+
+ %% 4.1.3:3
+ gn([[tGenErr1]]),
+% ?line expect(40, genErr, 1, [{[tGenErr1], 'NULL'}]),
+ ?line expect(40, genErr, 1, any),
+ gn([[tGenErr2]]),
+% ?line expect(41, genErr, 1, [{[tGenErr2], 'NULL'}]),
+ ?line expect(41, genErr, 1, any),
+ gn([[sysDescr], [tGenErr3]]),
+% ?line expect(42, genErr, 2, [{[sysDescr], 'NULL'},
+% {[tGenErr3], 'NULL'}]).
+ ?line expect(42, genErr, 2, any).
+
+v1_set_p() ->
+ %% 4.1.5:1
+ s([{[1,3,7,0], i, 4}]),
+ ?line expect(10, noSuchName, 1, [{[1,3,7,0], 4}]),
+ s([{[tDescr,0], s, "outside mibview"}]),
+ ?line expect(11, noSuchName, 1, [{[tDescr,0], "outside mibview"}]),
+ s([{[tDescr3,0], s, "read-only"}]),
+ ?line expect(12, noSuchName, 1, [{[tDescr3,0], "read-only"}]),
+ s([{[tDescr3], s, "noSuchObject"}]),
+ ?line expect(13, noSuchName, 1, [{[tDescr3], "noSuchObject"}]),
+ s([{[tDescr3,1], s, "noSuchInstance"}]),
+ ?line expect(14, noSuchName, 1, [{[tDescr3,1], "noSuchInstance"}]),
+ s([{[tDescr2,0], s, "inconsistentName"}]),
+ ?line expect(15, noSuchName, 1, [{[tDescr2,0], "inconsistentName"}]),
+
+ %% 4.1.5:2
+ s([{[tDescr2, 0], i, 4}]),
+ ?line expect(20, badValue, 1, [{[tDescr2, 0], 4}]),
+ s([{[tDescr2, 0], s, "badValue"}]),
+ ?line expect(21, badValue, 1, [{[tDescr2, 0], "badValue"}]),
+
+ %% 4.1.5:3
+ %% The standard is quite incorrect here. The resp pdu was too big. In
+ %% the resp pdu, we have the original vbs. In the tooBig pdu we still
+ %% have to original vbs => the tooBig pdu is too big as well!!! It
+ %% may not get it to the manager, unless the agent uses 'NULL' instead
+ %% of the std-like original value.
+ s([{[tTooBig, 0], s, ?tooBigStr}]),
+ %% according to std:
+% ?line expect(30, tooBig, 0, [{[tTooBig, 0], ?tooBigStr}]),
+ ?line expect(30, tooBig, 0, [{[tTooBig, 0], 'NULL'}]),
+
+ %% 4.1.5:4
+ s([{[tDescr2, 0], s, "is_set_ok_fail"}]),
+ ?line expect(40, genErr, 1, [{[tDescr2, 0], "is_set_ok_fail"}]),
+ s([{[tDescr2, 0], s, "commit_fail"}]),
+ ?line expect(41, genErr, 1, [{[tDescr2, 0], "commit_fail"}]).
+
+%% Req. Test2
+v2_proc() ->
+ %% According to RFC1905.
+ %% Template: <Section>:<list no>
+ ?DBG("v2_proc -> entry",[]),
+ v2_get_p(),
+ v2_get_next_p(),
+ v2_get_bulk_p(),
+ v2_set_p().
+
+v2_get_p() ->
+ %% 4.2.1:2
+ ?DBG("v2_get_p -> entry",[]),
+ g([[test2]]),
+ ?line expect(10, [{[test2], noSuchObject}]),
+ g([[tDescr]]),
+ ?line expect(11, [{[tDescr], noSuchObject}]),
+ g([[tDescr4,0]]),
+ ?line expect(12, [{[tDescr4,0], noSuchObject}]),
+ g([[sysDescr, 0], [tDescr,0]]), % Outside mibview
+ ?line expect(13, [{[sysDescr,0], "Erlang SNMP agent"},
+ {[tDescr,0], noSuchObject}]),
+ g([[tTable]]),
+ ?line expect(14, [{[tTable], noSuchObject}]),
+ g([[tEntry]]),
+ ?line expect(15, [{[tEntry], noSuchObject}]),
+
+ %% 4.2.1:3
+ g([[tDescr2,0]]), %% instrum ret noSuchName!!!
+ ?line expect(20, [{[tDescr2,0], noSuchInstance}]),
+ g([[tDescr3,0]]),
+ ?line expect(21, [{[tDescr3,0], noSuchInstance}]),
+ g([[sysDescr,3]]),
+ ?line expect(22, [{[sysDescr, 3], noSuchInstance}]),
+ g([[tIndex,1]]),
+ ?line expect(23, [{[tIndex, 1], noSuchInstance}]),
+
+ %% 4.2.1 - any other error: genErr
+ g([[tGenErr1, 0]]),
+ ?line expect(30, genErr, 1, [{[tGenErr1, 0], 'NULL'}]),
+ g([[tGenErr2, 0]]),
+ ?line expect(31, genErr, 1, [{[tGenErr2, 0], 'NULL'}]),
+ g([[sysDescr, 0], [tGenErr3, 0]]),
+ ?line expect(32, genErr, 2, [{[sysDescr, 0], 'NULL'},
+ {[tGenErr3, 0], 'NULL'}]),
+
+ %% 4.2.1 - tooBig
+ g([[tTooBig, 0]]),
+ ?line expect(40, tooBig, 0, []).
+
+
+v2_get_next_p() ->
+ %% 4.2.2:2
+ ?DBG("v2_get_next_p -> entry",[]),
+ gn([[1,3,7,1]]),
+ ?line expect(10, [{[1,3,7,1], endOfMibView}]),
+ gn([[sysDescr], [1,3,7,1]]),
+ ?line expect(11, [{[sysDescr, 0], "Erlang SNMP agent"},
+ {[1,3,7,1], endOfMibView}]),
+ gn([[tCnt2, 1]]),
+ ?line expect(12, [{[tCnt2,2], 100}]),
+ gn([[tCnt2, 2]]),
+ ?line expect(12, [{[tCnt2,2], endOfMibView}]),
+
+ %% 4.2.2 - any other error: genErr
+ gn([[tGenErr1]]),
+ ?line expect(20, genErr, 1, [{[tGenErr1], 'NULL'}]),
+ gn([[tGenErr2]]),
+ ?line expect(21, genErr, 1, [{[tGenErr2], 'NULL'}]),
+ gn([[sysDescr], [tGenErr3]]),
+ ?line expect(22, genErr, 2, [{[sysDescr], 'NULL'},
+ {[tGenErr3], 'NULL'}]),
+
+ %% 4.2.2 - tooBig
+ gn([[tTooBig]]),
+ ?line expect(20, tooBig, 0, []).
+
+v2_get_bulk_p() ->
+ %% 4.2.3
+ ?DBG("v2_get_bulk_p -> entry",[]),
+ gb(1, 1, []),
+ ?line expect(10, []),
+ gb(-1, 1, []),
+ ?line expect(11, []),
+ gb(-1, -1, []),
+ ?line expect(12, []),
+ gb(-1, -1, []),
+ ?line expect(13, []),
+ gb(2, 0, [[sysDescr], [1,3,7,1]]),
+ ?line expect(14, [{[sysDescr, 0], "Erlang SNMP agent"},
+ {[1,3,7,1], endOfMibView}]),
+ gb(1, 2, [[sysDescr], [1,3,7,1]]),
+ ?line expect(15, [{[sysDescr, 0], "Erlang SNMP agent"},
+ {[1,3,7,1], endOfMibView}]),
+ gb(0, 2, [[sysDescr], [1,3,7,1]]),
+ ?line expect(16, [{[sysDescr, 0], "Erlang SNMP agent"},
+ {[1,3,7,1], endOfMibView},
+ {[sysObjectID, 0], [1,2,3]},
+ {[1,3,7,1], endOfMibView}]),
+
+ gb(2, 2, [[sysDescr], [1,3,7,1], [sysDescr], [1,3,7,1]]),
+ ?line expect(17, [{[sysDescr, 0], "Erlang SNMP agent"},
+ {[1,3,7,1], endOfMibView},
+ {[sysDescr, 0], "Erlang SNMP agent"},
+ {[1,3,7,1], endOfMibView},
+ {[sysObjectID, 0], [1,2,3]},
+ {[1,3,7,1], endOfMibView}]),
+
+ gb(1, 2, [[sysDescr], [sysDescr], [tTooBig]]),
+ ?line expect(18, [{[sysDescr, 0], "Erlang SNMP agent"},
+ {[sysDescr, 0], "Erlang SNMP agent"}]),
+
+ gb(1,12, [[tDescr2], [sysDescr]]), % next one after tDescr2 is tTooBig.
+ ?line expect(19, []),
+
+ gb(2,2, [[sysDescr], [sysObjectID], [tGenErr1], [sysDescr]]),
+ ?line expect(20, genErr, 3, [{[sysDescr], 'NULL'},
+ {[sysObjectID], 'NULL'},
+ {[tGenErr1], 'NULL'},
+ {[sysDescr], 'NULL'}]),
+ gb(0, 2, [[tCnt2, 1]]),
+ ?line expect(21, [{[tCnt2,2], 100},
+ {[tCnt2,2], endOfMibView}]).
+
+
+v2_set_p() ->
+ %% 4.2.5:1
+ ?DBG("v2_set_p -> entry",[]),
+ s([{[1,3,7,0], i, 4}]),
+ ?line expect(10, noAccess, 1, [{[1,3,7,0], 4}]),
+ s([{[tDescr,0], s, "outside mibview"}]),
+ ?line expect(11, noAccess, 1, [{[tDescr,0], "outside mibview"}]),
+
+ %% 4.2.5:2
+ s([{[1,3,6,1,0], s, "noSuchObject"}]),
+ ?line expect(20, notWritable, 1, [{[1,3,6,1,0], "noSuchObject"}]),
+
+ %% 4.2.5:3
+ s([{[tDescr2, 0], i, 4}]),
+ ?line expect(30, wrongType, 1, [{[tDescr2, 0], 4}]),
+ s([{[tDescr2, 0], s, "badValue"}]),
+ ?line expect(31, badValue, 1, [{[tDescr2, 0], "badValue"}]),
+
+ %% 4.2.5:4
+ s([{[tStr, 0], s, ""}]),
+ ?line expect(40, wrongLength, 1, [{[tStr, 0], ""}]),
+ s([{[tStr, 0], s, "12345"}]),
+ ?line expect(40, wrongLength, 1, [{[tStr, 0], "12345"}]),
+
+ %% 4.2.5:5 - N/A
+
+ %% 4.2.5:6
+ s([{[tInt1, 0], i, 0}]),
+ ?line expect(60, wrongValue, 1, [{[tInt1, 0], 0}]),
+ s([{[tInt1, 0], i, 5}]),
+ ?line expect(61, wrongValue, 1, [{[tInt1, 0], 5}]),
+ s([{[tInt2, 0], i, 0}]),
+ ?line expect(62, wrongValue, 1, [{[tInt2, 0], 0}]),
+ s([{[tInt2, 0], i, 5}]),
+ ?line expect(63, wrongValue, 1, [{[tInt2, 0], 5}]),
+ s([{[tInt3, 0], i, 5}]),
+ ?line expect(64, wrongValue, 1, [{[tInt3, 0], 5}]),
+
+ %% 4.2.5:7
+ s([{[tDescrX, 1, 1], s, "noCreation"}]),
+ ?line expect(70, noCreation, 1, [{[tDescrX, 1, 1], "noCreation"}]),
+
+ %% 4.2.5:8
+ s([{[tDescrX, 1, 2], s, "inconsistentName"}]),
+ ?line expect(80, inconsistentName, 1,
+ [{[tDescrX, 1, 2], "inconsistentName"}]),
+
+ %% 4.2.5:9
+ s([{[tCnt, 1, 2], i, 5}]),
+ ?line expect(90, notWritable, 1, [{[tCnt, 1, 2], 5}]),
+ s([{[tDescr3,0], s, "read-only"}]),
+ ?line expect(90, notWritable, 1, [{[tDescr3,0], "read-only"}]),
+
+ %% 4.2.5:10
+ s([{[tDescr2,0], s, "inconsistentValue"}]),
+ ?line expect(100, inconsistentValue, 1,
+ [{[tDescr2,0], "inconsistentValue"}]),
+
+ %% 4.2.5:11
+ s([{[tDescr2,0], s, "resourceUnavailable"}]),
+ ?line expect(110, resourceUnavailable, 1,
+ [{[tDescr2,0],"resourceUnavailable"}]),
+
+ %% 4.2.5:12
+ s([{[tDescr2, 0], s, "is_set_ok_fail"}]),
+ ?line expect(120, genErr, 1, [{[tDescr2, 0], "is_set_ok_fail"}]).
+
+ %% commitFailed and undoFailed is tested by the 'undo' case.
+
+
+%% Req. OLD-SNMPEA-MIB
+table_test() ->
+ io:format("Testing simple get, next and set on communityTable...~n"),
+%% {[147,214,36,45], "public", 2, readWrite}.
+%% {[147,214,36,45], "standard trap", 2, read}.
+ Key1c3 = [intCommunityViewIndex,get(mip),is("public")],
+ Key2c3 = [intCommunityViewIndex,get(mip),is("standard trap")],
+ Key1c4 = [intCommunityAccess,get(mip),is("public")],
+ EndKey = [intCommunityEntry,[9],get(mip),is("public")],
+ gn([[intCommunityEntry]]),
+ ?line expect(7, [{Key1c3, 2}]),
+ gn([[intCommunityTable]]),
+ ?line expect(71, [{Key1c3, 2}]),
+ gn([[community]]),
+ ?line expect(72, [{Key1c3, 2}]),
+ gn([[otpSnmpeaMIB]]),
+ ?line expect(73, [{Key1c3, 2}]),
+ gn([[ericsson]]),
+ ?line expect(74, [{Key1c3, 2}]),
+ gn([Key1c3]),
+ ?line expect(8, [{Key2c3, 2}]),
+ gn([Key2c3]),
+ ?line expect(9, [{Key1c4, 2}]),
+ gn([EndKey]),
+ AgentIp = [intAgentIpAddress,0],
+ ?line expect(10, [{AgentIp, any}]),
+ g([Key1c3]),
+ ?line expect(11, [{Key1c3, 2}]),
+ g([EndKey]),
+ ?line ?v1_2(expect(12, noSuchName, 1, any),
+ expect(12, [{EndKey, noSuchObject}])),
+
+ io:format("Testing row creation/deletion on communityTable...~n"),
+ NewKeyc3 = [intCommunityViewIndex,get(mip),is("test")],
+ NewKeyc4 = [intCommunityAccess,get(mip),is("test")],
+ NewKeyc5 = [intCommunityStatus,get(mip),is("test")],
+ s([{NewKeyc5, ?createAndGo}]),
+ ?line expect(14, ?v1_2(badValue, inconsistentValue), 1,any),
+ s([{NewKeyc5, ?createAndGo}, {NewKeyc3, 2}, {NewKeyc4, 2}]),
+ ?line expect(15, [{NewKeyc5, ?createAndGo},{NewKeyc3, 2}, {NewKeyc4, 2}]),
+ g([NewKeyc4]),
+ ?line expect(16, [{NewKeyc4, 2}]),
+ s([{NewKeyc5, ?destroy}]),
+ ?line expect(17, [{NewKeyc5, ?destroy}]),
+ s([{NewKeyc4, 2}]),
+ ?line expect(18, ?v1_2(noSuchName, inconsistentName), 1,[{NewKeyc4, 2}]),
+ s([{NewKeyc5, ?createAndWait}]),
+ ?line expect(19, [{NewKeyc5, ?createAndWait}]),
+ g([NewKeyc5]),
+ ?line expect(20, [{NewKeyc5, ?notReady}]),
+ s([{NewKeyc4, 2}]),
+ ?line expect(21, [{NewKeyc4, 2}]),
+ g([NewKeyc5]),
+ ?line expect(22, [{NewKeyc5, ?notReady}]),
+ s([{NewKeyc3, 2}]),
+ ?line expect(23, [{NewKeyc3, 2}]),
+ g([NewKeyc5]),
+ ?line expect(24, [{NewKeyc5, ?notInService}]),
+ s([{NewKeyc5, ?active}]),
+ ?line expect(25, [{NewKeyc5, ?active}]),
+ s([{NewKeyc5, ?destroy}]),
+ ?line expect(26, [{NewKeyc5, ?destroy}]),
+ s([{NewKeyc3, 3}]),
+ ?line expect(27, ?v1_2(noSuchName, inconsistentName), 1,[{NewKeyc3, 3}]),
+ otp_1128().
+
+%% Req. system group
+simple_standard_test() ->
+ ?DBG("simple_standard_test -> entry",[]),
+ gn([[1,1]]),
+ ?line expect(1, [{[sysDescr,0], "Erlang SNMP agent"}]),
+ gn([[1,3]]),
+ ?line expect(11, [{[sysDescr,0], "Erlang SNMP agent"}]),
+ gn([[1,3,6]]),
+ ?line expect(12, [{[sysDescr,0], "Erlang SNMP agent"}]),
+ gn([[1,3,6,1]]),
+ ?line expect(13, [{[sysDescr,0], "Erlang SNMP agent"}]),
+ gn([[1,3,6,1,2]]),
+ ?line expect(14, [{[sysDescr,0], "Erlang SNMP agent"}]),
+ gn([[1,3,6,1,2,1]]),
+ ?line expect(15, [{[sysDescr,0], "Erlang SNMP agent"}]),
+ gn([[1,3,6,1,2,1,1]]),
+ ?line expect(16, [{[sysDescr,0], "Erlang SNMP agent"}]),
+ gn([[sysDescr]]),
+ ?line expect(17, [{[sysDescr,0], "Erlang SNMP agent"}]),
+ g([[sysDescr,0]]),
+ ?line expect(2, [{[sysDescr,0], "Erlang SNMP agent"}]),
+ g([[sysDescr]]),
+ ?line ?v1_2(expect(3, noSuchName, 1, any),
+ expect(3, [{[sysDescr], noSuchObject}])),
+ g([[1,6,7,0]]),
+ ?line ?v1_2(expect(41, noSuchName, 1, any),
+ expect(3, [{[1,6,7,0], noSuchObject}])),
+ gn([[1,13]]),
+ ?line ?v1_2(expect(4, noSuchName,1, any),
+ expect(4, [{[1,13], endOfMibView}])),
+ s([{[sysLocation, 0], "new_value"}]),
+ ?line expect(5, [{[sysLocation, 0], "new_value"}]),
+ g([[sysLocation, 0]]),
+ ?line expect(6, [{[sysLocation, 0], "new_value"}]),
+ io:format("Testing noSuchName and badValue...~n"),
+ s([{[sysServices,0], 3}]),
+ ?line expect(61, ?v1_2(noSuchName, notWritable), 1, any),
+ s([{[sysLocation, 0], i, 3}]),
+ ?line expect(62, ?v1_2(badValue, wrongType), 1, any),
+ ?DBG("simple_standard_test -> done",[]),
+ ok.
+
+%% This is run in the agent node
+db_notify_client(suite) -> [];
+db_notify_client(Config) when list(Config) ->
+ {SaNode, MgrNode, MibDir} = init_case(Config),
+ ?DBG("~n\tSaNode: ~p~n\tMgrNode: ~p~n\tMibDir: ~p",
+ [SaNode,MgrNode,MibDir]),
+ snmpa_local_db:register_notify_client(self(),?MODULE),
+
+ %% This call (the manager) will issue to set operations, so
+ %% we expect to receive to notify(insert) calls.
+ try_test(db_notify_client_test),
+
+ ?DBG("await first notify",[]),
+ receive
+ {db_notify_test_reply,insert} -> ?DBG("first notify received",[]),ok
+ end,
+
+ ?DBG("await second notify",[]),
+ receive
+ {db_notify_test_reply,insert} -> ?DBG("second notify received",[]),ok
+ end,
+
+ snmpa_local_db:unregister_notify_client(self()).
+
+
+%% This is run in the manager node
+db_notify_client_test() ->
+ ?DBG("set first new sysLocation",[]),
+ s([{[sysLocation, 0], "new_value"}]),
+ ?line expect(5, [{[sysLocation, 0], "new_value"}]),
+
+ ?DBG("set second new sysLocation",[]),
+ s([{[sysLocation, 0], "new_value"}]),
+ ?line expect(5, [{[sysLocation, 0], "new_value"}]).
+
+notify(Pid,What) ->
+ ?DBG("notify(~p,~p) -> called",[Pid,What]),
+ Pid ! {db_notify_test_reply,What}.
+
+
+%% Req: system group, OLD-SNMPEA-MIB, Klas1
+big_test() ->
+ ?DBG("big_test -> testing simple next/get/set @ master agent...",[]),
+ simple_standard_test(),
+
+ ?DBG("big_test -> testing simple next/get/set @ subagent...",[]),
+ gn([[klas1]]),
+ ?line expect(1, [{[fname,0], ""}]),
+ g([[fname,0]]),
+ ?line expect(2, [{[fname,0], ""}]),
+ s([{[fname,0], s, "test set"}]),
+ ?line expect(3, [{[fname,0], "test set"}]),
+ g([[fname,0]]),
+ ?line expect(4, [{[fname,0], "test set"}]),
+
+ ?DBG("big_test -> "
+ "testing next from last instance in master to subagent...",[]),
+ gn([[?v1_2(sysServices, sysORLastChange),0]]),
+ ?line expect(5, [{[fname,0], "test set"}]),
+ gn([[1,1],
+ [?v1_2(sysServices, sysORLastChange),0]]),
+ ?line expect(51, [{[sysDescr,0], "Erlang SNMP agent"},
+ {[fname,0], "test set"}]),
+ s([{[fname,0], s, ""}]),
+ ?line expect(52, [{[fname,0], ""}]),
+
+ table_test(),
+
+ ?DBG("big_test -> adding one row in subagent table",[]),
+ _FTab = [friendsEntry],
+ s([{[friendsEntry, [2, 3]], s, "kompis3"},
+ {[friendsEntry, [3, 3]], i, ?createAndGo}]),
+ ?line expect(6, [{[friendsEntry, [2, 3]], "kompis3"},
+ {[friendsEntry, [3, 3]], ?createAndGo}]),
+ g([[friendsEntry, [2, 3]],
+ [friendsEntry, [3, 3]]]),
+ ?line expect(7, [{[friendsEntry, [2, 3]], "kompis3"},
+ {[friendsEntry, [3, 3]], ?active}]),
+ s([{[friendsEntry, [3, 3]], i, ?destroy}]),
+ ?line expect(8, [{[friendsEntry, [3, 3]], ?destroy}]),
+
+ otp_1131(),
+
+ ?DBG("big_test -> adding two rows in subagent table with special INDEX",
+ []),
+ s([{[kompissEntry, [1, 3]], s, "kompis3"},
+ {[kompissEntry, [2, 3]], i, ?createAndGo}]),
+ ?line expect(9, [{[kompissEntry, [1, 3]], "kompis3"},
+ {[kompissEntry, [2, 3]], ?createAndGo}]),
+ g([[kompissEntry, [1, 3]],
+ [kompissEntry, [2, 3]]]),
+ ?line expect(10, [{[kompissEntry, [1, 3]], "kompis3"},
+ {[kompissEntry, [2, 3]], ?active}]),
+ gn([[kompissEntry, [1]],
+ [kompissEntry, [2]]]),
+ ?line expect(11, [{[kompissEntry, [1, 3]], "kompis3"},
+ {[kompissEntry, [2, 3]], ?active}]),
+ s([{[kompissEntry, [1, 2]], s, "kompis3"},
+ {[kompissEntry, [2, 2]], i, ?createAndGo}]),
+ ?line expect(12, [{[kompissEntry, [1, 2]], "kompis3"},
+ {[kompissEntry, [2, 2]], ?createAndGo}]),
+ gn([[kompissEntry, [1, 1]],
+ [kompissEntry, [2, 1]]]),
+ ?line expect(13, [{[kompissEntry, [1, 2]], "kompis3"},
+ {[kompissEntry, [2, 2]], ?active}]),
+ s([{[kompissEntry, [2, 3]], i, ?destroy}]),
+ ?line expect(14, [{[kompissEntry, [2, 3]], ?destroy}]),
+ s([{[kompissEntry, [2, 2]], i, ?destroy}]),
+ ?line expect(15, [{[kompissEntry, [2, 2]], ?destroy}]),
+ ?DBG("big_test -> done",[]),
+ ok.
+
+%% Req. system group, Klas2, OLD-SNMPEA-MIB
+big_test_2() ->
+ p("Testing simple next/get/set @ master agent (2)..."),
+ simple_standard_test(),
+
+ p("Testing simple next/get/set @ subagent (2)..."),
+ gn([[klas2]]),
+ ?line expect(1, [{[fname2,0], ""}]),
+ g([[fname2,0]]),
+ ?line expect(2, [{[fname2,0], ""}]),
+ s([{[fname2,0], s, "test set"}]),
+ ?line expect(3, [{[fname2,0], "test set"}]),
+ g([[fname2,0]]),
+ ?line expect(4, [{[fname2,0], "test set"}]),
+
+ otp_1298(),
+
+ p("Testing next from last object in master to subagent (2)..."),
+ gn([[?v1_2(sysServices, sysORLastChange),0]]),
+ ?line expect(5, [{[fname2,0], "test set"}]),
+ gn([[1,1],
+ [?v1_2(sysServices, sysORLastChange),0]]),
+ ?line expect(51, [{[sysDescr,0], "Erlang SNMP agent"},
+ {[fname2,0], "test set"}]),
+
+ table_test(),
+
+ p("Adding one row in subagent table (2)"),
+ _FTab = [friendsEntry2],
+ s([{[friendsEntry2, [2, 3]], s, "kompis3"},
+ {[friendsEntry2, [3, 3]], i, ?createAndGo}]),
+ ?line expect(6, [{[friendsEntry2, [2, 3]], "kompis3"},
+ {[friendsEntry2, [3, 3]], ?createAndGo}]),
+ g([[friendsEntry2, [2, 3]],
+ [friendsEntry2, [3, 3]]]),
+ ?line expect(7, [{[friendsEntry2, [2, 3]], "kompis3"},
+ {[friendsEntry2, [3, 3]], ?active}]),
+ s([{[friendsEntry2, [3, 3]], i, ?destroy}]),
+ ?line expect(8, [{[friendsEntry2, [3, 3]], ?destroy}]),
+
+ p("Adding two rows in subagent table with special INDEX (2)"),
+ s([{[kompissEntry2, [1, 3]], s, "kompis3"},
+ {[kompissEntry2, [2, 3]], i, ?createAndGo}]),
+ ?line expect(9, [{[kompissEntry2, [1, 3]], "kompis3"},
+ {[kompissEntry2, [2, 3]], ?createAndGo}]),
+ g([[kompissEntry2, [1, 3]],
+ [kompissEntry2, [2, 3]]]),
+ ?line expect(10, [{[kompissEntry2, [1, 3]], "kompis3"},
+ {[kompissEntry2, [2, 3]], ?active}]),
+ gn([[kompissEntry2, [1]],
+ [kompissEntry2, [2]]]),
+ ?line expect(11, [{[kompissEntry2, [1, 3]], "kompis3"},
+ {[kompissEntry2, [2, 3]], ?active}]),
+ s([{[kompissEntry2, [1, 2]], s, "kompis3"},
+ {[kompissEntry2, [2, 2]], i, ?createAndGo}]),
+ ?line expect(12, [{[kompissEntry2, [1, 2]], "kompis3"},
+ {[kompissEntry2, [2, 2]], ?createAndGo}]),
+ gn([[kompissEntry2, [1, 1]],
+ [kompissEntry2, [2, 1]]]),
+ ?line expect(13, [{[kompissEntry2, [1, 2]], "kompis3"},
+ {[kompissEntry2, [2, 2]], ?active}]),
+ s([{[kompissEntry2, [2, 3]], i, ?destroy}]),
+ ?line expect(14, [{[kompissEntry2, [2, 3]], ?destroy}]),
+ s([{[kompissEntry2, [2, 2]], i, ?destroy}]),
+ ?line expect(15, [{[kompissEntry2, [2, 2]], ?destroy}]),
+ ok.
+
+%% Req. Test1
+multi_threaded_test() ->
+ p("Testing multi threaded agent..."),
+ g([[multiStr,0]]),
+ Pid = get_multi_pid(),
+ g([[sysUpTime,0]]),
+ ?line expect(1, [{[sysUpTime,0], any}]),
+ s([{[sysLocation, 0], s, "pelle"}]),
+ ?line expect(2, [{[sysLocation, 0], "pelle"}]),
+ Pid ! continue,
+ ?line expect(3, [{[multiStr,0], "ok"}]),
+
+ s([{[multiStr, 0], s, "block"}]),
+ Pid2 = get_multi_pid(),
+ g([[sysUpTime,0]]),
+ ?line expect(4, [{[sysUpTime,0], any}]),
+ g([[multiStr,0]]),
+ Pid3 = get_multi_pid(),
+ g([[sysUpTime,0]]),
+ ?line expect(5, [{[sysUpTime,0], any}]),
+ s([{[sysLocation, 0], s, "kalle"}]),
+ Pid3 ! continue,
+ ?line expect(6, [{[multiStr,0], "ok"}]),
+ Pid2 ! continue,
+ ?line expect(7, [{[multiStr,0], "block"}]),
+ ?line expect(8, [{[sysLocation,0], "kalle"}]).
+
+%% Req. Test1, TestTrapv2
+mt_trap_test(MA) ->
+ snmpa:send_trap(MA, testTrapv22, "standard trap"),
+ ?line expect(1, v2trap, [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?system ++ [0,1]}]),
+
+ snmpa:send_trap(MA, mtTrap, "standard trap"),
+ Pid = get_multi_pid(),
+ g([[sysUpTime,0]]),
+ ?line expect(2, [{[sysUpTime,0], any}]),
+ snmpa:send_trap(MA, testTrapv22, "standard trap"),
+ ?line expect(3, v2trap, [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?system ++ [0,1]}]),
+ Pid ! continue,
+ ?line expect(4, v2trap, [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?testTrap ++ [2]},
+ {[multiStr,0], "ok"}]).
+
+
+get_multi_pid() ->
+ get_multi_pid(10).
+get_multi_pid(0) ->
+ ?line ?FAIL(no_global_name);
+get_multi_pid(N) ->
+ sleep(1000),
+ case global:whereis_name(snmp_multi_tester) of
+ Pid when pid(Pid) -> Pid;
+ _ -> get_multi_pid(N-1)
+ end.
+
+%% Req. Test1
+types_v2_test() ->
+ p("Testing v2 types..."),
+
+ s([{[bits1,0], 2#10}]),
+ ?line expect(1, [{[bits1,0], ?str(2#10)}]),
+ g([[bits1,0]]),
+ ?line expect(2, [{[bits1,0], ?str(2#101)}]),
+
+ s([{[bits2,0], 2#11000000110}]),
+ ?line expect(3, [{[bits2,0], ?str(2#11000000110)}]),
+ g([[bits2,0]]),
+ ?line expect(4, [{[bits2,0], ?str(2#11000000110)}]),
+
+ g([[bits3,0]]),
+ ?line expect(50, genErr, 1, any),
+
+ g([[bits4,0]]),
+ ?line expect(51, genErr, 1, any),
+
+ s([{[bits1,0], s, [2#10]}]),
+ ?line expect(6, ?v1_2(badValue, wrongValue), 1, any),
+
+ s([{[bits2,0], 2#11001001101010011}]),
+ ?line expect(7, ?v1_2(badValue, wrongValue), 1, any).
+
+
+%% Req. Test1
+implied_test(MA) ->
+ ?LOG("implied_test -> start",[]),
+ p("Testing IMPLIED..."),
+
+ snmpa:verbosity(MA,trace),
+ snmpa:verbosity(MA,trace),
+
+ %% Create two rows, check that they are get-nexted in correct order.
+ Idx1 = "apa",
+ Idx2 = "qq",
+ ?DBG("implied_test -> (send) create row 1 '~s' in table 1",[Idx1]),
+ s([{[testStatus, Idx1], i, ?createAndGo}, {[testDescr, Idx1],s,"row 1"}]),
+ ?line expect(1, [{[testStatus, Idx1], ?createAndGo},
+ {[testDescr, Idx1], "row 1"}]),
+ ?DBG("implied_test -> (send) create row 2 '~s' in table 1",[Idx2]),
+ s([{[testStatus, Idx2], i, ?createAndGo}, {[testDescr, Idx2],s,"row 2"}]),
+ ?line expect(2, [{[testStatus, Idx2], ?createAndGo},
+ {[testDescr, Idx2], "row 2"}]),
+ ?DBG("implied_test -> get-next(testDescr)",[]),
+ gn([[testDescr]]),
+ ?line expect(3, [{[testDescr,Idx1], "row 1"}]),
+ ?DBG("implied_test -> get-next(testDescr) of row 1",[]),
+ gn([[testDescr,Idx1]]),
+ ?line expect(4, [{[testDescr,Idx2], "row 2"}]),
+
+ % Delete the rows
+ ?DBG("implied_test -> (send) delete row 1 '~s' from table 1",[Idx1]),
+ s([{[testStatus, Idx1], i, ?destroy}]),
+ ?line expect(5, [{[testStatus, Idx1], ?destroy}]),
+ ?DBG("implied_test -> (send) delete row 2 '~s' from table 1",[Idx2]),
+ s([{[testStatus, Idx2], i, ?destroy}]),
+ ?line expect(6, [{[testStatus, Idx2], ?destroy}]),
+
+ %% Try the same in other table
+ Idx3 = [1, "apa"],
+ Idx4 = [1, "qq"],
+ ?DBG("implied_test -> (send) create row 1 '~s' in table 2",[Idx3]),
+ s([{[testStatus2, Idx3], i, ?createAndGo}, {[testDescr2,Idx3],s,"row 1"}]),
+ ?line expect(1, [{[testStatus2, Idx3], ?createAndGo},
+ {[testDescr2, Idx3], "row 1"}]),
+ ?DBG("implied_test -> (send) create row 2 '~s' in table 2",[Idx4]),
+ s([{[testStatus2, Idx4], i, ?createAndGo}, {[testDescr2,Idx4],s,"row 2"}]),
+ ?line expect(2, [{[testStatus2, Idx4], ?createAndGo},
+ {[testDescr2, Idx4], "row 2"}]),
+ ?DBG("implied_test -> get-next(testDescr2)",[]),
+ gn([[testDescr2]]),
+ ?line expect(3, [{[testDescr2,Idx3], "row 1"}]),
+ ?DBG("implied_test -> get-next(testDescr2) of row 1",[]),
+ gn([[testDescr2,Idx3]]),
+ ?line expect(4, [{[testDescr2,Idx4], "row 2"}]),
+
+ % Delete the rows
+ ?DBG("implied_test -> (send) delete row 1 '~s' from table 2",[Idx3]),
+ s([{[testStatus2, Idx3], i, ?destroy}]),
+ ?line expect(5, [{[testStatus2, Idx3], ?destroy}]),
+ ?DBG("implied_test -> (send) delete row 2 '~s' from table 2",[Idx4]),
+ s([{[testStatus2, Idx4], i, ?destroy}]),
+ ?line expect(6, [{[testStatus2, Idx4], ?destroy}]),
+
+ snmpa:verbosity(MA,log),
+
+ ?LOG("implied_test -> done",[]).
+
+
+
+%% Req. Test1
+sparse_table_test() ->
+ p("Testing sparse table..."),
+
+ %% Create two rows, check that they are get-nexted in correct order.
+ Idx1 = 1,
+ Idx2 = 2,
+ s([{[sparseStatus, Idx1], i, ?createAndGo},
+ {[sparseDescr, Idx1], s, "row 1"}]),
+ ?line expect(1, [{[sparseStatus, Idx1], ?createAndGo},
+ {[sparseDescr, Idx1], "row 1"}]),
+ s([{[sparseStatus, Idx2], i, ?createAndGo},
+ {[sparseDescr, Idx2], s, "row 2"}]),
+ ?line expect(2, [{[sparseStatus, Idx2], ?createAndGo},
+ {[sparseDescr, Idx2], "row 2"}]),
+ ?v1_2(gn([[sparseIndex], [sparseDescr,Idx1], [sparseDescr,Idx2],
+ [sparseStatus,Idx1], [sparseStatus,Idx2]]),
+ gb(0,5,[[sparseIndex]])),
+ ?line expect(3, [{[sparseDescr,Idx1], "row 1"},
+ {[sparseDescr,Idx2], "row 2"},
+ {[sparseStatus,Idx1], ?active},
+ {[sparseStatus,Idx2], ?active},
+ {[sparseStr,0], "slut"}]),
+ % Delete the rows
+ s([{[sparseStatus, Idx1], i, ?destroy}]),
+ ?line expect(4, [{[sparseStatus, Idx1], ?destroy}]),
+ s([{[sparseStatus, Idx2], i, ?destroy}]),
+ ?line expect(5, [{[sparseStatus, Idx2], ?destroy}]).
+
+
+%% Req. Test1
+cnt_64_test(MA) ->
+ ?LOG("start cnt64 test (~p)",[MA]),
+ snmpa:verbosity(MA,trace),
+ ?LOG("start cnt64 test",[]),
+ p("Testing Counter64, and at the same time, RowStatus is not last column"),
+
+ ?DBG("get cnt64",[]),
+ g([[cnt64,0]]),
+ ?DBG("await response",[]),
+ ?line ?v1_2(expect(1, noSuchName, 1, any),
+ expect(1, [{[cnt64,0],18446744073709551615}])),
+ ?DBG("get-next cnt64",[]),
+ gn([[cnt64]]),
+ ?DBG("await response",[]),
+ ?line ?v1_2(expect(2, [{[cnt64Str,0], "after cnt64"}]),
+ expect(2, [{[cnt64,0],18446744073709551615}])),
+ ?DBG("send cntTrap",[]),
+ snmpa:send_trap(MA,cntTrap,"standard trap",[{sysContact,"pelle"},
+ {cnt64, 10},
+ {sysLocation, "here"}]),
+ ?DBG("await response",[]),
+ ?line ?v1_2(expect(3, trap, [test], 6, 1, [{[sysContact,0], "pelle"},
+ {[sysLocation,0], "here"}]),
+ expect(3, v2trap, [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?testTrap ++ [1]},
+ {[sysContact,0], "pelle"},
+ {[cnt64,0], 10},
+ {[sysLocation,0], "here"}])),
+
+ %% Create two rows, check that they are get-nexted in correct order.
+ Idx1 = 1,
+ Idx2 = 2,
+ ?DBG("create row (cntStatus): ~p",[Idx1]),
+ s([{[cntStatus, Idx1], i, ?createAndGo}]),
+ ?DBG("await response",[]),
+ ?line expect(1, [{[cntStatus, Idx1], ?createAndGo}]),
+ ?DBG("create row (cntStatus): ~p",[Idx2]),
+ s([{[cntStatus, Idx2], i, ?createAndGo}]),
+ ?DBG("await response",[]),
+ ?line expect(2, [{[cntStatus, Idx2], ?createAndGo}]),
+
+ ?DBG("get-next (cntIndex)",[]),
+ gn([[cntIndex]]),
+ ?DBG("await response",[]),
+ ?line ?v1_2(expect(3, [{[cntStatus,Idx1], ?active}]),
+ expect(3, [{[cntCnt,Idx1], 0}])),
+ % Delete the rows
+ ?DBG("delete row (cntStatus): ~p",[Idx1]),
+ s([{[cntStatus, Idx1], i, ?destroy}]),
+ ?DBG("await response",[]),
+ ?line expect(4, [{[cntStatus, Idx1], ?destroy}]),
+ ?DBG("delete row (cntStatus): ~p",[Idx2]),
+ s([{[cntStatus, Idx2], i, ?destroy}]),
+ ?DBG("await response",[]),
+ ?line expect(5, [{[cntStatus, Idx2], ?destroy}]),
+ catch snmpa:verbosity(MA,log),
+ ?DBG("done",[]),
+ ok.
+
+%% Req. Test1
+opaque_test() ->
+ p("Testing Opaque datatype..."),
+ g([[opaqueObj,0]]),
+ ?line expect(1, [{[opaqueObj,0], "opaque-data"}]).
+
+%% Req. OLD-SNMPEA-MIB
+api_test(MaNode) ->
+ ?line {value, OID} = rpc:call(MaNode, snmp, name_to_oid,
+ [intAgentIpAddress]),
+ ?line {value, intAgentIpAddress} = rpc:call(MaNode, snmp,
+ oid_to_name, [OID]),
+ ?line false = rpc:call(MaNode, snmp, name_to_oid, [intAgentIpAddres]),
+ ?line false = rpc:call(MaNode, snmp, oid_to_name,
+ [[1,5,32,3,54,3,3,34,4]]),
+ ?line {value, 2} = rpc:call(MaNode, snmp, enum_to_int,
+ [intViewType, excluded]),
+ ?line {value, excluded} = rpc:call(MaNode, snmp, int_to_enum,
+ [intViewType, 2]),
+ ?line false = rpc:call(MaNode, snmp, enum_to_int, [intViewType, exclude]),
+ ?line false = rpc:call(MaNode, snmp, enum_to_int,
+ [intAgentIpAddress, exclude]),
+ ?line false = rpc:call(MaNode, snmp, enum_to_int,
+ [intAgentIpAddre, exclude]),
+ ?line false = rpc:call(MaNode, snmp, int_to_enum, [intViewType, 3]),
+ ?line false = rpc:call(MaNode, snmp, int_to_enum, [intAgentIpAddress, 2]),
+ ?line false = rpc:call(MaNode, snmp, int_to_enum, [intAgentIpAddre, 2]),
+ ?line {value, active} = rpc:call(MaNode, snmp,
+ int_to_enum, ['RowStatus', ?active]),
+ ?line {value, ?destroy} = rpc:call(MaNode, snmp,
+ enum_to_int, ['RowStatus', destroy]),
+ ?line false = rpc:call(MaNode, snmp,
+ enum_to_int, ['RowStatus', xxxdestroy]),
+ ?line false = rpc:call(MaNode, snmp,
+ enum_to_int, ['xxRowStatus', destroy]),
+ ?line false = rpc:call(MaNode, snmp, int_to_enum, ['RowStatus', 25]),
+ ?line false = rpc:call(MaNode, snmp, int_to_enum, ['xxRowStatus', 1]),
+ ?line case snmp:date_and_time() of
+ List when list(List), length(List) == 8 -> ok;
+ List when list(List), length(List) == 11 -> ok
+ end.
+
+%% Req. Klas3
+api_test2() ->
+ g([[fname3,0]]),
+ ?line expect(1, [{[fname3,0], "ok"}]),
+ g([[fname4,0]]),
+ ?line expect(2, [{[fname4,0], 1}]).
+
+api_test3() ->
+ g([[fname3,0]]),
+ ?line expect(1, [{[fname3,0], "ok"}]).
+
+
+unreg_test() ->
+ gn([[?v1_2(sysServices, sysORLastChange),0]]),
+ ?line expect(1, [{[snmpInPkts, 0], any}]).
+
+load_test() ->
+ gn([[?v1_2(sysServices, sysORLastChange),0]]),
+ ?line expect(1, [{[fname,0], ""}]).
+
+%% Req. Klas1
+load_test_sa() ->
+ gn([[?v1_2(sysServices,sysORLastChange), 0]]),
+ ?line expect(1, [{[fname,0], any}]).
+
+%% Req. system group, Klas1, OLD-SNMPEA-MIB
+do_mul_get() ->
+ Key1c3 = [intCommunityEntry,[3],get(mip),is("public")],
+ Key1c4 = [intCommunityEntry,[4],get(mip),is("public")],
+ s([{[fname,0], s, "test set"}]),
+ ?line expect(3, [{[fname,0], "test set"}]),
+ g([[sysDescr,0], Key1c4, [fname,0],Key1c3,
+ [sysName,0]]),
+ ?line expect(1, [{[sysDescr,0], "Erlang SNMP agent"},
+ {Key1c4, 2},
+ {[fname,0], "test set"},
+ {Key1c3, 2},
+ {[sysName,0], "test"}]),
+ g([[1,3,7,1], Key1c4, [sysDescr,0], [1,3,7,2], Key1c3, [sysDescr,0]]),
+ ?line ?v1_2(expect(2, noSuchName, [1,4], any),
+ expect(2, [{[1,3,7,1], noSuchObject},
+ {Key1c4, 2},
+ {[sysDescr,0], "Erlang SNMP agent"},
+ {[1,3,7,2], noSuchObject},
+ {Key1c3, 2},
+ {[sysDescr,0], "Erlang SNMP agent"}])).
+
+%% Req. v1, system group, Klas1, OLD-SNMPEA-MIB, *ej* Klas3.
+do_mul_get_err() ->
+ Key1c3 = [intCommunityEntry,[3],get(mip),is("public")],
+ Key1c4 = [intCommunityEntry,[4],get(mip),is("public")],
+ s([{[fname,0], s, "test set"}]),
+ ?line expect(3, [{[fname,0], "test set"}]),
+ g([[sysDescr,0],Key1c4,[fname,0], Key1c3, [sysName,2]]),
+ ?line ?v1_2(expect(1, noSuchName, 5, any),
+ expect(1, [{[sysDescr,0], "Erlang SNMP agent"},
+ {Key1c4, 2},
+ {[fname,0], "test set"},
+ {Key1c3, 2},
+ {[sysName,2], noSuchInstance}])),
+ g([[sysDescr,0],Key1c4,[fname3,0], Key1c3, [sysName,1]]),
+ ?line ?v1_2(expect(1, noSuchName, [3,5], any),
+ expect(1, [{[sysDescr,0], "Erlang SNMP agent"},
+ {Key1c4, 2},
+ {[fname3,0], noSuchObject},
+ {Key1c3, 2},
+ {[sysName,1], noSuchInstance}])).
+
+
+%% Req. system group, Klas1, OLD-SNMPEA-MIB
+do_mul_next() ->
+ Key1c3s = [intCommunityEntry,[3],get(mip),is("publi")],
+ Key1c4s = [intCommunityEntry,[4],get(mip),is("publi")],
+ Key1c3 = [intCommunityEntry,[3],get(mip),is("public")],
+ Key1c4 = [intCommunityEntry,[4],get(mip),is("public")],
+ s([{[fname,0], s, "test set"}]),
+ ?line expect(3, [{[fname,0], "test set"}]),
+ gn([[sysDescr], Key1c4s, [fname],Key1c3s,[sysName]]),
+ ?line expect(1, [{[sysDescr,0], "Erlang SNMP agent"},
+ {Key1c4, 2}, {[fname,0], "test set"},
+ {Key1c3, 2}, {[sysName,0], "test"}]).
+
+%% Req. system group, Klas1, OLD-SNMPEA-MIB
+do_mul_next_err() ->
+ Key1c3s = [intCommunityEntry,[3],get(mip),is("publi")],
+ Key1c4s = [intCommunityEntry,[4],get(mip),is("publi")],
+ Key1c3 = [intCommunityEntry,[3],get(mip),is("public")],
+ Key1c4 = [intCommunityEntry,[4],get(mip),is("public")],
+ s([{[fname,0], s, "test set"}]),
+ ?line expect(3, [{[fname,0], "test set"}]),
+ gn([[sysDescr], Key1c4s, [1,3,6,999], [fname],[1,3,90], Key1c3s,[sysName]]),
+ ?line ?v1_2(expect(1, noSuchName, [3,5], any),
+ expect(1, [{[sysDescr,0], "Erlang SNMP agent"},
+ {Key1c4, 2},
+ {[1,3,6,999], endOfMibView},
+ {[fname,0], "test set"},
+ {[1,3,90], endOfMibView},
+ {Key1c3, 2},
+ {[sysName,0], "test"}])).
+
+
+%% Req. system group, Klas1, OLD-SNMPEA-MIB
+do_mul_set() ->
+ p("Adding one row in subagent table, and one in master table"),
+ NewKeyc3 = [intCommunityEntry,[3],get(mip),is("test")],
+ NewKeyc4 = [intCommunityEntry,[4],get(mip),is("test")],
+ NewKeyc5 = [intCommunityEntry,[5],get(mip),is("test")],
+ s([{[friendsEntry, [2, 3]], "kompis3"},
+ {NewKeyc3, 2},
+ {[sysLocation,0], "new_value"},
+ {NewKeyc5, ?createAndGo},
+ {NewKeyc4, 2},
+ {[friendsEntry, [3, 3]], ?createAndGo}]),
+ ?line expect(1, [{[friendsEntry, [2, 3]], "kompis3"},
+ {NewKeyc3, 2},
+ {[sysLocation,0], "new_value"},
+ {NewKeyc5, ?createAndGo},
+ {NewKeyc4, 2},
+ {[friendsEntry, [3, 3]], ?createAndGo}]),
+ g([[friendsEntry, [2, 3]],
+ [sysLocation,0],
+ [friendsEntry, [3, 3]]]),
+ ?line expect(2, [{[friendsEntry, [2, 3]], "kompis3"},
+ {[sysLocation,0], "new_value"},
+ {[friendsEntry, [3, 3]], ?active}]),
+ g([NewKeyc4]),
+ ?line expect(3, [{NewKeyc4, 2}]),
+ s([{[friendsEntry, [3, 3]], ?destroy},
+ {NewKeyc5, ?destroy}]),
+ ?line expect(4, [{[friendsEntry, [3, 3]], ?destroy},
+ {NewKeyc5, ?destroy}]).
+
+%% Req. system group, Klas1, OLD-SNMPEA-MIB
+do_mul_set_err() ->
+ NewKeyc3 = [intCommunityEntry,[3],get(mip),is("test")],
+ NewKeyc4 = [intCommunityEntry,[4],get(mip),is("test")],
+ NewKeyc5 = [intCommunityEntry,[5],get(mip),is("test")],
+ p("Adding one row in subagent table, and one in master table"),
+ s([{[friendsEntry, [2, 3]], s, "kompis3"},
+ {NewKeyc3, 2},
+ {[sysUpTime,0], 45}, % sysUpTime (readOnly)
+ {NewKeyc5, ?createAndGo},
+ {NewKeyc4, 2},
+ {[friendsEntry, [3, 3]], ?createAndGo}]),
+ ?line expect(1, ?v1_2(noSuchName, notWritable), 3, any),
+ g([[friendsEntry, [2, 3]]]),
+ ?line ?v1_2(expect(2, noSuchName, 1, any),
+ expect(2, [{[friendsEntry, [2,3]], noSuchInstance}])),
+ g([NewKeyc4]),
+ ?line ?v1_2(expect(3, noSuchName, 1, any),
+ expect(3, [{NewKeyc4, noSuchInstance}])).
+
+%% Req. SA-MIB
+sa_mib() ->
+ g([[sa, [2,0]]]),
+ ?line expect(1, [{[sa, [2,0]], 3}]),
+ s([{[sa, [1,0]], s, "sa_test"}]),
+ ?line expect(2, [{[sa, [1,0]], "sa_test"}]).
+
+ma_trap1(MA) ->
+ snmpa:send_trap(MA, testTrap2, "standard trap"),
+ ?line expect(1, trap, [system], 6, 1, [{[system, [4,0]],
+ "{mbj,eklas}@erlang.ericsson.se"}]),
+ snmpa:send_trap(MA, testTrap1, "standard trap"),
+ ?line expect(2, trap, [1,2,3] , 1, 0, [{[system, [4,0]],
+ "{mbj,eklas}@erlang.ericsson.se"}]).
+
+ma_trap2(MA) ->
+ snmpa:send_trap(MA,testTrap2,"standard trap",[{sysContact,"pelle"}]),
+ ?line expect(3, trap, [system], 6, 1, [{[system, [4,0]], "pelle"}]).
+
+ma_v2_2_v1_trap(MA) ->
+ snmpa:send_trap(MA,testTrapv22,"standard trap",[{sysContact,"pelle"}]),
+ ?line expect(3, trap, [system], 6, 1, [{[system, [4,0]], "pelle"}]).
+
+ma_v2_2_v1_trap2(MA) ->
+ snmpa:send_trap(MA,linkUp,"standard trap",[{ifIndex, [1], 1},
+ {ifAdminStatus, [1], 1},
+ {ifOperStatus, [1], 2}]),
+ ?line expect(3, trap, [1,2,3], 3, 0, [{[ifIndex, 1], 1},
+ {[ifAdminStatus, 1], 1},
+ {[ifOperStatus, 1], 2}]).
+
+sa_trap1(SA) ->
+ snmpa:send_trap(SA, saTrap, "standard trap"),
+ ?line expect(4, trap, [ericsson], 6, 1, [{[system, [4,0]],
+ "{mbj,eklas}@erlang.ericsson.se"},
+ {[sa, [1,0]], "sa_test"}]).
+
+sa_trap2(SA) ->
+ snmpa:send_trap(SA, saTrap, "standard trap",[{sysContact,"pelle"}]),
+ ?line expect(5, trap, [ericsson], 6, 1, [{[system, [4,0]],
+ "pelle"},
+ {[sa, [1,0]], "sa_test"}]).
+
+sa_trap3(SA) ->
+ snmpa:send_trap(SA, saTrap2, "standard trap",
+ [{intViewSubtree, [4], [1,2,3,4]}]),
+ ?line expect(6, trap, [ericsson], 6, 2, [{[system, [4,0]],
+ "{mbj,eklas}@erlang.ericsson.se"},
+ {[sa, [1,0]], "sa_test"},
+ {[intViewSubtree,4],[1,2,3,4]}]).
+
+ma_v2_trap1(MA) ->
+ ?DBG("ma_v2_traps -> entry with MA = ~p => "
+ "send standard trap: testTrapv22",[MA]),
+ snmpa:send_trap(MA, testTrapv22, "standard trap"),
+ ?line expect(1, v2trap, [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?system ++ [0,1]}]),
+ ?DBG("ma_v2_traps -> send standard trap: testTrapv21",[]),
+ snmpa:send_trap(MA, testTrapv21, "standard trap"),
+ ?line expect(2, v2trap, [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?snmp ++ [1]}]).
+
+ma_v2_trap2(MA) ->
+ snmpa:send_trap(MA,testTrapv22,"standard trap",[{sysContact,"pelle"}]),
+ ?line expect(3, v2trap, [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?system ++ [0,1]},
+ {[system, [4,0]], "pelle"}]).
+
+%% Note: This test case takes a while... actually a couple of minutes.
+ma_v2_inform1(MA) ->
+ ?DBG("ma_v2_inform -> entry with MA = ~p => "
+ "send notification: testTrapv22",[MA]),
+ ?line snmpa:send_notification(MA, testTrapv22, no_receiver, "standard inform", []),
+ ?line expect(1, {inform, true},
+ [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?system ++ [0,1]}]),
+
+ ?DBG("ma_v2_inform -> send notification: testTrapv22",[]),
+ snmpa:send_notification(MA, testTrapv22, {tag1, self()},
+ "standard inform", []),
+ ?line expect(1, {inform, true},
+ [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?system ++ [0,1]}]),
+ ?DBG("ma_v2_inform -> await targets",[]),
+ receive
+ {snmp_targets, tag1, [_]} ->
+ ok;
+ {snmp_targets, tag1, Addrs1} ->
+ ?line ?FAIL({bad_addrs, Addrs1})
+ after
+ 5000 ->
+ ?ERR("ma_v2_inform1 -> awaiting snmp_targets(tag1) timeout",[]),
+ ?line ?FAIL(nothing_at_all)
+ end,
+ ?DBG("ma_v2_inform -> await notification",[]),
+ receive
+ {snmp_notification, tag1, {got_response, _}} ->
+ ok;
+ {snmp_notification, tag1, {no_response, _}} ->
+ ?line ?FAIL(no_response)
+ after
+ 20000 ->
+ ?ERR("ma_v2_inform1 -> "
+ "awaiting snmp_notification(tag1) timeout",[]),
+ ?line ?FAIL(nothing_at_all)
+ end,
+
+ %%
+ %% -- The rest is possibly erroneous...
+ %%
+
+ ?DBG("ma_v2_inform -> send notification: testTrapv22",[]),
+ snmpa:send_notification(MA, testTrapv22, {tag2, self()},
+ "standard inform", []),
+ ?line expect(2, {inform, false},
+ [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?system ++ [0,1]}]),
+ ?DBG("ma_v2_inform -> await targets",[]),
+ receive
+ {snmp_targets, tag2, [_]} ->
+ ok;
+ {snmp_targets, tag2, Addrs2} ->
+ ?ERR("ma_v2_inform1 -> awaiting snmp_targets(tag2) timeout",[]),
+ ?line ?FAIL({bad_addrs, Addrs2})
+ after
+ 5000 ->
+ ?line ?FAIL(nothing_at_all)
+ end,
+ ?DBG("ma_v2_inform -> await notification",[]),
+ receive
+ {snmp_notification, tag2, {got_response, _}} ->
+ ?line ?FAIL(got_response);
+ {snmp_notification, tag2, {no_response, _}} ->
+ ok
+ after
+ 240000 ->
+ ?ERR("ma_v2_inform1 -> "
+ "awaiting snmp_notification(tag2) timeout",[]),
+ ?line ?FAIL(nothing_at_all)
+ end.
+
+
+ma_v1_2_v2_trap(MA) ->
+ snmpa:send_trap(MA,linkDown,"standard trap",[{ifIndex, [1], 1}]),
+ ?line expect(2, v2trap, [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?snmpTraps ++ [3]},
+ {[ifIndex, 1], 1},
+ {[snmpTrapEnterprise, 0], [1,2,3]}]).
+
+
+ma_v1_2_v2_trap2(MA) ->
+ snmpa:send_trap(MA,testTrap2,"standard trap",[{sysContact,"pelle"}]),
+ ?line expect(3, v2trap, [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?system ++ [0,1]},
+ {[system, [4,0]], "pelle"},
+ {[snmpTrapEnterprise, 0], ?system}]).
+
+
+sa_v1_2_v2_trap1(SA) ->
+ snmpa:send_trap(SA, saTrap, "standard trap"),
+ ?line expect(4, v2trap, [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?ericsson ++ [0, 1]},
+ {[system, [4,0]],
+ "{mbj,eklas}@erlang.ericsson.se"},
+ {[sa, [1,0]], "sa_test"},
+ {[snmpTrapEnterprise, 0], ?ericsson}]).
+
+sa_v1_2_v2_trap2(SA) ->
+ snmpa:send_trap(SA, saTrap, "standard trap",[{sysContact,"pelle"}]),
+ ?line expect(4, v2trap, [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?ericsson ++ [0, 1]},
+ {[system, [4,0]], "pelle"},
+ {[sa, [1,0]], "sa_test"},
+ {[snmpTrapEnterprise, 0], ?ericsson}]).
+
+
+sa_v1_2_v2_trap3(SA) ->
+ snmpa:send_trap(SA, saTrap2, "standard trap",
+ [{intViewSubtree, [4], [1,2,3,4]}]),
+ ?line expect(4, v2trap, [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?ericsson ++ [0, 2]},
+ {[system, [4,0]],
+ "{mbj,eklas}@erlang.ericsson.se"},
+ {[sa, [1,0]], "sa_test"},
+ {[intViewSubtree,4],[1,2,3,4]},
+ {[snmpTrapEnterprise, 0], ?ericsson}]).
+
+
+%% Req. SA-MIB, OLD-SNMPEA-MIB
+sa_errs_bad_value() ->
+ NewKeyc3 = [intCommunityEntry,[3],get(mip),is("test")],
+ NewKeyc4 = [intCommunityEntry,[4],get(mip),is("test")],
+ NewKeyc5 = [intCommunityEntry,[5],get(mip),is("test")],
+ s([{NewKeyc3, 2},
+ {[sa, [2,0]], 5}, % badValue (i is_set_ok)
+ {NewKeyc5, ?createAndGo},
+ {NewKeyc4, 2}]),
+ ?line expect(1, badValue, 2, any),
+ s([{NewKeyc3, 2},
+ {[sa, [2,0]], 6}, % wrongValue (i is_set_ok)
+ {NewKeyc5, ?createAndGo},
+ {NewKeyc4, 2}]),
+ ?line expect(1, ?v1_2(badValue, wrongValue), 2, any),
+ g([NewKeyc4]),
+ ?line ?v1_2(expect(2, noSuchName, 1, any),
+ expect(2, [{NewKeyc4, noSuchInstance}])).
+
+%% Req. SA-MIB, OLD-SNMPEA-MIB
+sa_errs_gen_err() ->
+ NewKeyc3 = [intCommunityEntry,[3],get(mip),is("test")],
+ NewKeyc4 = [intCommunityEntry,[4],get(mip),is("test")],
+ NewKeyc5 = [intCommunityEntry,[5],get(mip),is("test")],
+ s([{NewKeyc3, 2},{NewKeyc4, 2},
+ {NewKeyc5, ?createAndGo}, {[sa, [3,0]], 5}]),
+ ?line expect(1, genErr, 4, any),
+% The row might have been added; we don't know.
+% (as a matter of fact we do - it is added, because the agent
+% first sets its own vars, and then th SAs. Lets destroy it.
+ s([{NewKeyc5, ?destroy}]),
+ ?line expect(2, [{NewKeyc5, ?destroy}]).
+
+%% Req. SA-MIB, OLD-SNMPEA-MIB
+sa_too_big() ->
+ g([[sa, [4,0]]]),
+ ?line expect(1, tooBig).
+
+%% Req. Klas1, system group, snmp group (v1/v2)
+next_across_sa() ->
+ gn([[sysDescr],[klas1,5]]),
+ ?line expect(1, [{[sysDescr,0], "Erlang SNMP agent"},
+ {[snmpInPkts, 0], any}]).
+
+%% snmp_test_mgr:s([{[fStatus3, 1], 4}, {[fname3,0], "ok"}]). -> noError
+%% snmp_test_mgr:s([{[fStatus3, 1], 4}, {[fname3,0], "hoj"}]). -> {badValue, 2}
+%% snmp_test_mgr:s([{[fStatus3, 3], 4}, {[fname3,0], "hoj"}]). -> {genErr, 1}
+%% snmp_test_mgr:s([{[fStatus3, 4], 4}, {[fname3,0], "ok"}]). -> {genErr, 1}
+%% snmp_test_mgr:s([{[fStatus3, 4], 4}, {[fname3,0], "ufail"}]). -> {genErr, 1}
+%% snmp_test_mgr:s([{[fStatus3, 1], 4}, {[fname3,0], "xfail"}]). -> {genErr, 2}
+%% Req. Klas3, Klas4
+undo_test() ->
+ s([{[fStatus3, 1], 4}, {[fname3,0], "ok"}]),
+ ?line expect(1, [{[fStatus3, 1], 4}, {[fname3,0], "ok"}]),
+ s([{[fStatus3, 1], 4}, {[fname3,0], "hoj"}]),
+ ?line expect(2, ?v1_2(badValue, inconsistentValue), 2, any),
+ s([{[fStatus3, 3], 4}, {[fname3,0], "hoj"}]),
+ ?line expect(3, ?v1_2(genErr, undoFailed), 1, any),
+ s([{[fStatus3, 4], 4}, {[fname3,0], "ok"}]),
+ ?line expect(4, ?v1_2(genErr, commitFailed), 1, any),
+% unfortunatly we don't know if we'll get undoFailed or commitFailed.
+% it depends on which order the agent traverses the varbind list.
+% s([{[fStatus3, 4], 4}, {[fname3,0], "ufail"}]),
+% ?line expect(5, ?v1_2(genErr, undoFailed), 1, any),
+ s([{[fStatus3, 1], 4}, {[fname3,0], "xfail"}]),
+ ?line expect(6, genErr, 2, any).
+
+%% Req. Klas3, Klas4
+bad_return() ->
+ g([[fStatus4,4],
+ [fName4,4]]),
+ ?line expect(4, genErr, 2, any),
+ g([[fStatus4,5],
+ [fName4,5]]),
+ ?line expect(5, genErr, 1, any),
+ g([[fStatus4,6],
+ [fName4,6]]),
+ ?line expect(6, genErr, 2, any),
+ gn([[fStatus4,7],
+ [fName4,7]]),
+ ?line expect(7, genErr, 2, any),
+ gn([[fStatus4,8],
+ [fName4,8]]),
+ ?line expect(8, genErr, 1, any),
+ gn([[fStatus4,9],
+ [fName4,9]]),
+ ?line expect(9, genErr, 2, any).
+
+
+%%%-----------------------------------------------------------------
+%%% Test the implementation of standard mibs.
+%%% We should *at least* try to GET all variables, just to make
+%%% sure the instrumentation functions work.
+%%% Note that many of the functions in the standard mib is
+%%% already tested by the normal tests.
+%%%-----------------------------------------------------------------
+standard_mibs(suite) ->
+ [snmp_standard_mib, snmp_community_mib,
+ snmp_framework_mib,
+ snmp_target_mib, snmp_notification_mib,
+ snmp_view_based_acm_mib].
+
+standard_mibs_2(suite) ->
+ [snmpv2_mib_2, snmp_community_mib_2,
+ snmp_framework_mib_2,
+ snmp_target_mib_2, snmp_notification_mib_2,
+ snmp_view_based_acm_mib_2].
+
+standard_mibs_3(suite) ->
+ [snmpv2_mib_3,snmp_framework_mib_3, snmp_mpd_mib_3,
+ snmp_target_mib_3, snmp_notification_mib_3,
+ snmp_view_based_acm_mib_3, snmp_user_based_sm_mib_3].
+
+%%-----------------------------------------------------------------
+%% For this test, the agent is configured for v1.
+%% o Test the counters and control objects in SNMP-STANDARD-MIB
+%%-----------------------------------------------------------------
+snmp_standard_mib(suite) -> [];
+snmp_standard_mib(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?DBG("snmp_standard_mib -> std_mib_init", []),
+ try_test(std_mib_init),
+
+ ?DBG("snmp_standard_mib -> std_mib_a", []),
+ InBadVsns = try_test(std_mib_a),
+ put(vsn, v2),
+ ?DBG("snmp_standard_mib -> std_mib_read", []),
+ try_test(std_mib_read),
+ put(vsn, v1),
+
+ ?DBG("snmp_standard_mib -> std_mib_b (~w)", [InBadVsns]),
+ Bad = try_test(std_mib_b, [InBadVsns]),
+ ?DBG("snmp_standard_mib -> std_mib_read (community: 'bad community')", []),
+ try_test(std_mib_read, [], [{community, "bad community"}]),
+ ?DBG("snmp_standard_mib -> std_mib_write (community: 'public')", []),
+ try_test(std_mib_write, [], [{community, "public"}]),
+ ?DBG("snmp_standard_mib -> std_mib_asn_err", []),
+ try_test(std_mib_asn_err),
+ ?DBG("snmp_standard_mib -> std_mib_c (~w)", [Bad]),
+ try_test(std_mib_c, [Bad]),
+ ?DBG("snmp_standard_mib -> std_mib_a", []),
+ try_test(standard_mib_a),
+
+ ?DBG("snmp_standard_mib -> std_mib_finish", []),
+ try_test(std_mib_finish),
+ ?DBG("snmp_standard_mib -> std_mib_test_finish", []),
+ try_test(standard_mib_test_finish, [], [{community, "bad community"}]).
+
+%% Req. SNMP-STANDARD-MIB
+standard_mib_a() ->
+ ?line [OutPkts] = get_req(2, [[snmpOutPkts,0]]),
+ ?line [OutPkts2] = get_req(3, [[snmpOutPkts,0]]),
+ ?line OutPkts2 = OutPkts + 1,
+ %% There are some more counters we could test here, but it's not that
+ %% important, since they are removed from SNMPv2-MIB.
+ ok.
+
+%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB
+std_mib_init() ->
+ %% disable authentication failure traps. (otherwise w'd get many of
+ %% them - this is also a test to see that it works).
+ s([{[snmpEnableAuthenTraps,0], 2}]),
+ ?line expect(1, [{[snmpEnableAuthenTraps, 0], 2}]).
+
+%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB
+std_mib_finish() ->
+ %% enable again
+ s([{[snmpEnableAuthenTraps,0], 1}]),
+ ?line expect(1, [{[snmpEnableAuthenTraps, 0], 1}]).
+
+%% Req. SNMP-STANDARD-MIB
+standard_mib_test_finish() ->
+ %% force a authenticationFailure
+ std_mib_write(),
+ %% check that we got a trap
+ ?line expect(2, trap, [1,2,3], 4, 0, []).
+
+%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB
+std_mib_read() ->
+ ?DBG("std_mib_read -> entry", []),
+ g([[sysUpTime,0]]), % try a bad <something>; msg dropped, no reply
+ ?DBG("std_mib_read -> await timeout (i.e. no reply)", []),
+ ?line expect(1, timeout). % make sure we don't get a trap!
+
+
+%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB
+std_mib_write() ->
+ ?DBG("std_mib_write -> entry", []),
+ s([{[sysLocation, 0], "new_value"}]).
+
+%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB
+std_mib_asn_err() ->
+ snmp_test_mgr:send_bytes([48,99,67,12,0,0,0,0,0,0,5]).
+
+%%-----------------------------------------------------------------
+%% For this test, the agent is configured for v2 and v3.
+%% o Test the counters and control objects in SNMPv2-MIB
+%%-----------------------------------------------------------------
+snmpv2_mib_2(suite) -> [];
+snmpv2_mib_2(Config) when list(Config) ->
+ ?LOG("snmpv2_mib_2 -> start",[]),
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ ?DBG("snmpv2_mib_2 -> standard mib init",[]),
+ try_test(std_mib_init),
+
+ ?DBG("snmpv2_mib_2 -> get number of (so far) bad versions",[]),
+ InBadVsns = try_test(std_mib_a),
+
+ ?DBG("snmpv2_mib_2 -> make a bad version read",[]),
+ put(vsn, v1),
+ try_test(std_mib_read),
+
+ ?DBG("snmpv2_mib_2 -> bad version read",[]),
+ put(vsn, v2),
+ Bad = try_test(std_mib_b, [InBadVsns]),
+
+ ?DBG("snmpv2_mib_2 -> read with bad community",[]),
+ try_test(std_mib_read, [], [{community, "bad community"}]),
+
+ ?DBG("snmpv2_mib_2 -> write with public community",[]),
+ try_test(std_mib_write, [], [{community, "public"}]),
+
+ ?DBG("snmpv2_mib_2 -> asn err",[]),
+ try_test(std_mib_asn_err),
+
+ ?DBG("snmpv2_mib_2 -> check counters",[]),
+ try_test(std_mib_c, [Bad]),
+
+ ?DBG("snmpv2_mib_2 -> get som counters",[]),
+ try_test(snmpv2_mib_a),
+
+ ?DBG("snmpv2_mib_2 -> enable auth traps, and await some",[]),
+ try_test(std_mib_finish),
+
+ ?DBG("snmpv2_mib_2 -> force auth failure, and await trap, "
+ "then disable auth traps",[]),
+ try_test(snmpv2_mib_test_finish, [], [{community, "bad community"}]),
+
+ ?LOG("snmpv2_mib_2 -> done",[]).
+
+%% Req. SNMPv2-MIB
+snmpv2_mib_3(suite) -> [];
+snmpv2_mib_3(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ InBadVsns = try_test(std_mib_a),
+ put(vsn, v1),
+ try_test(std_mib_read),
+ put(vsn, v3),
+ _Bad = try_test(std_mib_b, [InBadVsns]),
+ try_test(snmpv2_mib_a),
+
+ try_test(std_mib_finish).
+
+-define(authenticationFailure, [1,3,6,1,6,3,1,1,5,5]).
+
+%% Req. SNMPv2-MIB
+snmpv2_mib_test_finish() ->
+ %% force a authenticationFailure
+ ?DBG("ma_v2_inform -> write to std mib",[]),
+ std_mib_write(),
+
+ %% check that we got a trap
+ ?DBG("ma_v2_inform -> await trap",[]),
+ ?line expect(2, v2trap, [{[sysUpTime,0], any},
+ {[snmpTrapOID,0], ?authenticationFailure}]),
+
+ %% and the the inform
+ ?DBG("ma_v2_inform -> await inform",[]),
+ ?line expect(2, {inform,true}, [{[sysUpTime,0], any},
+ {[snmpTrapOID,0],?authenticationFailure}]).
+
+%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB
+std_mib_a() ->
+ ?line [InPkts] = get_req(2, [[snmpInPkts,0]]),
+ ?line [InPkts2] = get_req(3, [[snmpInPkts,0]]),
+ ?line InPkts2 = InPkts + 1,
+
+ ?line [InBadVsns] = get_req(4, [[snmpInBadVersions,0]]),
+ InBadVsns.
+
+%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB
+std_mib_b(InBadVsns) ->
+ ?line [InBadVsns2] = get_req(1, [[snmpInBadVersions,0]]),
+ ?line InBadVsns2 = InBadVsns + 1,
+ ?line [InPkts] = get_req(2, [[snmpInPkts,0]]),
+ ?line [InPkts2] = get_req(3, [[snmpInPkts,0]]),
+ ?line InPkts2 = InPkts + 1,
+ ?line [InBadCommunityNames, InBadCommunityUses, InASNErrs] =
+ get_req(4, [[snmpInBadCommunityNames,0],
+ [snmpInBadCommunityUses,0],
+ [snmpInASNParseErrs, 0]]),
+ {InBadCommunityNames, InBadCommunityUses, InASNErrs}.
+
+%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB
+std_mib_c({InBadCommunityNames, InBadCommunityUses, InASNErrs}) ->
+ ?line [InBadCommunityNames2, InBadCommunityUses2, InASNErrs2] =
+ get_req(1, [[snmpInBadCommunityNames,0],
+ [snmpInBadCommunityUses,0],
+ [snmpInASNParseErrs, 0]]),
+ ?line InBadCommunityNames2 = InBadCommunityNames + 1,
+ ?line InBadCommunityUses2 = InBadCommunityUses + 1,
+ ?line InASNErrs2 = InASNErrs + 1.
+
+%% Req. SNMPv2-MIB
+snmpv2_mib_a() ->
+ ?line [SetSerial] = get_req(2, [[snmpSetSerialNo,0]]),
+ s([{[snmpSetSerialNo,0], SetSerial}, {[sysLocation, 0], "val2"}]),
+ ?line expect(3, [{[snmpSetSerialNo,0], SetSerial},
+ {[sysLocation, 0], "val2"}]),
+ s([{[sysLocation, 0], "val3"}, {[snmpSetSerialNo,0], SetSerial}]),
+ ?line expect(4, inconsistentValue, 2,
+ [{[sysLocation, 0], "val3"},
+ {[snmpSetSerialNo,0], SetSerial}]),
+ ?line ["val2"] = get_req(5, [[sysLocation,0]]).
+
+
+%%-----------------------------------------------------------------
+%% o Bad community uses/name is tested already
+%% in SNMPv2-MIB and STANDARD-MIB.
+%% o Test add/deletion of rows.
+%%-----------------------------------------------------------------
+snmp_community_mib(suite) -> [];
+snmp_community_mib(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?line load_master_std("SNMP-COMMUNITY-MIB"),
+ try_test(snmp_community_mib),
+ ?line unload_master("SNMP-COMMUNITY-MIB").
+
+snmp_community_mib_2(X) -> snmp_community_mib(X).
+
+%% Req. SNMP-COMMUNITY-MIB
+snmp_community_mib() ->
+ ?INF("NOT YET IMPLEMENTED", []),
+ nyi.
+
+%%-----------------------------------------------------------------
+%% o Test engine boots / time
+%%-----------------------------------------------------------------
+snmp_framework_mib(suite) -> [];
+snmp_framework_mib(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?line load_master_std("SNMP-FRAMEWORK-MIB"),
+ try_test(snmp_framework_mib),
+ ?line unload_master("SNMP-FRAMEWORK-MIB").
+
+snmp_framework_mib_2(X) -> snmp_framework_mib(X).
+
+snmp_framework_mib_3(suite) -> [];
+snmp_framework_mib_3(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ try_test(snmp_framework_mib).
+
+
+%% Req. SNMP-FRAMEWORK-MIB
+snmp_framework_mib() ->
+ ?line ["agentEngine"] = get_req(1, [[snmpEngineID,0]]),
+ ?line [EngineTime] = get_req(2, [[snmpEngineTime,0]]),
+ sleep(5000),
+ ?line [EngineTime2] = get_req(3, [[snmpEngineTime,0]]),
+ if
+ EngineTime+7 < EngineTime2 ->
+ ?line ?FAIL({too_large_diff, EngineTime, EngineTime2});
+ EngineTime+4 > EngineTime2 ->
+ ?line ?FAIL({too_large_diff, EngineTime, EngineTime2});
+ true -> ok
+ end,
+ ?line case get_req(4, [[snmpEngineBoots,0]]) of
+ [Boots] when integer(Boots) -> ok;
+ Else -> ?FAIL(Else)
+ end,
+ ok.
+
+%%-----------------------------------------------------------------
+%% o Test the counters
+%%-----------------------------------------------------------------
+snmp_mpd_mib_3(suite) -> [];
+snmp_mpd_mib_3(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ UnknownPDUHs = try_test(snmp_mpd_mib_a),
+ try_test(snmp_mpd_mib_b, [], [{context_engine_id, "bad engine"}]),
+ try_test(snmp_mpd_mib_c, [UnknownPDUHs]).
+
+
+%% Req. SNMP-MPD-MIB
+snmp_mpd_mib_a() ->
+ ?line [UnknownSecs, InvalidMsgs] =
+ get_req(1, [[snmpUnknownSecurityModels,0],
+ [snmpInvalidMsgs,0]]),
+ Pdu = #pdu{type = 'get-request',
+ request_id = 23,
+ error_status = noError,
+ error_index = 0,
+ varbinds = []},
+ SPdu = #scopedPdu{contextEngineID = "agentEngine",
+ contextName = "",
+ data = Pdu},
+ ?line SPDUBytes = snmp_pdus:enc_scoped_pdu(SPdu),
+ V3Hdr1 = #v3_hdr{msgID = 21,
+ msgMaxSize = 484,
+ msgFlags = [7],
+ msgSecurityModel = 23, % bad sec model
+ msgSecurityParameters = []},
+ V3Hdr2 = #v3_hdr{msgID = 21,
+ msgMaxSize = 484,
+ msgFlags = [6], % bad flag combination
+ msgSecurityModel = 3,
+ msgSecurityParameters = []},
+ Message1 = #message{version = 'version-3', vsn_hdr = V3Hdr1,
+ data = SPDUBytes},
+ Message2 = #message{version = 'version-3', vsn_hdr = V3Hdr2,
+ data = SPDUBytes},
+ ?line MsgBytes1 = snmp_pdus:enc_message_only(Message1),
+ ?line MsgBytes2 = snmp_pdus:enc_message_only(Message2),
+ snmp_test_mgr:send_bytes(MsgBytes1),
+ snmp_test_mgr:send_bytes(MsgBytes2),
+
+ ?line [UnknownSecs2, InvalidMsgs2, UnknownPDUHs] =
+ get_req(1, [[snmpUnknownSecurityModels,0],
+ [snmpInvalidMsgs,0],
+ [snmpUnknownPDUHandlers, 0]]),
+ ?line UnknownSecs2 = UnknownSecs + 1,
+ ?line InvalidMsgs2 = InvalidMsgs + 1,
+ UnknownPDUHs.
+
+-define(snmpUnknownPDUHandlers_instance, [1,3,6,1,6,3,11,2,1,3,0]).
+snmp_mpd_mib_b() ->
+ g([[sysUpTime,0]]),
+ ?line expect(1, report, [{?snmpUnknownPDUHandlers_instance, any}]).
+
+
+snmp_mpd_mib_c(UnknownPDUHs) ->
+ ?line [UnknownPDUHs2] = get_req(1, [[snmpUnknownPDUHandlers, 0]]),
+ ?line UnknownPDUHs2 = UnknownPDUHs + 1.
+
+
+snmp_target_mib(suite) -> [];
+snmp_target_mib(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?line load_master_std("SNMP-TARGET-MIB"),
+ try_test(snmp_target_mib),
+ ?line unload_master("SNMP-TARGET-MIB").
+
+snmp_target_mib_2(X) -> snmp_target_mib(X).
+
+snmp_target_mib_3(X) -> snmp_target_mib(X).
+
+snmp_target_mib() ->
+ ?INF("NOT YET IMPLEMENTED", []),
+ nyi.
+
+snmp_notification_mib(suite) -> [];
+snmp_notification_mib(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?line load_master_std("SNMP-NOTIFICATION-MIB"),
+ try_test(snmp_notification_mib),
+ ?line unload_master("SNMP-NOTIFICATION-MIB").
+
+snmp_notification_mib_2(X) -> snmp_notification_mib(X).
+
+snmp_notification_mib_3(X) -> snmp_notification_mib(X).
+
+snmp_notification_mib() ->
+ ?INF("NOT YET IMPLEMENTED", []),
+ nyi.
+
+%%-----------------------------------------------------------------
+%% o add/delete views and try them
+%% o try boundaries
+%%-----------------------------------------------------------------
+snmp_view_based_acm_mib(suite) -> [];
+snmp_view_based_acm_mib(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"),
+ ?line load_master("Test2"),
+ snmp_view_based_acm_mib(),
+ ?line unload_master("Test2"),
+ ?line unload_master("SNMP-VIEW-BASED-ACM-MIB").
+
+snmp_view_based_acm_mib_2(X) -> snmp_view_based_acm_mib(X).
+
+snmp_view_based_acm_mib_3(X) -> snmp_view_based_acm_mib(X).
+
+snmp_view_based_acm_mib() ->
+ snmpa:verbosity(net_if,trace),
+ snmpa:verbosity(master_agent,trace),
+ ?LOG("start snmp_view_based_acm_mib test",[]),
+ %% The user "no-rights" is present in USM, and is mapped to security
+ %% name 'no-rights", which is not present in VACM.
+ %% So, we'll add rights for it, try them and delete them.
+ %% We'll give "no-rights" write access to tDescr.0 and read access
+ %% to tDescr2.0
+ %% These are the options we'll use to the mgr
+ Opts = [{user, "no-rights"}, {community, "no-rights"}],
+ %% Find the valid secmodel, and one invalid secmodel.
+ {SecMod, InvSecMod} =
+ case get(vsn) of
+ v1 -> {?SEC_V1, ?SEC_V2C};
+ v2 -> {?SEC_V2C, ?SEC_USM};
+ v3 -> {?SEC_USM, ?SEC_V1}
+ end,
+ ?DBG("assign rights for 'no-rights'",[]),
+ ?line try_test(use_no_rights, [], Opts),
+
+ %% Now, add a mapping from "no-rights" -> "no-rights-group"
+ GRow1Status = [vacmSecurityToGroupStatus,[SecMod, 9,"no-rights"]],
+ GRow1 =
+ [{[vacmGroupName, [SecMod, 9,"no-rights"]], "no-rights-group"},
+ {GRow1Status, ?createAndGo}],
+ ?DBG("set '~p'",[GRow1]),
+ ?line try_test(do_set, [GRow1]),
+
+ ?DBG("assign rights for 'no-rights'",[]),
+ ?line try_test(use_no_rights, [], Opts),
+
+ %% Create a mapping for another sec model, and make sure it dosn't
+ %% give us access
+ GRow2Status = [vacmSecurityToGroupStatus,[InvSecMod, 9,"no-rights"]],
+ GRow2 = [{[vacmGroupName, [InvSecMod, 9, "no-rights"]], "initial"},
+ {GRow2Status, ?createAndGo}],
+
+ ?DBG("set '~p'",[GRow2]),
+ ?line try_test(do_set, [GRow2]),
+
+ ?DBG("assign rights for 'no-rights'",[]),
+ ?line try_test(use_no_rights, [], Opts),
+
+ %% Delete that row
+ ?line try_test(del_row, [GRow2Status]),
+
+ RVName = "rv_name",
+ WVName = "wv_name",
+
+ %% Access row
+ ARow1Idx = [15 | "no-rights-group"] ++ [0, ?SEC_ANY, 1],
+ ARow1Status = [vacmAccessStatus, ARow1Idx],
+ ARow1 = [{[vacmAccessContextMatch, ARow1Idx], 1},
+ {[vacmAccessReadViewName, ARow1Idx], RVName},
+ {[vacmAccessWriteViewName, ARow1Idx], WVName},
+ {ARow1Status, ?createAndGo}],
+
+ %% This access row would give acces, if InvSecMod was valid.
+ ARow2Idx = [15 | "no-rights-group"] ++ [0, InvSecMod, 1],
+ ARow2Status = [vacmAccessStatus, ARow2Idx],
+ ARow2 = [{[vacmAccessContextMatch, ARow2Idx], 1},
+ {[vacmAccessReadViewName, ARow2Idx], "internet"},
+ {[vacmAccessWriteViewName, ARow2Idx], "internet"},
+ {ARow2Status, ?createAndGo}],
+
+ ?line try_test(do_set, [ARow2]),
+
+ ?line try_test(use_no_rights, [], Opts),
+
+ %% Delete that row
+ ?line try_test(del_row, [ARow2Status]),
+
+
+ %% Add valid row
+ ?line try_test(do_set, [ARow1]),
+
+ ?line try_test(use_no_rights, [], Opts),
+
+ %% Create the view family
+ VRow1Idx = mk_ln(RVName) ++ mk_ln(?xDescr), % object access
+ VRow2Idx = mk_ln(RVName) ++ mk_ln(?xDescr2 ++ [0]), % instance access
+ VRow3Idx = mk_ln(WVName) ++ mk_ln(?xDescr), % object access
+ VRow4Idx = mk_ln(WVName) ++ mk_ln(?xDescr ++ [0]), % instance access
+ VRow1Status = [vacmViewTreeFamilyStatus, VRow1Idx],
+ VRow2Status = [vacmViewTreeFamilyStatus, VRow2Idx],
+ VRow3Status = [vacmViewTreeFamilyStatus, VRow3Idx],
+ VRow4Status = [vacmViewTreeFamilyStatus, VRow4Idx],
+
+ ?line try_test(add_row, [VRow1Status]),
+ ?line try_test(add_row, [VRow2Status]),
+ ?line try_test(add_row, [VRow3Status]),
+
+ %% We're supposed to have access now...
+ ?line try_test(use_rights, [], Opts),
+
+ %% Change Row3 to Row4
+ ?line try_test(del_row, [VRow3Status]),
+ ?line try_test(add_row, [VRow4Status]),
+
+ %% We should still have access...
+ ?line try_test(use_rights, [], Opts),
+
+ %% Delete rows
+ ?line try_test(del_row, [GRow1Status]),
+
+ ?line try_test(use_no_rights, [], Opts),
+
+ %% Delete rest of rows
+ ?line try_test(del_row, [ARow1Status]),
+ ?line try_test(del_row, [VRow1Status]),
+ ?line try_test(del_row, [VRow2Status]),
+ ?line try_test(del_row, [VRow4Status]),
+
+ ?line try_test(use_no_rights, [], Opts),
+ snmpa:verbosity(master_agent,log).
+
+do_set(Row) ->
+ s(Row),
+ expect(1, Row).
+
+add_row(RowStatus) ->
+ s([{RowStatus, ?createAndGo}]),
+ expect(1, [{RowStatus, ?createAndGo}]).
+
+del_row(RowStatus) ->
+ s([{RowStatus, ?destroy}]),
+ expect(1, [{RowStatus, ?destroy}]).
+
+
+
+use_no_rights() ->
+ g([[xDescr,0]]),
+ ?v1_2_3(expect(11, noSuchName, 1, any),
+ expect(12, [{[xDescr,0], noSuchObject}]),
+ expect(13, authorizationError, 1, any)),
+ g([[xDescr2,0]]),
+ ?v1_2_3(expect(21, noSuchName, 1, any),
+ expect(22, [{[xDescr2,0], noSuchObject}]),
+ expect(23, authorizationError, 1, any)),
+ gn([[xDescr]]),
+ ?v1_2_3(expect(31, noSuchName, 1, any),
+ expect(32, [{[xDescr], endOfMibView}]),
+ expect(33, authorizationError, 1, any)),
+ s([{[xDescr,0], "tryit"}]),
+ ?v1_2_3(expect(41, noSuchName, 1, any),
+ expect(42, noAccess, 1, any),
+ expect(43, authorizationError, 1, any)).
+
+
+use_rights() ->
+ g([[xDescr,0]]),
+ expect(1, [{[xDescr,0], any}]),
+ g([[xDescr2,0]]),
+ expect(2, [{[xDescr2,0], any}]),
+ s([{[xDescr,0], "tryit"}]),
+ expect(3, noError, 0, any),
+ g([[xDescr,0]]),
+ expect(4, [{[xDescr,0], "tryit"}]).
+
+mk_ln(X) ->
+ [length(X) | X].
+
+%%-----------------------------------------------------------------
+%% o add/delete users and try them
+%% o test all secLevels
+%% o test all combinations of protocols
+%% o try bad ops; check counters
+%%-----------------------------------------------------------------
+snmp_user_based_sm_mib_3(suite) -> [];
+snmp_user_based_sm_mib_3(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ _AgentDir = ?config(agent_dir, Config),
+ ?line load_master_std("SNMP-USER-BASED-SM-MIB"),
+
+ %% The newUser used here already has VACM access.
+
+ %% Add a new user in the simplest way; just createAndGo
+ try_test(v3_sync, [[{usm_add_user1, []}]],
+ [{sec_level, authPriv}, {user, "privDES"}]),
+
+ %% Try to use the new user
+ ?line load_master("Test2"),
+ try_test(v3_sync, [[{usm_use_user, []}]],
+ [{sec_level, authPriv}, {user, "newUser"}]),
+ ?line unload_master("Test2"),
+
+ ShaKey1 = snmp:passwd2localized_key(sha, "new sha password", "agentEngine"),
+ DesKey1 = lists:sublist(ShaKey1, 16),
+
+ %% Change the new user's keys - 1
+ try_test(v3_sync, [[{usm_key_change1, [ShaKey1, DesKey1]}]],
+ [{sec_level, authPriv}, {user, "newUser"}]),
+
+ %% Try to use the new keys
+ MgrDir = ?config(mgr_dir, Config),
+ ?line rewrite_usm_mgr(MgrDir, ShaKey1, DesKey1),
+ ?line load_master("Test2"),
+ try_test(v3_sync, [[{usm_use_user, []}]],
+ [{sec_level, authPriv}, {user, "newUser"}]),
+ ?line unload_master("Test2"),
+
+ ShaKey2 = snmp:passwd2localized_key(sha, "newer password", "agentEngine"),
+ DesKey2 = lists:sublist(ShaKey2, 16),
+
+ %% Change the new user's keys - 2
+ ?line try_test(v3_sync,
+ [[{usm_key_change2, [ShaKey1, DesKey1, ShaKey2, DesKey2]}]],
+ [{sec_level, authPriv}, {user, "newUser"}]),
+
+ %% Try to use the new keys
+ reset_usm_mgr(MgrDir),
+ ?line rewrite_usm_mgr(MgrDir, ShaKey2, DesKey2),
+ ?line load_master("Test2"),
+ ?line try_test(v3_sync, [[{usm_use_user, []}]],
+ [{sec_level, authPriv}, {user, "newUser"}]),
+ ?line unload_master("Test2"),
+ reset_usm_mgr(MgrDir),
+
+ %% Change the new user's keys - 3
+ ?line try_test(v3_sync,
+ [[{usm_key_change3, [ShaKey2, DesKey2, ShaKey1, DesKey1]}]],
+ [{sec_level, authPriv}, {user, "privDES"}]),
+
+ %% Try to use the new keys
+ ?line rewrite_usm_mgr(MgrDir, ShaKey1, DesKey1),
+ ?line load_master("Test2"),
+ try_test(v3_sync, [[{usm_use_user, []}]],
+ [{sec_level, authPriv}, {user, "newUser"}]),
+ ?line unload_master("Test2"),
+ reset_usm_mgr(MgrDir),
+
+ %% Try some read requests
+ ?line try_test(v3_sync, [[{usm_read, []}]],
+ [{sec_level, authPriv}, {user, "privDES"}]),
+
+ %% Delete the new user
+ ?line try_test(v3_sync, [[{usm_del_user, []}]],
+ [{sec_level, authPriv}, {user, "privDES"}]),
+
+ %% Try some bad requests
+ ?line try_test(v3_sync, [[{usm_bad, []}]],
+ [{sec_level, authPriv}, {user, "privDES"}]),
+
+ ?line unload_master("SNMP-USER-BASED-SM-MIB").
+
+-define(usmUserSecurityName, [1,3,6,1,6,3,15,1,2,2,1,3]).
+
+usm_add_user1() ->
+ NewRowIndex = [11,"agentEngine", 7, "newUser"],
+ RowPointer = ?usmUserSecurityName ++ [11|"agentEngine"] ++ [7|"privDES"],
+ Vbs1 = [{[usmUserCloneFrom, NewRowIndex], RowPointer},
+ {[usmUserStatus, NewRowIndex], ?createAndGo}],
+ ?line s(Vbs1),
+ ?line expect(1, Vbs1),
+ ok.
+
+usm_use_user() ->
+ v2_proc().
+
+
+%% Change own public keys
+usm_key_change1(ShaKey, DesKey) ->
+ NewRowIndex = [11,"agentEngine", 7, "newUser"],
+ ShaKeyChange = snmp_user_based_sm_mib:mk_key_change(sha,
+ "passwd_shaxxxxxxxxxx",
+ ShaKey),
+ DesKeyChange = snmp_user_based_sm_mib:mk_key_change(sha,
+ "passwd_desxxxxxx",
+ DesKey),
+ Vbs1 = [{[usmUserAuthKeyChange, NewRowIndex], ShaKeyChange},
+ {[usmUserPrivKeyChange, NewRowIndex], DesKeyChange}],
+ s(Vbs1),
+ ?line expect(1, Vbs1).
+
+%% Change own private keys
+usm_key_change2(OldShaKey, OldDesKey, ShaKey, DesKey) ->
+ NewRowIndex = [11,"agentEngine", 7, "newUser"],
+ ShaKeyChange = snmp_user_based_sm_mib:mk_key_change(sha,
+ OldShaKey,
+ ShaKey),
+ DesKeyChange = snmp_user_based_sm_mib:mk_key_change(sha,
+ OldDesKey,
+ DesKey),
+ Vbs1 = [{[usmUserOwnAuthKeyChange, NewRowIndex], ShaKeyChange},
+ {[usmUserOwnPrivKeyChange, NewRowIndex], DesKeyChange}],
+ s(Vbs1),
+ ?line expect(1, Vbs1).
+
+%% Change other's public keys
+usm_key_change3(OldShaKey, OldDesKey, ShaKey, DesKey) ->
+ NewRowIndex = [11,"agentEngine", 7, "newUser"],
+ ShaKeyChange = snmp_user_based_sm_mib:mk_key_change(sha,
+ OldShaKey,
+ ShaKey),
+ DesKeyChange = snmp_user_based_sm_mib:mk_key_change(sha,
+ OldDesKey,
+ DesKey),
+ Vbs1 = [{[usmUserOwnAuthKeyChange, NewRowIndex], ShaKeyChange}],
+ s(Vbs1),
+ ?line expect(1, noAccess, 1, any),
+ Vbs2 = [{[usmUserOwnPrivKeyChange, NewRowIndex], DesKeyChange}],
+ s(Vbs2),
+ ?line expect(2, noAccess, 1, any),
+
+
+ Vbs3 = [{[usmUserAuthKeyChange, NewRowIndex], ShaKeyChange},
+ {[usmUserPrivKeyChange, NewRowIndex], DesKeyChange}],
+ s(Vbs3),
+ ?line expect(1, Vbs3).
+
+usm_read() ->
+ NewRowIndex = [11,"agentEngine", 7, "newUser"],
+ ?line g([[usmUserSecurityName, NewRowIndex],
+ [usmUserCloneFrom, NewRowIndex],
+ [usmUserAuthKeyChange, NewRowIndex],
+ [usmUserOwnAuthKeyChange, NewRowIndex],
+ [usmUserPrivKeyChange, NewRowIndex],
+ [usmUserOwnPrivKeyChange, NewRowIndex]]),
+ ?line expect(1,
+ [{[usmUserSecurityName, NewRowIndex], "newUser"},
+ {[usmUserCloneFrom, NewRowIndex], [0,0]},
+ {[usmUserAuthKeyChange, NewRowIndex], ""},
+ {[usmUserOwnAuthKeyChange, NewRowIndex], ""},
+ {[usmUserPrivKeyChange, NewRowIndex], ""},
+ {[usmUserOwnPrivKeyChange, NewRowIndex], ""}]),
+ ok.
+
+
+
+usm_del_user() ->
+ NewRowIndex = [11,"agentEngine", 7, "newUser"],
+ Vbs1 = [{[usmUserStatus, NewRowIndex], ?destroy}],
+ ?line s(Vbs1),
+ ?line expect(1, Vbs1),
+ ok.
+
+-define(usmUserCloneFrom, [1,3,6,1,6,3,15,1,2,2,1,4]).
+
+-define(usmNoAuthProtocol, [1,3,6,1,6,3,10,1,1,1]).
+
+-define(usmHMACMD5AuthProtocol, [1,3,6,1,6,3,10,1,1,2]).
+
+-define(usmHMACSHAAuthProtocol, [1,3,6,1,6,3,10,1,1,3]).
+
+-define(usmNoPrivProtocol, [1,3,6,1,6,3,10,1,2,1]).
+
+-define(usmDESPrivProtocol, [1,3,6,1,6,3,10,1,2,2]).
+
+usm_bad() ->
+ NewRowIndex = [11,"agentEngine", 7, "newUser"],
+ RowPointer1 = ?usmUserSecurityName ++ [11|"agentEngine"] ++ [7|"privDOS"],
+ Vbs1 = [{[usmUserCloneFrom, NewRowIndex], RowPointer1},
+ {[usmUserStatus, NewRowIndex], ?createAndGo}],
+ ?line s(Vbs1),
+ ?line expect(1, inconsistentName, 1, any),
+
+ RowPointer2 = ?usmUserCloneFrom ++ [11|"agentEngine"] ++ [7|"privDES"],
+ Vbs2 = [{[usmUserCloneFrom, NewRowIndex], RowPointer2},
+ {[usmUserStatus, NewRowIndex], ?createAndGo}],
+ ?line s(Vbs2),
+ ?line expect(2, wrongValue, 1, any),
+
+ RowPointer3 = ?usmUserSecurityName ++ [11|"agentEngine"] ++ [7|"privDES"],
+ Vbs3 = [{[usmUserCloneFrom, NewRowIndex], RowPointer3},
+ {[usmUserStatus, NewRowIndex], ?createAndGo}],
+ ?line s(Vbs3),
+ ?line expect(3, Vbs3),
+ ?line s([{[usmUserAuthProtocol, NewRowIndex], ?usmNoAuthProtocol}]),
+ ?line expect(4, inconsistentValue, 1, any),
+ ?line s([{[usmUserAuthProtocol, NewRowIndex], ?usmHMACMD5AuthProtocol}]),
+ ?line expect(5, inconsistentValue, 1, any),
+ ?line s([{[usmUserAuthProtocol, NewRowIndex], ?usmDESPrivProtocol}]),
+ ?line expect(6, wrongValue, 1, any),
+ ?line s([{[usmUserPrivProtocol, NewRowIndex], ?usmHMACSHAAuthProtocol}]),
+ ?line expect(7, wrongValue, 1, any),
+
+ Vbs4 = [{[usmUserStatus, NewRowIndex], ?destroy}],
+ ?line s(Vbs4),
+ ?line expect(1, Vbs4),
+
+ ok.
+
+
+%%-----------------------------------------------------------------
+%% Loop through entire MIB, to make sure that all instrum. funcs
+%% works.
+%% Load all std mibs that are not loaded by default.
+%%-----------------------------------------------------------------
+loop_mib(suite) -> [];
+loop_mib(Config) when list(Config) ->
+ ?LOG("loop_mib -> initiate case",[]),
+ %% snmpa:verbosity(master_agent,debug),
+ %% snmpa:verbosity(mib_server,info),
+ {SaNode, MgrNode, MibDir} = init_case(Config),
+ ?DBG("loop_mib -> ~n"
+ "\tSaNode: ~p~n"
+ "\tMgrNode: ~p~n"
+ "\tMibDir: ~p",[SaNode, MgrNode, MibDir]),
+ ?DBG("loop_mib -> load mib SNMP-COMMUNITY-MIB",[]),
+ ?line load_master_std("SNMP-COMMUNITY-MIB"),
+ ?DBG("loop_mib -> load mib SNMP-MPD-MIB",[]),
+ ?line load_master_std("SNMP-MPD-MIB"),
+ ?DBG("loop_mib -> load mib SNMP-TARGET-MIB",[]),
+ ?line load_master_std("SNMP-TARGET-MIB"),
+ ?DBG("loop_mib -> load mib SNMP-NOTIFICATION-MIB",[]),
+ ?line load_master_std("SNMP-NOTIFICATION-MIB"),
+ ?DBG("loop_mib -> load mib SNMP-FRAMEWORK-MIB",[]),
+ ?line load_master_std("SNMP-FRAMEWORK-MIB"),
+ ?DBG("loop_mib -> load mib SNMP-VIEW-BASED-ACM-MIB",[]),
+ ?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"),
+ ?DBG("loop_mib -> try",[]),
+ try_test(loop_mib_1),
+ ?DBG("loop_mib -> unload mib SNMP-COMMUNITY-MIB",[]),
+ ?line unload_master("SNMP-COMMUNITY-MIB"),
+ ?DBG("loop_mib -> unload mib SNMP-MPD-MIB",[]),
+ ?line unload_master("SNMP-MPD-MIB"),
+ ?DBG("loop_mib -> unload mib SNMP-TARGET-MIB",[]),
+ ?line unload_master("SNMP-TARGET-MIB"),
+ ?DBG("loop_mib -> unload mib SNMP-NOTIFICATION-MIB",[]),
+ ?line unload_master("SNMP-NOTIFICATION-MIB"),
+ ?DBG("loop_mib -> unload mib SNMP-FRAMEWORK-MIB",[]),
+ ?line unload_master("SNMP-FRAMEWORK-MIB"),
+ ?DBG("loop_mib -> unload mib SNMP-VIEW-BASED-ACM-MIB",[]),
+ ?line unload_master("SNMP-VIEW-BASED-ACM-MIB"),
+ %% snmpa:verbosity(master_agent,log),
+ %% snmpa:verbosity(mib_server,silence),
+ ?LOG("loop_mib -> done",[]).
+
+
+loop_mib_2(suite) -> [];
+loop_mib_2(Config) when list(Config) ->
+ ?LOG("loop_mib_2 -> initiate case",[]),
+ {SaNode, MgrNode, MibDir} = init_case(Config),
+ ?DBG("loop_mib_2 -> ~n"
+ "\tSaNode: ~p~n"
+ "\tMgrNode: ~p~n"
+ "\tMibDir: ~p",[SaNode, MgrNode, MibDir]),
+ ?DBG("loop_mib_2 -> load mibs",[]),
+ ?line load_master_std("SNMP-COMMUNITY-MIB"),
+ ?line load_master_std("SNMP-MPD-MIB"),
+ ?line load_master_std("SNMP-TARGET-MIB"),
+ ?line load_master_std("SNMP-NOTIFICATION-MIB"),
+ ?line load_master_std("SNMP-FRAMEWORK-MIB"),
+ ?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"),
+ try_test(loop_mib_2),
+ ?DBG("loop_mib_2 -> unload mibs",[]),
+ ?line unload_master("SNMP-COMMUNITY-MIB"),
+ ?line unload_master("SNMP-MPD-MIB"),
+ ?line unload_master("SNMP-TARGET-MIB"),
+ ?line unload_master("SNMP-NOTIFICATION-MIB"),
+ ?line unload_master("SNMP-FRAMEWORK-MIB"),
+ ?line unload_master("SNMP-VIEW-BASED-ACM-MIB"),
+ ?LOG("loop_mib_2 -> done",[]).
+
+
+loop_mib_3(suite) -> [];
+loop_mib_3(Config) when list(Config) ->
+ ?LOG("loop_mib_3 -> initiate case",[]),
+ {SaNode, MgrNode, MibDir} = init_case(Config),
+ ?DBG("loop_mib_3 -> ~n"
+ "\tSaNode: ~p~n"
+ "\tMgrNode: ~p~n"
+ "\tMibDir: ~p",[SaNode, MgrNode, MibDir]),
+ ?DBG("loop_mib_3 -> load mibs",[]),
+ ?line load_master_std("SNMP-TARGET-MIB"),
+ ?line load_master_std("SNMP-NOTIFICATION-MIB"),
+ ?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"),
+ ?line load_master_std("SNMP-USER-BASED-SM-MIB"),
+ try_test(loop_mib_2),
+ ?DBG("loop_mib_3 -> unload mibs",[]),
+ ?line unload_master("SNMP-TARGET-MIB"),
+ ?line unload_master("SNMP-NOTIFICATION-MIB"),
+ ?line unload_master("SNMP-VIEW-BASED-ACM-MIB"),
+ ?line unload_master("SNMP-USER-BASED-SM-MIB"),
+ ?LOG("loop_mib_3 -> done",[]).
+
+
+%% Req. As many mibs all possible
+loop_mib_1() ->
+ ?DBG("loop_mib_1 -> entry",[]),
+ N = loop_it_1([1,1], 0),
+ io:format(user, "found ~w varibles\n", [N]),
+ ?line N = if N < 100 -> 100;
+ true -> N
+ end.
+
+
+loop_it_1(Oid, N) ->
+ ?DBG("loop_it_1 -> entry with~n"
+ "\tOid: ~p~n"
+ "\tN: ~p",[Oid,N]),
+ case get_next_req([Oid]) of
+ #pdu{type='get-response', error_status=noError, error_index=0,
+ varbinds=[#varbind{oid = NOid,value = Value}]} when NOid > Oid ->
+ ?DBG("loop_it_1 -> ~n"
+ "\tNOid: ~p~n"
+ "\tValue: ~p",[NOid,Value]),
+ ?line [Value2] = get_req(1, [NOid]), % must not be same
+ ?DBG("loop_it_1 -> ~n"
+ "\tValue2: ~p",[Value2]),
+ loop_it_1(NOid, N+1);
+ #pdu{type='get-response', error_status=noSuchName, error_index=1,
+ varbinds=[_]} ->
+ ?DBG("loop_it_1 -> done",[]),
+ N;
+
+ #pdu{type = Type, error_status = Err, error_index = Idx,
+ varbinds = Vbs} ->
+ exit({unexpected_pdu, ?LINE, Type, Err, Idx, Vbs})
+ end.
+
+%% Req. As many mibs all possible
+loop_mib_2() ->
+ ?DBG("loop_mib_1 -> entry",[]),
+ N = loop_it_2([1,1], 0),
+ io:format(user, "found ~w varibles\n", [N]),
+ ?line N = if N < 100 -> 100;
+ true -> N
+ end.
+
+
+loop_it_2(Oid, N) ->
+ ?DBG("loop_it_2 -> entry with~n"
+ "\tOid: ~p~n"
+ "\tN: ~p",[Oid,N]),
+ case get_next_req([Oid]) of
+ #pdu{type='get-response', error_status=noError, error_index=0,
+ varbinds=[#varbind{oid = NOid, value = endOfMibView}]} ->
+ ?DBG("loop_it_2 -> ~n"
+ "\tNOid: ~p",[NOid]),
+ N;
+ #pdu{type='get-response', error_status=noError, error_index=0,
+ varbinds=[#varbind{oid = NOid,value = Value}]} when NOid > Oid ->
+ ?DBG("loop_it_2 -> ~n"
+ "\tNOid: ~p~n"
+ "\tValue: ~p",[NOid,Value]),
+ ?line [Value2] = get_req(1, [NOid]), % must not be same
+ ?DBG("loop_it_2 -> ~n"
+ "\tValue2: ~p",[Value2]),
+ loop_it_2(NOid, N+1)
+ end.
+
+
+%%%-----------------------------------------------------------------
+%%% Testing of reported bugs and other tickets.
+%%%-----------------------------------------------------------------
+
+reported_bugs(suite) ->
+ [otp_1128, otp_1129, otp_1131, otp_1162,
+ otp_1222, otp_1298, otp_1331, otp_1338,
+ otp_1342, otp_2776, otp_2979, otp_3187, otp_3725].
+
+reported_bugs_2(suite) ->
+ [otp_1128_2, otp_1129_2, otp_1131_2, otp_1162_2,
+ otp_1222_2, otp_1298_2, otp_1331_2, otp_1338_2,
+ otp_1342_2, otp_2776_2, otp_2979_2, otp_3187_2].
+
+reported_bugs_3(suite) ->
+ [otp_1128_3, otp_1129_3, otp_1131_3, otp_1162_3,
+ otp_1222_3, otp_1298_3, otp_1331_3, otp_1338_3,
+ otp_1342_3, otp_2776_3, otp_2979_3, otp_3187_3,
+ otp_3542].
+
+
+%% These are (ticket) test cases where the initiation has to be done
+%% individually.
+tickets(suite) ->
+ [otp_4394].
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-1128
+%% Slogan: Bug in handling of createAndWait set-requests.
+%%-----------------------------------------------------------------
+otp_1128(suite) -> [];
+otp_1128(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?line load_master("OLD-SNMPEA-MIB"),
+ ?line init_old(),
+ try_test(otp_1128),
+ ?line unload_master("OLD-SNMPEA-MIB").
+
+otp_1128_2(X) -> otp_1128(X).
+
+otp_1128_3(X) -> otp_1128(X).
+
+otp_1128() ->
+ io:format("Testing bug reported in ticket OTP-1128...~n"),
+
+ NewKeyc3 = [intCommunityViewIndex,get(mip),is("test")],
+ NewKeyc4 = [intCommunityAccess,get(mip),is("test")],
+ NewKeyc5 = [intCommunityStatus,get(mip),is("test")],
+
+ s([{NewKeyc5, ?createAndWait}, {NewKeyc4, 2}]),
+ ?line expect(28, [{NewKeyc5, ?createAndWait}, {NewKeyc4, 2}]),
+ g([NewKeyc5]),
+ ?line expect(29, [{NewKeyc5, ?notReady}]),
+ s([{NewKeyc5, ?active}, {NewKeyc3, 2}]),
+ ?line expect(30, [{NewKeyc5, ?active}, {NewKeyc3, 2}]),
+ g([NewKeyc5]),
+ ?line expect(31, [{NewKeyc5, ?active}]),
+ s([{NewKeyc5, ?destroy}]),
+ ?line expect(32, [{NewKeyc5, ?destroy}]).
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-1129, OTP-1169
+%% Slogan: snmpa:int_to_enum crashes on bad oids
+%%-----------------------------------------------------------------
+otp_1129(suite) -> [];
+otp_1129(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?line load_master("Klas3"),
+ try_test(otp_1129_i, [node()]),
+ ?line unload_master("Klas3").
+
+otp_1129_2(X) -> otp_1129(X).
+
+otp_1129_3(X) -> otp_1129(X).
+
+otp_1129_i(MaNode) ->
+ io:format("Testing bug reported in ticket OTP-1129...~n"),
+ false = rpc:call(MaNode, snmp, int_to_enum, [iso, 1]),
+ false = rpc:call(MaNode, snmp, int_to_enum, [isox, 1]).
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-1131
+%% Slogan: Agent crashes / erlang node halts if RowIndex in a
+%% setrequest is of bad type, e.g. an INDEX {INTEGER},
+%% and RowIdenx [3,2].
+%%-----------------------------------------------------------------
+otp_1131(suite) -> [];
+otp_1131(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?line load_master("Klas1"),
+ try_test(otp_1131),
+ ?line unload_master("Klas1").
+
+otp_1131_2(X) -> otp_1131(X).
+
+otp_1131_3(X) -> otp_1131(X).
+
+otp_1131() ->
+ io:format("Testing bug reported in ticket OTP-1131...~n"),
+ s([{[friendsEntry, [2, 3, 1]], s, "kompis3"},
+ {[friendsEntry, [3, 3, 1]], i, ?createAndGo}]),
+ ?line expect(1, ?v1_2(noSuchName, noCreation), 2, any).
+
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-1162
+%% Slogan: snmp_agent can't handle wrongValue from instrum.func
+%%-----------------------------------------------------------------
+otp_1162(suite) -> [];
+otp_1162(Config) when list(Config) ->
+ {SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?line {ok, SA} = start_subagent(SaNode, ?sa, "SA-MIB"),
+ try_test(otp_1162),
+ stop_subagent(SA).
+
+otp_1162_2(X) -> otp_1162(X).
+
+otp_1162_3(X) -> otp_1162(X).
+
+otp_1162() ->
+ s([{[sa, [2,0]], 6}]), % wrongValue (i is_set_ok)
+ ?line expect(1, ?v1_2(badValue, wrongValue), 1, any).
+
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-1222
+%% Slogan: snmp agent crash if faulty index is returned from instrum
+%%-----------------------------------------------------------------
+otp_1222(suite) -> [];
+otp_1222(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?line load_master("Klas3"),
+ ?line load_master("Klas4"),
+ try_test(otp_1222),
+ ?line unload_master("Klas3"),
+ ?line unload_master("Klas4").
+
+otp_1222_2(X) -> otp_1222(X).
+
+otp_1222_3(X) -> otp_1222(X).
+
+otp_1222() ->
+ io:format("Testing bug reported in ticket OTP-1222...~n"),
+ s([{[fStatus4,1], 4}, {[fName4,1], 1}]),
+ ?line expect(1, genErr, 0, any),
+ s([{[fStatus4,2], 4}, {[fName4,2], 1}]),
+ ?line expect(2, genErr, 0, any).
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-1298
+%% Slogan: Negative INTEGER values are treated as positive.
+%%-----------------------------------------------------------------
+otp_1298(suite) -> [];
+otp_1298(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?line load_master("Klas2"),
+ try_test(otp_1298),
+ ?line unload_master("Klas2").
+
+otp_1298_2(X) -> otp_1298(X).
+
+otp_1298_3(X) -> otp_1298(X).
+
+otp_1298() ->
+ io:format("Testing bug reported in ticket OTP-1298...~n"),
+ s([{[fint,0], -1}]),
+ ?line expect(1298, [{[fint,0], -1}]).
+
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-1331
+%% Slogan: snmp_generic should return noError when deleting non-ex row
+%%-----------------------------------------------------------------
+otp_1331(suite) -> [];
+otp_1331(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?line load_master("OLD-SNMPEA-MIB"),
+ ?line init_old(),
+ try_test(otp_1331),
+ ?line unload_master("OLD-SNMPEA-MIB").
+
+otp_1331_2(X) -> otp_1331(X).
+
+otp_1331_3(X) -> otp_1331(X).
+
+otp_1331() ->
+ NewKeyc5 = [intCommunityStatus,[127,32,0,0],is("test")],
+ s([{NewKeyc5, ?destroy}]),
+ ?line expect(1, [{NewKeyc5, ?destroy}]).
+
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-1338
+%% Slogan: snmp bug in initialisation of default values for mnesia tabs
+%%-----------------------------------------------------------------
+otp_1338(suite) -> [];
+otp_1338(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?line load_master("Klas2"),
+ try_test(otp_1338),
+ ?line unload_master("Klas2").
+
+otp_1338_2(X) -> otp_1338(X).
+
+otp_1338_3(X) -> otp_1338(X).
+
+otp_1338() ->
+ s([{[kStatus2, 7], i, ?createAndGo}]),
+ ?line expect(1, [{[kStatus2, 7], ?createAndGo}]),
+ g([[kName2, 7]]),
+ ?line expect(2, [{[kName2, 7], "JJJ"}]).
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-1342
+%% Slogan: default impl of snmp table can't handle bad index access,
+%% Set when INDEX is read-write gets into an infinite loop!
+%%-----------------------------------------------------------------
+otp_1342(suite) -> [];
+otp_1342(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?line load_master("Klas4"),
+ try_test(otp_1342),
+ ?line unload_master("Klas4").
+
+otp_1342_2(X) -> otp_1342(X).
+
+otp_1342_3(X) -> otp_1342(X).
+
+otp_1342() ->
+ s([{[fIndex5, 1], i, 1},
+ {[fName5, 1], i, 3},
+ {[fStatus5, 1], i, ?createAndGo}]),
+ ?line expect(1, ?v1_2(noSuchName, noCreation), 3, any).
+
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-1366
+%% Slogan: snmp traps not sent to all managers
+%% Note: NYI! We need a way to tell the test server that we need
+%% mgrs on two different machines.
+%%-----------------------------------------------------------------
+otp_1366(suite) -> [];
+otp_1366(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?line load_master("OLD-SNMPEA-MIB"),
+ ?line init_old(),
+ try_test(otp_1366),
+ ?line unload_master("OLD-SNMPEA-MIB").
+
+otp_1366_2(X) -> otp_1366(X).
+
+otp_1366_3(X) -> otp_1366(X).
+
+otp_1366() ->
+ ?INF("NOT YET IMPLEMENTED", []),
+ 'NYI'.
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-2776
+%% Slogan: snmp:validate_date_and_time() fails when time is 00:00
+%%-----------------------------------------------------------------
+otp_2776(suite) -> [];
+otp_2776(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ try_test(otp_2776).
+
+otp_2776_2(X) -> otp_2776(X).
+
+otp_2776_3(X) -> otp_2776(X).
+
+otp_2776() ->
+ io:format("Testing bug reported in ticket OTP-2776...~n"),
+
+ Dt01_valid = [19,98,9,1,1,0,23,0,43,0,0],
+ Dt02_valid = [19,98,9,1,0,0,0,0,43,0,0], % This is what is fixed: 00:00
+ Dt03_valid = [19,98,2,28,1,0,23,0,43,0,0],
+ Dt04_invalid = [19,98,2,29,1,0,23,0,43,0,0],
+ Dt05_valid = [19,96,2,29,1,0,23,0,43,0,0],
+ Dt06_valid = [20,0,2,29,1,0,23,0,43,0,0],
+ Dt07_invalid = [19,96,2,30,1,0,23,0,43,0,0], % This is also fixed: 30/2
+ Dt08_valid = [19,98,4,30,1,0,23,0,43,0,0],
+ Dt09_invalid = [19,98,4,31,1,0,23,0,43,0,0], % This is also fixed: 31/4
+ Dt10_invalid = [],
+ Dt11_invalid = [kalle,hobbe],
+ L = [{ 1, true, Dt01_valid},
+ { 2, true, Dt02_valid},
+ { 3, true, Dt03_valid},
+ { 4, false, Dt04_invalid},
+ { 5, true, Dt05_valid},
+ { 6, true, Dt06_valid},
+ { 7, false, Dt07_invalid},
+ { 8, true, Dt08_valid},
+ { 9, false, Dt09_invalid},
+ {10, false, Dt10_invalid},
+ {11, false, Dt11_invalid}],
+
+ ?line ok = validate_dat(L).
+
+
+validate_dat(L) -> validate_dat(L,[]).
+
+validate_dat([],V) ->
+ Fun = fun({_,X}) -> case X of
+ ok -> false;
+ _ -> true
+ end
+ end,
+ validate_dat1( lists:reverse( lists:filter(Fun,V) ) );
+validate_dat([{Id,E,Dat}|T],V) ->
+ validate_dat(T,[validate_dat2(Id,E,Dat) | V]).
+
+validate_dat1([]) -> ok;
+validate_dat1(L) -> {error,L}.
+
+validate_dat2(Id, E, Dat) ->
+ Res = case {E,snmp:validate_date_and_time(Dat)} of
+ {E,E} -> ok;
+ {E,A} -> {E,A}
+ end,
+ {Id, Res}.
+
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-2979
+%% Slogan: get-next on more than 1 column in an empty table
+%% returns bad response.
+%%-----------------------------------------------------------------
+otp_2979(suite) -> [];
+otp_2979(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?line load_master("Test1"),
+ ?line init_old(),
+ try_test(otp_2979),
+ ?line unload_master("Test1").
+
+otp_2979_2(X) -> otp_2979(X).
+
+otp_2979_3(X) -> otp_2979(X).
+
+otp_2979() ->
+ gn([[sparseDescr], [sparseStatus]]),
+ ?line expect(1, [{[sparseStr,0], "slut"},
+ {[sparseStr,0], "slut"}]).
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-3187
+%% Slogan: get-next on vacmAccessTable for colums > 5 returns
+%% endOfTable - should return value.
+%%-----------------------------------------------------------------
+otp_3187(suite) -> [];
+otp_3187(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"),
+ otp_3187(),
+ ?line unload_master("SNMP-VIEW-BASED-ACM-MIB").
+
+otp_3187_2(X) -> otp_3187(X).
+
+otp_3187_3(X) -> otp_3187(X).
+
+otp_3187() ->
+ ?line Elements =
+ snmp_view_based_acm_mib:vacmAccessTable(get_next,[],[4,5,6]),
+ lists:foreach(fun(E) ->
+ ?line if E == endOfTable ->
+ ?FAIL(endOfTable);
+ true -> ok
+ end
+ end, Elements).
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-3542
+%% Slogan:
+%%-----------------------------------------------------------------
+otp_3542(suite) -> [];
+otp_3542(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ try_test(otp_3542).
+
+otp_3542() ->
+ io:format("SNMP v3 discovery...~n"),
+ ?line Res = snmp_test_mgr:d(),
+ io:format("SNMP v3 discovery result: ~p~n",[Res]).
+
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-3725
+%% Slogan: Slow response time on snmpa:int_to_enum
+%%-----------------------------------------------------------------
+otp_3725(suite) -> [];
+otp_3725(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ ?line load_master("OLD-SNMPEA-MIB"),
+ ?line init_old(),
+ try_test(otp_3725_test, [node()]),
+ ?line unload_master("OLD-SNMPEA-MIB").
+
+%% Req. OLD-SNMPEA-MIB
+otp_3725_test(MaNode) ->
+ io:format("Testing feature requested in ticket OTP-3725...~n"),
+ ?line rpc:call(MaNode,snmpa,verbosity,[symbolic_store,trace]),
+ ?line Db = rpc:call(MaNode,snmp,get_symbolic_store_db,[]),
+ ?DBG("otp_3725_test -> Db = ~p",[Db]),
+
+ ?line {value, OID} = rpc:call(MaNode, snmp, name_to_oid,
+ [Db, intAgentIpAddress]),
+ ?DBG("otp_3725_test -> name_to_oid for ~p: ~p",[intAgentIpAddress,OID]),
+ ?line {value, intAgentIpAddress} = rpc:call(MaNode, snmp, oid_to_name,
+ [Db,OID]),
+ ?DBG("otp_3725_test -> oid_to_name for ~p: ~p",[OID,intAgentIpAddress]),
+ ?line false = rpc:call(MaNode, snmp, name_to_oid, [Db, intAgentIpAddres]),
+ ?line false = rpc:call(MaNode, snmp, oid_to_name,
+ [Db, [1,5,32,3,54,3,3,34,4]]),
+ ?line {value, 2} = rpc:call(MaNode, snmp, enum_to_int,
+ [Db, intViewType, excluded]),
+ ?line {value, excluded} = rpc:call(MaNode, snmp, int_to_enum,
+ [Db, intViewType, 2]),
+ ?line false = rpc:call(MaNode, snmp, enum_to_int,
+ [Db, intViewType, exclude]),
+ ?line false = rpc:call(MaNode, snmp, enum_to_int,
+ [Db, intAgentIpAddress, exclude]),
+ ?line false = rpc:call(MaNode, snmp, enum_to_int,
+ [Db, intAgentIpAddre, exclude]),
+ ?line false = rpc:call(MaNode, snmp, int_to_enum, [Db, intViewType, 3]),
+ ?line false = rpc:call(MaNode, snmp, int_to_enum,
+ [Db, intAgentIpAddress, 2]),
+ ?line false = rpc:call(MaNode, snmp, int_to_enum,
+ [Db, intAgentIpAddre, 2]),
+ ?line {value, active} = rpc:call(MaNode, snmp, int_to_enum,
+ [Db, 'RowStatus', ?active]),
+ ?line {value, ?destroy} = rpc:call(MaNode, snmp, enum_to_int,
+ [Db, 'RowStatus', destroy]),
+ ?line false = rpc:call(MaNode, snmp, enum_to_int,
+ [Db, 'RowStatus', xxxdestroy]),
+ ?line false = rpc:call(MaNode, snmp, enum_to_int,
+ [Db, 'xxRowStatus', destroy]),
+ ?line false = rpc:call(MaNode, snmp, int_to_enum, [Db, 'RowStatus', 25]),
+ ?line false = rpc:call(MaNode, snmp, int_to_enum, [Db, 'xxRowStatus', 1]),
+ ok.
+
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-4394
+%% Slogan: Target mib tag list check invalid
+%%-----------------------------------------------------------------
+
+
+otp_4394(suite) -> {req, [], {conf,
+ init_otp_4394,
+ [otp_4394_test],
+ finish_otp_4394}}.
+
+init_otp_4394(Config) when list(Config) ->
+ ?DBG("init_otp_4394 -> entry with"
+ "~n Config: ~p", [Config]),
+ ?line AgentDir = ?config(agent_dir, Config),
+ ?line MgrDir = ?config(mgr_dir, Config),
+ ?line Ip = ?config(ip, Config),
+ ?line otp_4394_config(AgentDir, MgrDir, Ip),
+ MasterAgentVerbosity = {master_agent_verbosity, trace},
+ NetIfVerbosity = {net_if_verbosity, trace},
+ Opts = [MasterAgentVerbosity,NetIfVerbosity],
+ [{vsn, v1} | start_v1_agent(Config,Opts)].
+
+otp_4394_config(AgentDir, MgrDir, Ip0) ->
+ ?DBG("otp_4394_config -> entry with"
+ "~n AgentDir: ~p"
+ "~n MgrDir: ~p"
+ "~n Ip0: ~p", [AgentDir, MgrDir, Ip0]),
+ Vsn = [v1],
+ Ip = tuple_to_list(Ip0),
+ ?line snmp_config:write_agent_snmp_files(AgentDir, Vsn, Ip,
+ ?TRAP_UDP, Ip, 4000,
+ "OTP-4394 test"),
+ ?line case update_usm(Vsn, AgentDir) of
+ true ->
+ ?line copy_file(filename:join(AgentDir, "usm.conf"),
+ filename:join(MgrDir, "usm.conf")),
+ ?line update_usm_mgr(Vsn, MgrDir);
+ false ->
+ ?line ok
+ end,
+ C1 = {"a", "all-rights", "initial", "", "pc"},
+ C2 = {"c", "secret", "secret_name", "", "secret_tag"},
+ ?line write_community_conf(AgentDir, [C1, C2]),
+ ?line update_vacm(Vsn, AgentDir),
+ Ta1 = {"shelob v1",
+ [134,138,177,177], 5000, 1500, 3, %% Anv�nd Ip och modda
+ "pc1",
+ "target_v1", "",
+ %% [255,255,255,255,0,0],
+ [],
+ 2048},
+ Ta2 = {"bifur v1",
+ [134,138,177,75], 5000, 1500, 3, %% Anv�nd Ip
+ "pc2",
+ "target_v1", "",
+ %% [255,255,255,255,0,0],
+ [], 2048},
+ ?line write_target_addr_conf(AgentDir, [Ta1, Ta2]),
+ ?line write_target_params_conf(AgentDir, Vsn),
+ ?line write_notify_conf(AgentDir),
+ ok.
+
+
+
+finish_otp_4394(Config) when list(Config) ->
+ ?DBG("finish_otp_4394 -> entry", []),
+ C1 = stop_agent(Config),
+ delete_files(C1),
+ erase(mgr_node),
+ lists:keydelete(vsn, 1, C1).
+
+otp_4394_test(suite) -> [];
+otp_4394_test(Config) ->
+ ?DBG("otp_4394_test -> entry", []),
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ try_test(otp_4394_test1),
+ ?DBG("otp_4394_test -> done", []),
+ ok.
+
+otp_4394_test1() ->
+ ?DBG("otp_4394_test1 -> entry", []),
+ gn([[1,1]]),
+ Res =
+ case snmp_test_mgr:expect(1, [{[sysDescr,0], "Erlang SNMP agent"}]) of
+ %% {error, 1, {"?",[]}, {"~w",[timeout]}}
+ {error, 1, _, {_, [timeout]}} ->
+ ?DBG("otp_4394_test1 -> expected result: timeout", []),
+ ok;
+ Else ->
+ Else
+ end,
+ ?DBG("otp_4394_test1 -> done with: ~p", [Res]),
+ Res.
+
+
+%%%--------------------------------------------------
+%%% Used to test the standard mib with our
+%%% configuration.
+%%%--------------------------------------------------
+run(F, A, Opts) ->
+ M = get(mib_dir),
+ Dir = get(mgr_dir),
+ User = snmp_misc:get_option(user, Opts, "all-rights"),
+ SecLevel = snmp_misc:get_option(sec_level, Opts, noAuthNoPriv),
+ EngineID = snmp_misc:get_option(engine_id, Opts, "agentEngine"),
+ CtxEngineID = snmp_misc:get_option(context_engine_id, Opts, EngineID),
+ Community = snmp_misc:get_option(community, Opts, "all-rights"),
+ ?DBG("run -> start crypto app",[]),
+ Crypto = case os:type() of
+ vxworks ->
+ no_crypto;
+ _ ->
+ ?CRYPTO_START()
+ end,
+ ?DBG("run -> Crypto: ~p",[Crypto]),
+ catch snmp_test_mgr:stop(), % If we had a running mgr from a failed case
+ StdM = filename:join(code:priv_dir(snmp), "mibs") ++ "/",
+ ?DBG("run -> config:~n"
+ "\tM: ~p~n"
+ "\tDir: ~p~n"
+ "\tUser: ~p~n"
+ "\tSecLevel: ~p~n"
+ "\tEngineID: ~p~n"
+ "\tCtxEngineID: ~p~n"
+ "\tCommunity: ~p~n"
+ "\tStdM: ~p",
+ [M,Dir,User,SecLevel,EngineID,CtxEngineID,Community,StdM]),
+ case snmp_test_mgr:start([%% {agent, snmp_test_lib:hostname()},
+ {packet_server_debug,true},
+ {debug,true},
+ {agent, get(master_host)},
+ {agent_udp, 4000},
+ {trap_udp, 5000},
+ {recbuf,65535},
+ quiet,
+ get(vsn),
+ {community, Community},
+ {user, User},
+ {sec_level, SecLevel},
+ {engine_id, EngineID},
+ {context_engine_id, CtxEngineID},
+ {dir, Dir},
+ {mibs, mibs(StdM, M)}]) of
+ {ok, _Pid} ->
+ Res = apply(?MODULE, F, A),
+ catch snmp_test_mgr:stop(),
+ Res;
+ Err ->
+ io:format("Error starting manager: ~p\n", [Err]),
+ catch snmp_test_mgr:stop(),
+ ?line exit({mgr_start, Err})
+ end.
+
+
+mibs(StdMibDir,MibDir) ->
+ [join(StdMibDir, ?v1_2("STANDARD-MIB.bin", "SNMPv2-MIB.bin")),
+ join(MibDir, "OLD-SNMPEA-MIB.bin"),
+ join(StdMibDir, "SNMP-FRAMEWORK-MIB"),
+ join(StdMibDir, "SNMP-MPD-MIB"),
+ join(StdMibDir, "SNMP-VIEW-BASED-ACM-MIB"),
+ join(StdMibDir, "SNMP-USER-BASED-SM-MIB"),
+ join(StdMibDir, "SNMP-TARGET-MIB"),
+ join(StdMibDir, "SNMP-NOTIFICATION-MIB"),
+ join(MibDir, "Klas1.bin"),
+ join(MibDir, "Klas2.bin"),
+ join(MibDir, "Klas3.bin"),
+ join(MibDir, "Klas4.bin"),
+ join(MibDir, "SA-MIB.bin"),
+ join(MibDir, "TestTrap.bin"),
+ join(MibDir, "Test1.bin"),
+ join(MibDir, "Test2.bin"),
+ join(MibDir, "TestTrapv2.bin")].
+
+join(D,F) ->
+ filename:join(D,F).
+
+%% string used in index
+is(S) -> [length(S) | S].
+
+try_test(Func) ->
+ call(get(mgr_node), ?MODULE, run, [Func, [], []]).
+
+try_test(Func, A) ->
+ call(get(mgr_node), ?MODULE, run, [Func, A, []]).
+
+try_test(Func, A, Opts) ->
+ call(get(mgr_node), ?MODULE, run, [Func, A, Opts]).
+
+call(N,M,F,A) ->
+ ?DBG("call -> entry with~n"
+ " N: ~p~n"
+ " M: ~p~n"
+ " F: ~p~n"
+ " A: ~p~n"
+ " when~n"
+ " get(): ~p",
+ [N,M,F,A,get()]),
+ spawn(N, ?MODULE, wait, [self(),get(),M,F,A]),
+ receive
+ {done, {'EXIT', Rn}, Loc} ->
+ ?DBG("call -> returned ~p",[{done, {'EXIT', Rn}, Loc}]),
+ put(test_server_loc, Loc),
+ exit(Rn);
+ {done, Ret, Zed} ->
+ ?DBG("call -> returned ~p~n",[{done, Ret, Zed}]),
+ Ret
+ end.
+
+wait(From, Env, M, F, A) ->
+ ?DBG("wait -> entry with ~n"
+ "\tFrom: ~p~n"
+ "\tEnv: ~p",[From,Env]),
+ lists:foreach(fun({K,V}) -> put(K,V) end, Env),
+ Rn = (catch apply(M, F, A)),
+ ?DBG("wait -> Rn: ~n~p", [Rn]),
+ From ! {done, Rn, get(test_server_loc)},
+ exit(Rn).
+
+expect(A,B) -> ok = snmp_test_mgr:expect(A,B).
+expect(A,B,C) -> ok = snmp_test_mgr:expect(A,B,C).
+expect(A,B,C,D) -> ok = snmp_test_mgr:expect(A,B,C,D).
+expect(A,B,C,D,E,F) -> ok = snmp_test_mgr:expect(A,B,C,D,E,F).
+
+get_req(Id, Vars) ->
+ ?DBG("get_req -> entry with~n"
+ "\tId: ~p~n"
+ "\tVars: ~p",[Id,Vars]),
+ g(Vars),
+ ?DBG("get_req -> await response",[]),
+ {ok, Val} = snmp_test_mgr:get_response(Id, Vars),
+ ?DBG("get_req -> response: ~p",[Val]),
+ Val.
+
+get_next_req(Vars) ->
+ ?DBG("get_next_req -> entry with Vars '~p', send request",[Vars]),
+ gn(Vars),
+ ?DBG("get_next_req -> await response",[]),
+ Response = snmp_test_mgr:receive_response(),
+ ?DBG("get_next_req -> response: ~p",[Response]),
+ Response.
+
+
+
+start_node(Name) ->
+ ?LOG("start_node -> entry with Name: ~p",[Name]),
+ M = list_to_atom(?HOSTNAME(node())),
+ ?DBG("start_node -> M: ~p",[M]),
+ Pa = filename:dirname(code:which(?MODULE)),
+ ?DBG("start_node -> Pa: ~p",[Pa]),
+
+ Args = case init:get_argument('CC_TEST') of
+ {ok, [[]]} ->
+ " -pa /clearcase/otp/libraries/snmp/ebin ";
+ {ok, [[Path]]} ->
+ " -pa " ++ Path;
+ error ->
+ ""
+ end,
+ %% Do not use start_link!!! (the proc that calls this one is tmp)
+ ?DBG("start_node -> Args: ~p~n",[Args]),
+ A = Args ++ " -pa " ++ Pa,
+ case (catch ?START_NODE(Name, A)) of
+ {ok, Node} ->
+ %% Tell the test_server to not clean up things it never started.
+ ?DBG("start_node -> Node: ~p",[Node]),
+ {ok, Node};
+ Else ->
+ ?ERR("start_node -> failed with(other): Else: ~p",[Else]),
+ ?line ?FAIL(Else)
+ end.
+
+
+stop_node(Node) ->
+ ?LOG("stop_node -> Node: ~p",[Node]),
+ rpc:cast(Node, erlang, halt, []).
+
+p(X) ->
+ io:format(user, X++"\n", []).
+
+sleep(X) ->
+ receive
+ after
+ X -> ok
+ end.
+
+%%%-----------------------------------------------------------------
+%%% Configuration
+%%%-----------------------------------------------------------------
+config(Vsns, MgrDir, AgentDir, MIp, AIp) ->
+ ?line snmp_config:write_agent_snmp_files(AgentDir, Vsns, MIp,
+ ?TRAP_UDP, AIp, 4000,
+ "test"),
+ ?line case update_usm(Vsns, AgentDir) of
+ true ->
+ ?line copy_file(filename:join(AgentDir, "usm.conf"),
+ filename:join(MgrDir, "usm.conf")),
+ ?line update_usm_mgr(Vsns, MgrDir);
+ false ->
+ ?line ok
+ end,
+ ?line update_community(Vsns, AgentDir),
+ ?line update_vacm(Vsns, AgentDir),
+ ?line write_target_addr_conf(AgentDir, MIp, ?TRAP_UDP, Vsns),
+ ?line write_target_params_conf(AgentDir, Vsns),
+ ?line write_notify_conf(AgentDir),
+ ok.
+
+delete_files(Config) ->
+ Dir = ?config(agent_dir, Config),
+ {ok, List} = file:list_dir(Dir),
+ lists:foreach(fun(FName) -> file:delete(filename:join(Dir, FName)) end,
+ List).
+
+update_usm(Vsns, Dir) ->
+ case lists:member(v3, Vsns) of
+ true ->
+ {ok, Fid} = file:open(filename:join(Dir,"usm.conf"),[read,write]),
+ file:position(Fid, eof),
+ ok = io:format(Fid, "{\"agentEngine\", \"all-rights\", "
+ "\"all-rights\", zeroDotZero, "
+ "usmNoAuthProtocol, \"\", \"\", "
+ "usmNoPrivProtocol, \"\", \"\", \"\", "
+ "\"\", \"\"}.\n", []),
+ ok = io:format(Fid, "{\"agentEngine\", \"no-rights\", "
+ "\"no-rights\", zeroDotZero, "
+ "usmNoAuthProtocol, \"\", \"\", "
+ "usmNoPrivProtocol, \"\", \"\", \"\", "
+ "\"\", \"\"}.\n", []),
+ ok = io:format(Fid, "{\"agentEngine\", \"authMD5\", "
+ "\"authMD5\", zeroDotZero, "
+ "usmHMACMD5AuthProtocol, \"\", \"\", "
+ "usmNoPrivProtocol, \"\", \"\", \"\", "
+ "\"passwd_md5xxxxxx\", \"\"}.\n", []),
+ ok = io:format(Fid, "{\"agentEngine\", \"authSHA\", "
+ "\"authSHA\", zeroDotZero, "
+ "usmHMACSHAAuthProtocol, \"\", \"\", "
+ "usmNoPrivProtocol, \"\", \"\", \"\", "
+ "\"passwd_shaxxxxxxxxxx\", \"\"}.\n", []),
+ ok = io:format(Fid, "{\"agentEngine\", \"privDES\", "
+ "\"privDES\", zeroDotZero, "
+ "usmHMACSHAAuthProtocol, \"\", \"\", "
+ "usmDESPrivProtocol, \"\", \"\", \"\", "
+ "\"passwd_shaxxxxxxxxxx\", \"passwd_desxxxxxx\"}.\n",
+ []),
+ ok = io:format(Fid, "{\"mgrEngine\", \"all-rights\", "
+ "\"all-rights\", zeroDotZero, "
+ "usmNoAuthProtocol, \"\", \"\", "
+ "usmNoPrivProtocol, \"\", \"\", \"\", "
+ "\"\", \"\"}.\n", []),
+ ok = io:format(Fid, "{\"mgrEngine\", \"no-rights\", "
+ "\"no-rights\", zeroDotZero, "
+ "usmNoAuthProtocol, \"\", \"\", "
+ "usmNoPrivProtocol, \"\", \"\", \"\", "
+ "\"\", \"\"}.\n", []),
+ ok = io:format(Fid, "{\"mgrEngine\", \"authMD5\", "
+ "\"authMD5\", zeroDotZero, "
+ "usmHMACMD5AuthProtocol, \"\", \"\", "
+ "usmNoPrivProtocol, \"\", \"\", \"\", "
+ "\"passwd_md5xxxxxx\", \"\"}.\n", []),
+ ok = io:format(Fid, "{\"mgrEngine\", \"authSHA\", "
+ "\"authSHA\", zeroDotZero, "
+ "usmHMACSHAAuthProtocol, \"\", \"\", "
+ "usmNoPrivProtocol, \"\", \"\", \"\", "
+ "\"passwd_shaxxxxxxxxxx\", \"\"}.\n", []),
+ ok = io:format(Fid, "{\"mgrEngine\", \"privDES\", "
+ "\"privDES\", zeroDotZero, "
+ "usmHMACSHAAuthProtocol, \"\", \"\", "
+ "usmDESPrivProtocol, \"\", \"\", \"\", "
+ "\"passwd_shaxxxxxxxxxx\", \"passwd_desxxxxxx\"}.\n",
+ []),
+ file:close(Fid),
+ true;
+ false ->
+ false
+ end.
+
+update_usm_mgr(Vsns, Dir) ->
+ case lists:member(v3, Vsns) of
+ true ->
+ {ok, Fid} = file:open(filename:join(Dir,"usm.conf"),[read,write]),
+ file:position(Fid, eof),
+ ok = io:format(Fid, "{\"agentEngine\", \"newUser\", "
+ "\"newUser\", zeroDotZero, "
+ "usmHMACSHAAuthProtocol, \"\", \"\", "
+ "usmDESPrivProtocol, \"\", \"\", \"\", "
+ "\"passwd_shaxxxxxxxxxx\", \"passwd_desxxxxxx\"}.\n",
+ []),
+ ok = io:format(Fid, "{\"mgrEngine\", \"newUser\", "
+ "\"newUser\", zeroDotZero, "
+ "usmHMACSHAAuthProtocol, \"\", \"\", "
+ "usmDESPrivProtocol, \"\", \"\", \"\", "
+ "\"passwd_shaxxxxxxxxxx\", \"passwd_desxxxxxx\"}.\n",
+ []),
+ file:close(Fid),
+ true;
+ false ->
+ false
+ end.
+
+rewrite_usm_mgr(Dir, ShaKey, DesKey) ->
+ ?line ok = file:rename(filename:join(Dir,"usm.conf"),
+ filename:join(Dir,"usm.old")),
+ ?line {ok, Fid} = file:open(filename:join(Dir,"usm.conf"),write),
+ ok = io:format(Fid, "{\"agentEngine\", \"newUser\", "
+ "\"newUser\", zeroDotZero, "
+ "usmHMACSHAAuthProtocol, \"\", \"\", "
+ "usmDESPrivProtocol, \"\", \"\", \"\", "
+ "\"~s\", \"~s\"}.\n",
+ [ShaKey, DesKey]),
+ ok = io:format(Fid, "{\"mgrEngine\", \"newUser\", "
+ "\"newUser\", zeroDotZero, "
+ "usmHMACSHAAuthProtocol, \"\", \"\", "
+ "usmDESPrivProtocol, \"\", \"\", \"\", "
+ "\"~s\", \"~s\"}.\n",
+ [ShaKey, DesKey]),
+ file:close(Fid).
+
+reset_usm_mgr(Dir) ->
+ ?line ok = file:rename(filename:join(Dir,"usm.old"),
+ filename:join(Dir,"usm.conf")).
+
+
+update_community([v3], _Dir) -> ok;
+update_community(_, Dir) ->
+ {ok, Fid} = file:open(filename:join(Dir,"community.conf"),[read,write]),
+ file:position(Fid, eof),
+ ok=io:format(Fid,"{\"no-rights\",\"no-rights\",\"no-rights\",\"\",\"\"}.\n",
+ []),
+ file:close(Fid).
+
+
+-define(tDescr_instance, [1,3,6,1,2,1,16,1,0]).
+update_vacm(_Vsn, Dir) ->
+ {ok, Fid} = file:open(filename:join(Dir,"vacm.conf"),[read,write]),
+ file:position(Fid, eof),
+ ok=io:format(Fid,"{vacmSecurityToGroup,usm,\"authMD5\",\"initial\"}.\n",[]),
+ ok=io:format(Fid,"{vacmSecurityToGroup,usm,\"authSHA\",\"initial\"}.\n",[]),
+ ok=io:format(Fid,"{vacmSecurityToGroup,usm,\"privDES\",\"initial\"}.\n",[]),
+ ok=io:format(Fid,"{vacmSecurityToGroup,usm,\"newUser\",\"initial\"}.\n",[]),
+ ok = io:format(Fid, "{vacmViewTreeFamily, \"internet\", "
+ "~w, excluded, null}.\n", [?tDescr_instance]),
+ file:close(Fid).
+
+
+vacm_ver(v1) -> v1;
+vacm_ver(v2) -> v2c;
+vacm_ver(v3) -> usm.
+
+
+write_community_conf(Dir, Confs) ->
+ {ok, Fid} = file:open(filename:join(Dir,"community.conf"),write),
+ ok = write_community_conf1(Fid, Confs),
+ file:close(Fid).
+
+write_community_conf1(_, []) ->
+ ok;
+write_community_conf1(Fid, [{ComIdx, ComName, SecName, CtxName, TransTag}|Confs]) ->
+ ok = io:format(Fid, "{\"~s\", \"~s\", \"~s\", \"~s\", \"~s\"}.~n",
+ [ComIdx, ComName, SecName, CtxName, TransTag]),
+ write_community_conf1(Fid, Confs).
+
+
+write_target_addr_conf(Dir, Confs) ->
+ {ok, Fid} = file:open(filename:join(Dir,"target_addr.conf"),write),
+ ok = write_target_addr_conf1(Fid, Confs),
+ file:close(Fid).
+
+
+write_target_addr_conf1(_, []) ->
+ ok;
+write_target_addr_conf1(Fid,
+ [{Name, Ip, Port, Timeout, Retry, TagList, ParamName,
+ EngineId, TMask, MaxMsgSz}|Confs]) ->
+ ok = io:format(Fid, "{\"~s\", ~w, ~w, ~w, ~w, \"~s\", \"~s\", \"~s\", ~w, ~w}.~n",
+ [Name, Ip, Port, Timeout, Retry, TagList, ParamName,
+ EngineId, TMask, MaxMsgSz]),
+ write_target_addr_conf1(Fid, Confs).
+
+write_target_addr_conf(Dir, ManagerIp, UDP, Vsns) ->
+ {ok, Fid} = file:open(filename:join(Dir,"target_addr.conf"),write),
+ lists:foreach(fun(Vsn) ->
+ ok = io:format(Fid,
+ "{\"~s\", ~w, ~w, 1500, 3, "
+ "\"std_trap\", \"~s\"}.~n",
+ [mk_ip(ManagerIp, Vsn),
+ ManagerIp, UDP, mk_param(Vsn)]),
+ case Vsn of
+ v1 -> ok;
+ v2 ->
+ ok = io:format(Fid,
+ "{\"~s.2\",~w,~w,1500,3, "
+ "\"std_inform\", \"~s\"}.~n",
+ [mk_ip(ManagerIp, Vsn),
+ ManagerIp, UDP,
+ mk_param(Vsn)]);
+ v3 ->
+ ok = io:format(Fid,
+ "{\"~s.3\",~w,~w,1500,3, "
+ "\"std_inform\", \"~s\", "
+ "\"mgrEngine\", [], 1024}.~n",
+ [mk_ip(ManagerIp, Vsn),
+ ManagerIp, UDP,
+ mk_param(Vsn)])
+ end
+ end,
+ Vsns),
+ file:close(Fid).
+
+mk_param(v1) -> "target_v1";
+mk_param(v2) -> "target_v2";
+mk_param(v3) -> "target_v3".
+
+mk_ip([A,B,C,D], Vsn) ->
+ io_lib:format("~w.~w.~w.~w ~w", [A,B,C,D,Vsn]).
+
+
+rewrite_target_addr_conf(Dir,NewPort) ->
+ TAFile = filename:join(Dir, "target_addr.conf"),
+ ?DBG("rewrite_target_addr_conf -> read target file info of address config file",[]),
+ case file:read_file_info(TAFile) of
+ {ok, _} -> ok;
+ {error, R} -> ?ERR("failure reading file info of "
+ "target address config file: ~p",[R]),
+ ok
+ end,
+
+ ?line [TrapAddr|Addrs] =
+ snmp_conf:read(TAFile,fun(R) -> rewrite_target_addr_conf1(R) end),
+
+ ?DBG("rewrite_target_addr_conf -> TrapAddr: ~p",[TrapAddr]),
+
+ NewAddrs = [rewrite_target_addr_conf2(NewPort,TrapAddr)|Addrs],
+
+ ?DBG("rewrite_target_addr_conf -> NewAddrs: ~p",[NewAddrs]),
+
+ ?line ok = file:rename(filename:join(Dir,"target_addr.conf"),
+ filename:join(Dir,"target_addr.old")),
+ ?line {ok, Fid} = file:open(filename:join(Dir,"target_addr.conf"),write),
+
+ ?line ok = rewrite_target_addr_conf3(Fid,NewAddrs),
+
+ file:close(Fid).
+
+rewrite_target_addr_conf1(O) ->
+ {ok,O}.
+
+rewrite_target_addr_conf2(NewPort,{Name,Ip,_Port,Timeout,Retry,
+ "std_trap",EngineId}) ->
+ ?LOG("rewrite_target_addr_conf2 -> entry with std_trap",[]),
+ {Name,Ip,NewPort,Timeout,Retry,"std_trap",EngineId};
+rewrite_target_addr_conf2(_NewPort,O) ->
+ ?LOG("rewrite_target_addr_conf2 -> entry with "
+ "~n O: ~p",[O]),
+ O.
+
+
+rewrite_target_addr_conf3(_,[]) -> ok;
+rewrite_target_addr_conf3(Fid,[{Name,Ip,Port,Timeout,Retry,
+ ParamName,EngineId}|T]) ->
+ ?LOG("rewrite_target_addr_conf3 -> write(1) ~s",[ParamName]),
+ io:format(Fid,
+ "{\"~s\", " % Name
+ "~p, " % Ip
+ "~p, " % Port
+ "~p, " % Timeout
+ "~p, " % Retry
+ "\"~s\", " % ParamsName
+ "\"~s\"}.", % EngineId
+ [Name,Ip,Port,Timeout,Retry,ParamName,EngineId]),
+ rewrite_target_addr_conf3(Fid,T);
+rewrite_target_addr_conf3(Fid,[{Name,Ip,Port,Timeout,Retry,TagList,
+ ParamName,EngineId,TMask,MMS}|T]) ->
+ ?LOG("rewrite_target_addr_conf3 -> write(2) ~s",[ParamName]),
+ io:format(Fid,
+ "{\"~s\", " % Name
+ "~p, " % Ip
+ "~p, " % Port
+ "~p, " % Timeout
+ "~p, " % Retry
+ "\"~s\", " % TagList
+ "\"~s\", " % ParamsName
+ "\"~s\"," % EngineId
+ "~p, " % TMask
+ "~p}.", % MMS
+ [Name,Ip,Port,Timeout,Retry,TagList,ParamName,
+ EngineId,TMask,MMS]),
+ rewrite_target_addr_conf3(Fid,T).
+
+reset_target_addr_conf(Dir) ->
+ ?line ok = file:rename(filename:join(Dir,"target_addr.old"),
+ filename:join(Dir,"target_addr.conf")).
+
+write_target_params_conf(Dir, Vsns) ->
+ {ok, Fid} = file:open(filename:join(Dir,"target_params.conf"),write),
+ lists:foreach(fun(Vsn) ->
+ MP = if Vsn == v1 -> v1;
+ Vsn == v2 -> v2c;
+ Vsn == v3 -> v3
+ end,
+ SM = if Vsn == v1 -> v1;
+ Vsn == v2 -> v2c;
+ Vsn == v3 -> usm
+ end,
+ ok = io:format(Fid, "{\"target_~w\", ~w, ~w, "
+ "\"all-rights\", noAuthNoPriv}.~n",
+ [Vsn, MP, SM])
+ end,
+ Vsns),
+ file:close(Fid).
+
+rewrite_target_params_conf(Dir, SecName, SecLevel) ->
+ ?line ok = file:rename(filename:join(Dir,"target_params.conf"),
+ filename:join(Dir,"target_params.old")),
+ ?line {ok, Fid} = file:open(filename:join(Dir,"target_params.conf"),write),
+ ?line ok = io:format(Fid, "{\"target_v3\", v3, usm, \"~s\", ~w}.~n",
+ [SecName, SecLevel]),
+ file:close(Fid).
+
+reset_target_params_conf(Dir) ->
+ ?line ok = file:rename(filename:join(Dir,"target_params.old"),
+ filename:join(Dir,"target_params.conf")).
+
+write_notify_conf(Dir) ->
+ {ok, Fid} = file:open(filename:join(Dir,"notify.conf"),write),
+ ok = io:format(Fid, "{\"standard trap\", \"std_trap\", trap}.~n", []),
+ ok = io:format(Fid, "{\"standard inform\", \"std_inform\",inform}.~n", []),
+ file:close(Fid).
+
+ver_to_trap_str([v1]) -> "v1";
+ver_to_trap_str([v2]) -> "v2";
+% default is to use the latest snmp version
+ver_to_trap_str([v1,v2]) -> "v2".
+
+
+
+write_view_conf(Dir) ->
+ {ok, Fid} = file:open(a(Dir,"view.conf"),write),
+ ok = io:format(Fid, "{2, [1,3,6], included, null}.~n", []),
+ ok = io:format(Fid, "{2, ~w, excluded, null}.~n", [?tDescr_instance]),
+ file:close(Fid).
+
+a(A,B) -> lists:append(A,B).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+copy_file(From, To) ->
+ {ok, Bin} = file:read_file(From),
+ ok = file:write_file(To, Bin).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+display_memory_usage() ->
+ Info = snmpa:info(snmp_master_agent),
+ TreeSize = lists_key1search(tree_size_bytes, Info),
+ ProcMem = lists_key1search(process_memory, Info),
+ MibDbSize = lists_key1search([db_memory,mib], Info),
+ NodeDbSize = lists_key1search([db_memory,node], Info),
+ TreeDbSize = lists_key1search([db_memory,tree], Info),
+ ?INF("Memory usage: "
+ "~n Tree size: ~p"
+ "~n Process memory size: ~p"
+ "~n Mib db size: ~p"
+ "~n Node db size: ~p"
+ "~n Tree db size: ~p",
+ [TreeSize, ProcMem, MibDbSize, NodeDbSize, TreeDbSize]).
+
+lists_key1search([], Res) ->
+ Res;
+lists_key1search([Key|Keys], List) when atom(Key), list(List) ->
+ case lists:keysearch(Key, 1, List) of
+ {value, {Key, Val}} ->
+ lists_key1search(Keys, Val);
+ false ->
+ undefined
+ end;
+lists_key1search(Key, List) when atom(Key) ->
+ case lists:keysearch(Key, 1, List) of
+ {value, {Key, Val}} ->
+ Val;
+ false ->
+ undefined
+ end.
+
+
+regs() ->
+ lists:sort(registered()).
diff --git a/lib/snmp/test/snmp_agent_mt_test.erl b/lib/snmp/test/snmp_agent_mt_test.erl
new file mode 100644
index 0000000000..8d5a57f58d
--- /dev/null
+++ b/lib/snmp/test/snmp_agent_mt_test.erl
@@ -0,0 +1,5657 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2005-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%
+%%
+
+-module(snmp_agent_mt_test).
+
+%% TODO
+%% * Test fault-tolerance (kill master etc)
+%%
+
+-compile(export_all).
+
+-define(application, snmp).
+
+-include_lib("kernel/include/file.hrl").
+-include("test_server.hrl").
+-include("snmp_test_lib.hrl").
+-define(SNMP_USE_V3, true).
+-include_lib("snmp/include/snmp_types.hrl").
+%% -include_lib("snmp/include/SNMP-COMMUNITY-MIB.hrl").
+%% -include_lib("snmp/include/SNMP-VIEW-BASED-ACM-MIB.hrl").
+%% -include_lib("snmp/include/SNMP-USER-BASED-SM-MIB.hrl").
+
+
+-define(klas1, [1,3,6,1,2,1,7]).
+-define(klas2, [1,3,6,1,2,1,9]).
+-define(klas3, [1,3,6,1,2,1,8,1]).
+-define(klas4, [1,3,6,1,2,1,8,4]).
+-define(sa, [1,3,6,1,4,1,193,2]).
+-define(system, [1,3,6,1,2,1,1]).
+-define(snmp, [1,3,6,1,2,1,11]).
+-define(snmpTraps, [1,3,6,1,6,3,1,1,5]).
+-define(ericsson, [1,3,6,1,4,1,193]).
+-define(testTrap, [1,3,6,1,2,1,15,0]).
+-define(xDescr, [1,3,6,1,2,1,17,1]).
+-define(xDescr2, [1,3,6,1,2,1,17,2]).
+
+-define(active, 1).
+-define(notInService, 2).
+-define(notReady, 3).
+-define(createAndGo, 4).
+-define(createAndWait, 5).
+-define(destroy, 6).
+
+-define(TRAP_UDP, 5000).
+
+-define(tooBigStr, "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").
+
+-define(str(X), snmp_pdus:bits_to_str(X)).
+
+-define(break(), begin io:format(user, "break at line ~w: pid: ~p\n",
+ [?LINE, self()]),
+ receive cont -> ok end
+ end).
+
+
+-import(snmp_test_mgr, [gn/1, g/1, s/1, gb/3]).
+-define(v1_2(V1,V2),
+ case get(vsn) of
+ v1 -> V1;
+ _ -> V2
+ end).
+
+-define(v1_2_3(V1,V2,V3),
+ case get(vsn) of
+ v1 -> V1;
+ v2 -> V2;
+ _ -> V3
+ end).
+
+all(suite) -> {req,
+ [mnesia, distribution,
+ {local_slave_nodes, 2}, {time, 360}],
+ [{conf, init_all, cases(), finish_all}]}.
+
+init_per_testcase(_Case, Config) when list(Config) ->
+ Dog = ?t:timetrap(?t:minutes(6)),
+ [{watchdog, Dog}|Config].
+
+fin_per_testcase(_Case, Config) when list(Config) ->
+ Dog = ?config(watchdog, Config),
+ ?t:timetrap_cancel(Dog),
+ Config.
+
+cases() ->
+ case ?OSTYPE() of
+ vxworks ->
+ %% No crypto app, so skip v3 testcases
+ [
+ app_info,
+ test_v1, test_v2, test_v1_v2,
+ test_multi_threaded,
+ mib_storage,
+ tickets];
+ _Else ->
+ [
+ app_info,
+ test_v1, test_v2, test_v1_v2, test_v3,
+ test_multi_threaded,
+ mib_storage,
+ tickets
+ ]
+ end.
+
+
+%%%-----------------------------------------------------------------
+%%% The test case structure is as follows:
+%%%
+%%% init_all - starts mnesia,
+%%%
+%%% init_v1 - starts agent
+%%% simple
+%%% big - e.g. starts/stops subagent, load/unloads mibs
+%%% init_mul
+%%% mul_get
+%%% mul_set
+%%% <etc>
+%%% finish_mul
+%%% <etc>
+%%% finish_v1
+%%%
+%%% init_v2 - starts agent
+%%% finish_v2
+%%%
+%%% init_bilingual - starts agent
+%%% finish_bilingual
+%%%
+%%% finish_all
+%%%
+%%% There is still one problem with these testsuites. If one test
+%%% fails, it may not be possible to run some other cases, as it
+%%% may have e.g. created some row or loaded some table, that it
+%%% didn't undo (since it failed).
+%%%-----------------------------------------------------------------
+
+init_all(Config0) when list(Config0) ->
+ ?LOG("init_all -> entry with"
+ "~n Config0: ~p",[Config0]),
+
+ %% --
+ %% Fix config:
+ %%
+
+ DataDir0 = ?config(data_dir, Config0),
+ DataDir1 = filename:split(filename:absname(DataDir0)),
+ [_|DataDir2] = lists:reverse(DataDir1),
+ DataDir3 = filename:join(lists:reverse(DataDir2) ++ [?snmp_test_data]),
+ Config1 = lists:keydelete(data_dir, 1, Config0),
+ Config = [{data_dir, DataDir3 ++ "/"}|Config1],
+
+ %% --
+ %% Start nodes
+ %%
+
+ ?line {ok, SaNode} = start_node(snmp_sa),
+ ?line {ok, MgrNode} = start_node(snmp_mgr),
+
+
+ %% --
+ %% Create necessary files
+ %%
+
+ Dir = ?config(priv_dir, Config),
+ ?DBG("init_all -> Dir ~p", [Dir]),
+
+ DataDir = ?config(data_dir, Config),
+ ?DBG("init_all -> DataDir ~p", [DataDir]),
+
+ file:make_dir(MgrDir = filename:join(Dir, "mgr_dir/")),
+ ?DBG("init_all -> MgrDir ~p", [MgrDir]),
+
+ file:make_dir(AgentDir = filename:join(Dir, "agent_dir/")),
+ ?DBG("init_all -> AgentDir ~p", [AgentDir]),
+
+ file:make_dir(SaDir = filename:join(Dir, "sa_dir/")),
+ ?DBG("init_all -> SaDir ~p", [SaDir]),
+
+
+ %% --
+ %% Start and initiate mnesia
+ %%
+
+ ?DBG("init_all -> load application mnesia", []),
+ ?line ok = application:load(mnesia),
+
+ ?DBG("init_all -> load application mnesia on node ~p", [SaNode]),
+ ?line ok = rpc:call(SaNode, application, load, [mnesia]),
+
+ ?DBG("init_all -> application mnesia: set_env dir",[]),
+ ?line application_controller:set_env(mnesia, dir,
+ filename:join(Dir, "Mnesia1")),
+
+ ?DBG("init_all -> application mnesia: set_env dir on node ~p",[SaNode]),
+ ?line rpc:call(SaNode, application_controller, set_env,
+ [mnesia, dir, filename:join(Dir, "Mnesia2")]),
+
+ ?DBG("init_all -> create mnesia schema",[]),
+ ?line ok = mnesia:create_schema([SaNode, node()]),
+
+ ?DBG("init_all -> start application mnesia",[]),
+ ?line ok = application:start(mnesia),
+
+ ?DBG("init_all -> start application mnesia on ~p",[SaNode]),
+ ?line ok = rpc:call(SaNode, application, start, [mnesia]),
+ Ip = ?LOCALHOST(),
+ [{snmp_sa, SaNode},
+ {snmp_mgr, MgrNode},
+ {agent_dir, AgentDir ++ "/"},
+ {mgr_dir, MgrDir ++ "/"},
+ {sa_dir, SaDir ++ "/"},
+ {mib_dir, DataDir},
+ {ip, Ip} |
+ Config].
+
+finish_all(Config) when list(Config) ->
+ SaNode = ?config(snmp_sa, Config),
+ MgrNode = ?config(snmp_mgr, Config),
+ stop_node(SaNode),
+ stop_node(MgrNode),
+ application:stop(mnesia).
+
+start_v1_agent(Config) when list(Config) ->
+ start_agent(Config, [v1]).
+
+start_v1_agent(Config,Opts) when list(Config), list(Opts) ->
+ start_agent(Config, [v1], Opts).
+
+start_v2_agent(Config) when list(Config) ->
+ start_agent(Config, [v2]).
+
+start_v3_agent(Config) when list(Config) ->
+ start_agent(Config, [v3]).
+
+start_bilingual_agent(Config) when list(Config) ->
+ start_agent(Config, [v1,v2]).
+
+start_multi_threaded_agent(Config) when list(Config) ->
+ start_agent(Config, [v2], [{snmp_multi_threaded, true}]).
+
+stop_agent(Config) when list(Config) ->
+ ?LOG("stop_agent -> entry with"
+ "~n Config: ~p",[Config]),
+
+ {Sup, Par} = ?config(snmp_sup, Config),
+ ?DBG("stop_agent -> attempt to stop (sup) ~p"
+ "~n Sup: ~p"
+ "~n Par: ~p",
+ [Sup,
+ (catch process_info(Sup)),
+ (catch process_info(Par))]),
+ stop_sup(Sup, Par),
+
+ {Sup2, Par2} = ?config(snmp_sub, Config),
+ ?DBG("stop_agent -> attempt to stop (sub) ~p"
+ "~n Sup2: ~p"
+ "~n Par2: ~p",
+ [Sup2,
+ (catch process_info(Sup2)),
+ (catch process_info(Par2))]),
+ stop_sup(Sup2, Par2),
+
+ ?DBG("stop_agent -> done - now cleanup config", []),
+ C1 = lists:keydelete(snmp_sup, 1, Config),
+ lists:keydelete(snmp_sub, 1, C1).
+
+
+stop_sup(Pid, _) when node(Pid) == node() ->
+ case (catch process_info(Pid)) of
+ PI when list(PI) ->
+ ?LOG("stop_sup -> attempt to stop ~p", [Pid]),
+ Ref = erlang:monitor(process, Pid),
+ exit(Pid, kill),
+ await_stopped(Pid, Ref);
+ {'EXIT', _Reason} ->
+ ?LOG("stop_sup -> ~p not running", [Pid]),
+ ok
+ end;
+stop_sup(Pid, _) ->
+ ?LOG("stop_sup -> attempt to stop ~p", [Pid]),
+ Ref = erlang:monitor(process, Pid),
+ ?LOG("stop_sup -> Ref: ~p", [Ref]),
+ %% Pid ! {'EXIT', Parent, shutdown}, % usch
+ exit(Pid, kill),
+ await_stopped(Pid, Ref).
+
+await_stopped(Pid, Ref) ->
+ receive
+ {'DOWN', Ref, process, Pid, _Reason} ->
+ ?DBG("received down message for ~p", [Pid]),
+ ok
+ after 10000 ->
+ ?INF("await_stopped -> timeout for ~p",[Pid]),
+ erlang:demonitor(Ref),
+ ?FAIL({failed_stop,Pid})
+ end.
+
+
+start_agent(Config, Vsn) ->
+ start_agent(Config, Vsn, []).
+start_agent(Config, Vsn, Opts) ->
+ ?LOG("start_agent -> entry (~p) with"
+ "~n Config: ~p"
+ "~n Vsn: ~p"
+ "~n Opts: ~p",[node(), Config, Vsn, Opts]),
+
+ ?line AgentDir = ?config(agent_dir, Config),
+ ?line SaNode = ?config(snmp_sa, Config),
+
+ snmp_app_env_init(vsn_init(Vsn) ++
+ [{audit_trail_log, read_write_log},
+ {audit_trail_log_dir, AgentDir},
+ {audit_trail_log_size, {10240, 10}},
+ {force_config_reload, false},
+ {snmp_agent_type, master},
+ {snmp_config_dir, AgentDir},
+ {snmp_db_dir, AgentDir},
+ {snmp_local_db_auto_repair, true},
+ {snmp_master_agent_verbosity, trace},
+ {snmp_supervisor_verbosity, trace},
+ {snmp_mibserver_verbosity, trace},
+ {snmp_symbolic_store_verbosity, trace},
+ {snmp_note_store_verbosity, trace},
+ {snmp_net_if_verbosity, trace}],
+ Opts),
+
+
+ process_flag(trap_exit,true),
+
+ {ok, AppSup} = snmp_app_sup:start_link(),
+ unlink(AppSup),
+ ?DBG("start_agent -> snmp app supervisor: ~p",[AppSup]),
+
+ ?DBG("start_agent -> start master agent (old style)",[]),
+ Sup = case (catch snmpa_app:start(normal)) of
+ {ok, S} ->
+ ?DBG("start_agent -> started, Sup: ~p",[S]),
+ S;
+
+ Else ->
+ ?DBG("start_agent -> unknown result: ~n~p",[Else]),
+ %% Get info about the apps we depend on
+ MnesiaInfo = mnesia_running(),
+ ?FAIL({start_failed,Else,MnesiaInfo})
+ end,
+
+ ?DBG("start_agent -> unlink from supervisor",[]),
+ ?line unlink(Sup),
+ ?line SaDir = ?config(sa_dir, Config),
+ ?DBG("start_agent -> (rpc) start sub on ~p",[SaNode]),
+ ?line {ok, Sub} = rpc:call(SaNode, ?MODULE, start_sub, [SaDir]),
+ ?DBG("start_agent -> done",[]),
+ ?line [{snmp_sup, {Sup, self()}}, {snmp_sub, Sub} | Config].
+
+
+vsn_init(Vsn) ->
+ vsn_init([v1,v2,v3], Vsn, []).
+
+vsn_init([], _Vsn, Acc) ->
+ Acc;
+vsn_init([V|Vsns], Vsn, Acc) ->
+ case lists:member(V, Vsn) of
+ true ->
+ vsn_init(Vsns, Vsn, [{V, true}|Acc]);
+ false ->
+ vsn_init(Vsns, Vsn, [{V, false}|Acc])
+ end.
+
+snmp_app_env_init(Env0, Opts) ->
+ ?DBG("snmp_app_env_init -> unload snmp",[]),
+ ?line application:unload(snmp),
+ ?DBG("snmp_app_env_init -> load snmp",[]),
+ ?line application:load(snmp),
+ ?DBG("snmp_app_env_init -> initiate (snmp) application env",[]),
+ F1 = fun({Key,Val} = New, Acc0) ->
+ ?DBG("snmp_app_env_init -> "
+ "updating setting ~p to ~p", [Key, Val]),
+ case lists:keyreplace(Key, 1, Acc0, New) of
+ Acc0 ->
+ [New|Acc0];
+ Acc ->
+ Acc
+ end
+ end,
+ Env = lists:foldr(F1, Env0, Opts),
+ ?DBG("snmp_app_env_init -> Env: ~p",[Env]),
+ F2 = fun({Key,Val}) ->
+ ?DBG("snmp_app_env_init -> setting ~p to ~p",[Key, Val]),
+ application_controller:set_env(snmp, Key, Val)
+ end,
+ lists:foreach(F2, Env).
+
+
+
+
+%% Test if application is running
+mnesia_running() -> ?IS_MNESIA_RUNNING().
+crypto_running() -> ?IS_CRYPTO_RUNNING().
+
+
+start_sub(Dir) ->
+ ?DBG("start_sub -> entry",[]),
+ Opts = [{db_dir, Dir},
+ {supervisor, [{verbosity, trace}]}],
+ %% BMK BMK
+% {ok, P} = snmp_supervisor:start_sub(Dir),
+ {ok, P} = snmpa_supervisor:start_sub_sup(Opts),
+ unlink(P),
+ {ok, {P, self()}}.
+
+create_tables(SaNode) ->
+ ?line {atomic, ok} = mnesia:create_table([{name, friendsTable2},
+ {ram_copies, [SaNode]},
+ {snmp, [{key, integer}]},
+ {attributes, [a1,a2,a3]}]),
+ ?line {atomic, ok} = mnesia:create_table([{name, kompissTable2},
+ {ram_copies, [SaNode]},
+ {snmp, [{key, integer}]},
+ {attributes, [a1,a2,a3]}]),
+ ?line {atomic, ok} = mnesia:create_table([{name, snmp_variables},
+ {attributes, [a1,a2]}]).
+
+delete_tables() ->
+ mnesia:delete_table(friendsTable2),
+ mnesia:delete_table(kompissTable2),
+ mnesia:delete_table(snmp_variables).
+
+%% Creation is done in runtime!
+delete_mib_storage_mnesia_tables() ->
+ mnesia:delete_table(snmpa_mib_data),
+ mnesia:delete_table(snmpa_mib_tree),
+ mnesia:delete_table(snmpa_symbolic_store).
+
+%%-----------------------------------------------------------------
+%% A test case is always one of:
+%% - v1 specific case
+%% - v2 specific case
+%% - v1 and v2 case
+%% All v1 specific cases are prefixed with v1_, and all v2 with
+%% v2_. E.g. v1_trap/v2_trap.
+%%
+%% All other cases are shared. However, the testserver uses the name
+%% of the case to generate a file for that case. The same case cannot
+%% be used in different configurations in the same suite. Therefore
+%% all these functions exists in two variants, the base function
+%% <base>, and a second version <base>_2. There may be several
+%% versions as well, <base>_N.
+%%-----------------------------------------------------------------
+mib_storage(suite) -> [
+ mib_storage_ets,
+ mib_storage_dets,
+ mib_storage_mnesia,
+ mib_storage_size_check_ets,
+ mib_storage_size_check_dets,
+ mib_storage_size_check_mnesia,
+ mib_storage_varm_dets,
+ mib_storage_varm_mnesia
+ ].
+
+mib_storage_ets(suite) -> {req, [], {conf, init_mib_storage_ets,
+ mib_storage_ets_cases(),
+ finish_mib_storage_ets}}.
+
+mib_storage_dets(suite) -> {req, [], {conf, init_mib_storage_dets,
+ mib_storage_dets_cases(),
+ finish_mib_storage_dets}}.
+
+mib_storage_mnesia(suite) -> {req, [], {conf, init_mib_storage_mnesia,
+ mib_storage_mnesia_cases(),
+ finish_mib_storage_mnesia}}.
+
+mib_storage_size_check_ets(suite) ->
+ {req, [], {conf,
+ init_size_check_mse,
+ mse_size_check_cases(),
+ finish_size_check_mse}}.
+
+mib_storage_size_check_dets(suite) ->
+ {req, [], {conf,
+ init_size_check_msd,
+ msd_size_check_cases(),
+ finish_size_check_msd}}.
+
+mib_storage_size_check_mnesia(suite) ->
+ {req, [], {conf,
+ init_size_check_msm,
+ msm_size_check_cases(),
+ finish_size_check_msm}}.
+
+mib_storage_varm_dets(suite) ->
+ {req, [], {conf,
+ init_varm_mib_storage_dets,
+ varm_mib_storage_dets_cases(),
+ finish_varm_mib_storage_dets}}.
+
+mib_storage_varm_mnesia(suite) ->
+ {req, [], {conf,
+ init_varm_mib_storage_mnesia,
+ varm_mib_storage_mnesia_cases(),
+ finish_varm_mib_storage_mnesia}}.
+
+mib_storage_ets_cases() ->
+ [
+ mse_simple,
+ mse_v1_processing,
+ mse_big,
+ mse_big2,
+ mse_loop_mib,
+ mse_api,
+ mse_sa_register,
+ mse_v1_trap,
+ mse_sa_error,
+ mse_next_across_sa,
+ mse_undo,
+ mse_standard_mib,
+ mse_community_mib,
+ mse_framework_mib,
+ mse_target_mib,
+ mse_notification_mib,
+ mse_view_based_acm_mib,
+ mse_sparse_table,
+ mse_me_of,
+ mse_mib_of].
+
+mib_storage_dets_cases() ->
+ [
+ msd_simple,
+ msd_v1_processing,
+ msd_big,
+ msd_big2,
+ msd_loop_mib,
+ msd_api,
+ msd_sa_register,
+ msd_v1_trap,
+ msd_sa_error,
+ msd_next_across_sa,
+ msd_undo,
+ msd_standard_mib,
+ msd_community_mib,
+ msd_framework_mib,
+ msd_target_mib,
+ msd_notification_mib,
+ msd_view_based_acm_mib,
+ msd_sparse_table,
+ msd_me_of,
+ msd_mib_of
+ ].
+
+mib_storage_mnesia_cases() ->
+ [
+ msm_simple,
+ msm_v1_processing,
+ msm_big,
+ msm_big2,
+ msm_loop_mib,
+ msm_api,
+ msm_sa_register,
+ msm_v1_trap,
+ msm_sa_error,
+ msm_next_across_sa,
+ msm_undo,
+ msm_standard_mib,
+ msm_community_mib,
+ msm_framework_mib,
+ msm_target_mib,
+ msm_notification_mib,
+ msm_view_based_acm_mib,
+ msm_sparse_table,
+ msm_me_of,
+ msm_mib_of
+ ].
+
+mse_size_check_cases() ->
+ [mse_size_check].
+
+msd_size_check_cases() ->
+ [msd_size_check].
+
+msm_size_check_cases() ->
+ [msm_size_check].
+
+varm_mib_storage_dets_cases() ->
+ [msd_varm_mib_start].
+
+varm_mib_storage_mnesia_cases() ->
+ [msm_varm_mib_start].
+
+init_mib_storage_ets(Config) when list(Config) ->
+ ?LOG("init_mib_storage_ets -> entry", []),
+ MibStorage = {snmp_mib_storage,ets},
+ init_ms(Config, [MibStorage]).
+
+init_mib_storage_dets(Config) when list(Config) ->
+ ?LOG("init_mib_storage_ets -> entry", []),
+ ?line AgentDir = ?GCONF(agent_dir, Config),
+ MibStorage = {snmp_mib_storage,{dets,AgentDir}},
+ init_ms(Config, [MibStorage]).
+
+init_mib_storage_mnesia(Config) when list(Config) ->
+ ?LOG("init_mib_storage_ets -> entry", []),
+ MibStorage = {snmp_mib_storage,{mnesia,[]}},
+ init_ms(Config, [MibStorage]).
+
+init_ms(Config, Opts) when list(Config) ->
+ ?LOG("init_mib_storage_ets -> entry", []),
+ ?line SaNode = ?GCONF(snmp_sa, Config),
+ ?line create_tables(SaNode),
+ ?line AgentDir = ?GCONF(agent_dir, Config),
+ ?line MgrDir = ?GCONF(mgr_dir, Config),
+ ?line Ip = ?GCONF(ip, Config),
+ ?line config([v1], MgrDir, AgentDir, tuple_to_list(Ip), tuple_to_list(Ip)),
+ MasterAgentVerbosity = {snmp_master_agent_verbosity, trace},
+ MibsVerbosity = {snmp_mibserver_verbosity, trace},
+ SymStoreVerbosity = {snmp_symbolic_store_verbosity, trace},
+ Opts1 = [MasterAgentVerbosity,MibsVerbosity,SymStoreVerbosity|Opts],
+ [{vsn, v1} | start_v1_agent(Config,Opts1)].
+
+init_size_check_mse(Config) when list(Config) ->
+ MibStorage = {snmp_mib_storage, ets},
+ init_size_check_ms(Config, [MibStorage]).
+
+init_size_check_msd(Config) when list(Config) ->
+ AgentDir = ?GCONF(agent_dir, Config),
+ MibStorage = {snmp_mib_storage, {dets, AgentDir}},
+ init_size_check_ms(Config, [MibStorage]).
+
+init_size_check_msm(Config) when list(Config) ->
+ MibStorage = {snmp_mib_storage, {mnesia,[]}},
+ init_size_check_ms(Config, [MibStorage]).
+
+init_size_check_ms(Config, Opts) when list(Config) ->
+ SaNode = ?GCONF(snmp_sa, Config),
+ %% We are using v3 here, so crypto must be supported or else...
+ case ?CRYPTO_START() of
+ ok ->
+ case ?CRYPTO_SUPPORT() of
+ {no, Reason} ->
+ ?SKIP({unsupported_encryption, Reason});
+ yes ->
+ ok
+ end;
+ {error, Reason} ->
+ ?SKIP({failed_starting_crypto, Reason})
+ end,
+ create_tables(SaNode),
+ AgentDir = ?GCONF(agent_dir, Config),
+ MgrDir = ?GCONF(mgr_dir, Config),
+ Ip = ?GCONF(ip, Config),
+ ?line ok =
+ config([v3], MgrDir, AgentDir, tuple_to_list(Ip), tuple_to_list(Ip)),
+ [{vsn, v3} | start_agent(Config, [v3], Opts)].
+
+init_varm_mib_storage_dets(Config) when list(Config) ->
+ ?LOG("init_varm_mib_storage_dets -> entry", []),
+ ?line SaNode = ?GCONF(snmp_sa, Config),
+ ?line create_tables(SaNode),
+ ?line AgentDir = ?GCONF(agent_dir, Config),
+ ?line MgrDir = ?GCONF(mgr_dir, Config),
+ ?line Ip = ?GCONF(ip, Config),
+ ?line config([v1], MgrDir, AgentDir, tuple_to_list(Ip), tuple_to_list(Ip)),
+ MibStorage = {snmp_mib_storage,{dets,AgentDir}},
+ MasterAgentVerbosity = {snmp_master_agent_verbosity, trace},
+ MibsVerbosity = {snmp_mibserver_verbosity, trace},
+ SymStoreVerbosity = {snmp_symbolic_store_verbosity, trace},
+ Opts = [MibStorage,MasterAgentVerbosity,MibsVerbosity,SymStoreVerbosity],
+ [{vsn, v1}, {agent_opts,Opts} | Config].
+
+init_varm_mib_storage_mnesia(Config) when list(Config) ->
+ ?LOG("init_varm_mib_storage_mnesia -> entry", []),
+ ?line SaNode = ?GCONF(snmp_sa, Config),
+ ?line create_tables(SaNode),
+ ?line AgentDir = ?GCONF(agent_dir, Config),
+ ?line MgrDir = ?GCONF(mgr_dir, Config),
+ ?line Ip = ?GCONF(ip, Config),
+ ?line config([v1], MgrDir, AgentDir, tuple_to_list(Ip), tuple_to_list(Ip)),
+ MibStorage = {snmp_mib_storage,{mnesia,[]}},
+ MasterAgentVerbosity = {snmp_master_agent_verbosity, trace},
+ MibsVerbosity = {snmp_mibserver_verbosity, trace},
+ SymStoreVerbosity = {snmp_symbolic_store_verbosity, trace},
+ Opts = [MibStorage,MasterAgentVerbosity,MibsVerbosity,SymStoreVerbosity],
+ [{vsn, v1}, {agent_opts,Opts} | Config].
+
+finish_mib_storage_ets(Config) when list(Config) ->
+ ?LOG("finish_mib_storage_ets -> entry", []),
+ delete_tables(),
+ C1 = stop_agent(Config),
+ delete_files(C1),
+ C2 = lists:keydelete(vsn, 1, C1),
+ lists:keydelete(agent_opts, 1, C2).
+
+finish_mib_storage_dets(Config) when list(Config) ->
+ ?LOG("finish_mib_storage_dets -> entry", []),
+ delete_tables(),
+ C1 = stop_agent(Config),
+ delete_files(C1),
+ C2 = lists:keydelete(vsn, 1, C1),
+ lists:keydelete(agent_opts, 1, C2).
+
+finish_mib_storage_mnesia(Config) when list(Config) ->
+ ?LOG("finish_mib_storage_mnesia -> entry", []),
+ delete_tables(),
+ delete_mib_storage_mnesia_tables(),
+ C1 = stop_agent(Config),
+ delete_files(C1),
+ C2 = lists:keydelete(vsn, 1, C1),
+ lists:keydelete(agent_opts, 1, C2).
+
+finish_varm_mib_storage_dets(Config) when list(Config) ->
+ ?LOG("finish_varm_mib_storage_dets -> entry", []),
+ delete_tables(),
+ %% C1 = stop_agent(Config), % In case something went wrong...
+ delete_files(Config),
+ C2 = lists:keydelete(vsn, 1, Config),
+ lists:keydelete(agent_opts, 1, C2).
+
+finish_varm_mib_storage_mnesia(Config) when list(Config) ->
+ ?LOG("finish_varm_mib_storage_mnesia -> entry", []),
+ delete_tables(),
+ delete_mib_storage_mnesia_tables(),
+ %% C1 = stop_agent(Config), % In case something went wrong...
+ delete_files(Config),
+ C2 = lists:keydelete(vsn, 1, Config),
+ lists:keydelete(agent_opts, 1, C2).
+
+finish_size_check_mse(Config) when list(Config) ->
+ finish_size_check_ms(Config).
+
+finish_size_check_msd(Config) when list(Config) ->
+ finish_size_check_ms(Config).
+
+finish_size_check_msm(Config) when list(Config) ->
+ finish_size_check_ms(Config).
+
+finish_size_check_ms(Config) when list(Config) ->
+ delete_tables(),
+ C1 = stop_agent(Config),
+ delete_files(C1),
+ lists:keydelete(vsn, 1, C1).
+
+
+%% These are just interface functions to fool the test server
+mse_simple(X) -> simple(X).
+mse_v1_processing(X) -> v1_processing(X).
+mse_big(X) -> big(X).
+mse_big2(X) -> big2(X).
+mse_loop_mib(X) -> loop_mib(X).
+mse_api(X) -> api(X).
+mse_sa_register(X) -> sa_register(X).
+mse_v1_trap(X) -> v1_trap(X).
+mse_sa_error(X) -> sa_error(X).
+mse_next_across_sa(X) -> next_across_sa(X).
+mse_undo(X) -> undo(X).
+mse_standard_mib(X) -> snmp_standard_mib(X).
+mse_community_mib(X) -> snmp_community_mib(X).
+mse_framework_mib(X) -> snmp_framework_mib(X).
+mse_target_mib(X) -> snmp_target_mib(X).
+mse_notification_mib(X) -> snmp_notification_mib(X).
+mse_view_based_acm_mib(X) -> snmp_view_based_acm_mib(X).
+mse_sparse_table(X) -> sparse_table(X).
+mse_me_of(X) -> ms_me_of(X).
+mse_mib_of(X) -> ms_mib_of(X).
+
+msd_simple(X) -> simple(X).
+msd_v1_processing(X) -> v1_processing(X).
+msd_big(X) -> big(X).
+msd_big2(X) -> big2(X).
+msd_loop_mib(X) -> loop_mib(X).
+msd_api(X) -> api(X).
+msd_sa_register(X) -> sa_register(X).
+msd_v1_trap(X) -> v1_trap(X).
+msd_sa_error(X) -> sa_error(X).
+msd_next_across_sa(X) -> next_across_sa(X).
+msd_undo(X) -> undo(X).
+msd_standard_mib(X) -> snmp_standard_mib(X).
+msd_community_mib(X) -> snmp_community_mib(X).
+msd_framework_mib(X) -> snmp_framework_mib(X).
+msd_target_mib(X) -> snmp_target_mib(X).
+msd_notification_mib(X) -> snmp_notification_mib(X).
+msd_view_based_acm_mib(X) -> snmp_view_based_acm_mib(X).
+msd_sparse_table(X) -> sparse_table(X).
+msd_me_of(X) -> ms_me_of(X).
+msd_mib_of(X) -> ms_mib_of(X).
+
+msm_simple(X) -> simple(X).
+msm_v1_processing(X) -> v1_processing(X).
+msm_big(X) -> big(X).
+msm_big2(X) -> big2(X).
+msm_loop_mib(X) -> loop_mib(X).
+msm_api(X) -> api(X).
+msm_sa_register(X) -> sa_register(X).
+msm_v1_trap(X) -> v1_trap(X).
+msm_sa_error(X) -> sa_error(X).
+msm_next_across_sa(X) -> next_across_sa(X).
+msm_undo(X) -> undo(X).
+msm_standard_mib(X) -> snmp_standard_mib(X).
+msm_community_mib(X) -> snmp_community_mib(X).
+msm_framework_mib(X) -> snmp_framework_mib(X).
+msm_target_mib(X) -> snmp_target_mib(X).
+msm_notification_mib(X) -> snmp_notification_mib(X).
+msm_view_based_acm_mib(X) -> snmp_view_based_acm_mib(X).
+msm_sparse_table(X) -> sparse_table(X).
+msm_me_of(X) -> ms_me_of(X).
+msm_mib_of(X) -> ms_mib_of(X).
+
+
+mse_size_check(X) -> p("mse_size_check..."), ms_size_check(X).
+msd_size_check(X) -> p("msd_size_check..."), ms_size_check(X).
+msm_size_check(X) -> p("msm_size_check..."), ms_size_check(X).
+
+msd_varm_mib_start(X) -> p("msd_varm_mib_start..."), varm_mib_start(X).
+msm_varm_mib_start(X) -> p("msm_varm_mib_start..."), varm_mib_start(X).
+
+ms_size_check(suite) -> [];
+ms_size_check(Config) when list(Config) ->
+ p("ms_size_check..."),
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?LOG("mib server size check...", []),
+
+ ?line load_master("Test2"),
+ ?line load_master("TestTrap"),
+ ?line load_master("TestTrapv2"),
+ ?line load_master_std("OTP-SNMPEA-MIB"),
+ ?line load_master_std("SNMP-COMMUNITY-MIB"),
+ ?line load_master_std("SNMP-FRAMEWORK-MIB"),
+ ?line load_master_std("SNMP-MPD-MIB"),
+ ?line load_master_std("SNMP-NOTIFICATION-MIB"),
+ ?line load_master_std("SNMP-TARGET-MIB"),
+ ?line load_master_std("SNMP-USER-BASED-SM-MIB"),
+ ?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"),
+ ?line load_master_std("SNMPv2-MIB"),
+ ?line load_master_std("SNMPv2-TM"),
+
+ ?SLEEP(2000),
+
+ ?line display_memory_usage(),
+
+ ?line unload_master("OTP-SNMPEA-MIB"),
+ ?line unload_master("SNMP-COMMUNITY-MIB"),
+ ?line unload_master("SNMP-FRAMEWORK-MIB"),
+ ?line unload_master("SNMP-MPD-MIB"),
+ ?line unload_master("SNMP-NOTIFICATION-MIB"),
+ ?line unload_master("SNMP-TARGET-MIB"),
+ ?line unload_master("SNMP-USER-BASED-SM-MIB"),
+ ?line unload_master("SNMP-VIEW-BASED-ACM-MIB"),
+ ?line unload_master("SNMPv2-MIB"),
+ ?line unload_master("SNMPv2-TM"),
+
+ ?line unload_master("TestTrapv2"),
+ ?line unload_master("TestTrap"),
+ ?line unload_master("Test2"),
+
+ ok.
+
+
+varm_mib_start(suite) -> [];
+varm_mib_start(Config) when list(Config) ->
+ p("varm_mib_start..."),
+ ?LOG("varm_mib_start -> entry", []),
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ %% Start the agent
+ Opts = ?GCONF(agent_opts, Config),
+ Config1 = start_v1_agent(Config, Opts),
+
+ %% Sleep some in order for the agent to start properly
+ ?DBG("varm_mib_start -> sleep some (before loading mobs)", []),
+ ?SLEEP(5000),
+
+ %% Load all the mibs
+ HardwiredMibs = loaded_mibs(),
+ ?DBG("varm_mib_start -> load all mibs", []),
+ ?line load_master_std("SNMP-COMMUNITY-MIB"),
+ ?line load_master_std("SNMP-FRAMEWORK-MIB"),
+ ?line load_master_std("SNMP-TARGET-MIB"),
+ ?line load_master_std("SNMP-NOTIFICATION-MIB"),
+
+ %% Unload the hardwired mibs
+ ?DBG("varm_mib_start -> sleep some (before unloading hardwired mibs)", []),
+ ?SLEEP(1000),
+ ?DBG("varm_mib_start -> unload (hardwired) mibs", []),
+ ?line unload_mibs(HardwiredMibs), %% unload hardwired
+
+ ?DBG("varm_mib_start -> sleep some (before stopping agent)", []),
+ ?SLEEP(1000),
+
+ %% Stop the agent (without deleting the stored files)
+ ?DBG("varm_mib_start -> stop the agent", []),
+ Config2 = stop_agent(Config1),
+
+ %% Sleep some in order for the agent to stop properly
+ ?DBG("varm_mib_start -> sleep some (before re-starting the agent)", []),
+ ?SLEEP(5000),
+
+ %% Start the agent (again)
+ ?DBG("varm_mib_start -> start the agent", []),
+ Config3 = start_v1_agent(Config2, Opts),
+
+ ?DBG("varm_mib_start -> sleep some (before starting tests)", []),
+ ?SLEEP(5000),
+
+ %% Perform the test(s)
+ ?DBG("varm_mib_start -> perform the tests", []),
+ try_test(snmp_community_mib),
+ try_test(snmp_framework_mib),
+ try_test(snmp_target_mib),
+ try_test(snmp_notification_mib),
+
+ %% Stop the agent (without deleting the stored files)
+ ?DBG("varm_mib_start -> stop the agent", []),
+ stop_agent(Config3),
+ ok.
+
+
+-define(snmpTrapCommunity_instance, [1,3,6,1,6,3,18,1,4,0]).
+-define(vacmViewSpinLock_instance, [1,3,6,1,6,3,16,1,5,1,0]).
+-define(usmStatsNotInTimeWindows_instance, [1,3,6,1,6,3,15,1,1,2,0]).
+
+ms_me_of(suite) -> [];
+ms_me_of(Config) when list(Config) ->
+ p("ms_me_of..."),
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ ?line load_master("Test2"),
+ ?line load_master("TestTrap"),
+ ?line load_master("TestTrapv2"),
+ ?line load_master_std("OTP-SNMPEA-MIB"),
+ ?line load_master_std("SNMP-COMMUNITY-MIB"),
+ ?line load_master_std("SNMP-FRAMEWORK-MIB"),
+ ?line load_master_std("SNMP-MPD-MIB"),
+ ?line load_master_std("SNMP-NOTIFICATION-MIB"),
+ ?line load_master_std("SNMP-TARGET-MIB"),
+ ?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"),
+
+ ?SLEEP(2000),
+
+ ?line display_memory_usage(),
+
+
+ ?DBG("ms_me_of -> find ~w from SNMP-COMMUNITY-MIB",
+ [?snmpTrapCommunity_instance]),
+ ?line ok = me_of(?snmpTrapCommunity_instance),
+
+ ?DBG("ms_me_of -> find ~w from SNMP-VIEW-BASED-ACM-MIB",
+ [?vacmViewSpinLock_instance]),
+ ?line ok = me_of(?vacmViewSpinLock_instance),
+
+ ?DBG("ms_me_of -> find ~w from SNMP-USER-BASED-SM-MIB",
+ [?usmStatsNotInTimeWindows_instance]),
+ ?line {error, _} = me_of(?usmStatsNotInTimeWindows_instance),
+
+
+ ?line unload_master("OTP-SNMPEA-MIB"),
+ ?line unload_master("SNMP-COMMUNITY-MIB"),
+ ?line unload_master("SNMP-FRAMEWORK-MIB"),
+ ?line unload_master("SNMP-MPD-MIB"),
+ ?line unload_master("SNMP-NOTIFICATION-MIB"),
+ ?line unload_master("SNMP-TARGET-MIB"),
+ ?line unload_master("SNMP-VIEW-BASED-ACM-MIB"),
+
+ ?line unload_master("TestTrapv2"),
+ ?line unload_master("TestTrap"),
+ ?line unload_master("Test2"),
+
+ ok.
+
+me_of(Oid) ->
+ case snmpa:me_of(Oid) of
+ {ok, #me{oid = Oid}} ->
+ ok;
+ {ok, #me{oid = OtherOid}} ->
+ case lists:reverse(Oid) of
+ [0|Rest] ->
+ case lists:reverse(Rest) of
+ OtherOid ->
+ ok;
+ AnotherOid ->
+ {error, {invalid_oid, Oid, AnotherOid}}
+ end;
+ _ ->
+ {error, {invalid_oid, Oid, OtherOid}}
+ end;
+ {error, Reason} ->
+ {error, Reason};
+ Else ->
+ {error, Else}
+ end.
+
+
+ms_mib_of(suite) -> [];
+ms_mib_of(Config) when list(Config) ->
+ p("ms_mib_of..."),
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ ?line load_master("Test2"),
+ ?line load_master("TestTrap"),
+ ?line load_master("TestTrapv2"),
+ ?line load_master_std("OTP-SNMPEA-MIB"),
+ ?line load_master_std("SNMP-COMMUNITY-MIB"),
+ ?line load_master_std("SNMP-FRAMEWORK-MIB"),
+ ?line load_master_std("SNMP-MPD-MIB"),
+ ?line load_master_std("SNMP-NOTIFICATION-MIB"),
+ ?line load_master_std("SNMP-TARGET-MIB"),
+ ?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"),
+
+ ?SLEEP(2000),
+
+ ?line display_memory_usage(),
+
+
+ ?DBG("ms_mib_of -> find ~w from SNMP-COMMUNITY-MIB",
+ [?snmpTrapCommunity_instance]),
+ ?line ok = mib_of(?snmpTrapCommunity_instance, 'SNMP-COMMUNITY-MIB'),
+
+ ?DBG("ms_mib_of -> find ~w from SNMP-VIEW-BASED-ACM-MIB",
+ [?vacmViewSpinLock_instance]),
+ ?line ok = mib_of(?vacmViewSpinLock_instance, 'SNMP-VIEW-BASED-ACM-MIB'),
+
+ ?DBG("ms_mib_of -> find ~w from SNMP-USER-BASED-SM-MIB",
+ [?usmStatsNotInTimeWindows_instance]),
+ ?line {error, _} = mib_of(?usmStatsNotInTimeWindows_instance,
+ 'SNMP-USER-BASED-SM-MIB'),
+
+
+ ?line unload_master("OTP-SNMPEA-MIB"),
+ ?line unload_master("SNMP-COMMUNITY-MIB"),
+ ?line unload_master("SNMP-FRAMEWORK-MIB"),
+ ?line unload_master("SNMP-MPD-MIB"),
+ ?line unload_master("SNMP-NOTIFICATION-MIB"),
+ ?line unload_master("SNMP-TARGET-MIB"),
+ ?line unload_master("SNMP-VIEW-BASED-ACM-MIB"),
+
+ ?line unload_master("TestTrapv2"),
+ ?line unload_master("TestTrap"),
+ ?line unload_master("Test2"),
+
+ ok.
+
+mib_of(Oid, ExpectedMibName) ->
+ ?DBG("mib_of -> entry with"
+ "~n Oid: ~p"
+ "~n ExpectedMibName: ~p", [Oid, ExpectedMibName]),
+ %% case snmpa:mib_of(Oid) of
+ MibOf = snmpa:mib_of(Oid),
+ ?DBG("mib_of -> MibOf: ~n~p", [MibOf]),
+ case MibOf of
+ {ok, ExpectedMibName} ->
+ ok;
+ {ok, OtherMibName} ->
+ {error, {invalid_mib, ExpectedMibName, OtherMibName}};
+ {error, Reason} ->
+ {error, Reason};
+ Else ->
+ ?DBG("mib_of -> Else: ~n~p", [Else]),
+ {error, Else}
+ end.
+
+
+app_info(suite) -> [];
+app_info(Config) when list(Config) ->
+ SnmpDir = app_dir(snmp),
+ SslDir = app_dir(ssl),
+ CryptoDir = app_dir(crypto),
+ Attr = snmp:module_info(attributes),
+ AppVsn =
+ case lists:keysearch(app_vsn, 1, Attr) of
+ {value, {app_vsn, V}} ->
+ V;
+ false ->
+ "undefined"
+ end,
+ io:format("Root dir: ~s~n"
+ "SNMP: Application dir: ~s~n"
+ " Application ver: ~s~n"
+ "SSL: Application dir: ~s~n"
+ "CRYPTO: Application dir: ~s~n",
+ [code:root_dir(), SnmpDir, AppVsn, SslDir, CryptoDir]),
+ ok.
+
+app_dir(App) ->
+ case code:lib_dir(App) of
+ D when list(D) ->
+ filename:basename(D);
+ {error, _Reason} ->
+ "undefined"
+ end.
+
+
+test_v1(suite) -> {req, [], {conf, init_v1, v1_cases(), finish_v1}}.
+
+%v1_cases() -> [loop_mib];
+v1_cases() ->
+ [simple,
+ db_notify_client,
+ v1_processing, big, big2, loop_mib,
+ api, subagent, mnesia, multiple_reqs,
+ sa_register, v1_trap, sa_error, next_across_sa, undo, reported_bugs,
+ standard_mibs, sparse_table, cnt_64,
+ opaque,
+ % opaque].
+
+ change_target_addr_config].
+
+init_v1(Config) when list(Config) ->
+ ?line SaNode = ?config(snmp_sa, Config),
+ ?line create_tables(SaNode),
+ ?line AgentDir = ?config(agent_dir, Config),
+ ?line MgrDir = ?config(mgr_dir, Config),
+ ?line Ip = ?config(ip, Config),
+ ?line config([v1], MgrDir, AgentDir, tuple_to_list(Ip), tuple_to_list(Ip)),
+ [{vsn, v1} | start_v1_agent(Config)].
+
+finish_v1(Config) when list(Config) ->
+ delete_tables(),
+ C1 = stop_agent(Config),
+ delete_files(C1),
+ lists:keydelete(vsn, 1, C1).
+
+test_v2(suite) -> {req, [], {conf, init_v2, v2_cases(), finish_v2}}.
+
+%v2_cases() -> [loop_mib_2];
+v2_cases() ->
+ [simple_2, v2_processing, big_2, big2_2, loop_mib_2,
+ api_2, subagent_2, mnesia_2,
+ multiple_reqs_2, sa_register_2, v2_trap, v2_inform, sa_error_2,
+ next_across_sa_2, undo_2, reported_bugs_2, standard_mibs_2,
+ v2_types, implied, sparse_table_2, cnt_64_2, opaque_2, v2_caps].
+
+init_v2(Config) when list(Config) ->
+ SaNode = ?config(snmp_sa, Config),
+ create_tables(SaNode),
+ AgentDir = ?config(agent_dir, Config),
+ MgrDir = ?config(mgr_dir, Config),
+ Ip = ?config(ip, Config),
+ config([v2], MgrDir, AgentDir, tuple_to_list(Ip), tuple_to_list(Ip)),
+ [{vsn, v2} | start_v2_agent(Config)].
+
+finish_v2(Config) when list(Config) ->
+ delete_tables(),
+ C1 = stop_agent(Config),
+ delete_files(C1),
+ lists:keydelete(vsn, 1, C1).
+
+test_v1_v2(suite) -> {req, [], {conf, init_v1_v2, v1_v2_cases(), finish_v1_v2}}.
+
+v1_v2_cases() ->
+ [simple_bi].
+
+init_v1_v2(Config) when list(Config) ->
+ SaNode = ?config(snmp_sa, Config),
+ create_tables(SaNode),
+ AgentDir = ?config(agent_dir, Config),
+ MgrDir = ?config(mgr_dir, Config),
+ Ip = ?config(ip, Config),
+ config([v1,v2], MgrDir, AgentDir, tuple_to_list(Ip), tuple_to_list(Ip)),
+ [{vsn, bilingual} | start_bilingual_agent(Config)].
+
+finish_v1_v2(Config) when list(Config) ->
+ delete_tables(),
+ C1 = stop_agent(Config),
+ delete_files(C1),
+ lists:keydelete(vsn, 1, C1).
+
+test_v3(suite) -> {req, [], {conf, init_v3, v3_cases(), finish_v3}}.
+
+%v3_cases() -> [loop_mib_3];
+v3_cases() ->
+ [simple_3, v3_processing,
+ big_3, big2_3, api_3, subagent_3, mnesia_3, loop_mib_3,
+ multiple_reqs_3, sa_register_3, v3_trap, v3_inform, sa_error_3,
+ next_across_sa_3, undo_3, reported_bugs_3, standard_mibs_3,
+ v3_security,
+ v2_types_3, implied_3, sparse_table_3, cnt_64_3, opaque_3, v2_caps_3].
+
+init_v3(Config) when list(Config) ->
+ %% Make sure crypto works, otherwise start_agent will fail
+ %% and we will be stuck with a bunch of mnesia tables for
+ %% the rest of this suite...
+ ?DBG("start_agent -> start crypto app",[]),
+ case os:type() of
+ vxworks ->
+ no_crypto;
+ _ ->
+ case ?CRYPTO_START() of
+ ok ->
+ case ?CRYPTO_SUPPORT() of
+ {no, Reason} ->
+ ?SKIP({unsupported_encryption, Reason});
+ yes ->
+ ok
+ end;
+ {error, Reason} ->
+ ?SKIP({failed_starting_crypto, Reason})
+ end
+ end,
+ SaNode = ?config(snmp_sa, Config),
+ create_tables(SaNode),
+ AgentDir = ?config(agent_dir, Config),
+ MgrDir = ?config(mgr_dir, Config),
+ Ip = ?config(ip, Config),
+ ?line ok = config([v3], MgrDir, AgentDir,
+ tuple_to_list(Ip), tuple_to_list(Ip)),
+ [{vsn, v3} | start_v3_agent(Config)].
+
+finish_v3(Config) when list(Config) ->
+ delete_tables(),
+ C1 = stop_agent(Config),
+ delete_files(C1),
+ lists:keydelete(vsn, 1, C1).
+
+test_multi_threaded(suite) -> {req, [], {conf, init_mt, mt_cases(), finish_mt}}.
+
+mt_cases() ->
+ [multi_threaded, mt_trap].
+
+init_mt(Config) when list(Config) ->
+ SaNode = ?config(snmp_sa, Config),
+ create_tables(SaNode),
+ AgentDir = ?config(agent_dir, Config),
+ MgrDir = ?config(mgr_dir, Config),
+ Ip = ?config(ip, Config),
+ ?line ok = config([v2], MgrDir, AgentDir, tuple_to_list(Ip), tuple_to_list(Ip)),
+ [{vsn, v2} | start_multi_threaded_agent(Config)].
+
+finish_mt(Config) when list(Config) ->
+ delete_tables(),
+ C1 = stop_agent(Config),
+ delete_files(C1),
+ lists:keydelete(vsn, 1, C1).
+
+%% This one *must* be run first in each case.
+init_case(Config) when list(Config) ->
+ ?DBG("init_case -> entry with"
+ "~n Config: ~p", [Config]),
+ SaNode = ?config(snmp_sa, Config),
+ MgrNode = ?config(snmp_mgr, Config),
+ MasterNode = node(),
+
+ SaHost = ?HOSTNAME(SaNode),
+ MgrHost = ?HOSTNAME(MgrNode),
+ MasterHost = ?HOSTNAME(MasterNode),
+ {ok, MasterIP} = snmp_misc:ip(MasterHost),
+ {ok, MIP} = snmp_misc:ip(MgrHost),
+ {ok, SIP} = snmp_misc:ip(SaHost),
+
+
+ put(mgr_node, MgrNode),
+ put(sa_node, SaNode),
+ put(master_node, MasterNode),
+ put(sa_host, SaHost),
+ put(mgr_host, MgrHost),
+ put(master_host, MasterHost),
+ put(mip, tuple_to_list(MIP)),
+ put(masterip , tuple_to_list(MasterIP)),
+ put(sip, tuple_to_list(SIP)),
+
+ MibDir = ?config(mib_dir, Config),
+ put(mib_dir, MibDir),
+ StdM = filename:join(code:priv_dir(snmp), "mibs") ++ "/",
+ put(std_mib_dir, StdM),
+
+ MgrDir = ?config(mgr_dir, Config),
+ put(mgr_dir, MgrDir),
+
+ put(vsn, ?config(vsn, Config)),
+ ?DBG("init_case -> exit with"
+ "~n MasterNode: ~p"
+ "~n SaNode: ~p"
+ "~n MgrNode: ~p"
+ "~n MibDir: ~p", [MasterNode, SaNode, MgrNode, MibDir]),
+ {SaNode, MgrNode, MibDir}.
+
+load_master(Mib) ->
+ ?DBG("load_master -> entry with"
+ "~n Mib: ~p", [Mib]),
+ snmpa:unload_mibs(snmp_master_agent, [Mib]), % Unload for safety
+ ok = snmpa:load_mibs(snmp_master_agent, [get(mib_dir) ++ Mib]).
+
+load_master_std(Mib) ->
+ ?DBG("load_master_std -> entry with"
+ "~n Mib: ~p", [Mib]),
+ snmpa:unload_mibs(snmp_master_agent, [Mib]), % Unload for safety
+ ok = snmpa:load_mibs(snmp_master_agent, [get(std_mib_dir) ++ Mib]).
+
+unload_master(Mib) ->
+ ?DBG("unload_master -> entry with"
+ "~n Mib: ~p", [Mib]),
+ ok = snmpa:unload_mibs(snmp_master_agent, [Mib]).
+
+loaded_mibs() ->
+ ?DBG("loaded_mibs -> entry",[]),
+ Info = snmpa:info(snmp_master_agent),
+ {value, {loaded_mibs, Mibs}} = lists:keysearch(loaded_mibs, 1, Info),
+ [atom_to_list(Mib) || {Mib,_,_} <- Mibs].
+
+unload_mibs(Mibs) ->
+ ?DBG("unload_mibs -> entry with"
+ "~n Mibs: ~p", [Mibs]),
+ ok = snmpa:unload_mibs(snmp_master_agent, Mibs).
+
+start_subagent(SaNode, RegTree, Mib) ->
+ ?DBG("start_subagent -> entry with"
+ "~n SaNode: ~p"
+ "~n RegTree: ~p"
+ "~n Mib: ~p", [SaNode, RegTree, Mib]),
+ MA = whereis(snmp_master_agent),
+ ?DBG("start_subagent -> MA: ~p", [MA]),
+ MibDir = get(mib_dir),
+ Mib1 = join(MibDir,Mib),
+ %% BMK BMK
+% case rpc:call(SaNode,snmp_supervisor,start_subagent,[MA,RegTree,[Mib1]]) of
+ case rpc:call(SaNode, snmpa_supervisor,
+ start_sub_agent, [MA, RegTree, [Mib1]]) of
+ {ok, SA} ->
+ ?DBG("start_subagent -> SA: ~p", [SA]),
+ {ok, SA};
+ Error ->
+ ?FAIL({subagent_start_failed, SaNode, Error, [MA, RegTree, Mib1]})
+ end.
+
+stop_subagent(SA) ->
+ ?DBG("stop_subagent -> entry with"
+ "~n SA: ~p", [SA]),
+ %% BNK BMK
+ %% rpc:call(node(SA), snmp_supervisor, stop_subagent, [SA]).
+ rpc:call(node(SA), snmpa_supervisor, stop_sub_agent, [SA]).
+
+%%-----------------------------------------------------------------
+%% This function takes care of the old OTP-SNMPEA-MIB.
+%% Unfortunately, the testcases were written to use the data in the
+%% internal tables, and these table are now obsolete and not used
+%% by the agent. Therefore, we emulate them by using
+%% OLD-SNMPEA-MIB, which uses the default impl. of all tables.
+%%
+%% These two rows must exist in intCommunityTable
+%% {[147,214,36,45], "public", 2, readWrite}.
+%% {[147,214,36,45], "standard trap", 2, read}.
+%% (But with the manager's IP address)
+%%
+%%-----------------------------------------------------------------
+init_old() ->
+ snmpa_local_db:table_create_row(intCommunityTable,
+ get(mip) ++ [6 | "public"],
+ {get(mip), "public", 2, 2}),
+ snmpa_local_db:table_create_row(intCommunityTable,
+ get(mip) ++ [13 | "standard trap"],
+ {get(mip), "standard trap", 2, 1}),
+ snmpa_local_db:variable_set(intAgentIpAddress, [127,0,0,1]).
+
+
+
+simple(suite) -> [];
+simple(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ try_test(simple_standard_test).
+
+simple_2(X) -> simple(X).
+
+simple_bi(suite) -> [];
+simple_bi(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ put(vsn, v1), % First, try v1 manager
+ try_test(simple_standard_test),
+
+ put(vsn, v2), % Then, try v2 manager
+ try_test(simple_standard_test).
+
+simple_3(X) ->
+ simple(X).
+
+big(suite) -> [];
+big(Config) when list(Config) ->
+ ?DBG("big -> entry", []),
+ {SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ p("Starting subagent..."),
+ ?line pong = net_adm:ping(SaNode),
+
+ ?line {ok, SA} = start_subagent(SaNode, ?klas1, "Klas1"),
+ ?DBG("big -> SA: ~p", [SA]),
+ ?line load_master("OLD-SNMPEA-MIB"),
+ ?line init_old(),
+ try_test(big_test),
+ ?line stop_subagent(SA),
+ ?line unload_master("OLD-SNMPEA-MIB").
+
+big_2(X) -> big(X).
+
+big_3(X) -> big(X).
+
+
+big2(suite) -> [];
+big2(Config) when list(Config) ->
+ %% This is exactly the same tests as 'big', but with the
+ %% v2 equivalent of the mibs.
+ {SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ p("Starting subagent..."),
+ ?line pong = net_adm:ping(SaNode),
+
+ ?line {ok, SA} = start_subagent(SaNode, ?klas1, "Klas1-v2"),
+ ?line load_master("OLD-SNMPEA-MIB-v2"),
+ ?line init_old(),
+ try_test(big_test),
+ ?line stop_subagent(SA),
+ ?line unload_master("OLD-SNMPEA-MIB-v2").
+
+big2_2(X) -> big2(X).
+
+big2_3(X) -> big2(X).
+
+
+multi_threaded(suite) -> [];
+multi_threaded(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ ?line load_master("Test1"),
+ try_test(multi_threaded_test),
+ ?line unload_master("Test1").
+
+mt_trap(suite) -> [];
+mt_trap(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ MA = whereis(snmp_master_agent),
+
+ ?line load_master("Test1"),
+ ?line load_master("TestTrapv2"),
+ try_test(mt_trap_test, [MA]),
+ ?line unload_master("TestTrapv2"),
+ ?line unload_master("Test1").
+
+v2_types(suite) -> [];
+v2_types(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ ?line load_master("Test1"),
+ try_test(types_v2_test),
+ ?line unload_master("Test1").
+
+v2_types_3(X) -> v2_types(X).
+
+
+implied(suite) -> [];
+implied(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ MA = whereis(snmp_master_agent),
+
+ ?line load_master("Test1"),
+ try_test(implied_test,[MA]),
+ ?line unload_master("Test1").
+
+implied_3(X) -> implied(X).
+
+
+sparse_table(suite) -> [];
+sparse_table(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ ?line load_master("Test1"),
+ try_test(sparse_table_test),
+ ?line unload_master("Test1").
+
+sparse_table_2(X) -> sparse_table(X).
+
+sparse_table_3(X) -> sparse_table(X).
+
+cnt_64(suite) -> [];
+cnt_64(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ MA = whereis(snmp_master_agent),
+
+ ?line load_master("Test1"),
+ try_test(cnt_64_test, [MA]),
+ ?line unload_master("Test1").
+
+cnt_64_2(X) -> cnt_64(X).
+
+cnt_64_3(X) -> cnt_64(X).
+
+opaque(suite) -> [];
+opaque(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ ?line load_master("Test1"),
+ try_test(opaque_test),
+ ?line unload_master("Test1").
+
+opaque_2(X) -> opaque(X).
+
+opaque_3(X) -> opaque(X).
+
+
+change_target_addr_config(suite) -> [];
+change_target_addr_config(Config) when list(Config) ->
+ p("Testing changing target address config..."),
+ ?LOG("change_target_addr_config -> entry",[]),
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ put(sname,snmp_suite),
+ put(verbosity,trace),
+
+ MA = whereis(snmp_master_agent),
+
+ ?LOG("change_target_addr_config -> load TestTrap",[]),
+ ?line load_master("TestTrap"),
+
+ ?LOG("change_target_addr_config -> set trace verbosity for local_db",[]),
+ ?line snmpa:verbosity(local_db,trace),
+
+ %% First send some traps that will arive att the original manager
+ ?LOG("change_target_addr_config -> send trap",[]),
+ try_test(ma_trap1, [MA]),
+
+ ?LOG("change_target_addr_config -> set silence verbosity for local_db",[]),
+ ?line snmpa:verbosity(local_db,silence),
+
+ %% Start new dummy listener
+ ?LOG("change_target_addr_config -> start dummy manager",[]),
+ ?line {ok,Pid,NewPort} = dummy_manager_start(MA),
+
+ %% Reconfigure
+ ?LOG("change_target_addr_config -> reconfigure",[]),
+ AgentDir = ?config(agent_dir, Config),
+ ?line rewrite_target_addr_conf(AgentDir, NewPort),
+ ?line snmp_target_mib:reconfigure(AgentDir),
+
+ %% Send the trap again
+ ?LOG("change_target_addr_config -> send trap again",[]),
+ catch dummy_manager_send_trap2(Pid),
+
+ ?LOG("change_target_addr_config -> await trap ack",[]),
+ catch dummy_manager_await_trap2_ack(),
+
+ ?LOG("change_target_addr_config -> stop dummy manager",[]),
+ ?line ok = dummy_manager_stop(Pid),
+
+ ?LOG("change_target_addr_config -> reset target address config",[]),
+ ?line reset_target_addr_conf(AgentDir),
+
+ ?LOG("change_target_addr_config -> unload TestTrap",[]),
+ ?line unload_master("TestTrap").
+
+
+dummy_manager_start(MA) ->
+ ?DBG("dummy_manager_start -> entry",[]),
+ Pid = spawn(get(mgr_node), ?MODULE,dummy_manager_init,[self(),MA]),
+ ?DBG("dummy_manager_start -> Pid: ~p",[Pid]),
+ await_dummy_manager_started(Pid).
+
+await_dummy_manager_started(Pid) ->
+ receive
+ {dummy_manager_started,Pid,Port} ->
+ ?DBG("dummy_manager_start -> acknowledge received with"
+ "~n Port: ~p",[Port]),
+ {ok,Pid,Port};
+ {'EXIT', Pid, Reason} ->
+ {error, Pid, Reason};
+ O ->
+ ?LOG("dummy_manager_start -> received unknown message:"
+ "~n ~p",[O]),
+ await_dummy_manager_started(Pid)
+ end.
+
+dummy_manager_stop(Pid) ->
+ ?DBG("dummy_manager_stop -> entry with Pid: ~p",[Pid]),
+ Pid ! stop,
+ receive
+ {dummy_manager_stopping, Pid} ->
+ ?DBG("dummy_manager_stop -> acknowledge received",[]),
+ ok
+ after 10000 ->
+ ?ERR("dummy_manager_stop -> timeout",[]),
+ timeout
+ end.
+
+dummy_manager_send_trap2(Pid) ->
+ ?DBG("dummy_manager_send_trap2 -> entry",[]),
+ Pid ! {send_trap,testTrap2}.
+
+dummy_manager_await_trap2_ack() ->
+ ?DBG("dummy_manager_await_trap2 -> entry",[]),
+ receive
+ {received_trap,Trap} ->
+ ?LOG("dummy_manager_await_trap2 -> received trap: ~p",[Trap]),
+ %% Note:
+ %% Without this sleep the v2_inform_i testcase failes! There
+ %% is no relation between these two test cases as far as I
+ %% able to figure out...
+ sleep(60000),
+ ok;
+ O ->
+ ?ERR("dummy_manager_await_trap2 -> unexpected message: ~p",[O]),
+ ok
+ after 10000 ->
+ ?ERR("dummy_manager_await_trap2 -> timeout",[]),
+ timeout
+ end.
+
+dummy_manager_init(Parent,MA) ->
+ ?DBG("dummy_manager_init -> entry with"
+ "~n Parent: ~p"
+ "~n MA: ~p",[Parent,MA]),
+ {ok,S} = gen_udp:open(0,[{recbuf,65535}]),
+ ?DBG("dummy_manager_init -> S: ~p",[S]),
+ {ok,Port} = inet:port(S),
+ ?DBG("dummy_manager_init -> Port: ~p",[Port]),
+ Parent ! {dummy_manager_started,self(),Port},
+ dummy_manager_loop(Parent,S,MA).
+
+dummy_manager_loop(P,S,MA) ->
+ ?LOG("dummy_manager_loop -> ready for receive",[]),
+ receive
+ {send_trap,Trap} ->
+ ?LOG("dummy_manager_loop -> received trap send request"
+ "~n Trap: ~p",[Trap]),
+ snmpa:send_trap(MA, Trap, "standard trap"),
+ dummy_manager_loop(P,S,MA);
+ {udp, _UdpId, Ip, UdpPort, Bytes} ->
+ ?LOG("dummy_manager_loop -> received upd message"
+ "~n from: ~p:~p"
+ "~n size: ~p",
+ [Ip, UdpPort, dummy_manager_message_sz(Bytes)]),
+ R = dummy_manager_handle_message(Bytes),
+ ?DBG("dummy_manager_loop -> R: ~p",[R]),
+ P ! R,
+ dummy_manager_loop(P,S,MA);
+ stop ->
+ ?DBG("dummy_manager_loop -> received stop request",[]),
+ P ! {dummy_manager_stopping, self()},
+ gen_udp:close(S),
+ exit(normal);
+ O ->
+ ?LOG("dummy_manager_loop -> received unknown message:"
+ "~n ~p",[O]),
+ dummy_manager_loop(P,S,MA)
+ end.
+
+dummy_manager_message_sz(B) when binary(B) ->
+ size(B);
+dummy_manager_message_sz(L) when list(L) ->
+ length(L);
+dummy_manager_message_sz(_) ->
+ undefined.
+
+dummy_manager_handle_message(Bytes) ->
+ case (catch snmp_pdus:dec_message(Bytes)) of
+ {'EXIT',Reason} ->
+ ?ERR("dummy_manager_handle_message -> "
+ "failed decoding message only:~n ~p",[Reason]),
+ {error,Reason};
+ M ->
+ ?DBG("dummy_manager_handle_message -> decoded message:"
+ "~n ~p",[M]),
+ {received_trap,M}
+ end.
+
+
+api(suite) -> [];
+api(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ ?line load_master("OLD-SNMPEA-MIB"),
+ ?line init_old(),
+ try_test(api_test, [node()]),
+ ?line unload_master("OLD-SNMPEA-MIB").
+
+api_2(X) -> api(X).
+
+api_3(X) -> api(X).
+
+
+subagent(suite) -> [];
+subagent(Config) when list(Config) ->
+ {SaNode, _MgrNode, MibDir} = init_case(Config),
+
+ ?line {ok, SA} = start_subagent(SaNode, ?klas1, "Klas1"),
+ try_test(load_test_sa),
+
+ p("Testing unregister subagent..."),
+ MA = whereis(snmp_master_agent),
+ rpc:call(SaNode, snmp, unregister_subagent, [MA, SA]),
+ try_test(unreg_test),
+
+ p("Loading previous subagent mib in master and testing..."),
+ ?line ok = snmpa:load_mibs(MA, [MibDir ++ "Klas1"]),
+ try_test(load_test),
+
+ p("Unloading previous subagent mib in master and testing..."),
+ ?line ok = snmpa:unload_mibs(MA, [MibDir ++ "Klas1"]),
+ try_test(unreg_test),
+ p("Testing register subagent..."),
+ rpc:call(SaNode, snmp, register_subagent,
+ [MA, ?klas1, SA]),
+ try_test(load_test_sa),
+
+ ?line stop_subagent(SA),
+ try_test(unreg_test).
+
+subagent_2(X) -> subagent(X).
+
+subagent_3(X) -> subagent(X).
+
+
+mnesia(suite) -> [];
+mnesia(Config) when list(Config) ->
+ {SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ p("Starting subagent with mnesia impl..."),
+ {ok, SA} = start_subagent(SaNode, ?klas2, "Klas2"),
+ ?line load_master("OLD-SNMPEA-MIB"),
+ ?line init_old(),
+
+ try_test(big_test_2),
+
+ p("Testing unregister subagent..."),
+ MA = whereis(snmp_master_agent),
+ rpc:call(SaNode, snmp, unregister_subagent, [MA, SA]),
+ try_test(unreg_test),
+ ?line unload_master("OLD-SNMPEA-MIB"),
+ ?line stop_subagent(SA).
+
+mnesia_2(X) -> mnesia(X).
+
+mnesia_3(X) -> mnesia(X).
+
+
+multiple_reqs(suite) ->
+ {req, [], {conf, init_mul, mul_cases(), finish_mul}}.
+
+mul_cases() ->
+ [mul_get, mul_get_err, mul_next, mul_next_err, mul_set_err].
+
+multiple_reqs_2(suite) ->
+ {req, [], {conf, init_mul, mul_cases_2(), finish_mul}}.
+
+multiple_reqs_3(_X) ->
+ {req, [], {conf, init_mul, mul_cases_3(), finish_mul}}.
+
+
+mul_cases_2() ->
+ [mul_get_2, mul_get_err_2, mul_next_2, mul_next_err_2, mul_set_err_2].
+
+
+mul_cases_3() ->
+ [mul_get_3, mul_get_err_3, mul_next_3, mul_next_err_3, mul_set_err_3].
+
+
+init_mul(Config) when list(Config) ->
+ {SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ ?line {ok, SA} = start_subagent(SaNode, ?klas1, "Klas1"),
+ ?line load_master("OLD-SNMPEA-MIB"),
+ ?line init_old(),
+ [{mul_sub, SA} | Config].
+
+finish_mul(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ SA = ?config(mul_sub, Config),
+
+ ?line unload_master("OLD-SNMPEA-MIB"),
+ ?line stop_subagent(SA),
+ lists:keydelete(mul_sub, 1, Config).
+
+mul_get(suite) -> [];
+mul_get(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ p("Testing multiple get..."),
+ try_test(do_mul_get).
+
+mul_get_2(X) -> mul_get(X).
+
+mul_get_3(X) -> mul_get(X).
+
+
+mul_get_err(suite) -> [];
+mul_get_err(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ p("Testing multiple get with error..."),
+ try_test(do_mul_get_err).
+
+mul_get_err_2(X) -> mul_get_err(X).
+
+mul_get_err_3(X) -> mul_get_err(X).
+
+
+mul_next(suite) -> [];
+mul_next(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ p("Testing multiple next..."),
+ try_test(do_mul_next).
+
+mul_next_2(X) -> mul_next(X).
+
+mul_next_3(X) -> mul_next(X).
+
+
+mul_next_err(suite) -> [];
+mul_next_err(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ p("Testing multiple next..."),
+ try_test(do_mul_next_err).
+
+mul_next_err_2(X) -> mul_next_err(X).
+
+mul_next_err_3(X) -> mul_next_err(X).
+
+
+mul_set(suite) -> [];
+mul_set(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ p("Testing multiple set..."),
+ try_test(do_mul_set).
+
+mul_set_2(X) -> mul_set(X).
+
+mul_set_3(X) -> mul_set(X).
+
+
+mul_set_err(suite) -> [];
+mul_set_err(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ p("Testing multiple set with error..."),
+ try_test(do_mul_set_err).
+
+mul_set_err_2(X) -> mul_set_err(X).
+
+mul_set_err_3(X) -> mul_set_err(X).
+
+
+sa_register(suite) -> [];
+sa_register(Config) when list(Config) ->
+ ?DBG("sa_register -> entry", []),
+ {SaNode, _MgrNode, MibDir} = init_case(Config),
+
+ ?DBG("sa_register -> start subagent", []),
+ ?line {ok, SA} = start_subagent(SaNode, ?klas1, "Klas1"),
+
+ ?DBG("sa_register -> unregister subagent", []),
+ p("Testing unregister subagent (2)..."),
+ MA = whereis(snmp_master_agent),
+ rpc:call(SaNode, snmp, unregister_subagent, [MA, ?klas1]),
+ try_test(unreg_test),
+
+ p("Loading SA-MIB..."),
+ ?DBG("sa_register -> unload mibs", []),
+ snmpa:unload_mibs(SA, [MibDir ++ "Klas1"]),
+ ?DBG("sa_register -> unload mibs", []),
+ snmpa:load_mibs(SA, [MibDir ++ "SA-MIB"]),
+ ?DBG("sa_register -> register subagent", []),
+ rpc:call(SaNode, snmp, register_subagent, [MA,?sa,SA]),
+ try_test(sa_mib),
+
+ ?DBG("sa_register -> stop subagent", []),
+ ?line stop_subagent(SA).
+
+sa_register_2(X) -> sa_register(X).
+
+sa_register_3(X) -> sa_register(X).
+
+
+v1_trap(suite) -> [];
+v1_trap(Config) when list(Config) ->
+ {SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ ?line {ok, SA} = start_subagent(SaNode, ?sa, "SA-MIB"),
+
+ p("Testing trap sending from master agent..."),
+ MA = whereis(snmp_master_agent),
+
+ ?line load_master("TestTrap"),
+ ?line load_master("TestTrapv2"),
+
+ try_test(ma_trap1, [MA]),
+ try_test(ma_trap2, [MA]),
+ try_test(ma_v2_2_v1_trap, [MA]),
+ try_test(ma_v2_2_v1_trap2, [MA]),
+
+ p("Testing trap sending from subagent..."),
+ try_test(sa_trap1, [SA]),
+ try_test(sa_trap2, [SA]),
+ try_test(sa_trap3, [SA]),
+
+ ?line unload_master("TestTrap"),
+ ?line unload_master("TestTrapv2"),
+
+ ?line stop_subagent(SA).
+
+v2_trap(suite) -> [];
+v2_trap(Config) when list(Config) ->
+ {SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ ?line {ok, SA} = start_subagent(SaNode, ?sa, "SA-MIB"),
+
+ p("Testing trap sending from master agent..."),
+ MA = whereis(snmp_master_agent),
+
+ ?line load_master("TestTrap"),
+ ?line load_master("TestTrapv2"),
+
+
+ try_test(ma_v2_trap1, [MA]),
+ try_test(ma_v2_trap2, [MA]),
+ try_test(ma_v1_2_v2_trap, [MA]),
+ try_test(ma_v1_2_v2_trap2, [MA]),
+
+ try_test(sa_mib),
+ p("Testing trap sending from subagent..."),
+ try_test(sa_v1_2_v2_trap1, [SA]),
+ try_test(sa_v1_2_v2_trap2, [SA]),
+ try_test(sa_v1_2_v2_trap3, [SA]),
+
+ ?line unload_master("TestTrap"),
+ ?line unload_master("TestTrapv2"),
+
+ ?line stop_subagent(SA).
+
+v3_trap(X) ->
+ v2_trap(X).
+
+v2_inform(suite) ->
+ {req, [], {conf, init_v2_inform, [v2_inform_i], finish_v2_inform}}.
+
+v3_inform(_X) ->
+ %% v2_inform(X).
+ {req, [], {conf, init_v3_inform, [v3_inform_i], finish_v3_inform}}.
+
+init_v2_inform(Config) when list(Config) ->
+ _Dir = ?config(agent_dir, Config),
+% snmp_internal_mib:configure(Dir),
+ Config.
+
+init_v3_inform(X) ->
+ init_v2_inform(X).
+
+finish_v2_inform(Config) when list(Config) ->
+ _Dir = ?config(agent_dir, Config),
+% snmp_internal_mib:configure(Dir),
+ Config.
+
+finish_v3_inform(X) ->
+ finish_v2_inform(X).
+
+
+
+v2_inform_i(suite) -> [];
+v2_inform_i(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ p("Testing inform sending from master agent... NOTE! This test\ntakes a "
+ "few minutes (5) to complete."),
+ MA = whereis(snmp_master_agent),
+
+ ?line load_master("TestTrap"),
+ ?line load_master("TestTrapv2"),
+
+ try_test(ma_v2_inform1, [MA]),
+
+ ?line unload_master("TestTrap"),
+ ?line unload_master("TestTrapv2").
+
+v3_inform_i(X) -> v2_inform_i(X).
+
+
+sa_error(suite) -> [];
+sa_error(Config) when list(Config) ->
+ {SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ ?line load_master("OLD-SNMPEA-MIB"),
+ ?line init_old(),
+ ?line {ok, SA} = start_subagent(SaNode, ?sa, "SA-MIB"),
+
+ p("Testing sa bad value (is_set_ok)..."),
+ try_test(sa_errs_bad_value),
+
+ p("Testing sa gen err (set)..."),
+ try_test(sa_errs_gen_err),
+
+ p("Testing too big..."),
+ try_test(sa_too_big),
+
+ ?line unload_master("OLD-SNMPEA-MIB"),
+ stop_subagent(SA).
+
+sa_error_2(X) -> sa_error(X).
+
+sa_error_3(X) -> sa_error(X).
+
+
+next_across_sa(suite) -> [];
+next_across_sa(Config) when list(Config) ->
+ {SaNode, _MgrNode, MibDir} = init_case(Config),
+ MA = whereis(snmp_master_agent),
+
+ ?line {ok, SA} = start_subagent(SaNode, ?sa, "SA-MIB"),
+
+ p("Loading another subagent mib..."),
+ ?line ok = snmpa:load_mibs(SA, [MibDir ++ "Klas1"]),
+
+ rpc:call(SaNode, snmp, register_subagent, [MA, ?klas1, SA]),
+ try_test(load_test_sa),
+
+ p("Testing next across subagent (endOfMibView from SA)..."),
+ try_test(next_across_sa),
+
+ p("Unloading mib"),
+ snmpa:unload_mibs(SA, [MibDir ++ "Klas1"]),
+ rpc:call(SaNode, snmp, unregister_subagent, [MA, ?klas1]),
+ try_test(unreg_test),
+
+ p("Starting another subagent"),
+ ?line {ok, SA2} = start_subagent(SaNode, ?klas1, "Klas1"),
+ p("Testing next across subagent (wrong prefix from SA)..."),
+ try_test(next_across_sa),
+
+ stop_subagent(SA),
+ stop_subagent(SA2).
+
+next_across_sa_2(X) -> next_across_sa(X).
+
+next_across_sa_3(X) -> next_across_sa(X).
+
+
+undo(suite) -> [];
+undo(Config) when list(Config) ->
+ {SaNode, _MgrNode, MibDir} = init_case(Config),
+ MA = whereis(snmp_master_agent),
+
+ ?line {ok, SA} = start_subagent(SaNode, ?sa, "SA-MIB"),
+
+ p("Testing undo phase at master agent..."),
+ ?line ok = snmpa:load_mibs(MA, [MibDir ++ "Klas3"]),
+ ?line ok = snmpa:load_mibs(MA, [MibDir ++ "Klas4"]),
+ try_test(undo_test),
+ try_test(api_test2),
+ ?line ok = snmpa:unload_mibs(MA, [MibDir ++ "Klas3"]),
+
+ p("Testing bad return values from instrum. funcs..."),
+ try_test(bad_return),
+
+ ?line ok = snmpa:unload_mibs(MA, [MibDir ++ "Klas4"]),
+
+ p("Testing undo phase at subagent..."),
+ ?line ok = snmpa:load_mibs(SA, [MibDir ++ "Klas3"]),
+ ?line ok = snmpa:load_mibs(SA, [MibDir ++ "Klas4"]),
+ ?line ok = snmpa:register_subagent(MA, ?klas3, SA),
+ ?line ok = snmpa:register_subagent(MA, ?klas4, SA),
+ try_test(undo_test),
+ try_test(api_test3),
+
+ p("Testing undo phase across master/subagents..."),
+ try_test(undo_test),
+ try_test(api_test3),
+ stop_subagent(SA).
+
+undo_2(X) -> undo(X).
+
+undo_3(X) -> undo(X).
+
+%% Req. Test2
+v1_processing(suite) -> [];
+v1_processing(Config) when list(Config) ->
+ ?DBG("v1_processing -> entry", []),
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ ?line load_master("Test2"),
+ try_test(v1_proc),
+ ?line unload_master("Test2").
+
+%% Req. Test2
+v2_processing(suite) -> [];
+v2_processing(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ ?line load_master("Test2"),
+ try_test(v2_proc),
+ ?line unload_master("Test2").
+
+%% Req. Test2
+v3_processing(suite) -> [];
+v3_processing(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ ?line load_master("Test2"),
+ try_test(v2_proc), % same as v2!
+ ?line unload_master("Test2").
+
+
+%% We'll try get/set/trap and inform for all the auth & priv protocols.
+%% For informs, the mgr is auth-engine. The agent has to sync. This is
+%% accomplished by the first inform sent. That one will generate a
+%% report, which makes it in sync. The notification-generating
+%% application times out, and send again. This time it'll work.
+v3_security(suite) -> [v3_crypto_basic, v3_md5_auth, v3_sha_auth, v3_des_priv].
+
+v3_crypto_basic(suite) -> [];
+v3_crypto_basic(_Config) ->
+ EID = [0,0,0,0,0,0,0,0,0,0,0,2],
+ %% From rfc2274 appendix A.3.1
+ ?line KMd5_1 = snmp:passwd2localized_key(md5, "maplesyrup", EID),
+ ?line [16#52,16#6f,16#5e,16#ed,16#9f,16#cc,16#e2,16#6f,
+ 16#89,16#64,16#c2,16#93,16#07,16#87,16#d8,16#2b] =
+ KMd5_1,
+ %% From rfc2274 appendix A.3.2
+ ?line KSHA_1 = snmp:passwd2localized_key(sha, "maplesyrup", EID),
+ ?line [16#66,16#95,16#fe,16#bc,16#92,16#88,16#e3,16#62,16#82,16#23,
+ 16#5f,16#c7,16#15,16#1f,16#12,16#84,16#97,16#b3,16#8f,16#3f] =
+ KSHA_1,
+ %% From rfc2274, appendix A.5.1
+ ?line KMd5_2 = snmp:passwd2localized_key(md5, "newsyrup", EID),
+ ?line [16#00,16#00,16#00,16#00,16#00,16#00,16#00,16#00,
+ 16#00,16#00,16#00,16#00,16#00,16#00,16#00,16#00,
+ 16#88,16#05,16#61,16#51,16#41,16#67,16#6c,16#c9,
+ 16#19,16#61,16#74,16#e7,16#42,16#a3,16#25,16#51] =
+ snmp_user_based_sm_mib:mk_key_change(md5, KMd5_1, KMd5_2, 16,
+ [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]),
+ %% From rfc2274, appendix A.5.2
+ ?line KSHA_2 = snmp:passwd2localized_key(sha, "newsyrup", EID),
+ ?line [16#00,16#00,16#00,16#00,16#00,16#00,16#00,16#00,
+ 16#00,16#00,16#00,16#00,16#00,16#00,16#00,16#00,
+ 16#00,16#00,16#00,16#00,16#9c,16#10,16#17,16#f4,
+ 16#fd,16#48,16#3d,16#2d,16#e8,16#d5,16#fa,16#db,
+ 16#f8,16#43,16#92,16#cb,16#06,16#45,16#70,16#51] =
+ snmp_user_based_sm_mib:mk_key_change(sha, KSHA_1, KSHA_2, 20,
+ [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]),
+ KSHA_1t = lists:sublist(KSHA_1, 16),
+ KSHA_2t = lists:sublist(KSHA_2, 16),
+ ?line [16#00,16#00,16#00,16#00,16#00,16#00,16#00,16#00,
+ 16#00,16#00,16#00,16#00,16#00,16#00,16#00,16#00,
+ 16#7e,16#f8,16#d8,16#a4,16#c9,16#cd,16#b2,16#6b,
+ 16#47,16#59,16#1c,16#d8,16#52,16#ff,16#88,16#b5] =
+ snmp_user_based_sm_mib:mk_key_change(sha, KSHA_1t, KSHA_2t, 16,
+ [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]),
+
+ %% Try with correct random
+ ?line Kc1 = snmp_user_based_sm_mib:mk_key_change(md5, KMd5_1, KMd5_2),
+ ?line KMd5_2 = snmp_user_based_sm_mib:extract_new_key(md5, KMd5_1, Kc1),
+ ?line Kc2 = snmp_user_based_sm_mib:mk_key_change(sha, KSHA_1, KSHA_2),
+ ?line KSHA_2 = snmp_user_based_sm_mib:extract_new_key(sha, KSHA_1, Kc2),
+ ok.
+
+
+
+v3_md5_auth(suite) -> [];
+v3_md5_auth(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ p("Testing MD5 authentication...takes a few seconds..."),
+
+ AgentDir = ?config(agent_dir, Config),
+ ?line rewrite_target_params_conf(AgentDir, "authMD5", authNoPriv),
+ ?line snmp_target_mib:reconfigure(AgentDir),
+
+ MA = whereis(snmp_master_agent),
+
+ ?line load_master("Test2"),
+ ?line load_master("TestTrap"),
+ ?line load_master("TestTrapv2"),
+
+ try_test(v3_sync, [[{v2_proc, []},
+ {ma_v2_trap1, [MA]},
+ {v3_inform_sync, [MA]}]],
+ [{sec_level, authNoPriv}, {user, "authMD5"}]),
+
+ ?line unload_master("TestTrapv2"),
+ ?line unload_master("TestTrap"),
+ ?line unload_master("Test2"),
+ ?line reset_target_params_conf(AgentDir).
+
+v3_sha_auth(suite) -> [];
+v3_sha_auth(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ p("Testing SHA authentication...takes a few seconds..."),
+
+ AgentDir = ?config(agent_dir, Config),
+ ?line rewrite_target_params_conf(AgentDir, "authSHA", authNoPriv),
+ ?line snmp_target_mib:reconfigure(AgentDir),
+
+ MA = whereis(snmp_master_agent),
+
+ ?line load_master("Test2"),
+ ?line load_master("TestTrap"),
+ ?line load_master("TestTrapv2"),
+
+ try_test(v3_sync, [[{v2_proc, []},
+ {ma_v2_trap1, [MA]},
+ {v3_inform_sync, [MA]}]],
+ [{sec_level, authNoPriv}, {user, "authSHA"}]),
+
+ ?line unload_master("TestTrapv2"),
+ ?line unload_master("TestTrap"),
+ ?line unload_master("Test2"),
+ ?line reset_target_params_conf(AgentDir).
+
+v3_des_priv(suite) -> [];
+v3_des_priv(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ p("Testing DES encryption...takes a few seconds..."),
+
+ AgentDir = ?config(agent_dir, Config),
+ ?line rewrite_target_params_conf(AgentDir, "privDES", authPriv),
+ ?line snmp_target_mib:reconfigure(AgentDir),
+
+ MA = whereis(snmp_master_agent),
+
+ ?line load_master("Test2"),
+ ?line load_master("TestTrap"),
+ ?line load_master("TestTrapv2"),
+
+ try_test(v3_sync, [[{v2_proc, []},
+ {ma_v2_trap1, [MA]},
+ {v3_inform_sync, [MA]}]],
+ [{sec_level, authPriv}, {user, "privDES"}]),
+
+ ?line unload_master("TestTrapv2"),
+ ?line unload_master("TestTrap"),
+ ?line unload_master("Test2"),
+ ?line reset_target_params_conf(AgentDir).
+
+%% -define(usmStatsNotInTimeWindows_instance, [1,3,6,1,6,3,15,1,1,2,0]).
+
+%% Make sure mgr is in sync with agent
+v3_sync(Funcs) ->
+ ?DBG("v3_sync -> entry with Funcs: ~p",[Funcs]),
+ g([[sysDescr, 0]]),
+ expect(432, report, [{?usmStatsNotInTimeWindows_instance, any}]),
+ g([[sysDescr, 0]]),
+ expect(433, [{[sysDescr,0], any}]),
+ lists:foreach(fun({Func, Args}) -> apply(?MODULE, Func, Args) end, Funcs).
+
+v3_inform_sync(MA) ->
+ ?DBG("v3_sync -> entry with MA: ~p => Send notification",[MA]),
+ ?line snmpa:send_notification(MA, testTrapv22, no_receiver,
+ "standard inform", []),
+ %% Make sure agent is in sync with mgr...
+ ?DBG("v3_sync -> wait some time: ",[]),
+ sleep(20000), % more than 1500*10 in target_addr.conf
+ ?DBG("v3_sync -> await response",[]),
+ ?line expect(1, {inform, true},
+ [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?system ++ [0,1]}]).
+
+
+v2_caps(suite) -> [];
+v2_caps(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ try_test(v2_caps_i, [node()]).
+
+v2_caps_3(X) -> v2_caps(X).
+
+
+v2_caps_i(Node) ->
+ ?line Idx = rpc:call(Node, snmp, add_agent_caps, [[1,2,3,4,5], "test cap"]),
+ g([[sysORID, Idx], [sysORDescr, Idx]]),
+ ?line expect(1, [{[sysORID, Idx], [1,2,3,4,5]},
+ {[sysORDescr, Idx], "test cap"}]),
+ ?line rpc:call(Node, snmp, del_agent_caps, [Idx]),
+ g([[sysORID, Idx]]),
+ ?line expect(2, [{[sysORID, Idx], noSuchInstance}]).
+
+
+%% Req. Test2
+v1_proc() ->
+ ?DBG("v1_proc -> entry", []),
+ %% According to RFC1157.
+ %% Template: <Section>:<list no>
+ v1_get_p(),
+ v1_get_next_p(),
+ v1_set_p().
+
+
+v1_get_p() ->
+ %% 4.1.2:1
+ g([[test2]]),
+ ?line expect(10, noSuchName, 1, [{[test2], 'NULL'}]),
+ g([[tDescr]]),
+ ?line expect(11, noSuchName, 1, [{[tDescr], 'NULL'}]),
+ g([[tDescr2,0]]),
+ ?line expect(12, noSuchName, 1, [{[tDescr2,0], 'NULL'}]),
+ g([[tDescr3,0]]),
+ ?line expect(131, noSuchName, 1, [{[tDescr3,0], 'NULL'}]),
+ g([[tDescr4,0]]),
+ ?line expect(132, noSuchName, 1, [{[tDescr4,0], 'NULL'}]),
+ g([[sysDescr, 0], [tDescr,0]]), % Outside mibview
+ ?line expect(14, noSuchName, 2, [{[sysDescr, 0], 'NULL'},
+ {[tDescr,0], 'NULL'}]),
+ g([[sysDescr,3]]),
+ ?line expect(15, noSuchName, 1, [{[sysDescr, 3], 'NULL'}]),
+
+ %% 4.1.2:2
+ g([[tTable]]),
+ ?line expect(20, noSuchName, 1, [{[tTable], 'NULL'}]),
+ g([[tEntry]]),
+ ?line expect(21, noSuchName, 1, [{[tEntry], 'NULL'}]),
+
+ %% 4.1.2:3
+ g([[tTooBig, 0]]),
+ ?line expect(30, tooBig, 0, [{[tTooBig, 0], 'NULL'}]),
+
+ %% 4.1.2:4
+ g([[tGenErr1, 0]]),
+ ?line expect(40, genErr, 1, [{[tGenErr1, 0], 'NULL'}]),
+ g([[tGenErr2, 0]]),
+ ?line expect(41, genErr, 1, [{[tGenErr2, 0], 'NULL'}]),
+ g([[sysDescr, 0], [tGenErr3, 0]]),
+ ?line expect(42, genErr, 2, [{[sysDescr, 0], 'NULL'},
+ {[tGenErr3, 0], 'NULL'}]).
+
+
+v1_get_next_p() ->
+ %% 4.1.3:1
+ gn([[1,3,7,1]]),
+ ?line expect(10, noSuchName, 1, [{[1,3,7,1], 'NULL'}]),
+ gn([[tDescr2]]),
+ ?line expect(11, tooBig, 0, any),
+
+ %% 4.1.3:2
+ gn([[tTooBig]]),
+ io:format("We currently don't handle tooBig correct!!!\n"),
+% ?line expect(20, tooBig, 0, [{[tTooBig], 'NULL'}]),
+ ?line expect(20, tooBig, 0, any),
+
+ %% 4.1.3:3
+ gn([[tGenErr1]]),
+% ?line expect(40, genErr, 1, [{[tGenErr1], 'NULL'}]),
+ ?line expect(40, genErr, 1, any),
+ gn([[tGenErr2]]),
+% ?line expect(41, genErr, 1, [{[tGenErr2], 'NULL'}]),
+ ?line expect(41, genErr, 1, any),
+ gn([[sysDescr], [tGenErr3]]),
+% ?line expect(42, genErr, 2, [{[sysDescr], 'NULL'},
+% {[tGenErr3], 'NULL'}]).
+ ?line expect(42, genErr, 2, any).
+
+v1_set_p() ->
+ %% 4.1.5:1
+ s([{[1,3,7,0], i, 4}]),
+ ?line expect(10, noSuchName, 1, [{[1,3,7,0], 4}]),
+ s([{[tDescr,0], s, "outside mibview"}]),
+ ?line expect(11, noSuchName, 1, [{[tDescr,0], "outside mibview"}]),
+ s([{[tDescr3,0], s, "read-only"}]),
+ ?line expect(12, noSuchName, 1, [{[tDescr3,0], "read-only"}]),
+ s([{[tDescr3], s, "noSuchObject"}]),
+ ?line expect(13, noSuchName, 1, [{[tDescr3], "noSuchObject"}]),
+ s([{[tDescr3,1], s, "noSuchInstance"}]),
+ ?line expect(14, noSuchName, 1, [{[tDescr3,1], "noSuchInstance"}]),
+ s([{[tDescr2,0], s, "inconsistentName"}]),
+ ?line expect(15, noSuchName, 1, [{[tDescr2,0], "inconsistentName"}]),
+
+ %% 4.1.5:2
+ s([{[tDescr2, 0], i, 4}]),
+ ?line expect(20, badValue, 1, [{[tDescr2, 0], 4}]),
+ s([{[tDescr2, 0], s, "badValue"}]),
+ ?line expect(21, badValue, 1, [{[tDescr2, 0], "badValue"}]),
+
+ %% 4.1.5:3
+ %% The standard is quite incorrect here. The resp pdu was too big. In
+ %% the resp pdu, we have the original vbs. In the tooBig pdu we still
+ %% have to original vbs => the tooBig pdu is too big as well!!! It
+ %% may not get it to the manager, unless the agent uses 'NULL' instead
+ %% of the std-like original value.
+ s([{[tTooBig, 0], s, ?tooBigStr}]),
+ %% according to std:
+% ?line expect(30, tooBig, 0, [{[tTooBig, 0], ?tooBigStr}]),
+ ?line expect(30, tooBig, 0, [{[tTooBig, 0], 'NULL'}]),
+
+ %% 4.1.5:4
+ s([{[tDescr2, 0], s, "is_set_ok_fail"}]),
+ ?line expect(40, genErr, 1, [{[tDescr2, 0], "is_set_ok_fail"}]),
+ s([{[tDescr2, 0], s, "commit_fail"}]),
+ ?line expect(41, genErr, 1, [{[tDescr2, 0], "commit_fail"}]).
+
+%% Req. Test2
+v2_proc() ->
+ %% According to RFC1905.
+ %% Template: <Section>:<list no>
+ ?DBG("v2_proc -> entry",[]),
+ v2_get_p(),
+ v2_get_next_p(),
+ v2_get_bulk_p(),
+ v2_set_p().
+
+v2_get_p() ->
+ %% 4.2.1:2
+ ?DBG("v2_get_p -> entry",[]),
+ g([[test2]]),
+ ?line expect(10, [{[test2], noSuchObject}]),
+ g([[tDescr]]),
+ ?line expect(11, [{[tDescr], noSuchObject}]),
+ g([[tDescr4,0]]),
+ ?line expect(12, [{[tDescr4,0], noSuchObject}]),
+ g([[sysDescr, 0], [tDescr,0]]), % Outside mibview
+ ?line expect(13, [{[sysDescr,0], "Erlang SNMP agent"},
+ {[tDescr,0], noSuchObject}]),
+ g([[tTable]]),
+ ?line expect(14, [{[tTable], noSuchObject}]),
+ g([[tEntry]]),
+ ?line expect(15, [{[tEntry], noSuchObject}]),
+
+ %% 4.2.1:3
+ g([[tDescr2,0]]), %% instrum ret noSuchName!!!
+ ?line expect(20, [{[tDescr2,0], noSuchInstance}]),
+ g([[tDescr3,0]]),
+ ?line expect(21, [{[tDescr3,0], noSuchInstance}]),
+ g([[sysDescr,3]]),
+ ?line expect(22, [{[sysDescr, 3], noSuchInstance}]),
+ g([[tIndex,1]]),
+ ?line expect(23, [{[tIndex, 1], noSuchInstance}]),
+
+ %% 4.2.1 - any other error: genErr
+ g([[tGenErr1, 0]]),
+ ?line expect(30, genErr, 1, [{[tGenErr1, 0], 'NULL'}]),
+ g([[tGenErr2, 0]]),
+ ?line expect(31, genErr, 1, [{[tGenErr2, 0], 'NULL'}]),
+ g([[sysDescr, 0], [tGenErr3, 0]]),
+ ?line expect(32, genErr, 2, [{[sysDescr, 0], 'NULL'},
+ {[tGenErr3, 0], 'NULL'}]),
+
+ %% 4.2.1 - tooBig
+ g([[tTooBig, 0]]),
+ ?line expect(40, tooBig, 0, []).
+
+
+v2_get_next_p() ->
+ %% 4.2.2:2
+ ?DBG("v2_get_next_p -> entry",[]),
+ gn([[1,3,7,1]]),
+ ?line expect(10, [{[1,3,7,1], endOfMibView}]),
+ gn([[sysDescr], [1,3,7,1]]),
+ ?line expect(11, [{[sysDescr, 0], "Erlang SNMP agent"},
+ {[1,3,7,1], endOfMibView}]),
+ gn([[tCnt2, 1]]),
+ ?line expect(12, [{[tCnt2,2], 100}]),
+ gn([[tCnt2, 2]]),
+ ?line expect(12, [{[tCnt2,2], endOfMibView}]),
+
+ %% 4.2.2 - any other error: genErr
+ gn([[tGenErr1]]),
+ ?line expect(20, genErr, 1, [{[tGenErr1], 'NULL'}]),
+ gn([[tGenErr2]]),
+ ?line expect(21, genErr, 1, [{[tGenErr2], 'NULL'}]),
+ gn([[sysDescr], [tGenErr3]]),
+ ?line expect(22, genErr, 2, [{[sysDescr], 'NULL'},
+ {[tGenErr3], 'NULL'}]),
+
+ %% 4.2.2 - tooBig
+ gn([[tTooBig]]),
+ ?line expect(20, tooBig, 0, []).
+
+v2_get_bulk_p() ->
+ %% 4.2.3
+ ?DBG("v2_get_bulk_p -> entry",[]),
+ gb(1, 1, []),
+ ?line expect(10, []),
+ gb(-1, 1, []),
+ ?line expect(11, []),
+ gb(-1, -1, []),
+ ?line expect(12, []),
+ gb(-1, -1, []),
+ ?line expect(13, []),
+ gb(2, 0, [[sysDescr], [1,3,7,1]]),
+ ?line expect(14, [{[sysDescr, 0], "Erlang SNMP agent"},
+ {[1,3,7,1], endOfMibView}]),
+ gb(1, 2, [[sysDescr], [1,3,7,1]]),
+ ?line expect(15, [{[sysDescr, 0], "Erlang SNMP agent"},
+ {[1,3,7,1], endOfMibView}]),
+ gb(0, 2, [[sysDescr], [1,3,7,1]]),
+ ?line expect(16, [{[sysDescr, 0], "Erlang SNMP agent"},
+ {[1,3,7,1], endOfMibView},
+ {[sysObjectID, 0], [1,2,3]},
+ {[1,3,7,1], endOfMibView}]),
+
+ gb(2, 2, [[sysDescr], [1,3,7,1], [sysDescr], [1,3,7,1]]),
+ ?line expect(17, [{[sysDescr, 0], "Erlang SNMP agent"},
+ {[1,3,7,1], endOfMibView},
+ {[sysDescr, 0], "Erlang SNMP agent"},
+ {[1,3,7,1], endOfMibView},
+ {[sysObjectID, 0], [1,2,3]},
+ {[1,3,7,1], endOfMibView}]),
+
+ gb(1, 2, [[sysDescr], [sysDescr], [tTooBig]]),
+ ?line expect(18, [{[sysDescr, 0], "Erlang SNMP agent"},
+ {[sysDescr, 0], "Erlang SNMP agent"}]),
+
+ gb(1,12, [[tDescr2], [sysDescr]]), % next one after tDescr2 is tTooBig.
+ ?line expect(19, []),
+
+ gb(2,2, [[sysDescr], [sysObjectID], [tGenErr1], [sysDescr]]),
+ ?line expect(20, genErr, 3, [{[sysDescr], 'NULL'},
+ {[sysObjectID], 'NULL'},
+ {[tGenErr1], 'NULL'},
+ {[sysDescr], 'NULL'}]),
+ gb(0, 2, [[tCnt2, 1]]),
+ ?line expect(21, [{[tCnt2,2], 100},
+ {[tCnt2,2], endOfMibView}]).
+
+
+v2_set_p() ->
+ %% 4.2.5:1
+ ?DBG("v2_set_p -> entry",[]),
+ s([{[1,3,7,0], i, 4}]),
+ ?line expect(10, noAccess, 1, [{[1,3,7,0], 4}]),
+ s([{[tDescr,0], s, "outside mibview"}]),
+ ?line expect(11, noAccess, 1, [{[tDescr,0], "outside mibview"}]),
+
+ %% 4.2.5:2
+ s([{[1,3,6,1,0], s, "noSuchObject"}]),
+ ?line expect(20, notWritable, 1, [{[1,3,6,1,0], "noSuchObject"}]),
+
+ %% 4.2.5:3
+ s([{[tDescr2, 0], i, 4}]),
+ ?line expect(30, wrongType, 1, [{[tDescr2, 0], 4}]),
+ s([{[tDescr2, 0], s, "badValue"}]),
+ ?line expect(31, badValue, 1, [{[tDescr2, 0], "badValue"}]),
+
+ %% 4.2.5:4
+ s([{[tStr, 0], s, ""}]),
+ ?line expect(40, wrongLength, 1, [{[tStr, 0], ""}]),
+ s([{[tStr, 0], s, "12345"}]),
+ ?line expect(40, wrongLength, 1, [{[tStr, 0], "12345"}]),
+
+ %% 4.2.5:5 - N/A
+
+ %% 4.2.5:6
+ s([{[tInt1, 0], i, 0}]),
+ ?line expect(60, wrongValue, 1, [{[tInt1, 0], 0}]),
+ s([{[tInt1, 0], i, 5}]),
+ ?line expect(61, wrongValue, 1, [{[tInt1, 0], 5}]),
+ s([{[tInt2, 0], i, 0}]),
+ ?line expect(62, wrongValue, 1, [{[tInt2, 0], 0}]),
+ s([{[tInt2, 0], i, 5}]),
+ ?line expect(63, wrongValue, 1, [{[tInt2, 0], 5}]),
+ s([{[tInt3, 0], i, 5}]),
+ ?line expect(64, wrongValue, 1, [{[tInt3, 0], 5}]),
+
+ %% 4.2.5:7
+ s([{[tDescrX, 1, 1], s, "noCreation"}]),
+ ?line expect(70, noCreation, 1, [{[tDescrX, 1, 1], "noCreation"}]),
+
+ %% 4.2.5:8
+ s([{[tDescrX, 1, 2], s, "inconsistentName"}]),
+ ?line expect(80, inconsistentName, 1,
+ [{[tDescrX, 1, 2], "inconsistentName"}]),
+
+ %% 4.2.5:9
+ s([{[tCnt, 1, 2], i, 5}]),
+ ?line expect(90, notWritable, 1, [{[tCnt, 1, 2], 5}]),
+ s([{[tDescr3,0], s, "read-only"}]),
+ ?line expect(90, notWritable, 1, [{[tDescr3,0], "read-only"}]),
+
+ %% 4.2.5:10
+ s([{[tDescr2,0], s, "inconsistentValue"}]),
+ ?line expect(100, inconsistentValue, 1,
+ [{[tDescr2,0], "inconsistentValue"}]),
+
+ %% 4.2.5:11
+ s([{[tDescr2,0], s, "resourceUnavailable"}]),
+ ?line expect(110, resourceUnavailable, 1,
+ [{[tDescr2,0],"resourceUnavailable"}]),
+
+ %% 4.2.5:12
+ s([{[tDescr2, 0], s, "is_set_ok_fail"}]),
+ ?line expect(120, genErr, 1, [{[tDescr2, 0], "is_set_ok_fail"}]).
+
+ %% commitFailed and undoFailed is tested by the 'undo' case.
+
+
+%% Req. OLD-SNMPEA-MIB
+table_test() ->
+ io:format("Testing simple get, next and set on communityTable...~n"),
+%% {[147,214,36,45], "public", 2, readWrite}.
+%% {[147,214,36,45], "standard trap", 2, read}.
+ Key1c3 = [intCommunityViewIndex,get(mip),is("public")],
+ Key2c3 = [intCommunityViewIndex,get(mip),is("standard trap")],
+ Key1c4 = [intCommunityAccess,get(mip),is("public")],
+ EndKey = [intCommunityEntry,[9],get(mip),is("public")],
+ gn([[intCommunityEntry]]),
+ ?line expect(7, [{Key1c3, 2}]),
+ gn([[intCommunityTable]]),
+ ?line expect(71, [{Key1c3, 2}]),
+ gn([[community]]),
+ ?line expect(72, [{Key1c3, 2}]),
+ gn([[otpSnmpeaMIB]]),
+ ?line expect(73, [{Key1c3, 2}]),
+ gn([[ericsson]]),
+ ?line expect(74, [{Key1c3, 2}]),
+ gn([Key1c3]),
+ ?line expect(8, [{Key2c3, 2}]),
+ gn([Key2c3]),
+ ?line expect(9, [{Key1c4, 2}]),
+ gn([EndKey]),
+ AgentIp = [intAgentIpAddress,0],
+ ?line expect(10, [{AgentIp, any}]),
+ g([Key1c3]),
+ ?line expect(11, [{Key1c3, 2}]),
+ g([EndKey]),
+ ?line ?v1_2(expect(12, noSuchName, 1, any),
+ expect(12, [{EndKey, noSuchObject}])),
+
+ io:format("Testing row creation/deletion on communityTable...~n"),
+ NewKeyc3 = [intCommunityViewIndex,get(mip),is("test")],
+ NewKeyc4 = [intCommunityAccess,get(mip),is("test")],
+ NewKeyc5 = [intCommunityStatus,get(mip),is("test")],
+ s([{NewKeyc5, ?createAndGo}]),
+ ?line expect(14, ?v1_2(badValue, inconsistentValue), 1,any),
+ s([{NewKeyc5, ?createAndGo}, {NewKeyc3, 2}, {NewKeyc4, 2}]),
+ ?line expect(15, [{NewKeyc5, ?createAndGo},{NewKeyc3, 2}, {NewKeyc4, 2}]),
+ g([NewKeyc4]),
+ ?line expect(16, [{NewKeyc4, 2}]),
+ s([{NewKeyc5, ?destroy}]),
+ ?line expect(17, [{NewKeyc5, ?destroy}]),
+ s([{NewKeyc4, 2}]),
+ ?line expect(18, ?v1_2(noSuchName, inconsistentName), 1,[{NewKeyc4, 2}]),
+ s([{NewKeyc5, ?createAndWait}]),
+ ?line expect(19, [{NewKeyc5, ?createAndWait}]),
+ g([NewKeyc5]),
+ ?line expect(20, [{NewKeyc5, ?notReady}]),
+ s([{NewKeyc4, 2}]),
+ ?line expect(21, [{NewKeyc4, 2}]),
+ g([NewKeyc5]),
+ ?line expect(22, [{NewKeyc5, ?notReady}]),
+ s([{NewKeyc3, 2}]),
+ ?line expect(23, [{NewKeyc3, 2}]),
+ g([NewKeyc5]),
+ ?line expect(24, [{NewKeyc5, ?notInService}]),
+ s([{NewKeyc5, ?active}]),
+ ?line expect(25, [{NewKeyc5, ?active}]),
+ s([{NewKeyc5, ?destroy}]),
+ ?line expect(26, [{NewKeyc5, ?destroy}]),
+ s([{NewKeyc3, 3}]),
+ ?line expect(27, ?v1_2(noSuchName, inconsistentName), 1,[{NewKeyc3, 3}]),
+ otp_1128().
+
+%% Req. system group
+simple_standard_test() ->
+ ?DBG("simple_standard_test -> entry",[]),
+ gn([[1,1]]),
+ ?line expect(1, [{[sysDescr,0], "Erlang SNMP agent"}]),
+ gn([[1,3]]),
+ ?line expect(11, [{[sysDescr,0], "Erlang SNMP agent"}]),
+ gn([[1,3,6]]),
+ ?line expect(12, [{[sysDescr,0], "Erlang SNMP agent"}]),
+ gn([[1,3,6,1]]),
+ ?line expect(13, [{[sysDescr,0], "Erlang SNMP agent"}]),
+ gn([[1,3,6,1,2]]),
+ ?line expect(14, [{[sysDescr,0], "Erlang SNMP agent"}]),
+ gn([[1,3,6,1,2,1]]),
+ ?line expect(15, [{[sysDescr,0], "Erlang SNMP agent"}]),
+ gn([[1,3,6,1,2,1,1]]),
+ ?line expect(16, [{[sysDescr,0], "Erlang SNMP agent"}]),
+ gn([[sysDescr]]),
+ ?line expect(17, [{[sysDescr,0], "Erlang SNMP agent"}]),
+ g([[sysDescr,0]]),
+ ?line expect(2, [{[sysDescr,0], "Erlang SNMP agent"}]),
+ g([[sysDescr]]),
+ ?line ?v1_2(expect(3, noSuchName, 1, any),
+ expect(3, [{[sysDescr], noSuchObject}])),
+ g([[1,6,7,0]]),
+ ?line ?v1_2(expect(41, noSuchName, 1, any),
+ expect(3, [{[1,6,7,0], noSuchObject}])),
+ gn([[1,13]]),
+ ?line ?v1_2(expect(4, noSuchName,1, any),
+ expect(4, [{[1,13], endOfMibView}])),
+ s([{[sysLocation, 0], "new_value"}]),
+ ?line expect(5, [{[sysLocation, 0], "new_value"}]),
+ g([[sysLocation, 0]]),
+ ?line expect(6, [{[sysLocation, 0], "new_value"}]),
+ io:format("Testing noSuchName and badValue...~n"),
+ s([{[sysServices,0], 3}]),
+ ?line expect(61, ?v1_2(noSuchName, notWritable), 1, any),
+ s([{[sysLocation, 0], i, 3}]),
+ ?line expect(62, ?v1_2(badValue, wrongType), 1, any),
+ ?DBG("simple_standard_test -> done",[]),
+ ok.
+
+%% This is run in the agent node
+db_notify_client(suite) -> [];
+db_notify_client(Config) when list(Config) ->
+ {SaNode, MgrNode, MibDir} = init_case(Config),
+ ?DBG("~n\tSaNode: ~p~n\tMgrNode: ~p~n\tMibDir: ~p",
+ [SaNode,MgrNode,MibDir]),
+ snmpa_local_db:register_notify_client(self(),?MODULE),
+
+ %% This call (the manager) will issue to set operations, so
+ %% we expect to receive to notify(insert) calls.
+ try_test(db_notify_client_test),
+
+ ?DBG("await first notify",[]),
+ receive
+ {db_notify_test_reply,insert} -> ?DBG("first notify received",[]),ok
+ end,
+
+ ?DBG("await second notify",[]),
+ receive
+ {db_notify_test_reply,insert} -> ?DBG("second notify received",[]),ok
+ end,
+
+ snmpa_local_db:unregister_notify_client(self()).
+
+
+%% This is run in the manager node
+db_notify_client_test() ->
+ ?DBG("set first new sysLocation",[]),
+ s([{[sysLocation, 0], "new_value"}]),
+ ?line expect(5, [{[sysLocation, 0], "new_value"}]),
+
+ ?DBG("set second new sysLocation",[]),
+ s([{[sysLocation, 0], "new_value"}]),
+ ?line expect(5, [{[sysLocation, 0], "new_value"}]).
+
+notify(Pid,What) ->
+ ?DBG("notify(~p,~p) -> called",[Pid,What]),
+ Pid ! {db_notify_test_reply,What}.
+
+
+%% Req: system group, OLD-SNMPEA-MIB, Klas1
+big_test() ->
+ ?DBG("big_test -> testing simple next/get/set @ master agent...",[]),
+ simple_standard_test(),
+
+ ?DBG("big_test -> testing simple next/get/set @ subagent...",[]),
+ gn([[klas1]]),
+ ?line expect(1, [{[fname,0], ""}]),
+ g([[fname,0]]),
+ ?line expect(2, [{[fname,0], ""}]),
+ s([{[fname,0], s, "test set"}]),
+ ?line expect(3, [{[fname,0], "test set"}]),
+ g([[fname,0]]),
+ ?line expect(4, [{[fname,0], "test set"}]),
+
+ ?DBG("big_test -> "
+ "testing next from last instance in master to subagent...",[]),
+ gn([[?v1_2(sysServices, sysORLastChange),0]]),
+ ?line expect(5, [{[fname,0], "test set"}]),
+ gn([[1,1],
+ [?v1_2(sysServices, sysORLastChange),0]]),
+ ?line expect(51, [{[sysDescr,0], "Erlang SNMP agent"},
+ {[fname,0], "test set"}]),
+ s([{[fname,0], s, ""}]),
+ ?line expect(52, [{[fname,0], ""}]),
+
+ table_test(),
+
+ ?DBG("big_test -> adding one row in subagent table",[]),
+ _FTab = [friendsEntry],
+ s([{[friendsEntry, [2, 3]], s, "kompis3"},
+ {[friendsEntry, [3, 3]], i, ?createAndGo}]),
+ ?line expect(6, [{[friendsEntry, [2, 3]], "kompis3"},
+ {[friendsEntry, [3, 3]], ?createAndGo}]),
+ g([[friendsEntry, [2, 3]],
+ [friendsEntry, [3, 3]]]),
+ ?line expect(7, [{[friendsEntry, [2, 3]], "kompis3"},
+ {[friendsEntry, [3, 3]], ?active}]),
+ s([{[friendsEntry, [3, 3]], i, ?destroy}]),
+ ?line expect(8, [{[friendsEntry, [3, 3]], ?destroy}]),
+
+ otp_1131(),
+
+ ?DBG("big_test -> adding two rows in subagent table with special INDEX",
+ []),
+ s([{[kompissEntry, [1, 3]], s, "kompis3"},
+ {[kompissEntry, [2, 3]], i, ?createAndGo}]),
+ ?line expect(9, [{[kompissEntry, [1, 3]], "kompis3"},
+ {[kompissEntry, [2, 3]], ?createAndGo}]),
+ g([[kompissEntry, [1, 3]],
+ [kompissEntry, [2, 3]]]),
+ ?line expect(10, [{[kompissEntry, [1, 3]], "kompis3"},
+ {[kompissEntry, [2, 3]], ?active}]),
+ gn([[kompissEntry, [1]],
+ [kompissEntry, [2]]]),
+ ?line expect(11, [{[kompissEntry, [1, 3]], "kompis3"},
+ {[kompissEntry, [2, 3]], ?active}]),
+ s([{[kompissEntry, [1, 2]], s, "kompis3"},
+ {[kompissEntry, [2, 2]], i, ?createAndGo}]),
+ ?line expect(12, [{[kompissEntry, [1, 2]], "kompis3"},
+ {[kompissEntry, [2, 2]], ?createAndGo}]),
+ gn([[kompissEntry, [1, 1]],
+ [kompissEntry, [2, 1]]]),
+ ?line expect(13, [{[kompissEntry, [1, 2]], "kompis3"},
+ {[kompissEntry, [2, 2]], ?active}]),
+ s([{[kompissEntry, [2, 3]], i, ?destroy}]),
+ ?line expect(14, [{[kompissEntry, [2, 3]], ?destroy}]),
+ s([{[kompissEntry, [2, 2]], i, ?destroy}]),
+ ?line expect(15, [{[kompissEntry, [2, 2]], ?destroy}]),
+ ?DBG("big_test -> done",[]),
+ ok.
+
+%% Req. system group, Klas2, OLD-SNMPEA-MIB
+big_test_2() ->
+ p("Testing simple next/get/set @ master agent (2)..."),
+ simple_standard_test(),
+
+ p("Testing simple next/get/set @ subagent (2)..."),
+ gn([[klas2]]),
+ ?line expect(1, [{[fname2,0], ""}]),
+ g([[fname2,0]]),
+ ?line expect(2, [{[fname2,0], ""}]),
+ s([{[fname2,0], s, "test set"}]),
+ ?line expect(3, [{[fname2,0], "test set"}]),
+ g([[fname2,0]]),
+ ?line expect(4, [{[fname2,0], "test set"}]),
+
+ otp_1298(),
+
+ p("Testing next from last object in master to subagent (2)..."),
+ gn([[?v1_2(sysServices, sysORLastChange),0]]),
+ ?line expect(5, [{[fname2,0], "test set"}]),
+ gn([[1,1],
+ [?v1_2(sysServices, sysORLastChange),0]]),
+ ?line expect(51, [{[sysDescr,0], "Erlang SNMP agent"},
+ {[fname2,0], "test set"}]),
+
+ table_test(),
+
+ p("Adding one row in subagent table (2)"),
+ _FTab = [friendsEntry2],
+ s([{[friendsEntry2, [2, 3]], s, "kompis3"},
+ {[friendsEntry2, [3, 3]], i, ?createAndGo}]),
+ ?line expect(6, [{[friendsEntry2, [2, 3]], "kompis3"},
+ {[friendsEntry2, [3, 3]], ?createAndGo}]),
+ g([[friendsEntry2, [2, 3]],
+ [friendsEntry2, [3, 3]]]),
+ ?line expect(7, [{[friendsEntry2, [2, 3]], "kompis3"},
+ {[friendsEntry2, [3, 3]], ?active}]),
+ s([{[friendsEntry2, [3, 3]], i, ?destroy}]),
+ ?line expect(8, [{[friendsEntry2, [3, 3]], ?destroy}]),
+
+ p("Adding two rows in subagent table with special INDEX (2)"),
+ s([{[kompissEntry2, [1, 3]], s, "kompis3"},
+ {[kompissEntry2, [2, 3]], i, ?createAndGo}]),
+ ?line expect(9, [{[kompissEntry2, [1, 3]], "kompis3"},
+ {[kompissEntry2, [2, 3]], ?createAndGo}]),
+ g([[kompissEntry2, [1, 3]],
+ [kompissEntry2, [2, 3]]]),
+ ?line expect(10, [{[kompissEntry2, [1, 3]], "kompis3"},
+ {[kompissEntry2, [2, 3]], ?active}]),
+ gn([[kompissEntry2, [1]],
+ [kompissEntry2, [2]]]),
+ ?line expect(11, [{[kompissEntry2, [1, 3]], "kompis3"},
+ {[kompissEntry2, [2, 3]], ?active}]),
+ s([{[kompissEntry2, [1, 2]], s, "kompis3"},
+ {[kompissEntry2, [2, 2]], i, ?createAndGo}]),
+ ?line expect(12, [{[kompissEntry2, [1, 2]], "kompis3"},
+ {[kompissEntry2, [2, 2]], ?createAndGo}]),
+ gn([[kompissEntry2, [1, 1]],
+ [kompissEntry2, [2, 1]]]),
+ ?line expect(13, [{[kompissEntry2, [1, 2]], "kompis3"},
+ {[kompissEntry2, [2, 2]], ?active}]),
+ s([{[kompissEntry2, [2, 3]], i, ?destroy}]),
+ ?line expect(14, [{[kompissEntry2, [2, 3]], ?destroy}]),
+ s([{[kompissEntry2, [2, 2]], i, ?destroy}]),
+ ?line expect(15, [{[kompissEntry2, [2, 2]], ?destroy}]),
+ ok.
+
+%% Req. Test1
+multi_threaded_test() ->
+ p("Testing multi threaded agent..."),
+ g([[multiStr,0]]),
+ Pid = get_multi_pid(),
+ g([[sysUpTime,0]]),
+ ?line expect(1, [{[sysUpTime,0], any}]),
+ s([{[sysLocation, 0], s, "pelle"}]),
+ ?line expect(2, [{[sysLocation, 0], "pelle"}]),
+ Pid ! continue,
+ ?line expect(3, [{[multiStr,0], "ok"}]),
+
+ s([{[multiStr, 0], s, "block"}]),
+ Pid2 = get_multi_pid(),
+ g([[sysUpTime,0]]),
+ ?line expect(4, [{[sysUpTime,0], any}]),
+ g([[multiStr,0]]),
+ Pid3 = get_multi_pid(),
+ g([[sysUpTime,0]]),
+ ?line expect(5, [{[sysUpTime,0], any}]),
+ s([{[sysLocation, 0], s, "kalle"}]),
+ Pid3 ! continue,
+ ?line expect(6, [{[multiStr,0], "ok"}]),
+ Pid2 ! continue,
+ ?line expect(7, [{[multiStr,0], "block"}]),
+ ?line expect(8, [{[sysLocation,0], "kalle"}]).
+
+%% Req. Test1, TestTrapv2
+mt_trap_test(MA) ->
+ snmpa:send_trap(MA, testTrapv22, "standard trap"),
+ ?line expect(1, v2trap, [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?system ++ [0,1]}]),
+
+ snmpa:send_trap(MA, mtTrap, "standard trap"),
+ Pid = get_multi_pid(),
+ g([[sysUpTime,0]]),
+ ?line expect(2, [{[sysUpTime,0], any}]),
+ snmpa:send_trap(MA, testTrapv22, "standard trap"),
+ ?line expect(3, v2trap, [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?system ++ [0,1]}]),
+ Pid ! continue,
+ ?line expect(4, v2trap, [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?testTrap ++ [2]},
+ {[multiStr,0], "ok"}]).
+
+
+get_multi_pid() ->
+ get_multi_pid(10).
+get_multi_pid(0) ->
+ ?line ?FAIL(no_global_name);
+get_multi_pid(N) ->
+ sleep(1000),
+ case global:whereis_name(snmp_multi_tester) of
+ Pid when pid(Pid) -> Pid;
+ _ -> get_multi_pid(N-1)
+ end.
+
+%% Req. Test1
+types_v2_test() ->
+ p("Testing v2 types..."),
+
+ s([{[bits1,0], 2#10}]),
+ ?line expect(1, [{[bits1,0], ?str(2#10)}]),
+ g([[bits1,0]]),
+ ?line expect(2, [{[bits1,0], ?str(2#101)}]),
+
+ s([{[bits2,0], 2#11000000110}]),
+ ?line expect(3, [{[bits2,0], ?str(2#11000000110)}]),
+ g([[bits2,0]]),
+ ?line expect(4, [{[bits2,0], ?str(2#11000000110)}]),
+
+ g([[bits3,0]]),
+ ?line expect(50, genErr, 1, any),
+
+ g([[bits4,0]]),
+ ?line expect(51, genErr, 1, any),
+
+ s([{[bits1,0], s, [2#10]}]),
+ ?line expect(6, ?v1_2(badValue, wrongValue), 1, any),
+
+ s([{[bits2,0], 2#11001001101010011}]),
+ ?line expect(7, ?v1_2(badValue, wrongValue), 1, any).
+
+
+%% Req. Test1
+implied_test(MA) ->
+ ?LOG("implied_test -> start",[]),
+ p("Testing IMPLIED..."),
+
+ snmpa:verbosity(MA,trace),
+ snmpa:verbosity(MA,trace),
+
+ %% Create two rows, check that they are get-nexted in correct order.
+ Idx1 = "apa",
+ Idx2 = "qq",
+ ?DBG("implied_test -> (send) create row 1 '~s' in table 1",[Idx1]),
+ s([{[testStatus, Idx1], i, ?createAndGo}, {[testDescr, Idx1],s,"row 1"}]),
+ ?line expect(1, [{[testStatus, Idx1], ?createAndGo},
+ {[testDescr, Idx1], "row 1"}]),
+ ?DBG("implied_test -> (send) create row 2 '~s' in table 1",[Idx2]),
+ s([{[testStatus, Idx2], i, ?createAndGo}, {[testDescr, Idx2],s,"row 2"}]),
+ ?line expect(2, [{[testStatus, Idx2], ?createAndGo},
+ {[testDescr, Idx2], "row 2"}]),
+ ?DBG("implied_test -> get-next(testDescr)",[]),
+ gn([[testDescr]]),
+ ?line expect(3, [{[testDescr,Idx1], "row 1"}]),
+ ?DBG("implied_test -> get-next(testDescr) of row 1",[]),
+ gn([[testDescr,Idx1]]),
+ ?line expect(4, [{[testDescr,Idx2], "row 2"}]),
+
+ % Delete the rows
+ ?DBG("implied_test -> (send) delete row 1 '~s' from table 1",[Idx1]),
+ s([{[testStatus, Idx1], i, ?destroy}]),
+ ?line expect(5, [{[testStatus, Idx1], ?destroy}]),
+ ?DBG("implied_test -> (send) delete row 2 '~s' from table 1",[Idx2]),
+ s([{[testStatus, Idx2], i, ?destroy}]),
+ ?line expect(6, [{[testStatus, Idx2], ?destroy}]),
+
+ %% Try the same in other table
+ Idx3 = [1, "apa"],
+ Idx4 = [1, "qq"],
+ ?DBG("implied_test -> (send) create row 1 '~s' in table 2",[Idx3]),
+ s([{[testStatus2, Idx3], i, ?createAndGo}, {[testDescr2,Idx3],s,"row 1"}]),
+ ?line expect(1, [{[testStatus2, Idx3], ?createAndGo},
+ {[testDescr2, Idx3], "row 1"}]),
+ ?DBG("implied_test -> (send) create row 2 '~s' in table 2",[Idx4]),
+ s([{[testStatus2, Idx4], i, ?createAndGo}, {[testDescr2,Idx4],s,"row 2"}]),
+ ?line expect(2, [{[testStatus2, Idx4], ?createAndGo},
+ {[testDescr2, Idx4], "row 2"}]),
+ ?DBG("implied_test -> get-next(testDescr2)",[]),
+ gn([[testDescr2]]),
+ ?line expect(3, [{[testDescr2,Idx3], "row 1"}]),
+ ?DBG("implied_test -> get-next(testDescr2) of row 1",[]),
+ gn([[testDescr2,Idx3]]),
+ ?line expect(4, [{[testDescr2,Idx4], "row 2"}]),
+
+ % Delete the rows
+ ?DBG("implied_test -> (send) delete row 1 '~s' from table 2",[Idx3]),
+ s([{[testStatus2, Idx3], i, ?destroy}]),
+ ?line expect(5, [{[testStatus2, Idx3], ?destroy}]),
+ ?DBG("implied_test -> (send) delete row 2 '~s' from table 2",[Idx4]),
+ s([{[testStatus2, Idx4], i, ?destroy}]),
+ ?line expect(6, [{[testStatus2, Idx4], ?destroy}]),
+
+ snmpa:verbosity(MA,log),
+
+ ?LOG("implied_test -> done",[]).
+
+
+
+%% Req. Test1
+sparse_table_test() ->
+ p("Testing sparse table..."),
+
+ %% Create two rows, check that they are get-nexted in correct order.
+ Idx1 = 1,
+ Idx2 = 2,
+ s([{[sparseStatus, Idx1], i, ?createAndGo},
+ {[sparseDescr, Idx1], s, "row 1"}]),
+ ?line expect(1, [{[sparseStatus, Idx1], ?createAndGo},
+ {[sparseDescr, Idx1], "row 1"}]),
+ s([{[sparseStatus, Idx2], i, ?createAndGo},
+ {[sparseDescr, Idx2], s, "row 2"}]),
+ ?line expect(2, [{[sparseStatus, Idx2], ?createAndGo},
+ {[sparseDescr, Idx2], "row 2"}]),
+ ?v1_2(gn([[sparseIndex], [sparseDescr,Idx1], [sparseDescr,Idx2],
+ [sparseStatus,Idx1], [sparseStatus,Idx2]]),
+ gb(0,5,[[sparseIndex]])),
+ ?line expect(3, [{[sparseDescr,Idx1], "row 1"},
+ {[sparseDescr,Idx2], "row 2"},
+ {[sparseStatus,Idx1], ?active},
+ {[sparseStatus,Idx2], ?active},
+ {[sparseStr,0], "slut"}]),
+ % Delete the rows
+ s([{[sparseStatus, Idx1], i, ?destroy}]),
+ ?line expect(4, [{[sparseStatus, Idx1], ?destroy}]),
+ s([{[sparseStatus, Idx2], i, ?destroy}]),
+ ?line expect(5, [{[sparseStatus, Idx2], ?destroy}]).
+
+
+%% Req. Test1
+cnt_64_test(MA) ->
+ ?LOG("start cnt64 test (~p)",[MA]),
+ snmpa:verbosity(MA,trace),
+ ?LOG("start cnt64 test",[]),
+ p("Testing Counter64, and at the same time, RowStatus is not last column"),
+
+ ?DBG("get cnt64",[]),
+ g([[cnt64,0]]),
+ ?DBG("await response",[]),
+ ?line ?v1_2(expect(1, noSuchName, 1, any),
+ expect(1, [{[cnt64,0],18446744073709551615}])),
+ ?DBG("get-next cnt64",[]),
+ gn([[cnt64]]),
+ ?DBG("await response",[]),
+ ?line ?v1_2(expect(2, [{[cnt64Str,0], "after cnt64"}]),
+ expect(2, [{[cnt64,0],18446744073709551615}])),
+ ?DBG("send cntTrap",[]),
+ snmpa:send_trap(MA,cntTrap,"standard trap",[{sysContact,"pelle"},
+ {cnt64, 10},
+ {sysLocation, "here"}]),
+ ?DBG("await response",[]),
+ ?line ?v1_2(expect(3, trap, [test], 6, 1, [{[sysContact,0], "pelle"},
+ {[sysLocation,0], "here"}]),
+ expect(3, v2trap, [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?testTrap ++ [1]},
+ {[sysContact,0], "pelle"},
+ {[cnt64,0], 10},
+ {[sysLocation,0], "here"}])),
+
+ %% Create two rows, check that they are get-nexted in correct order.
+ Idx1 = 1,
+ Idx2 = 2,
+ ?DBG("create row (cntStatus): ~p",[Idx1]),
+ s([{[cntStatus, Idx1], i, ?createAndGo}]),
+ ?DBG("await response",[]),
+ ?line expect(1, [{[cntStatus, Idx1], ?createAndGo}]),
+ ?DBG("create row (cntStatus): ~p",[Idx2]),
+ s([{[cntStatus, Idx2], i, ?createAndGo}]),
+ ?DBG("await response",[]),
+ ?line expect(2, [{[cntStatus, Idx2], ?createAndGo}]),
+
+ ?DBG("get-next (cntIndex)",[]),
+ gn([[cntIndex]]),
+ ?DBG("await response",[]),
+ ?line ?v1_2(expect(3, [{[cntStatus,Idx1], ?active}]),
+ expect(3, [{[cntCnt,Idx1], 0}])),
+ % Delete the rows
+ ?DBG("delete row (cntStatus): ~p",[Idx1]),
+ s([{[cntStatus, Idx1], i, ?destroy}]),
+ ?DBG("await response",[]),
+ ?line expect(4, [{[cntStatus, Idx1], ?destroy}]),
+ ?DBG("delete row (cntStatus): ~p",[Idx2]),
+ s([{[cntStatus, Idx2], i, ?destroy}]),
+ ?DBG("await response",[]),
+ ?line expect(5, [{[cntStatus, Idx2], ?destroy}]),
+ catch snmpa:verbosity(MA,log),
+ ?DBG("done",[]),
+ ok.
+
+%% Req. Test1
+opaque_test() ->
+ p("Testing Opaque datatype..."),
+ g([[opaqueObj,0]]),
+ ?line expect(1, [{[opaqueObj,0], "opaque-data"}]).
+
+%% Req. OLD-SNMPEA-MIB
+api_test(MaNode) ->
+ ?line {value, OID} = rpc:call(MaNode, snmp, name_to_oid,
+ [intAgentIpAddress]),
+ ?line {value, intAgentIpAddress} = rpc:call(MaNode, snmp,
+ oid_to_name, [OID]),
+ ?line false = rpc:call(MaNode, snmp, name_to_oid, [intAgentIpAddres]),
+ ?line false = rpc:call(MaNode, snmp, oid_to_name,
+ [[1,5,32,3,54,3,3,34,4]]),
+ ?line {value, 2} = rpc:call(MaNode, snmp, enum_to_int,
+ [intViewType, excluded]),
+ ?line {value, excluded} = rpc:call(MaNode, snmp, int_to_enum,
+ [intViewType, 2]),
+ ?line false = rpc:call(MaNode, snmp, enum_to_int, [intViewType, exclude]),
+ ?line false = rpc:call(MaNode, snmp, enum_to_int,
+ [intAgentIpAddress, exclude]),
+ ?line false = rpc:call(MaNode, snmp, enum_to_int,
+ [intAgentIpAddre, exclude]),
+ ?line false = rpc:call(MaNode, snmp, int_to_enum, [intViewType, 3]),
+ ?line false = rpc:call(MaNode, snmp, int_to_enum, [intAgentIpAddress, 2]),
+ ?line false = rpc:call(MaNode, snmp, int_to_enum, [intAgentIpAddre, 2]),
+ ?line {value, active} = rpc:call(MaNode, snmp,
+ int_to_enum, ['RowStatus', ?active]),
+ ?line {value, ?destroy} = rpc:call(MaNode, snmp,
+ enum_to_int, ['RowStatus', destroy]),
+ ?line false = rpc:call(MaNode, snmp,
+ enum_to_int, ['RowStatus', xxxdestroy]),
+ ?line false = rpc:call(MaNode, snmp,
+ enum_to_int, ['xxRowStatus', destroy]),
+ ?line false = rpc:call(MaNode, snmp, int_to_enum, ['RowStatus', 25]),
+ ?line false = rpc:call(MaNode, snmp, int_to_enum, ['xxRowStatus', 1]),
+ ?line case snmp:date_and_time() of
+ List when list(List), length(List) == 8 -> ok;
+ List when list(List), length(List) == 11 -> ok
+ end.
+
+%% Req. Klas3
+api_test2() ->
+ g([[fname3,0]]),
+ ?line expect(1, [{[fname3,0], "ok"}]),
+ g([[fname4,0]]),
+ ?line expect(2, [{[fname4,0], 1}]).
+
+api_test3() ->
+ g([[fname3,0]]),
+ ?line expect(1, [{[fname3,0], "ok"}]).
+
+
+unreg_test() ->
+ gn([[?v1_2(sysServices, sysORLastChange),0]]),
+ ?line expect(1, [{[snmpInPkts, 0], any}]).
+
+load_test() ->
+ gn([[?v1_2(sysServices, sysORLastChange),0]]),
+ ?line expect(1, [{[fname,0], ""}]).
+
+%% Req. Klas1
+load_test_sa() ->
+ gn([[?v1_2(sysServices,sysORLastChange), 0]]),
+ ?line expect(1, [{[fname,0], any}]).
+
+%% Req. system group, Klas1, OLD-SNMPEA-MIB
+do_mul_get() ->
+ Key1c3 = [intCommunityEntry,[3],get(mip),is("public")],
+ Key1c4 = [intCommunityEntry,[4],get(mip),is("public")],
+ s([{[fname,0], s, "test set"}]),
+ ?line expect(3, [{[fname,0], "test set"}]),
+ g([[sysDescr,0], Key1c4, [fname,0],Key1c3,
+ [sysName,0]]),
+ ?line expect(1, [{[sysDescr,0], "Erlang SNMP agent"},
+ {Key1c4, 2},
+ {[fname,0], "test set"},
+ {Key1c3, 2},
+ {[sysName,0], "test"}]),
+ g([[1,3,7,1], Key1c4, [sysDescr,0], [1,3,7,2], Key1c3, [sysDescr,0]]),
+ ?line ?v1_2(expect(2, noSuchName, [1,4], any),
+ expect(2, [{[1,3,7,1], noSuchObject},
+ {Key1c4, 2},
+ {[sysDescr,0], "Erlang SNMP agent"},
+ {[1,3,7,2], noSuchObject},
+ {Key1c3, 2},
+ {[sysDescr,0], "Erlang SNMP agent"}])).
+
+%% Req. v1, system group, Klas1, OLD-SNMPEA-MIB, *ej* Klas3.
+do_mul_get_err() ->
+ Key1c3 = [intCommunityEntry,[3],get(mip),is("public")],
+ Key1c4 = [intCommunityEntry,[4],get(mip),is("public")],
+ s([{[fname,0], s, "test set"}]),
+ ?line expect(3, [{[fname,0], "test set"}]),
+ g([[sysDescr,0],Key1c4,[fname,0], Key1c3, [sysName,2]]),
+ ?line ?v1_2(expect(1, noSuchName, 5, any),
+ expect(1, [{[sysDescr,0], "Erlang SNMP agent"},
+ {Key1c4, 2},
+ {[fname,0], "test set"},
+ {Key1c3, 2},
+ {[sysName,2], noSuchInstance}])),
+ g([[sysDescr,0],Key1c4,[fname3,0], Key1c3, [sysName,1]]),
+ ?line ?v1_2(expect(1, noSuchName, [3,5], any),
+ expect(1, [{[sysDescr,0], "Erlang SNMP agent"},
+ {Key1c4, 2},
+ {[fname3,0], noSuchObject},
+ {Key1c3, 2},
+ {[sysName,1], noSuchInstance}])).
+
+
+%% Req. system group, Klas1, OLD-SNMPEA-MIB
+do_mul_next() ->
+ Key1c3s = [intCommunityEntry,[3],get(mip),is("publi")],
+ Key1c4s = [intCommunityEntry,[4],get(mip),is("publi")],
+ Key1c3 = [intCommunityEntry,[3],get(mip),is("public")],
+ Key1c4 = [intCommunityEntry,[4],get(mip),is("public")],
+ s([{[fname,0], s, "test set"}]),
+ ?line expect(3, [{[fname,0], "test set"}]),
+ gn([[sysDescr], Key1c4s, [fname],Key1c3s,[sysName]]),
+ ?line expect(1, [{[sysDescr,0], "Erlang SNMP agent"},
+ {Key1c4, 2}, {[fname,0], "test set"},
+ {Key1c3, 2}, {[sysName,0], "test"}]).
+
+%% Req. system group, Klas1, OLD-SNMPEA-MIB
+do_mul_next_err() ->
+ Key1c3s = [intCommunityEntry,[3],get(mip),is("publi")],
+ Key1c4s = [intCommunityEntry,[4],get(mip),is("publi")],
+ Key1c3 = [intCommunityEntry,[3],get(mip),is("public")],
+ Key1c4 = [intCommunityEntry,[4],get(mip),is("public")],
+ s([{[fname,0], s, "test set"}]),
+ ?line expect(3, [{[fname,0], "test set"}]),
+ gn([[sysDescr], Key1c4s, [1,3,6,999], [fname],[1,3,90], Key1c3s,[sysName]]),
+ ?line ?v1_2(expect(1, noSuchName, [3,5], any),
+ expect(1, [{[sysDescr,0], "Erlang SNMP agent"},
+ {Key1c4, 2},
+ {[1,3,6,999], endOfMibView},
+ {[fname,0], "test set"},
+ {[1,3,90], endOfMibView},
+ {Key1c3, 2},
+ {[sysName,0], "test"}])).
+
+
+%% Req. system group, Klas1, OLD-SNMPEA-MIB
+do_mul_set() ->
+ p("Adding one row in subagent table, and one in master table"),
+ NewKeyc3 = [intCommunityEntry,[3],get(mip),is("test")],
+ NewKeyc4 = [intCommunityEntry,[4],get(mip),is("test")],
+ NewKeyc5 = [intCommunityEntry,[5],get(mip),is("test")],
+ s([{[friendsEntry, [2, 3]], "kompis3"},
+ {NewKeyc3, 2},
+ {[sysLocation,0], "new_value"},
+ {NewKeyc5, ?createAndGo},
+ {NewKeyc4, 2},
+ {[friendsEntry, [3, 3]], ?createAndGo}]),
+ ?line expect(1, [{[friendsEntry, [2, 3]], "kompis3"},
+ {NewKeyc3, 2},
+ {[sysLocation,0], "new_value"},
+ {NewKeyc5, ?createAndGo},
+ {NewKeyc4, 2},
+ {[friendsEntry, [3, 3]], ?createAndGo}]),
+ g([[friendsEntry, [2, 3]],
+ [sysLocation,0],
+ [friendsEntry, [3, 3]]]),
+ ?line expect(2, [{[friendsEntry, [2, 3]], "kompis3"},
+ {[sysLocation,0], "new_value"},
+ {[friendsEntry, [3, 3]], ?active}]),
+ g([NewKeyc4]),
+ ?line expect(3, [{NewKeyc4, 2}]),
+ s([{[friendsEntry, [3, 3]], ?destroy},
+ {NewKeyc5, ?destroy}]),
+ ?line expect(4, [{[friendsEntry, [3, 3]], ?destroy},
+ {NewKeyc5, ?destroy}]).
+
+%% Req. system group, Klas1, OLD-SNMPEA-MIB
+do_mul_set_err() ->
+ NewKeyc3 = [intCommunityEntry,[3],get(mip),is("test")],
+ NewKeyc4 = [intCommunityEntry,[4],get(mip),is("test")],
+ NewKeyc5 = [intCommunityEntry,[5],get(mip),is("test")],
+ p("Adding one row in subagent table, and one in master table"),
+ s([{[friendsEntry, [2, 3]], s, "kompis3"},
+ {NewKeyc3, 2},
+ {[sysUpTime,0], 45}, % sysUpTime (readOnly)
+ {NewKeyc5, ?createAndGo},
+ {NewKeyc4, 2},
+ {[friendsEntry, [3, 3]], ?createAndGo}]),
+ ?line expect(1, ?v1_2(noSuchName, notWritable), 3, any),
+ g([[friendsEntry, [2, 3]]]),
+ ?line ?v1_2(expect(2, noSuchName, 1, any),
+ expect(2, [{[friendsEntry, [2,3]], noSuchInstance}])),
+ g([NewKeyc4]),
+ ?line ?v1_2(expect(3, noSuchName, 1, any),
+ expect(3, [{NewKeyc4, noSuchInstance}])).
+
+%% Req. SA-MIB
+sa_mib() ->
+ g([[sa, [2,0]]]),
+ ?line expect(1, [{[sa, [2,0]], 3}]),
+ s([{[sa, [1,0]], s, "sa_test"}]),
+ ?line expect(2, [{[sa, [1,0]], "sa_test"}]).
+
+ma_trap1(MA) ->
+ snmpa:send_trap(MA, testTrap2, "standard trap"),
+ ?line expect(1, trap, [system], 6, 1, [{[system, [4,0]],
+ "{mbj,eklas}@erlang.ericsson.se"}]),
+ snmpa:send_trap(MA, testTrap1, "standard trap"),
+ ?line expect(2, trap, [1,2,3] , 1, 0, [{[system, [4,0]],
+ "{mbj,eklas}@erlang.ericsson.se"}]).
+
+ma_trap2(MA) ->
+ snmpa:send_trap(MA,testTrap2,"standard trap",[{sysContact,"pelle"}]),
+ ?line expect(3, trap, [system], 6, 1, [{[system, [4,0]], "pelle"}]).
+
+ma_v2_2_v1_trap(MA) ->
+ snmpa:send_trap(MA,testTrapv22,"standard trap",[{sysContact,"pelle"}]),
+ ?line expect(3, trap, [system], 6, 1, [{[system, [4,0]], "pelle"}]).
+
+ma_v2_2_v1_trap2(MA) ->
+ snmpa:send_trap(MA,linkUp,"standard trap",[{ifIndex, [1], 1},
+ {ifAdminStatus, [1], 1},
+ {ifOperStatus, [1], 2}]),
+ ?line expect(3, trap, [1,2,3], 3, 0, [{[ifIndex, 1], 1},
+ {[ifAdminStatus, 1], 1},
+ {[ifOperStatus, 1], 2}]).
+
+sa_trap1(SA) ->
+ snmpa:send_trap(SA, saTrap, "standard trap"),
+ ?line expect(4, trap, [ericsson], 6, 1, [{[system, [4,0]],
+ "{mbj,eklas}@erlang.ericsson.se"},
+ {[sa, [1,0]], "sa_test"}]).
+
+sa_trap2(SA) ->
+ snmpa:send_trap(SA, saTrap, "standard trap",[{sysContact,"pelle"}]),
+ ?line expect(5, trap, [ericsson], 6, 1, [{[system, [4,0]],
+ "pelle"},
+ {[sa, [1,0]], "sa_test"}]).
+
+sa_trap3(SA) ->
+ snmpa:send_trap(SA, saTrap2, "standard trap",
+ [{intViewSubtree, [4], [1,2,3,4]}]),
+ ?line expect(6, trap, [ericsson], 6, 2, [{[system, [4,0]],
+ "{mbj,eklas}@erlang.ericsson.se"},
+ {[sa, [1,0]], "sa_test"},
+ {[intViewSubtree,4],[1,2,3,4]}]).
+
+ma_v2_trap1(MA) ->
+ ?DBG("ma_v2_traps -> entry with MA = ~p => "
+ "send standard trap: testTrapv22",[MA]),
+ snmpa:send_trap(MA, testTrapv22, "standard trap"),
+ ?line expect(1, v2trap, [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?system ++ [0,1]}]),
+ ?DBG("ma_v2_traps -> send standard trap: testTrapv21",[]),
+ snmpa:send_trap(MA, testTrapv21, "standard trap"),
+ ?line expect(2, v2trap, [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?snmp ++ [1]}]).
+
+ma_v2_trap2(MA) ->
+ snmpa:send_trap(MA,testTrapv22,"standard trap",[{sysContact,"pelle"}]),
+ ?line expect(3, v2trap, [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?system ++ [0,1]},
+ {[system, [4,0]], "pelle"}]).
+
+%% Note: This test case takes a while... actually a couple of minutes.
+ma_v2_inform1(MA) ->
+ ?DBG("ma_v2_inform -> entry with MA = ~p => "
+ "send notification: testTrapv22",[MA]),
+ ?line snmpa:send_notification(MA, testTrapv22, no_receiver, "standard inform", []),
+ ?line expect(1, {inform, true},
+ [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?system ++ [0,1]}]),
+
+ ?DBG("ma_v2_inform -> send notification: testTrapv22",[]),
+ snmpa:send_notification(MA, testTrapv22, {tag1, self()},
+ "standard inform", []),
+ ?line expect(1, {inform, true},
+ [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?system ++ [0,1]}]),
+ ?DBG("ma_v2_inform -> await targets",[]),
+ receive
+ {snmp_targets, tag1, [_]} ->
+ ok;
+ {snmp_targets, tag1, Addrs1} ->
+ ?line ?FAIL({bad_addrs, Addrs1})
+ after
+ 5000 ->
+ ?ERR("ma_v2_inform1 -> awaiting snmp_targets(tag1) timeout",[]),
+ ?line ?FAIL(nothing_at_all)
+ end,
+ ?DBG("ma_v2_inform -> await notification",[]),
+ receive
+ {snmp_notification, tag1, {got_response, _}} ->
+ ok;
+ {snmp_notification, tag1, {no_response, _}} ->
+ ?line ?FAIL(no_response)
+ after
+ 20000 ->
+ ?ERR("ma_v2_inform1 -> "
+ "awaiting snmp_notification(tag1) timeout",[]),
+ ?line ?FAIL(nothing_at_all)
+ end,
+
+ %%
+ %% -- The rest is possibly erroneous...
+ %%
+
+ ?DBG("ma_v2_inform -> send notification: testTrapv22",[]),
+ snmpa:send_notification(MA, testTrapv22, {tag2, self()},
+ "standard inform", []),
+ ?line expect(2, {inform, false},
+ [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?system ++ [0,1]}]),
+ ?DBG("ma_v2_inform -> await targets",[]),
+ receive
+ {snmp_targets, tag2, [_]} ->
+ ok;
+ {snmp_targets, tag2, Addrs2} ->
+ ?ERR("ma_v2_inform1 -> awaiting snmp_targets(tag2) timeout",[]),
+ ?line ?FAIL({bad_addrs, Addrs2})
+ after
+ 5000 ->
+ ?line ?FAIL(nothing_at_all)
+ end,
+ ?DBG("ma_v2_inform -> await notification",[]),
+ receive
+ {snmp_notification, tag2, {got_response, _}} ->
+ ?line ?FAIL(got_response);
+ {snmp_notification, tag2, {no_response, _}} ->
+ ok
+ after
+ 240000 ->
+ ?ERR("ma_v2_inform1 -> "
+ "awaiting snmp_notification(tag2) timeout",[]),
+ ?line ?FAIL(nothing_at_all)
+ end.
+
+
+ma_v1_2_v2_trap(MA) ->
+ snmpa:send_trap(MA,linkDown,"standard trap",[{ifIndex, [1], 1}]),
+ ?line expect(2, v2trap, [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?snmpTraps ++ [3]},
+ {[ifIndex, 1], 1},
+ {[snmpTrapEnterprise, 0], [1,2,3]}]).
+
+
+ma_v1_2_v2_trap2(MA) ->
+ snmpa:send_trap(MA,testTrap2,"standard trap",[{sysContact,"pelle"}]),
+ ?line expect(3, v2trap, [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?system ++ [0,1]},
+ {[system, [4,0]], "pelle"},
+ {[snmpTrapEnterprise, 0], ?system}]).
+
+
+sa_v1_2_v2_trap1(SA) ->
+ snmpa:send_trap(SA, saTrap, "standard trap"),
+ ?line expect(4, v2trap, [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?ericsson ++ [0, 1]},
+ {[system, [4,0]],
+ "{mbj,eklas}@erlang.ericsson.se"},
+ {[sa, [1,0]], "sa_test"},
+ {[snmpTrapEnterprise, 0], ?ericsson}]).
+
+sa_v1_2_v2_trap2(SA) ->
+ snmpa:send_trap(SA, saTrap, "standard trap",[{sysContact,"pelle"}]),
+ ?line expect(4, v2trap, [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?ericsson ++ [0, 1]},
+ {[system, [4,0]], "pelle"},
+ {[sa, [1,0]], "sa_test"},
+ {[snmpTrapEnterprise, 0], ?ericsson}]).
+
+
+sa_v1_2_v2_trap3(SA) ->
+ snmpa:send_trap(SA, saTrap2, "standard trap",
+ [{intViewSubtree, [4], [1,2,3,4]}]),
+ ?line expect(4, v2trap, [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?ericsson ++ [0, 2]},
+ {[system, [4,0]],
+ "{mbj,eklas}@erlang.ericsson.se"},
+ {[sa, [1,0]], "sa_test"},
+ {[intViewSubtree,4],[1,2,3,4]},
+ {[snmpTrapEnterprise, 0], ?ericsson}]).
+
+
+%% Req. SA-MIB, OLD-SNMPEA-MIB
+sa_errs_bad_value() ->
+ NewKeyc3 = [intCommunityEntry,[3],get(mip),is("test")],
+ NewKeyc4 = [intCommunityEntry,[4],get(mip),is("test")],
+ NewKeyc5 = [intCommunityEntry,[5],get(mip),is("test")],
+ s([{NewKeyc3, 2},
+ {[sa, [2,0]], 5}, % badValue (i is_set_ok)
+ {NewKeyc5, ?createAndGo},
+ {NewKeyc4, 2}]),
+ ?line expect(1, badValue, 2, any),
+ s([{NewKeyc3, 2},
+ {[sa, [2,0]], 6}, % wrongValue (i is_set_ok)
+ {NewKeyc5, ?createAndGo},
+ {NewKeyc4, 2}]),
+ ?line expect(1, ?v1_2(badValue, wrongValue), 2, any),
+ g([NewKeyc4]),
+ ?line ?v1_2(expect(2, noSuchName, 1, any),
+ expect(2, [{NewKeyc4, noSuchInstance}])).
+
+%% Req. SA-MIB, OLD-SNMPEA-MIB
+sa_errs_gen_err() ->
+ NewKeyc3 = [intCommunityEntry,[3],get(mip),is("test")],
+ NewKeyc4 = [intCommunityEntry,[4],get(mip),is("test")],
+ NewKeyc5 = [intCommunityEntry,[5],get(mip),is("test")],
+ s([{NewKeyc3, 2},{NewKeyc4, 2},
+ {NewKeyc5, ?createAndGo}, {[sa, [3,0]], 5}]),
+ ?line expect(1, genErr, 4, any),
+% The row might have been added; we don't know.
+% (as a matter of fact we do - it is added, because the agent
+% first sets its own vars, and then th SAs. Lets destroy it.
+ s([{NewKeyc5, ?destroy}]),
+ ?line expect(2, [{NewKeyc5, ?destroy}]).
+
+%% Req. SA-MIB, OLD-SNMPEA-MIB
+sa_too_big() ->
+ g([[sa, [4,0]]]),
+ ?line expect(1, tooBig).
+
+%% Req. Klas1, system group, snmp group (v1/v2)
+next_across_sa() ->
+ gn([[sysDescr],[klas1,5]]),
+ ?line expect(1, [{[sysDescr,0], "Erlang SNMP agent"},
+ {[snmpInPkts, 0], any}]).
+
+%% snmp_test_mgr:s([{[fStatus3, 1], 4}, {[fname3,0], "ok"}]). -> noError
+%% snmp_test_mgr:s([{[fStatus3, 1], 4}, {[fname3,0], "hoj"}]). -> {badValue, 2}
+%% snmp_test_mgr:s([{[fStatus3, 3], 4}, {[fname3,0], "hoj"}]). -> {genErr, 1}
+%% snmp_test_mgr:s([{[fStatus3, 4], 4}, {[fname3,0], "ok"}]). -> {genErr, 1}
+%% snmp_test_mgr:s([{[fStatus3, 4], 4}, {[fname3,0], "ufail"}]). -> {genErr, 1}
+%% snmp_test_mgr:s([{[fStatus3, 1], 4}, {[fname3,0], "xfail"}]). -> {genErr, 2}
+%% Req. Klas3, Klas4
+undo_test() ->
+ s([{[fStatus3, 1], 4}, {[fname3,0], "ok"}]),
+ ?line expect(1, [{[fStatus3, 1], 4}, {[fname3,0], "ok"}]),
+ s([{[fStatus3, 1], 4}, {[fname3,0], "hoj"}]),
+ ?line expect(2, ?v1_2(badValue, inconsistentValue), 2, any),
+ s([{[fStatus3, 3], 4}, {[fname3,0], "hoj"}]),
+ ?line expect(3, ?v1_2(genErr, undoFailed), 1, any),
+ s([{[fStatus3, 4], 4}, {[fname3,0], "ok"}]),
+ ?line expect(4, ?v1_2(genErr, commitFailed), 1, any),
+% unfortunatly we don't know if we'll get undoFailed or commitFailed.
+% it depends on which order the agent traverses the varbind list.
+% s([{[fStatus3, 4], 4}, {[fname3,0], "ufail"}]),
+% ?line expect(5, ?v1_2(genErr, undoFailed), 1, any),
+ s([{[fStatus3, 1], 4}, {[fname3,0], "xfail"}]),
+ ?line expect(6, genErr, 2, any).
+
+%% Req. Klas3, Klas4
+bad_return() ->
+ g([[fStatus4,4],
+ [fName4,4]]),
+ ?line expect(4, genErr, 2, any),
+ g([[fStatus4,5],
+ [fName4,5]]),
+ ?line expect(5, genErr, 1, any),
+ g([[fStatus4,6],
+ [fName4,6]]),
+ ?line expect(6, genErr, 2, any),
+ gn([[fStatus4,7],
+ [fName4,7]]),
+ ?line expect(7, genErr, 2, any),
+ gn([[fStatus4,8],
+ [fName4,8]]),
+ ?line expect(8, genErr, 1, any),
+ gn([[fStatus4,9],
+ [fName4,9]]),
+ ?line expect(9, genErr, 2, any).
+
+
+%%%-----------------------------------------------------------------
+%%% Test the implementation of standard mibs.
+%%% We should *at least* try to GET all variables, just to make
+%%% sure the instrumentation functions work.
+%%% Note that many of the functions in the standard mib is
+%%% already tested by the normal tests.
+%%%-----------------------------------------------------------------
+standard_mibs(suite) ->
+ [snmp_standard_mib, snmp_community_mib,
+ snmp_framework_mib,
+ snmp_target_mib, snmp_notification_mib,
+ snmp_view_based_acm_mib].
+
+standard_mibs_2(suite) ->
+ [snmpv2_mib_2, snmp_community_mib_2,
+ snmp_framework_mib_2,
+ snmp_target_mib_2, snmp_notification_mib_2,
+ snmp_view_based_acm_mib_2].
+
+standard_mibs_3(suite) ->
+ [snmpv2_mib_3,snmp_framework_mib_3, snmp_mpd_mib_3,
+ snmp_target_mib_3, snmp_notification_mib_3,
+ snmp_view_based_acm_mib_3, snmp_user_based_sm_mib_3].
+
+%%-----------------------------------------------------------------
+%% For this test, the agent is configured for v1.
+%% o Test the counters and control objects in SNMP-STANDARD-MIB
+%%-----------------------------------------------------------------
+snmp_standard_mib(suite) -> [];
+snmp_standard_mib(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?DBG("snmp_standard_mib -> std_mib_init", []),
+ try_test(std_mib_init),
+
+ ?DBG("snmp_standard_mib -> std_mib_a", []),
+ InBadVsns = try_test(std_mib_a),
+ put(vsn, v2),
+ ?DBG("snmp_standard_mib -> std_mib_read", []),
+ try_test(std_mib_read),
+ put(vsn, v1),
+
+ ?DBG("snmp_standard_mib -> std_mib_b (~w)", [InBadVsns]),
+ Bad = try_test(std_mib_b, [InBadVsns]),
+ ?DBG("snmp_standard_mib -> std_mib_read (community: 'bad community')", []),
+ try_test(std_mib_read, [], [{community, "bad community"}]),
+ ?DBG("snmp_standard_mib -> std_mib_write (community: 'public')", []),
+ try_test(std_mib_write, [], [{community, "public"}]),
+ ?DBG("snmp_standard_mib -> std_mib_asn_err", []),
+ try_test(std_mib_asn_err),
+ ?DBG("snmp_standard_mib -> std_mib_c (~w)", [Bad]),
+ try_test(std_mib_c, [Bad]),
+ ?DBG("snmp_standard_mib -> std_mib_a", []),
+ try_test(standard_mib_a),
+
+ ?DBG("snmp_standard_mib -> std_mib_finish", []),
+ try_test(std_mib_finish),
+ ?DBG("snmp_standard_mib -> std_mib_test_finish", []),
+ try_test(standard_mib_test_finish, [], [{community, "bad community"}]).
+
+%% Req. SNMP-STANDARD-MIB
+standard_mib_a() ->
+ ?line [OutPkts] = get_req(2, [[snmpOutPkts,0]]),
+ ?line [OutPkts2] = get_req(3, [[snmpOutPkts,0]]),
+ ?line OutPkts2 = OutPkts + 1,
+ %% There are some more counters we could test here, but it's not that
+ %% important, since they are removed from SNMPv2-MIB.
+ ok.
+
+%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB
+std_mib_init() ->
+ %% disable authentication failure traps. (otherwise w'd get many of
+ %% them - this is also a test to see that it works).
+ s([{[snmpEnableAuthenTraps,0], 2}]),
+ ?line expect(1, [{[snmpEnableAuthenTraps, 0], 2}]).
+
+%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB
+std_mib_finish() ->
+ %% enable again
+ s([{[snmpEnableAuthenTraps,0], 1}]),
+ ?line expect(1, [{[snmpEnableAuthenTraps, 0], 1}]).
+
+%% Req. SNMP-STANDARD-MIB
+standard_mib_test_finish() ->
+ %% force a authenticationFailure
+ std_mib_write(),
+ %% check that we got a trap
+ ?line expect(2, trap, [1,2,3], 4, 0, []).
+
+%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB
+std_mib_read() ->
+ ?DBG("std_mib_read -> entry", []),
+ g([[sysUpTime,0]]), % try a bad <something>; msg dropped, no reply
+ ?DBG("std_mib_read -> await timeout (i.e. no reply)", []),
+ ?line expect(1, timeout). % make sure we don't get a trap!
+
+
+%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB
+std_mib_write() ->
+ ?DBG("std_mib_write -> entry", []),
+ s([{[sysLocation, 0], "new_value"}]).
+
+%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB
+std_mib_asn_err() ->
+ snmp_test_mgr:send_bytes([48,99,67,12,0,0,0,0,0,0,5]).
+
+%%-----------------------------------------------------------------
+%% For this test, the agent is configured for v2 and v3.
+%% o Test the counters and control objects in SNMPv2-MIB
+%%-----------------------------------------------------------------
+snmpv2_mib_2(suite) -> [];
+snmpv2_mib_2(Config) when list(Config) ->
+ ?LOG("snmpv2_mib_2 -> start",[]),
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ ?DBG("snmpv2_mib_2 -> standard mib init",[]),
+ try_test(std_mib_init),
+
+ ?DBG("snmpv2_mib_2 -> get number of (so far) bad versions",[]),
+ InBadVsns = try_test(std_mib_a),
+
+ ?DBG("snmpv2_mib_2 -> make a bad version read",[]),
+ put(vsn, v1),
+ try_test(std_mib_read),
+
+ ?DBG("snmpv2_mib_2 -> bad version read",[]),
+ put(vsn, v2),
+ Bad = try_test(std_mib_b, [InBadVsns]),
+
+ ?DBG("snmpv2_mib_2 -> read with bad community",[]),
+ try_test(std_mib_read, [], [{community, "bad community"}]),
+
+ ?DBG("snmpv2_mib_2 -> write with public community",[]),
+ try_test(std_mib_write, [], [{community, "public"}]),
+
+ ?DBG("snmpv2_mib_2 -> asn err",[]),
+ try_test(std_mib_asn_err),
+
+ ?DBG("snmpv2_mib_2 -> check counters",[]),
+ try_test(std_mib_c, [Bad]),
+
+ ?DBG("snmpv2_mib_2 -> get som counters",[]),
+ try_test(snmpv2_mib_a),
+
+ ?DBG("snmpv2_mib_2 -> enable auth traps, and await some",[]),
+ try_test(std_mib_finish),
+
+ ?DBG("snmpv2_mib_2 -> force auth failure, and await trap, "
+ "then disable auth traps",[]),
+ try_test(snmpv2_mib_test_finish, [], [{community, "bad community"}]),
+
+ ?LOG("snmpv2_mib_2 -> done",[]).
+
+%% Req. SNMPv2-MIB
+snmpv2_mib_3(suite) -> [];
+snmpv2_mib_3(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ InBadVsns = try_test(std_mib_a),
+ put(vsn, v1),
+ try_test(std_mib_read),
+ put(vsn, v3),
+ _Bad = try_test(std_mib_b, [InBadVsns]),
+ try_test(snmpv2_mib_a),
+
+ try_test(std_mib_finish).
+
+-define(authenticationFailure, [1,3,6,1,6,3,1,1,5,5]).
+
+%% Req. SNMPv2-MIB
+snmpv2_mib_test_finish() ->
+ %% force a authenticationFailure
+ ?DBG("ma_v2_inform -> write to std mib",[]),
+ std_mib_write(),
+
+ %% check that we got a trap
+ ?DBG("ma_v2_inform -> await trap",[]),
+ ?line expect(2, v2trap, [{[sysUpTime,0], any},
+ {[snmpTrapOID,0], ?authenticationFailure}]),
+
+ %% and the the inform
+ ?DBG("ma_v2_inform -> await inform",[]),
+ ?line expect(2, {inform,true}, [{[sysUpTime,0], any},
+ {[snmpTrapOID,0],?authenticationFailure}]).
+
+%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB
+std_mib_a() ->
+ ?line [InPkts] = get_req(2, [[snmpInPkts,0]]),
+ ?line [InPkts2] = get_req(3, [[snmpInPkts,0]]),
+ ?line InPkts2 = InPkts + 1,
+
+ ?line [InBadVsns] = get_req(4, [[snmpInBadVersions,0]]),
+ InBadVsns.
+
+%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB
+std_mib_b(InBadVsns) ->
+ ?line [InBadVsns2] = get_req(1, [[snmpInBadVersions,0]]),
+ ?line InBadVsns2 = InBadVsns + 1,
+ ?line [InPkts] = get_req(2, [[snmpInPkts,0]]),
+ ?line [InPkts2] = get_req(3, [[snmpInPkts,0]]),
+ ?line InPkts2 = InPkts + 1,
+ ?line [InBadCommunityNames, InBadCommunityUses, InASNErrs] =
+ get_req(4, [[snmpInBadCommunityNames,0],
+ [snmpInBadCommunityUses,0],
+ [snmpInASNParseErrs, 0]]),
+ {InBadCommunityNames, InBadCommunityUses, InASNErrs}.
+
+%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB
+std_mib_c({InBadCommunityNames, InBadCommunityUses, InASNErrs}) ->
+ ?line [InBadCommunityNames2, InBadCommunityUses2, InASNErrs2] =
+ get_req(1, [[snmpInBadCommunityNames,0],
+ [snmpInBadCommunityUses,0],
+ [snmpInASNParseErrs, 0]]),
+ ?line InBadCommunityNames2 = InBadCommunityNames + 1,
+ ?line InBadCommunityUses2 = InBadCommunityUses + 1,
+ ?line InASNErrs2 = InASNErrs + 1.
+
+%% Req. SNMPv2-MIB
+snmpv2_mib_a() ->
+ ?line [SetSerial] = get_req(2, [[snmpSetSerialNo,0]]),
+ s([{[snmpSetSerialNo,0], SetSerial}, {[sysLocation, 0], "val2"}]),
+ ?line expect(3, [{[snmpSetSerialNo,0], SetSerial},
+ {[sysLocation, 0], "val2"}]),
+ s([{[sysLocation, 0], "val3"}, {[snmpSetSerialNo,0], SetSerial}]),
+ ?line expect(4, inconsistentValue, 2,
+ [{[sysLocation, 0], "val3"},
+ {[snmpSetSerialNo,0], SetSerial}]),
+ ?line ["val2"] = get_req(5, [[sysLocation,0]]).
+
+
+%%-----------------------------------------------------------------
+%% o Bad community uses/name is tested already
+%% in SNMPv2-MIB and STANDARD-MIB.
+%% o Test add/deletion of rows.
+%%-----------------------------------------------------------------
+snmp_community_mib(suite) -> [];
+snmp_community_mib(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?line load_master_std("SNMP-COMMUNITY-MIB"),
+ try_test(snmp_community_mib),
+ ?line unload_master("SNMP-COMMUNITY-MIB").
+
+snmp_community_mib_2(X) -> snmp_community_mib(X).
+
+%% Req. SNMP-COMMUNITY-MIB
+snmp_community_mib() ->
+ ?INF("NOT YET IMPLEMENTED", []),
+ nyi.
+
+%%-----------------------------------------------------------------
+%% o Test engine boots / time
+%%-----------------------------------------------------------------
+snmp_framework_mib(suite) -> [];
+snmp_framework_mib(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?line load_master_std("SNMP-FRAMEWORK-MIB"),
+ try_test(snmp_framework_mib),
+ ?line unload_master("SNMP-FRAMEWORK-MIB").
+
+snmp_framework_mib_2(X) -> snmp_framework_mib(X).
+
+snmp_framework_mib_3(suite) -> [];
+snmp_framework_mib_3(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ try_test(snmp_framework_mib).
+
+
+%% Req. SNMP-FRAMEWORK-MIB
+snmp_framework_mib() ->
+ ?line ["agentEngine"] = get_req(1, [[snmpEngineID,0]]),
+ ?line [EngineTime] = get_req(2, [[snmpEngineTime,0]]),
+ sleep(5000),
+ ?line [EngineTime2] = get_req(3, [[snmpEngineTime,0]]),
+ if
+ EngineTime+7 < EngineTime2 ->
+ ?line ?FAIL({too_large_diff, EngineTime, EngineTime2});
+ EngineTime+4 > EngineTime2 ->
+ ?line ?FAIL({too_large_diff, EngineTime, EngineTime2});
+ true -> ok
+ end,
+ ?line case get_req(4, [[snmpEngineBoots,0]]) of
+ [Boots] when integer(Boots) -> ok;
+ Else -> ?FAIL(Else)
+ end,
+ ok.
+
+%%-----------------------------------------------------------------
+%% o Test the counters
+%%-----------------------------------------------------------------
+snmp_mpd_mib_3(suite) -> [];
+snmp_mpd_mib_3(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ UnknownPDUHs = try_test(snmp_mpd_mib_a),
+ try_test(snmp_mpd_mib_b, [], [{context_engine_id, "bad engine"}]),
+ try_test(snmp_mpd_mib_c, [UnknownPDUHs]).
+
+
+%% Req. SNMP-MPD-MIB
+snmp_mpd_mib_a() ->
+ ?line [UnknownSecs, InvalidMsgs] =
+ get_req(1, [[snmpUnknownSecurityModels,0],
+ [snmpInvalidMsgs,0]]),
+ Pdu = #pdu{type = 'get-request',
+ request_id = 23,
+ error_status = noError,
+ error_index = 0,
+ varbinds = []},
+ SPdu = #scopedPdu{contextEngineID = "agentEngine",
+ contextName = "",
+ data = Pdu},
+ ?line SPDUBytes = snmp_pdus:enc_scoped_pdu(SPdu),
+ V3Hdr1 = #v3_hdr{msgID = 21,
+ msgMaxSize = 484,
+ msgFlags = [7],
+ msgSecurityModel = 23, % bad sec model
+ msgSecurityParameters = []},
+ V3Hdr2 = #v3_hdr{msgID = 21,
+ msgMaxSize = 484,
+ msgFlags = [6], % bad flag combination
+ msgSecurityModel = 3,
+ msgSecurityParameters = []},
+ Message1 = #message{version = 'version-3', vsn_hdr = V3Hdr1,
+ data = SPDUBytes},
+ Message2 = #message{version = 'version-3', vsn_hdr = V3Hdr2,
+ data = SPDUBytes},
+ ?line MsgBytes1 = snmp_pdus:enc_message_only(Message1),
+ ?line MsgBytes2 = snmp_pdus:enc_message_only(Message2),
+ snmp_test_mgr:send_bytes(MsgBytes1),
+ snmp_test_mgr:send_bytes(MsgBytes2),
+
+ ?line [UnknownSecs2, InvalidMsgs2, UnknownPDUHs] =
+ get_req(1, [[snmpUnknownSecurityModels,0],
+ [snmpInvalidMsgs,0],
+ [snmpUnknownPDUHandlers, 0]]),
+ ?line UnknownSecs2 = UnknownSecs + 1,
+ ?line InvalidMsgs2 = InvalidMsgs + 1,
+ UnknownPDUHs.
+
+-define(snmpUnknownPDUHandlers_instance, [1,3,6,1,6,3,11,2,1,3,0]).
+snmp_mpd_mib_b() ->
+ g([[sysUpTime,0]]),
+ ?line expect(1, report, [{?snmpUnknownPDUHandlers_instance, any}]).
+
+
+snmp_mpd_mib_c(UnknownPDUHs) ->
+ ?line [UnknownPDUHs2] = get_req(1, [[snmpUnknownPDUHandlers, 0]]),
+ ?line UnknownPDUHs2 = UnknownPDUHs + 1.
+
+
+snmp_target_mib(suite) -> [];
+snmp_target_mib(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?line load_master_std("SNMP-TARGET-MIB"),
+ try_test(snmp_target_mib),
+ ?line unload_master("SNMP-TARGET-MIB").
+
+snmp_target_mib_2(X) -> snmp_target_mib(X).
+
+snmp_target_mib_3(X) -> snmp_target_mib(X).
+
+snmp_target_mib() ->
+ ?INF("NOT YET IMPLEMENTED", []),
+ nyi.
+
+snmp_notification_mib(suite) -> [];
+snmp_notification_mib(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?line load_master_std("SNMP-NOTIFICATION-MIB"),
+ try_test(snmp_notification_mib),
+ ?line unload_master("SNMP-NOTIFICATION-MIB").
+
+snmp_notification_mib_2(X) -> snmp_notification_mib(X).
+
+snmp_notification_mib_3(X) -> snmp_notification_mib(X).
+
+snmp_notification_mib() ->
+ ?INF("NOT YET IMPLEMENTED", []),
+ nyi.
+
+%%-----------------------------------------------------------------
+%% o add/delete views and try them
+%% o try boundaries
+%%-----------------------------------------------------------------
+snmp_view_based_acm_mib(suite) -> [];
+snmp_view_based_acm_mib(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"),
+ ?line load_master("Test2"),
+ snmp_view_based_acm_mib(),
+ ?line unload_master("Test2"),
+ ?line unload_master("SNMP-VIEW-BASED-ACM-MIB").
+
+snmp_view_based_acm_mib_2(X) -> snmp_view_based_acm_mib(X).
+
+snmp_view_based_acm_mib_3(X) -> snmp_view_based_acm_mib(X).
+
+snmp_view_based_acm_mib() ->
+ snmpa:verbosity(net_if,trace),
+ snmpa:verbosity(master_agent,trace),
+ ?LOG("start snmp_view_based_acm_mib test",[]),
+ %% The user "no-rights" is present in USM, and is mapped to security
+ %% name 'no-rights", which is not present in VACM.
+ %% So, we'll add rights for it, try them and delete them.
+ %% We'll give "no-rights" write access to tDescr.0 and read access
+ %% to tDescr2.0
+ %% These are the options we'll use to the mgr
+ Opts = [{user, "no-rights"}, {community, "no-rights"}],
+ %% Find the valid secmodel, and one invalid secmodel.
+ {SecMod, InvSecMod} =
+ case get(vsn) of
+ v1 -> {?SEC_V1, ?SEC_V2C};
+ v2 -> {?SEC_V2C, ?SEC_USM};
+ v3 -> {?SEC_USM, ?SEC_V1}
+ end,
+ ?DBG("assign rights for 'no-rights'",[]),
+ ?line try_test(use_no_rights, [], Opts),
+
+ %% Now, add a mapping from "no-rights" -> "no-rights-group"
+ GRow1Status = [vacmSecurityToGroupStatus,[SecMod, 9,"no-rights"]],
+ GRow1 =
+ [{[vacmGroupName, [SecMod, 9,"no-rights"]], "no-rights-group"},
+ {GRow1Status, ?createAndGo}],
+ ?DBG("set '~p'",[GRow1]),
+ ?line try_test(do_set, [GRow1]),
+
+ ?DBG("assign rights for 'no-rights'",[]),
+ ?line try_test(use_no_rights, [], Opts),
+
+ %% Create a mapping for another sec model, and make sure it dosn't
+ %% give us access
+ GRow2Status = [vacmSecurityToGroupStatus,[InvSecMod, 9,"no-rights"]],
+ GRow2 = [{[vacmGroupName, [InvSecMod, 9, "no-rights"]], "initial"},
+ {GRow2Status, ?createAndGo}],
+
+ ?DBG("set '~p'",[GRow2]),
+ ?line try_test(do_set, [GRow2]),
+
+ ?DBG("assign rights for 'no-rights'",[]),
+ ?line try_test(use_no_rights, [], Opts),
+
+ %% Delete that row
+ ?line try_test(del_row, [GRow2Status]),
+
+ RVName = "rv_name",
+ WVName = "wv_name",
+
+ %% Access row
+ ARow1Idx = [15 | "no-rights-group"] ++ [0, ?SEC_ANY, 1],
+ ARow1Status = [vacmAccessStatus, ARow1Idx],
+ ARow1 = [{[vacmAccessContextMatch, ARow1Idx], 1},
+ {[vacmAccessReadViewName, ARow1Idx], RVName},
+ {[vacmAccessWriteViewName, ARow1Idx], WVName},
+ {ARow1Status, ?createAndGo}],
+
+ %% This access row would give acces, if InvSecMod was valid.
+ ARow2Idx = [15 | "no-rights-group"] ++ [0, InvSecMod, 1],
+ ARow2Status = [vacmAccessStatus, ARow2Idx],
+ ARow2 = [{[vacmAccessContextMatch, ARow2Idx], 1},
+ {[vacmAccessReadViewName, ARow2Idx], "internet"},
+ {[vacmAccessWriteViewName, ARow2Idx], "internet"},
+ {ARow2Status, ?createAndGo}],
+
+ ?line try_test(do_set, [ARow2]),
+
+ ?line try_test(use_no_rights, [], Opts),
+
+ %% Delete that row
+ ?line try_test(del_row, [ARow2Status]),
+
+
+ %% Add valid row
+ ?line try_test(do_set, [ARow1]),
+
+ ?line try_test(use_no_rights, [], Opts),
+
+ %% Create the view family
+ VRow1Idx = mk_ln(RVName) ++ mk_ln(?xDescr), % object access
+ VRow2Idx = mk_ln(RVName) ++ mk_ln(?xDescr2 ++ [0]), % instance access
+ VRow3Idx = mk_ln(WVName) ++ mk_ln(?xDescr), % object access
+ VRow4Idx = mk_ln(WVName) ++ mk_ln(?xDescr ++ [0]), % instance access
+ VRow1Status = [vacmViewTreeFamilyStatus, VRow1Idx],
+ VRow2Status = [vacmViewTreeFamilyStatus, VRow2Idx],
+ VRow3Status = [vacmViewTreeFamilyStatus, VRow3Idx],
+ VRow4Status = [vacmViewTreeFamilyStatus, VRow4Idx],
+
+ ?line try_test(add_row, [VRow1Status]),
+ ?line try_test(add_row, [VRow2Status]),
+ ?line try_test(add_row, [VRow3Status]),
+
+ %% We're supposed to have access now...
+ ?line try_test(use_rights, [], Opts),
+
+ %% Change Row3 to Row4
+ ?line try_test(del_row, [VRow3Status]),
+ ?line try_test(add_row, [VRow4Status]),
+
+ %% We should still have access...
+ ?line try_test(use_rights, [], Opts),
+
+ %% Delete rows
+ ?line try_test(del_row, [GRow1Status]),
+
+ ?line try_test(use_no_rights, [], Opts),
+
+ %% Delete rest of rows
+ ?line try_test(del_row, [ARow1Status]),
+ ?line try_test(del_row, [VRow1Status]),
+ ?line try_test(del_row, [VRow2Status]),
+ ?line try_test(del_row, [VRow4Status]),
+
+ ?line try_test(use_no_rights, [], Opts),
+ snmpa:verbosity(master_agent,log).
+
+do_set(Row) ->
+ s(Row),
+ expect(1, Row).
+
+add_row(RowStatus) ->
+ s([{RowStatus, ?createAndGo}]),
+ expect(1, [{RowStatus, ?createAndGo}]).
+
+del_row(RowStatus) ->
+ s([{RowStatus, ?destroy}]),
+ expect(1, [{RowStatus, ?destroy}]).
+
+
+
+use_no_rights() ->
+ g([[xDescr,0]]),
+ ?v1_2_3(expect(11, noSuchName, 1, any),
+ expect(12, [{[xDescr,0], noSuchObject}]),
+ expect(13, authorizationError, 1, any)),
+ g([[xDescr2,0]]),
+ ?v1_2_3(expect(21, noSuchName, 1, any),
+ expect(22, [{[xDescr2,0], noSuchObject}]),
+ expect(23, authorizationError, 1, any)),
+ gn([[xDescr]]),
+ ?v1_2_3(expect(31, noSuchName, 1, any),
+ expect(32, [{[xDescr], endOfMibView}]),
+ expect(33, authorizationError, 1, any)),
+ s([{[xDescr,0], "tryit"}]),
+ ?v1_2_3(expect(41, noSuchName, 1, any),
+ expect(42, noAccess, 1, any),
+ expect(43, authorizationError, 1, any)).
+
+
+use_rights() ->
+ g([[xDescr,0]]),
+ expect(1, [{[xDescr,0], any}]),
+ g([[xDescr2,0]]),
+ expect(2, [{[xDescr2,0], any}]),
+ s([{[xDescr,0], "tryit"}]),
+ expect(3, noError, 0, any),
+ g([[xDescr,0]]),
+ expect(4, [{[xDescr,0], "tryit"}]).
+
+mk_ln(X) ->
+ [length(X) | X].
+
+%%-----------------------------------------------------------------
+%% o add/delete users and try them
+%% o test all secLevels
+%% o test all combinations of protocols
+%% o try bad ops; check counters
+%%-----------------------------------------------------------------
+snmp_user_based_sm_mib_3(suite) -> [];
+snmp_user_based_sm_mib_3(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ _AgentDir = ?config(agent_dir, Config),
+ ?line load_master_std("SNMP-USER-BASED-SM-MIB"),
+
+ %% The newUser used here already has VACM access.
+
+ %% Add a new user in the simplest way; just createAndGo
+ try_test(v3_sync, [[{usm_add_user1, []}]],
+ [{sec_level, authPriv}, {user, "privDES"}]),
+
+ %% Try to use the new user
+ ?line load_master("Test2"),
+ try_test(v3_sync, [[{usm_use_user, []}]],
+ [{sec_level, authPriv}, {user, "newUser"}]),
+ ?line unload_master("Test2"),
+
+ ShaKey1 = snmp:passwd2localized_key(sha, "new sha password", "agentEngine"),
+ DesKey1 = lists:sublist(ShaKey1, 16),
+
+ %% Change the new user's keys - 1
+ try_test(v3_sync, [[{usm_key_change1, [ShaKey1, DesKey1]}]],
+ [{sec_level, authPriv}, {user, "newUser"}]),
+
+ %% Try to use the new keys
+ MgrDir = ?config(mgr_dir, Config),
+ ?line rewrite_usm_mgr(MgrDir, ShaKey1, DesKey1),
+ ?line load_master("Test2"),
+ try_test(v3_sync, [[{usm_use_user, []}]],
+ [{sec_level, authPriv}, {user, "newUser"}]),
+ ?line unload_master("Test2"),
+
+ ShaKey2 = snmp:passwd2localized_key(sha, "newer password", "agentEngine"),
+ DesKey2 = lists:sublist(ShaKey2, 16),
+
+ %% Change the new user's keys - 2
+ ?line try_test(v3_sync,
+ [[{usm_key_change2, [ShaKey1, DesKey1, ShaKey2, DesKey2]}]],
+ [{sec_level, authPriv}, {user, "newUser"}]),
+
+ %% Try to use the new keys
+ reset_usm_mgr(MgrDir),
+ ?line rewrite_usm_mgr(MgrDir, ShaKey2, DesKey2),
+ ?line load_master("Test2"),
+ ?line try_test(v3_sync, [[{usm_use_user, []}]],
+ [{sec_level, authPriv}, {user, "newUser"}]),
+ ?line unload_master("Test2"),
+ reset_usm_mgr(MgrDir),
+
+ %% Change the new user's keys - 3
+ ?line try_test(v3_sync,
+ [[{usm_key_change3, [ShaKey2, DesKey2, ShaKey1, DesKey1]}]],
+ [{sec_level, authPriv}, {user, "privDES"}]),
+
+ %% Try to use the new keys
+ ?line rewrite_usm_mgr(MgrDir, ShaKey1, DesKey1),
+ ?line load_master("Test2"),
+ try_test(v3_sync, [[{usm_use_user, []}]],
+ [{sec_level, authPriv}, {user, "newUser"}]),
+ ?line unload_master("Test2"),
+ reset_usm_mgr(MgrDir),
+
+ %% Try some read requests
+ ?line try_test(v3_sync, [[{usm_read, []}]],
+ [{sec_level, authPriv}, {user, "privDES"}]),
+
+ %% Delete the new user
+ ?line try_test(v3_sync, [[{usm_del_user, []}]],
+ [{sec_level, authPriv}, {user, "privDES"}]),
+
+ %% Try some bad requests
+ ?line try_test(v3_sync, [[{usm_bad, []}]],
+ [{sec_level, authPriv}, {user, "privDES"}]),
+
+ ?line unload_master("SNMP-USER-BASED-SM-MIB").
+
+-define(usmUserSecurityName, [1,3,6,1,6,3,15,1,2,2,1,3]).
+
+usm_add_user1() ->
+ NewRowIndex = [11,"agentEngine", 7, "newUser"],
+ RowPointer = ?usmUserSecurityName ++ [11|"agentEngine"] ++ [7|"privDES"],
+ Vbs1 = [{[usmUserCloneFrom, NewRowIndex], RowPointer},
+ {[usmUserStatus, NewRowIndex], ?createAndGo}],
+ ?line s(Vbs1),
+ ?line expect(1, Vbs1),
+ ok.
+
+usm_use_user() ->
+ v2_proc().
+
+
+%% Change own public keys
+usm_key_change1(ShaKey, DesKey) ->
+ NewRowIndex = [11,"agentEngine", 7, "newUser"],
+ ShaKeyChange = snmp_user_based_sm_mib:mk_key_change(sha,
+ "passwd_shaxxxxxxxxxx",
+ ShaKey),
+ DesKeyChange = snmp_user_based_sm_mib:mk_key_change(sha,
+ "passwd_desxxxxxx",
+ DesKey),
+ Vbs1 = [{[usmUserAuthKeyChange, NewRowIndex], ShaKeyChange},
+ {[usmUserPrivKeyChange, NewRowIndex], DesKeyChange}],
+ s(Vbs1),
+ ?line expect(1, Vbs1).
+
+%% Change own private keys
+usm_key_change2(OldShaKey, OldDesKey, ShaKey, DesKey) ->
+ NewRowIndex = [11,"agentEngine", 7, "newUser"],
+ ShaKeyChange = snmp_user_based_sm_mib:mk_key_change(sha,
+ OldShaKey,
+ ShaKey),
+ DesKeyChange = snmp_user_based_sm_mib:mk_key_change(sha,
+ OldDesKey,
+ DesKey),
+ Vbs1 = [{[usmUserOwnAuthKeyChange, NewRowIndex], ShaKeyChange},
+ {[usmUserOwnPrivKeyChange, NewRowIndex], DesKeyChange}],
+ s(Vbs1),
+ ?line expect(1, Vbs1).
+
+%% Change other's public keys
+usm_key_change3(OldShaKey, OldDesKey, ShaKey, DesKey) ->
+ NewRowIndex = [11,"agentEngine", 7, "newUser"],
+ ShaKeyChange = snmp_user_based_sm_mib:mk_key_change(sha,
+ OldShaKey,
+ ShaKey),
+ DesKeyChange = snmp_user_based_sm_mib:mk_key_change(sha,
+ OldDesKey,
+ DesKey),
+ Vbs1 = [{[usmUserOwnAuthKeyChange, NewRowIndex], ShaKeyChange}],
+ s(Vbs1),
+ ?line expect(1, noAccess, 1, any),
+ Vbs2 = [{[usmUserOwnPrivKeyChange, NewRowIndex], DesKeyChange}],
+ s(Vbs2),
+ ?line expect(2, noAccess, 1, any),
+
+
+ Vbs3 = [{[usmUserAuthKeyChange, NewRowIndex], ShaKeyChange},
+ {[usmUserPrivKeyChange, NewRowIndex], DesKeyChange}],
+ s(Vbs3),
+ ?line expect(1, Vbs3).
+
+usm_read() ->
+ NewRowIndex = [11,"agentEngine", 7, "newUser"],
+ ?line g([[usmUserSecurityName, NewRowIndex],
+ [usmUserCloneFrom, NewRowIndex],
+ [usmUserAuthKeyChange, NewRowIndex],
+ [usmUserOwnAuthKeyChange, NewRowIndex],
+ [usmUserPrivKeyChange, NewRowIndex],
+ [usmUserOwnPrivKeyChange, NewRowIndex]]),
+ ?line expect(1,
+ [{[usmUserSecurityName, NewRowIndex], "newUser"},
+ {[usmUserCloneFrom, NewRowIndex], [0,0]},
+ {[usmUserAuthKeyChange, NewRowIndex], ""},
+ {[usmUserOwnAuthKeyChange, NewRowIndex], ""},
+ {[usmUserPrivKeyChange, NewRowIndex], ""},
+ {[usmUserOwnPrivKeyChange, NewRowIndex], ""}]),
+ ok.
+
+
+
+usm_del_user() ->
+ NewRowIndex = [11,"agentEngine", 7, "newUser"],
+ Vbs1 = [{[usmUserStatus, NewRowIndex], ?destroy}],
+ ?line s(Vbs1),
+ ?line expect(1, Vbs1),
+ ok.
+
+-define(usmUserCloneFrom, [1,3,6,1,6,3,15,1,2,2,1,4]).
+
+-define(usmNoAuthProtocol, [1,3,6,1,6,3,10,1,1,1]).
+
+-define(usmHMACMD5AuthProtocol, [1,3,6,1,6,3,10,1,1,2]).
+
+-define(usmHMACSHAAuthProtocol, [1,3,6,1,6,3,10,1,1,3]).
+
+-define(usmNoPrivProtocol, [1,3,6,1,6,3,10,1,2,1]).
+
+-define(usmDESPrivProtocol, [1,3,6,1,6,3,10,1,2,2]).
+
+usm_bad() ->
+ NewRowIndex = [11,"agentEngine", 7, "newUser"],
+ RowPointer1 = ?usmUserSecurityName ++ [11|"agentEngine"] ++ [7|"privDOS"],
+ Vbs1 = [{[usmUserCloneFrom, NewRowIndex], RowPointer1},
+ {[usmUserStatus, NewRowIndex], ?createAndGo}],
+ ?line s(Vbs1),
+ ?line expect(1, inconsistentName, 1, any),
+
+ RowPointer2 = ?usmUserCloneFrom ++ [11|"agentEngine"] ++ [7|"privDES"],
+ Vbs2 = [{[usmUserCloneFrom, NewRowIndex], RowPointer2},
+ {[usmUserStatus, NewRowIndex], ?createAndGo}],
+ ?line s(Vbs2),
+ ?line expect(2, wrongValue, 1, any),
+
+ RowPointer3 = ?usmUserSecurityName ++ [11|"agentEngine"] ++ [7|"privDES"],
+ Vbs3 = [{[usmUserCloneFrom, NewRowIndex], RowPointer3},
+ {[usmUserStatus, NewRowIndex], ?createAndGo}],
+ ?line s(Vbs3),
+ ?line expect(3, Vbs3),
+ ?line s([{[usmUserAuthProtocol, NewRowIndex], ?usmNoAuthProtocol}]),
+ ?line expect(4, inconsistentValue, 1, any),
+ ?line s([{[usmUserAuthProtocol, NewRowIndex], ?usmHMACMD5AuthProtocol}]),
+ ?line expect(5, inconsistentValue, 1, any),
+ ?line s([{[usmUserAuthProtocol, NewRowIndex], ?usmDESPrivProtocol}]),
+ ?line expect(6, wrongValue, 1, any),
+ ?line s([{[usmUserPrivProtocol, NewRowIndex], ?usmHMACSHAAuthProtocol}]),
+ ?line expect(7, wrongValue, 1, any),
+
+ Vbs4 = [{[usmUserStatus, NewRowIndex], ?destroy}],
+ ?line s(Vbs4),
+ ?line expect(1, Vbs4),
+
+ ok.
+
+
+%%-----------------------------------------------------------------
+%% Loop through entire MIB, to make sure that all instrum. funcs
+%% works.
+%% Load all std mibs that are not loaded by default.
+%%-----------------------------------------------------------------
+loop_mib(suite) -> [];
+loop_mib(Config) when list(Config) ->
+ ?LOG("loop_mib -> initiate case",[]),
+ %% snmpa:verbosity(master_agent,debug),
+ %% snmpa:verbosity(mib_server,info),
+ {SaNode, MgrNode, MibDir} = init_case(Config),
+ ?DBG("loop_mib -> ~n"
+ "\tSaNode: ~p~n"
+ "\tMgrNode: ~p~n"
+ "\tMibDir: ~p",[SaNode, MgrNode, MibDir]),
+ ?DBG("loop_mib -> load mib SNMP-COMMUNITY-MIB",[]),
+ ?line load_master_std("SNMP-COMMUNITY-MIB"),
+ ?DBG("loop_mib -> load mib SNMP-MPD-MIB",[]),
+ ?line load_master_std("SNMP-MPD-MIB"),
+ ?DBG("loop_mib -> load mib SNMP-TARGET-MIB",[]),
+ ?line load_master_std("SNMP-TARGET-MIB"),
+ ?DBG("loop_mib -> load mib SNMP-NOTIFICATION-MIB",[]),
+ ?line load_master_std("SNMP-NOTIFICATION-MIB"),
+ ?DBG("loop_mib -> load mib SNMP-FRAMEWORK-MIB",[]),
+ ?line load_master_std("SNMP-FRAMEWORK-MIB"),
+ ?DBG("loop_mib -> load mib SNMP-VIEW-BASED-ACM-MIB",[]),
+ ?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"),
+ ?DBG("loop_mib -> try",[]),
+ try_test(loop_mib_1),
+ ?DBG("loop_mib -> unload mib SNMP-COMMUNITY-MIB",[]),
+ ?line unload_master("SNMP-COMMUNITY-MIB"),
+ ?DBG("loop_mib -> unload mib SNMP-MPD-MIB",[]),
+ ?line unload_master("SNMP-MPD-MIB"),
+ ?DBG("loop_mib -> unload mib SNMP-TARGET-MIB",[]),
+ ?line unload_master("SNMP-TARGET-MIB"),
+ ?DBG("loop_mib -> unload mib SNMP-NOTIFICATION-MIB",[]),
+ ?line unload_master("SNMP-NOTIFICATION-MIB"),
+ ?DBG("loop_mib -> unload mib SNMP-FRAMEWORK-MIB",[]),
+ ?line unload_master("SNMP-FRAMEWORK-MIB"),
+ ?DBG("loop_mib -> unload mib SNMP-VIEW-BASED-ACM-MIB",[]),
+ ?line unload_master("SNMP-VIEW-BASED-ACM-MIB"),
+ %% snmpa:verbosity(master_agent,log),
+ %% snmpa:verbosity(mib_server,silence),
+ ?LOG("loop_mib -> done",[]).
+
+
+loop_mib_2(suite) -> [];
+loop_mib_2(Config) when list(Config) ->
+ ?LOG("loop_mib_2 -> initiate case",[]),
+ {SaNode, MgrNode, MibDir} = init_case(Config),
+ ?DBG("loop_mib_2 -> ~n"
+ "\tSaNode: ~p~n"
+ "\tMgrNode: ~p~n"
+ "\tMibDir: ~p",[SaNode, MgrNode, MibDir]),
+ ?DBG("loop_mib_2 -> load mibs",[]),
+ ?line load_master_std("SNMP-COMMUNITY-MIB"),
+ ?line load_master_std("SNMP-MPD-MIB"),
+ ?line load_master_std("SNMP-TARGET-MIB"),
+ ?line load_master_std("SNMP-NOTIFICATION-MIB"),
+ ?line load_master_std("SNMP-FRAMEWORK-MIB"),
+ ?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"),
+ try_test(loop_mib_2),
+ ?DBG("loop_mib_2 -> unload mibs",[]),
+ ?line unload_master("SNMP-COMMUNITY-MIB"),
+ ?line unload_master("SNMP-MPD-MIB"),
+ ?line unload_master("SNMP-TARGET-MIB"),
+ ?line unload_master("SNMP-NOTIFICATION-MIB"),
+ ?line unload_master("SNMP-FRAMEWORK-MIB"),
+ ?line unload_master("SNMP-VIEW-BASED-ACM-MIB"),
+ ?LOG("loop_mib_2 -> done",[]).
+
+
+loop_mib_3(suite) -> [];
+loop_mib_3(Config) when list(Config) ->
+ ?LOG("loop_mib_3 -> initiate case",[]),
+ {SaNode, MgrNode, MibDir} = init_case(Config),
+ ?DBG("loop_mib_3 -> ~n"
+ "\tSaNode: ~p~n"
+ "\tMgrNode: ~p~n"
+ "\tMibDir: ~p",[SaNode, MgrNode, MibDir]),
+ ?DBG("loop_mib_3 -> load mibs",[]),
+ ?line load_master_std("SNMP-TARGET-MIB"),
+ ?line load_master_std("SNMP-NOTIFICATION-MIB"),
+ ?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"),
+ ?line load_master_std("SNMP-USER-BASED-SM-MIB"),
+ try_test(loop_mib_2),
+ ?DBG("loop_mib_3 -> unload mibs",[]),
+ ?line unload_master("SNMP-TARGET-MIB"),
+ ?line unload_master("SNMP-NOTIFICATION-MIB"),
+ ?line unload_master("SNMP-VIEW-BASED-ACM-MIB"),
+ ?line unload_master("SNMP-USER-BASED-SM-MIB"),
+ ?LOG("loop_mib_3 -> done",[]).
+
+
+%% Req. As many mibs all possible
+loop_mib_1() ->
+ ?DBG("loop_mib_1 -> entry",[]),
+ N = loop_it_1([1,1], 0),
+ io:format(user, "found ~w varibles\n", [N]),
+ ?line N = if N < 100 -> 100;
+ true -> N
+ end.
+
+
+loop_it_1(Oid, N) ->
+ ?DBG("loop_it_1 -> entry with~n"
+ "\tOid: ~p~n"
+ "\tN: ~p",[Oid,N]),
+ case get_next_req([Oid]) of
+ #pdu{type='get-response', error_status=noError, error_index=0,
+ varbinds=[#varbind{oid = NOid,value = Value}]} when NOid > Oid ->
+ ?DBG("loop_it_1 -> ~n"
+ "\tNOid: ~p~n"
+ "\tValue: ~p",[NOid,Value]),
+ ?line [Value2] = get_req(1, [NOid]), % must not be same
+ ?DBG("loop_it_1 -> ~n"
+ "\tValue2: ~p",[Value2]),
+ loop_it_1(NOid, N+1);
+ #pdu{type='get-response', error_status=noSuchName, error_index=1,
+ varbinds=[_]} ->
+ ?DBG("loop_it_1 -> done",[]),
+ N;
+
+ #pdu{type = Type, error_status = Err, error_index = Idx,
+ varbinds = Vbs} ->
+ exit({unexpected_pdu, ?LINE, Type, Err, Idx, Vbs})
+ end.
+
+%% Req. As many mibs all possible
+loop_mib_2() ->
+ ?DBG("loop_mib_1 -> entry",[]),
+ N = loop_it_2([1,1], 0),
+ io:format(user, "found ~w varibles\n", [N]),
+ ?line N = if N < 100 -> 100;
+ true -> N
+ end.
+
+
+loop_it_2(Oid, N) ->
+ ?DBG("loop_it_2 -> entry with~n"
+ "\tOid: ~p~n"
+ "\tN: ~p",[Oid,N]),
+ case get_next_req([Oid]) of
+ #pdu{type='get-response', error_status=noError, error_index=0,
+ varbinds=[#varbind{oid = NOid, value = endOfMibView}]} ->
+ ?DBG("loop_it_2 -> ~n"
+ "\tNOid: ~p",[NOid]),
+ N;
+ #pdu{type='get-response', error_status=noError, error_index=0,
+ varbinds=[#varbind{oid = NOid,value = Value}]} when NOid > Oid ->
+ ?DBG("loop_it_2 -> ~n"
+ "\tNOid: ~p~n"
+ "\tValue: ~p",[NOid,Value]),
+ ?line [Value2] = get_req(1, [NOid]), % must not be same
+ ?DBG("loop_it_2 -> ~n"
+ "\tValue2: ~p",[Value2]),
+ loop_it_2(NOid, N+1)
+ end.
+
+
+%%%-----------------------------------------------------------------
+%%% Testing of reported bugs and other tickets.
+%%%-----------------------------------------------------------------
+
+reported_bugs(suite) ->
+ [otp_1128, otp_1129, otp_1131, otp_1162,
+ otp_1222, otp_1298, otp_1331, otp_1338,
+ otp_1342, otp_2776, otp_2979, otp_3187, otp_3725].
+
+reported_bugs_2(suite) ->
+ [otp_1128_2, otp_1129_2, otp_1131_2, otp_1162_2,
+ otp_1222_2, otp_1298_2, otp_1331_2, otp_1338_2,
+ otp_1342_2, otp_2776_2, otp_2979_2, otp_3187_2].
+
+reported_bugs_3(suite) ->
+ [otp_1128_3, otp_1129_3, otp_1131_3, otp_1162_3,
+ otp_1222_3, otp_1298_3, otp_1331_3, otp_1338_3,
+ otp_1342_3, otp_2776_3, otp_2979_3, otp_3187_3,
+ otp_3542].
+
+
+%% These are (ticket) test cases where the initiation has to be done
+%% individually.
+tickets(suite) ->
+ [otp_4394].
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-1128
+%% Slogan: Bug in handling of createAndWait set-requests.
+%%-----------------------------------------------------------------
+otp_1128(suite) -> [];
+otp_1128(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?line load_master("OLD-SNMPEA-MIB"),
+ ?line init_old(),
+ try_test(otp_1128),
+ ?line unload_master("OLD-SNMPEA-MIB").
+
+otp_1128_2(X) -> otp_1128(X).
+
+otp_1128_3(X) -> otp_1128(X).
+
+otp_1128() ->
+ io:format("Testing bug reported in ticket OTP-1128...~n"),
+
+ NewKeyc3 = [intCommunityViewIndex,get(mip),is("test")],
+ NewKeyc4 = [intCommunityAccess,get(mip),is("test")],
+ NewKeyc5 = [intCommunityStatus,get(mip),is("test")],
+
+ s([{NewKeyc5, ?createAndWait}, {NewKeyc4, 2}]),
+ ?line expect(28, [{NewKeyc5, ?createAndWait}, {NewKeyc4, 2}]),
+ g([NewKeyc5]),
+ ?line expect(29, [{NewKeyc5, ?notReady}]),
+ s([{NewKeyc5, ?active}, {NewKeyc3, 2}]),
+ ?line expect(30, [{NewKeyc5, ?active}, {NewKeyc3, 2}]),
+ g([NewKeyc5]),
+ ?line expect(31, [{NewKeyc5, ?active}]),
+ s([{NewKeyc5, ?destroy}]),
+ ?line expect(32, [{NewKeyc5, ?destroy}]).
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-1129, OTP-1169
+%% Slogan: snmpa:int_to_enum crashes on bad oids
+%%-----------------------------------------------------------------
+otp_1129(suite) -> [];
+otp_1129(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?line load_master("Klas3"),
+ try_test(otp_1129_i, [node()]),
+ ?line unload_master("Klas3").
+
+otp_1129_2(X) -> otp_1129(X).
+
+otp_1129_3(X) -> otp_1129(X).
+
+otp_1129_i(MaNode) ->
+ io:format("Testing bug reported in ticket OTP-1129...~n"),
+ false = rpc:call(MaNode, snmp, int_to_enum, [iso, 1]),
+ false = rpc:call(MaNode, snmp, int_to_enum, [isox, 1]).
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-1131
+%% Slogan: Agent crashes / erlang node halts if RowIndex in a
+%% setrequest is of bad type, e.g. an INDEX {INTEGER},
+%% and RowIdenx [3,2].
+%%-----------------------------------------------------------------
+otp_1131(suite) -> [];
+otp_1131(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?line load_master("Klas1"),
+ try_test(otp_1131),
+ ?line unload_master("Klas1").
+
+otp_1131_2(X) -> otp_1131(X).
+
+otp_1131_3(X) -> otp_1131(X).
+
+otp_1131() ->
+ io:format("Testing bug reported in ticket OTP-1131...~n"),
+ s([{[friendsEntry, [2, 3, 1]], s, "kompis3"},
+ {[friendsEntry, [3, 3, 1]], i, ?createAndGo}]),
+ ?line expect(1, ?v1_2(noSuchName, noCreation), 2, any).
+
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-1162
+%% Slogan: snmp_agent can't handle wrongValue from instrum.func
+%%-----------------------------------------------------------------
+otp_1162(suite) -> [];
+otp_1162(Config) when list(Config) ->
+ {SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?line {ok, SA} = start_subagent(SaNode, ?sa, "SA-MIB"),
+ try_test(otp_1162),
+ stop_subagent(SA).
+
+otp_1162_2(X) -> otp_1162(X).
+
+otp_1162_3(X) -> otp_1162(X).
+
+otp_1162() ->
+ s([{[sa, [2,0]], 6}]), % wrongValue (i is_set_ok)
+ ?line expect(1, ?v1_2(badValue, wrongValue), 1, any).
+
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-1222
+%% Slogan: snmp agent crash if faulty index is returned from instrum
+%%-----------------------------------------------------------------
+otp_1222(suite) -> [];
+otp_1222(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?line load_master("Klas3"),
+ ?line load_master("Klas4"),
+ try_test(otp_1222),
+ ?line unload_master("Klas3"),
+ ?line unload_master("Klas4").
+
+otp_1222_2(X) -> otp_1222(X).
+
+otp_1222_3(X) -> otp_1222(X).
+
+otp_1222() ->
+ io:format("Testing bug reported in ticket OTP-1222...~n"),
+ s([{[fStatus4,1], 4}, {[fName4,1], 1}]),
+ ?line expect(1, genErr, 0, any),
+ s([{[fStatus4,2], 4}, {[fName4,2], 1}]),
+ ?line expect(2, genErr, 0, any).
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-1298
+%% Slogan: Negative INTEGER values are treated as positive.
+%%-----------------------------------------------------------------
+otp_1298(suite) -> [];
+otp_1298(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?line load_master("Klas2"),
+ try_test(otp_1298),
+ ?line unload_master("Klas2").
+
+otp_1298_2(X) -> otp_1298(X).
+
+otp_1298_3(X) -> otp_1298(X).
+
+otp_1298() ->
+ io:format("Testing bug reported in ticket OTP-1298...~n"),
+ s([{[fint,0], -1}]),
+ ?line expect(1298, [{[fint,0], -1}]).
+
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-1331
+%% Slogan: snmp_generic should return noError when deleting non-ex row
+%%-----------------------------------------------------------------
+otp_1331(suite) -> [];
+otp_1331(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?line load_master("OLD-SNMPEA-MIB"),
+ ?line init_old(),
+ try_test(otp_1331),
+ ?line unload_master("OLD-SNMPEA-MIB").
+
+otp_1331_2(X) -> otp_1331(X).
+
+otp_1331_3(X) -> otp_1331(X).
+
+otp_1331() ->
+ NewKeyc5 = [intCommunityStatus,[127,32,0,0],is("test")],
+ s([{NewKeyc5, ?destroy}]),
+ ?line expect(1, [{NewKeyc5, ?destroy}]).
+
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-1338
+%% Slogan: snmp bug in initialisation of default values for mnesia tabs
+%%-----------------------------------------------------------------
+otp_1338(suite) -> [];
+otp_1338(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?line load_master("Klas2"),
+ try_test(otp_1338),
+ ?line unload_master("Klas2").
+
+otp_1338_2(X) -> otp_1338(X).
+
+otp_1338_3(X) -> otp_1338(X).
+
+otp_1338() ->
+ s([{[kStatus2, 7], i, ?createAndGo}]),
+ ?line expect(1, [{[kStatus2, 7], ?createAndGo}]),
+ g([[kName2, 7]]),
+ ?line expect(2, [{[kName2, 7], "JJJ"}]).
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-1342
+%% Slogan: default impl of snmp table can't handle bad index access,
+%% Set when INDEX is read-write gets into an infinite loop!
+%%-----------------------------------------------------------------
+otp_1342(suite) -> [];
+otp_1342(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?line load_master("Klas4"),
+ try_test(otp_1342),
+ ?line unload_master("Klas4").
+
+otp_1342_2(X) -> otp_1342(X).
+
+otp_1342_3(X) -> otp_1342(X).
+
+otp_1342() ->
+ s([{[fIndex5, 1], i, 1},
+ {[fName5, 1], i, 3},
+ {[fStatus5, 1], i, ?createAndGo}]),
+ ?line expect(1, ?v1_2(noSuchName, noCreation), 3, any).
+
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-1366
+%% Slogan: snmp traps not sent to all managers
+%% Note: NYI! We need a way to tell the test server that we need
+%% mgrs on two different machines.
+%%-----------------------------------------------------------------
+otp_1366(suite) -> [];
+otp_1366(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?line load_master("OLD-SNMPEA-MIB"),
+ ?line init_old(),
+ try_test(otp_1366),
+ ?line unload_master("OLD-SNMPEA-MIB").
+
+otp_1366_2(X) -> otp_1366(X).
+
+otp_1366_3(X) -> otp_1366(X).
+
+otp_1366() ->
+ ?INF("NOT YET IMPLEMENTED", []),
+ 'NYI'.
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-2776
+%% Slogan: snmp:validate_date_and_time() fails when time is 00:00
+%%-----------------------------------------------------------------
+otp_2776(suite) -> [];
+otp_2776(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ try_test(otp_2776).
+
+otp_2776_2(X) -> otp_2776(X).
+
+otp_2776_3(X) -> otp_2776(X).
+
+otp_2776() ->
+ io:format("Testing bug reported in ticket OTP-2776...~n"),
+
+ Dt01_valid = [19,98,9,1,1,0,23,0,43,0,0],
+ Dt02_valid = [19,98,9,1,0,0,0,0,43,0,0], % This is what is fixed: 00:00
+ Dt03_valid = [19,98,2,28,1,0,23,0,43,0,0],
+ Dt04_invalid = [19,98,2,29,1,0,23,0,43,0,0],
+ Dt05_valid = [19,96,2,29,1,0,23,0,43,0,0],
+ Dt06_valid = [20,0,2,29,1,0,23,0,43,0,0],
+ Dt07_invalid = [19,96,2,30,1,0,23,0,43,0,0], % This is also fixed: 30/2
+ Dt08_valid = [19,98,4,30,1,0,23,0,43,0,0],
+ Dt09_invalid = [19,98,4,31,1,0,23,0,43,0,0], % This is also fixed: 31/4
+ Dt10_invalid = [],
+ Dt11_invalid = [kalle,hobbe],
+ L = [{ 1, true, Dt01_valid},
+ { 2, true, Dt02_valid},
+ { 3, true, Dt03_valid},
+ { 4, false, Dt04_invalid},
+ { 5, true, Dt05_valid},
+ { 6, true, Dt06_valid},
+ { 7, false, Dt07_invalid},
+ { 8, true, Dt08_valid},
+ { 9, false, Dt09_invalid},
+ {10, false, Dt10_invalid},
+ {11, false, Dt11_invalid}],
+
+ ?line ok = validate_dat(L).
+
+
+validate_dat(L) -> validate_dat(L,[]).
+
+validate_dat([],V) ->
+ Fun = fun({_,X}) -> case X of
+ ok -> false;
+ _ -> true
+ end
+ end,
+ validate_dat1( lists:reverse( lists:filter(Fun,V) ) );
+validate_dat([{Id,E,Dat}|T],V) ->
+ validate_dat(T,[validate_dat2(Id,E,Dat) | V]).
+
+validate_dat1([]) -> ok;
+validate_dat1(L) -> {error,L}.
+
+validate_dat2(Id, E, Dat) ->
+ Res = case {E,snmp:validate_date_and_time(Dat)} of
+ {E,E} -> ok;
+ {E,A} -> {E,A}
+ end,
+ {Id, Res}.
+
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-2979
+%% Slogan: get-next on more than 1 column in an empty table
+%% returns bad response.
+%%-----------------------------------------------------------------
+otp_2979(suite) -> [];
+otp_2979(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?line load_master("Test1"),
+ ?line init_old(),
+ try_test(otp_2979),
+ ?line unload_master("Test1").
+
+otp_2979_2(X) -> otp_2979(X).
+
+otp_2979_3(X) -> otp_2979(X).
+
+otp_2979() ->
+ gn([[sparseDescr], [sparseStatus]]),
+ ?line expect(1, [{[sparseStr,0], "slut"},
+ {[sparseStr,0], "slut"}]).
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-3187
+%% Slogan: get-next on vacmAccessTable for colums > 5 returns
+%% endOfTable - should return value.
+%%-----------------------------------------------------------------
+otp_3187(suite) -> [];
+otp_3187(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"),
+ otp_3187(),
+ ?line unload_master("SNMP-VIEW-BASED-ACM-MIB").
+
+otp_3187_2(X) -> otp_3187(X).
+
+otp_3187_3(X) -> otp_3187(X).
+
+otp_3187() ->
+ ?line Elements =
+ snmp_view_based_acm_mib:vacmAccessTable(get_next,[],[4,5,6]),
+ lists:foreach(fun(E) ->
+ ?line if E == endOfTable ->
+ ?FAIL(endOfTable);
+ true -> ok
+ end
+ end, Elements).
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-3542
+%% Slogan:
+%%-----------------------------------------------------------------
+otp_3542(suite) -> [];
+otp_3542(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ try_test(otp_3542).
+
+otp_3542() ->
+ io:format("SNMP v3 discovery...~n"),
+ ?line Res = snmp_test_mgr:d(),
+ io:format("SNMP v3 discovery result: ~p~n",[Res]).
+
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-3725
+%% Slogan: Slow response time on snmpa:int_to_enum
+%%-----------------------------------------------------------------
+otp_3725(suite) -> [];
+otp_3725(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ ?line load_master("OLD-SNMPEA-MIB"),
+ ?line init_old(),
+ try_test(otp_3725_test, [node()]),
+ ?line unload_master("OLD-SNMPEA-MIB").
+
+%% Req. OLD-SNMPEA-MIB
+otp_3725_test(MaNode) ->
+ io:format("Testing feature requested in ticket OTP-3725...~n"),
+ ?line rpc:call(MaNode,snmpa,verbosity,[symbolic_store,trace]),
+ ?line Db = rpc:call(MaNode,snmp,get_symbolic_store_db,[]),
+ ?DBG("otp_3725_test -> Db = ~p",[Db]),
+
+ ?line {value, OID} = rpc:call(MaNode, snmp, name_to_oid,
+ [Db, intAgentIpAddress]),
+ ?DBG("otp_3725_test -> name_to_oid for ~p: ~p",[intAgentIpAddress,OID]),
+ ?line {value, intAgentIpAddress} = rpc:call(MaNode, snmp, oid_to_name,
+ [Db,OID]),
+ ?DBG("otp_3725_test -> oid_to_name for ~p: ~p",[OID,intAgentIpAddress]),
+ ?line false = rpc:call(MaNode, snmp, name_to_oid, [Db, intAgentIpAddres]),
+ ?line false = rpc:call(MaNode, snmp, oid_to_name,
+ [Db, [1,5,32,3,54,3,3,34,4]]),
+ ?line {value, 2} = rpc:call(MaNode, snmp, enum_to_int,
+ [Db, intViewType, excluded]),
+ ?line {value, excluded} = rpc:call(MaNode, snmp, int_to_enum,
+ [Db, intViewType, 2]),
+ ?line false = rpc:call(MaNode, snmp, enum_to_int,
+ [Db, intViewType, exclude]),
+ ?line false = rpc:call(MaNode, snmp, enum_to_int,
+ [Db, intAgentIpAddress, exclude]),
+ ?line false = rpc:call(MaNode, snmp, enum_to_int,
+ [Db, intAgentIpAddre, exclude]),
+ ?line false = rpc:call(MaNode, snmp, int_to_enum, [Db, intViewType, 3]),
+ ?line false = rpc:call(MaNode, snmp, int_to_enum,
+ [Db, intAgentIpAddress, 2]),
+ ?line false = rpc:call(MaNode, snmp, int_to_enum,
+ [Db, intAgentIpAddre, 2]),
+ ?line {value, active} = rpc:call(MaNode, snmp, int_to_enum,
+ [Db, 'RowStatus', ?active]),
+ ?line {value, ?destroy} = rpc:call(MaNode, snmp, enum_to_int,
+ [Db, 'RowStatus', destroy]),
+ ?line false = rpc:call(MaNode, snmp, enum_to_int,
+ [Db, 'RowStatus', xxxdestroy]),
+ ?line false = rpc:call(MaNode, snmp, enum_to_int,
+ [Db, 'xxRowStatus', destroy]),
+ ?line false = rpc:call(MaNode, snmp, int_to_enum, [Db, 'RowStatus', 25]),
+ ?line false = rpc:call(MaNode, snmp, int_to_enum, [Db, 'xxRowStatus', 1]),
+ ok.
+
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-4394
+%% Slogan: Target mib tag list check invalid
+%%-----------------------------------------------------------------
+
+
+otp_4394(suite) -> {req, [], {conf,
+ init_otp_4394,
+ [otp_4394_test],
+ finish_otp_4394}}.
+
+init_otp_4394(Config) when list(Config) ->
+ ?DBG("init_otp_4394 -> entry with"
+ "~n Config: ~p", [Config]),
+ ?line AgentDir = ?config(agent_dir, Config),
+ ?line MgrDir = ?config(mgr_dir, Config),
+ ?line Ip = ?config(ip, Config),
+ ?line otp_4394_config(AgentDir, MgrDir, Ip),
+ MasterAgentVerbosity = {master_agent_verbosity, trace},
+ NetIfVerbosity = {net_if_verbosity, trace},
+ Opts = [MasterAgentVerbosity,NetIfVerbosity],
+ [{vsn, v1} | start_v1_agent(Config,Opts)].
+
+otp_4394_config(AgentDir, MgrDir, Ip0) ->
+ ?DBG("otp_4394_config -> entry with"
+ "~n AgentDir: ~p"
+ "~n MgrDir: ~p"
+ "~n Ip0: ~p", [AgentDir, MgrDir, Ip0]),
+ Vsn = [v1],
+ Ip = tuple_to_list(Ip0),
+ ?line snmp_config:write_agent_snmp_files(AgentDir, Vsn, Ip,
+ ?TRAP_UDP, Ip, 4000,
+ "OTP-4394 test"),
+ ?line case update_usm(Vsn, AgentDir) of
+ true ->
+ ?line copy_file(filename:join(AgentDir, "usm.conf"),
+ filename:join(MgrDir, "usm.conf")),
+ ?line update_usm_mgr(Vsn, MgrDir);
+ false ->
+ ?line ok
+ end,
+ C1 = {"a", "all-rights", "initial", "", "pc"},
+ C2 = {"c", "secret", "secret_name", "", "secret_tag"},
+ ?line write_community_conf(AgentDir, [C1, C2]),
+ ?line update_vacm(Vsn, AgentDir),
+ Ta1 = {"shelob v1",
+ [134,138,177,177], 5000, 1500, 3, %% Anv�nd Ip och modda
+ "pc1",
+ "target_v1", "",
+ %% [255,255,255,255,0,0],
+ [],
+ 2048},
+ Ta2 = {"bifur v1",
+ [134,138,177,75], 5000, 1500, 3, %% Anv�nd Ip
+ "pc2",
+ "target_v1", "",
+ %% [255,255,255,255,0,0],
+ [], 2048},
+ ?line write_target_addr_conf(AgentDir, [Ta1, Ta2]),
+ ?line write_target_params_conf(AgentDir, Vsn),
+ ?line write_notify_conf(AgentDir),
+ ok.
+
+
+
+finish_otp_4394(Config) when list(Config) ->
+ ?DBG("finish_otp_4394 -> entry", []),
+ C1 = stop_agent(Config),
+ delete_files(C1),
+ erase(mgr_node),
+ lists:keydelete(vsn, 1, C1).
+
+otp_4394_test(suite) -> [];
+otp_4394_test(Config) ->
+ ?DBG("otp_4394_test -> entry", []),
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ try_test(otp_4394_test1),
+ ?DBG("otp_4394_test -> done", []),
+ ok.
+
+otp_4394_test1() ->
+ ?DBG("otp_4394_test1 -> entry", []),
+ gn([[1,1]]),
+ Res =
+ case snmp_test_mgr:expect(1, [{[sysDescr,0], "Erlang SNMP agent"}]) of
+ %% {error, 1, {"?",[]}, {"~w",[timeout]}}
+ {error, 1, _, {_, [timeout]}} ->
+ ?DBG("otp_4394_test1 -> expected result: timeout", []),
+ ok;
+ Else ->
+ Else
+ end,
+ ?DBG("otp_4394_test1 -> done with: ~p", [Res]),
+ Res.
+
+
+%%%--------------------------------------------------
+%%% Used to test the standard mib with our
+%%% configuration.
+%%%--------------------------------------------------
+run(F, A, Opts) ->
+ M = get(mib_dir),
+ Dir = get(mgr_dir),
+ User = snmp_misc:get_option(user, Opts, "all-rights"),
+ SecLevel = snmp_misc:get_option(sec_level, Opts, noAuthNoPriv),
+ EngineID = snmp_misc:get_option(engine_id, Opts, "agentEngine"),
+ CtxEngineID = snmp_misc:get_option(context_engine_id, Opts, EngineID),
+ Community = snmp_misc:get_option(community, Opts, "all-rights"),
+ ?DBG("run -> start crypto app",[]),
+ Crypto = case os:type() of
+ vxworks ->
+ no_crypto;
+ _ ->
+ ?CRYPTO_START()
+ end,
+ ?DBG("run -> Crypto: ~p",[Crypto]),
+ catch snmp_test_mgr:stop(), % If we had a running mgr from a failed case
+ StdM = filename:join(code:priv_dir(snmp), "mibs") ++ "/",
+ ?DBG("run -> config:~n"
+ "\tM: ~p~n"
+ "\tDir: ~p~n"
+ "\tUser: ~p~n"
+ "\tSecLevel: ~p~n"
+ "\tEngineID: ~p~n"
+ "\tCtxEngineID: ~p~n"
+ "\tCommunity: ~p~n"
+ "\tStdM: ~p",
+ [M,Dir,User,SecLevel,EngineID,CtxEngineID,Community,StdM]),
+ case snmp_test_mgr:start([%% {agent, snmp_test_lib:hostname()},
+ {packet_server_debug,true},
+ {debug,true},
+ {agent, get(master_host)},
+ {agent_udp, 4000},
+ {trap_udp, 5000},
+ {recbuf,65535},
+ quiet,
+ get(vsn),
+ {community, Community},
+ {user, User},
+ {sec_level, SecLevel},
+ {engine_id, EngineID},
+ {context_engine_id, CtxEngineID},
+ {dir, Dir},
+ {mibs, mibs(StdM, M)}]) of
+ {ok, _Pid} ->
+ Res = apply(?MODULE, F, A),
+ catch snmp_test_mgr:stop(),
+ Res;
+ Err ->
+ io:format("Error starting manager: ~p\n", [Err]),
+ catch snmp_test_mgr:stop(),
+ ?line exit({mgr_start, Err})
+ end.
+
+
+mibs(StdMibDir,MibDir) ->
+ [join(StdMibDir, ?v1_2("STANDARD-MIB.bin", "SNMPv2-MIB.bin")),
+ join(MibDir, "OLD-SNMPEA-MIB.bin"),
+ join(StdMibDir, "SNMP-FRAMEWORK-MIB"),
+ join(StdMibDir, "SNMP-MPD-MIB"),
+ join(StdMibDir, "SNMP-VIEW-BASED-ACM-MIB"),
+ join(StdMibDir, "SNMP-USER-BASED-SM-MIB"),
+ join(StdMibDir, "SNMP-TARGET-MIB"),
+ join(StdMibDir, "SNMP-NOTIFICATION-MIB"),
+ join(MibDir, "Klas1.bin"),
+ join(MibDir, "Klas2.bin"),
+ join(MibDir, "Klas3.bin"),
+ join(MibDir, "Klas4.bin"),
+ join(MibDir, "SA-MIB.bin"),
+ join(MibDir, "TestTrap.bin"),
+ join(MibDir, "Test1.bin"),
+ join(MibDir, "Test2.bin"),
+ join(MibDir, "TestTrapv2.bin")].
+
+join(D,F) ->
+ filename:join(D,F).
+
+%% string used in index
+is(S) -> [length(S) | S].
+
+try_test(Func) ->
+ call(get(mgr_node), ?MODULE, run, [Func, [], []]).
+
+try_test(Func, A) ->
+ call(get(mgr_node), ?MODULE, run, [Func, A, []]).
+
+try_test(Func, A, Opts) ->
+ call(get(mgr_node), ?MODULE, run, [Func, A, Opts]).
+
+call(N,M,F,A) ->
+ ?DBG("call -> entry with~n"
+ " N: ~p~n"
+ " M: ~p~n"
+ " F: ~p~n"
+ " A: ~p~n"
+ " when~n"
+ " get(): ~p",
+ [N,M,F,A,get()]),
+ spawn(N, ?MODULE, wait, [self(),get(),M,F,A]),
+ receive
+ {done, {'EXIT', Rn}, Loc} ->
+ ?DBG("call -> returned ~p",[{done, {'EXIT', Rn}, Loc}]),
+ put(test_server_loc, Loc),
+ exit(Rn);
+ {done, Ret, Zed} ->
+ ?DBG("call -> returned ~p~n",[{done, Ret, Zed}]),
+ Ret
+ end.
+
+wait(From, Env, M, F, A) ->
+ ?DBG("wait -> entry with ~n"
+ "\tFrom: ~p~n"
+ "\tEnv: ~p",[From,Env]),
+ lists:foreach(fun({K,V}) -> put(K,V) end, Env),
+ Rn = (catch apply(M, F, A)),
+ ?DBG("wait -> Rn: ~n~p", [Rn]),
+ From ! {done, Rn, get(test_server_loc)},
+ exit(Rn).
+
+expect(A,B) -> ok = snmp_test_mgr:expect(A,B).
+expect(A,B,C) -> ok = snmp_test_mgr:expect(A,B,C).
+expect(A,B,C,D) -> ok = snmp_test_mgr:expect(A,B,C,D).
+expect(A,B,C,D,E,F) -> ok = snmp_test_mgr:expect(A,B,C,D,E,F).
+
+get_req(Id, Vars) ->
+ ?DBG("get_req -> entry with~n"
+ "\tId: ~p~n"
+ "\tVars: ~p",[Id,Vars]),
+ g(Vars),
+ ?DBG("get_req -> await response",[]),
+ {ok, Val} = snmp_test_mgr:get_response(Id, Vars),
+ ?DBG("get_req -> response: ~p",[Val]),
+ Val.
+
+get_next_req(Vars) ->
+ ?DBG("get_next_req -> entry with Vars '~p', send request",[Vars]),
+ gn(Vars),
+ ?DBG("get_next_req -> await response",[]),
+ Response = snmp_test_mgr:receive_response(),
+ ?DBG("get_next_req -> response: ~p",[Response]),
+ Response.
+
+
+
+start_node(Name) ->
+ ?LOG("start_node -> entry with Name: ~p",[Name]),
+ M = list_to_atom(?HOSTNAME(node())),
+ ?DBG("start_node -> M: ~p",[M]),
+ Pa = filename:dirname(code:which(?MODULE)),
+ ?DBG("start_node -> Pa: ~p",[Pa]),
+
+ Args = case init:get_argument('CC_TEST') of
+ {ok, [[]]} ->
+ " -pa /clearcase/otp/libraries/snmp/ebin ";
+ {ok, [[Path]]} ->
+ " -pa " ++ Path;
+ error ->
+ ""
+ end,
+ %% Do not use start_link!!! (the proc that calls this one is tmp)
+ ?DBG("start_node -> Args: ~p~n",[Args]),
+ A = Args ++ " -pa " ++ Pa,
+ case (catch ?START_NODE(Name, A)) of
+ {ok, Node} ->
+ %% Tell the test_server to not clean up things it never started.
+ ?DBG("start_node -> Node: ~p",[Node]),
+ {ok, Node};
+ Else ->
+ ?ERR("start_node -> failed with(other): Else: ~p",[Else]),
+ ?line ?FAIL(Else)
+ end.
+
+
+stop_node(Node) ->
+ ?LOG("stop_node -> Node: ~p",[Node]),
+ rpc:cast(Node, erlang, halt, []).
+
+p(X) ->
+ io:format(user, X++"\n", []).
+
+sleep(X) ->
+ receive
+ after
+ X -> ok
+ end.
+
+%%%-----------------------------------------------------------------
+%%% Configuration
+%%%-----------------------------------------------------------------
+config(Vsns, MgrDir, AgentDir, MIp, AIp) ->
+ ?line snmp_config:write_agent_snmp_files(AgentDir, Vsns, MIp,
+ ?TRAP_UDP, AIp, 4000,
+ "test"),
+ ?line case update_usm(Vsns, AgentDir) of
+ true ->
+ ?line copy_file(filename:join(AgentDir, "usm.conf"),
+ filename:join(MgrDir, "usm.conf")),
+ ?line update_usm_mgr(Vsns, MgrDir);
+ false ->
+ ?line ok
+ end,
+ ?line update_community(Vsns, AgentDir),
+ ?line update_vacm(Vsns, AgentDir),
+ ?line write_target_addr_conf(AgentDir, MIp, ?TRAP_UDP, Vsns),
+ ?line write_target_params_conf(AgentDir, Vsns),
+ ?line write_notify_conf(AgentDir),
+ ok.
+
+delete_files(Config) ->
+ Dir = ?config(agent_dir, Config),
+ {ok, List} = file:list_dir(Dir),
+ lists:foreach(fun(FName) -> file:delete(filename:join(Dir, FName)) end,
+ List).
+
+update_usm(Vsns, Dir) ->
+ case lists:member(v3, Vsns) of
+ true ->
+ {ok, Fid} = file:open(filename:join(Dir,"usm.conf"),[read,write]),
+ file:position(Fid, eof),
+ ok = io:format(Fid, "{\"agentEngine\", \"all-rights\", "
+ "\"all-rights\", zeroDotZero, "
+ "usmNoAuthProtocol, \"\", \"\", "
+ "usmNoPrivProtocol, \"\", \"\", \"\", "
+ "\"\", \"\"}.\n", []),
+ ok = io:format(Fid, "{\"agentEngine\", \"no-rights\", "
+ "\"no-rights\", zeroDotZero, "
+ "usmNoAuthProtocol, \"\", \"\", "
+ "usmNoPrivProtocol, \"\", \"\", \"\", "
+ "\"\", \"\"}.\n", []),
+ ok = io:format(Fid, "{\"agentEngine\", \"authMD5\", "
+ "\"authMD5\", zeroDotZero, "
+ "usmHMACMD5AuthProtocol, \"\", \"\", "
+ "usmNoPrivProtocol, \"\", \"\", \"\", "
+ "\"passwd_md5xxxxxx\", \"\"}.\n", []),
+ ok = io:format(Fid, "{\"agentEngine\", \"authSHA\", "
+ "\"authSHA\", zeroDotZero, "
+ "usmHMACSHAAuthProtocol, \"\", \"\", "
+ "usmNoPrivProtocol, \"\", \"\", \"\", "
+ "\"passwd_shaxxxxxxxxxx\", \"\"}.\n", []),
+ ok = io:format(Fid, "{\"agentEngine\", \"privDES\", "
+ "\"privDES\", zeroDotZero, "
+ "usmHMACSHAAuthProtocol, \"\", \"\", "
+ "usmDESPrivProtocol, \"\", \"\", \"\", "
+ "\"passwd_shaxxxxxxxxxx\", \"passwd_desxxxxxx\"}.\n",
+ []),
+ ok = io:format(Fid, "{\"mgrEngine\", \"all-rights\", "
+ "\"all-rights\", zeroDotZero, "
+ "usmNoAuthProtocol, \"\", \"\", "
+ "usmNoPrivProtocol, \"\", \"\", \"\", "
+ "\"\", \"\"}.\n", []),
+ ok = io:format(Fid, "{\"mgrEngine\", \"no-rights\", "
+ "\"no-rights\", zeroDotZero, "
+ "usmNoAuthProtocol, \"\", \"\", "
+ "usmNoPrivProtocol, \"\", \"\", \"\", "
+ "\"\", \"\"}.\n", []),
+ ok = io:format(Fid, "{\"mgrEngine\", \"authMD5\", "
+ "\"authMD5\", zeroDotZero, "
+ "usmHMACMD5AuthProtocol, \"\", \"\", "
+ "usmNoPrivProtocol, \"\", \"\", \"\", "
+ "\"passwd_md5xxxxxx\", \"\"}.\n", []),
+ ok = io:format(Fid, "{\"mgrEngine\", \"authSHA\", "
+ "\"authSHA\", zeroDotZero, "
+ "usmHMACSHAAuthProtocol, \"\", \"\", "
+ "usmNoPrivProtocol, \"\", \"\", \"\", "
+ "\"passwd_shaxxxxxxxxxx\", \"\"}.\n", []),
+ ok = io:format(Fid, "{\"mgrEngine\", \"privDES\", "
+ "\"privDES\", zeroDotZero, "
+ "usmHMACSHAAuthProtocol, \"\", \"\", "
+ "usmDESPrivProtocol, \"\", \"\", \"\", "
+ "\"passwd_shaxxxxxxxxxx\", \"passwd_desxxxxxx\"}.\n",
+ []),
+ file:close(Fid),
+ true;
+ false ->
+ false
+ end.
+
+update_usm_mgr(Vsns, Dir) ->
+ case lists:member(v3, Vsns) of
+ true ->
+ {ok, Fid} = file:open(filename:join(Dir,"usm.conf"),[read,write]),
+ file:position(Fid, eof),
+ ok = io:format(Fid, "{\"agentEngine\", \"newUser\", "
+ "\"newUser\", zeroDotZero, "
+ "usmHMACSHAAuthProtocol, \"\", \"\", "
+ "usmDESPrivProtocol, \"\", \"\", \"\", "
+ "\"passwd_shaxxxxxxxxxx\", \"passwd_desxxxxxx\"}.\n",
+ []),
+ ok = io:format(Fid, "{\"mgrEngine\", \"newUser\", "
+ "\"newUser\", zeroDotZero, "
+ "usmHMACSHAAuthProtocol, \"\", \"\", "
+ "usmDESPrivProtocol, \"\", \"\", \"\", "
+ "\"passwd_shaxxxxxxxxxx\", \"passwd_desxxxxxx\"}.\n",
+ []),
+ file:close(Fid),
+ true;
+ false ->
+ false
+ end.
+
+rewrite_usm_mgr(Dir, ShaKey, DesKey) ->
+ ?line ok = file:rename(filename:join(Dir,"usm.conf"),
+ filename:join(Dir,"usm.old")),
+ ?line {ok, Fid} = file:open(filename:join(Dir,"usm.conf"),write),
+ ok = io:format(Fid, "{\"agentEngine\", \"newUser\", "
+ "\"newUser\", zeroDotZero, "
+ "usmHMACSHAAuthProtocol, \"\", \"\", "
+ "usmDESPrivProtocol, \"\", \"\", \"\", "
+ "\"~s\", \"~s\"}.\n",
+ [ShaKey, DesKey]),
+ ok = io:format(Fid, "{\"mgrEngine\", \"newUser\", "
+ "\"newUser\", zeroDotZero, "
+ "usmHMACSHAAuthProtocol, \"\", \"\", "
+ "usmDESPrivProtocol, \"\", \"\", \"\", "
+ "\"~s\", \"~s\"}.\n",
+ [ShaKey, DesKey]),
+ file:close(Fid).
+
+reset_usm_mgr(Dir) ->
+ ?line ok = file:rename(filename:join(Dir,"usm.old"),
+ filename:join(Dir,"usm.conf")).
+
+
+update_community([v3], _Dir) -> ok;
+update_community(_, Dir) ->
+ {ok, Fid} = file:open(filename:join(Dir,"community.conf"),[read,write]),
+ file:position(Fid, eof),
+ ok=io:format(Fid,"{\"no-rights\",\"no-rights\",\"no-rights\",\"\",\"\"}.\n",
+ []),
+ file:close(Fid).
+
+
+-define(tDescr_instance, [1,3,6,1,2,1,16,1,0]).
+update_vacm(_Vsn, Dir) ->
+ {ok, Fid} = file:open(filename:join(Dir,"vacm.conf"),[read,write]),
+ file:position(Fid, eof),
+ ok=io:format(Fid,"{vacmSecurityToGroup,usm,\"authMD5\",\"initial\"}.\n",[]),
+ ok=io:format(Fid,"{vacmSecurityToGroup,usm,\"authSHA\",\"initial\"}.\n",[]),
+ ok=io:format(Fid,"{vacmSecurityToGroup,usm,\"privDES\",\"initial\"}.\n",[]),
+ ok=io:format(Fid,"{vacmSecurityToGroup,usm,\"newUser\",\"initial\"}.\n",[]),
+ ok = io:format(Fid, "{vacmViewTreeFamily, \"internet\", "
+ "~w, excluded, null}.\n", [?tDescr_instance]),
+ file:close(Fid).
+
+
+vacm_ver(v1) -> v1;
+vacm_ver(v2) -> v2c;
+vacm_ver(v3) -> usm.
+
+
+write_community_conf(Dir, Confs) ->
+ {ok, Fid} = file:open(filename:join(Dir,"community.conf"),write),
+ ok = write_community_conf1(Fid, Confs),
+ file:close(Fid).
+
+write_community_conf1(_, []) ->
+ ok;
+write_community_conf1(Fid, [{ComIdx, ComName, SecName, CtxName, TransTag}|Confs]) ->
+ ok = io:format(Fid, "{\"~s\", \"~s\", \"~s\", \"~s\", \"~s\"}.~n",
+ [ComIdx, ComName, SecName, CtxName, TransTag]),
+ write_community_conf1(Fid, Confs).
+
+
+write_target_addr_conf(Dir, Confs) ->
+ {ok, Fid} = file:open(filename:join(Dir,"target_addr.conf"),write),
+ ok = write_target_addr_conf1(Fid, Confs),
+ file:close(Fid).
+
+
+write_target_addr_conf1(_, []) ->
+ ok;
+write_target_addr_conf1(Fid,
+ [{Name, Ip, Port, Timeout, Retry, TagList, ParamName,
+ EngineId, TMask, MaxMsgSz}|Confs]) ->
+ ok = io:format(Fid, "{\"~s\", ~w, ~w, ~w, ~w, \"~s\", \"~s\", \"~s\", ~w, ~w}.~n",
+ [Name, Ip, Port, Timeout, Retry, TagList, ParamName,
+ EngineId, TMask, MaxMsgSz]),
+ write_target_addr_conf1(Fid, Confs).
+
+write_target_addr_conf(Dir, ManagerIp, UDP, Vsns) ->
+ {ok, Fid} = file:open(filename:join(Dir,"target_addr.conf"),write),
+ lists:foreach(fun(Vsn) ->
+ ok = io:format(Fid,
+ "{\"~s\", ~w, ~w, 1500, 3, "
+ "\"std_trap\", \"~s\"}.~n",
+ [mk_ip(ManagerIp, Vsn),
+ ManagerIp, UDP, mk_param(Vsn)]),
+ case Vsn of
+ v1 -> ok;
+ v2 ->
+ ok = io:format(Fid,
+ "{\"~s.2\",~w,~w,1500,3, "
+ "\"std_inform\", \"~s\"}.~n",
+ [mk_ip(ManagerIp, Vsn),
+ ManagerIp, UDP,
+ mk_param(Vsn)]);
+ v3 ->
+ ok = io:format(Fid,
+ "{\"~s.3\",~w,~w,1500,3, "
+ "\"std_inform\", \"~s\", "
+ "\"mgrEngine\", [], 1024}.~n",
+ [mk_ip(ManagerIp, Vsn),
+ ManagerIp, UDP,
+ mk_param(Vsn)])
+ end
+ end,
+ Vsns),
+ file:close(Fid).
+
+mk_param(v1) -> "target_v1";
+mk_param(v2) -> "target_v2";
+mk_param(v3) -> "target_v3".
+
+mk_ip([A,B,C,D], Vsn) ->
+ io_lib:format("~w.~w.~w.~w ~w", [A,B,C,D,Vsn]).
+
+
+rewrite_target_addr_conf(Dir,NewPort) ->
+ TAFile = filename:join(Dir, "target_addr.conf"),
+ ?DBG("rewrite_target_addr_conf -> read target file info of address config file",[]),
+ case file:read_file_info(TAFile) of
+ {ok, _} -> ok;
+ {error, R} -> ?ERR("failure reading file info of "
+ "target address config file: ~p",[R]),
+ ok
+ end,
+
+ ?line [TrapAddr|Addrs] =
+ snmp_conf:read(TAFile,fun(R) -> rewrite_target_addr_conf1(R) end),
+
+ ?DBG("rewrite_target_addr_conf -> TrapAddr: ~p",[TrapAddr]),
+
+ NewAddrs = [rewrite_target_addr_conf2(NewPort,TrapAddr)|Addrs],
+
+ ?DBG("rewrite_target_addr_conf -> NewAddrs: ~p",[NewAddrs]),
+
+ ?line ok = file:rename(filename:join(Dir,"target_addr.conf"),
+ filename:join(Dir,"target_addr.old")),
+ ?line {ok, Fid} = file:open(filename:join(Dir,"target_addr.conf"),write),
+
+ ?line ok = rewrite_target_addr_conf3(Fid,NewAddrs),
+
+ file:close(Fid).
+
+rewrite_target_addr_conf1(O) ->
+ {ok,O}.
+
+rewrite_target_addr_conf2(NewPort,{Name,Ip,_Port,Timeout,Retry,
+ "std_trap",EngineId}) ->
+ ?LOG("rewrite_target_addr_conf2 -> entry with std_trap",[]),
+ {Name,Ip,NewPort,Timeout,Retry,"std_trap",EngineId};
+rewrite_target_addr_conf2(_NewPort,O) ->
+ ?LOG("rewrite_target_addr_conf2 -> entry with "
+ "~n O: ~p",[O]),
+ O.
+
+
+rewrite_target_addr_conf3(_,[]) -> ok;
+rewrite_target_addr_conf3(Fid,[{Name,Ip,Port,Timeout,Retry,
+ ParamName,EngineId}|T]) ->
+ ?LOG("rewrite_target_addr_conf3 -> write(1) ~s",[ParamName]),
+ io:format(Fid,
+ "{\"~s\", " % Name
+ "~p, " % Ip
+ "~p, " % Port
+ "~p, " % Timeout
+ "~p, " % Retry
+ "\"~s\", " % ParamsName
+ "\"~s\"}.", % EngineId
+ [Name,Ip,Port,Timeout,Retry,ParamName,EngineId]),
+ rewrite_target_addr_conf3(Fid,T);
+rewrite_target_addr_conf3(Fid,[{Name,Ip,Port,Timeout,Retry,TagList,
+ ParamName,EngineId,TMask,MMS}|T]) ->
+ ?LOG("rewrite_target_addr_conf3 -> write(2) ~s",[ParamName]),
+ io:format(Fid,
+ "{\"~s\", " % Name
+ "~p, " % Ip
+ "~p, " % Port
+ "~p, " % Timeout
+ "~p, " % Retry
+ "\"~s\", " % TagList
+ "\"~s\", " % ParamsName
+ "\"~s\"," % EngineId
+ "~p, " % TMask
+ "~p}.", % MMS
+ [Name,Ip,Port,Timeout,Retry,TagList,ParamName,
+ EngineId,TMask,MMS]),
+ rewrite_target_addr_conf3(Fid,T).
+
+reset_target_addr_conf(Dir) ->
+ ?line ok = file:rename(filename:join(Dir,"target_addr.old"),
+ filename:join(Dir,"target_addr.conf")).
+
+write_target_params_conf(Dir, Vsns) ->
+ {ok, Fid} = file:open(filename:join(Dir,"target_params.conf"),write),
+ lists:foreach(fun(Vsn) ->
+ MP = if Vsn == v1 -> v1;
+ Vsn == v2 -> v2c;
+ Vsn == v3 -> v3
+ end,
+ SM = if Vsn == v1 -> v1;
+ Vsn == v2 -> v2c;
+ Vsn == v3 -> usm
+ end,
+ ok = io:format(Fid, "{\"target_~w\", ~w, ~w, "
+ "\"all-rights\", noAuthNoPriv}.~n",
+ [Vsn, MP, SM])
+ end,
+ Vsns),
+ file:close(Fid).
+
+rewrite_target_params_conf(Dir, SecName, SecLevel) ->
+ ?line ok = file:rename(filename:join(Dir,"target_params.conf"),
+ filename:join(Dir,"target_params.old")),
+ ?line {ok, Fid} = file:open(filename:join(Dir,"target_params.conf"),write),
+ ?line ok = io:format(Fid, "{\"target_v3\", v3, usm, \"~s\", ~w}.~n",
+ [SecName, SecLevel]),
+ file:close(Fid).
+
+reset_target_params_conf(Dir) ->
+ ?line ok = file:rename(filename:join(Dir,"target_params.old"),
+ filename:join(Dir,"target_params.conf")).
+
+write_notify_conf(Dir) ->
+ {ok, Fid} = file:open(filename:join(Dir,"notify.conf"),write),
+ ok = io:format(Fid, "{\"standard trap\", \"std_trap\", trap}.~n", []),
+ ok = io:format(Fid, "{\"standard inform\", \"std_inform\",inform}.~n", []),
+ file:close(Fid).
+
+ver_to_trap_str([v1]) -> "v1";
+ver_to_trap_str([v2]) -> "v2";
+% default is to use the latest snmp version
+ver_to_trap_str([v1,v2]) -> "v2".
+
+
+
+write_view_conf(Dir) ->
+ {ok, Fid} = file:open(a(Dir,"view.conf"),write),
+ ok = io:format(Fid, "{2, [1,3,6], included, null}.~n", []),
+ ok = io:format(Fid, "{2, ~w, excluded, null}.~n", [?tDescr_instance]),
+ file:close(Fid).
+
+a(A,B) -> lists:append(A,B).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+copy_file(From, To) ->
+ {ok, Bin} = file:read_file(From),
+ ok = file:write_file(To, Bin).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+display_memory_usage() ->
+ Info = snmpa:info(snmp_master_agent),
+ TreeSize = lists_key1search(tree_size_bytes, Info),
+ ProcMem = lists_key1search(process_memory, Info),
+ MibDbSize = lists_key1search([db_memory,mib], Info),
+ NodeDbSize = lists_key1search([db_memory,node], Info),
+ TreeDbSize = lists_key1search([db_memory,tree], Info),
+ ?INF("Memory usage: "
+ "~n Tree size: ~p"
+ "~n Process memory size: ~p"
+ "~n Mib db size: ~p"
+ "~n Node db size: ~p"
+ "~n Tree db size: ~p",
+ [TreeSize, ProcMem, MibDbSize, NodeDbSize, TreeDbSize]).
+
+lists_key1search([], Res) ->
+ Res;
+lists_key1search([Key|Keys], List) when atom(Key), list(List) ->
+ case lists:keysearch(Key, 1, List) of
+ {value, {Key, Val}} ->
+ lists_key1search(Keys, Val);
+ false ->
+ undefined
+ end;
+lists_key1search(Key, List) when atom(Key) ->
+ case lists:keysearch(Key, 1, List) of
+ {value, {Key, Val}} ->
+ Val;
+ false ->
+ undefined
+ end.
+
+
+regs() ->
+ lists:sort(registered()).
diff --git a/lib/snmp/test/snmp_agent_nfilter_test.erl b/lib/snmp/test/snmp_agent_nfilter_test.erl
new file mode 100644
index 0000000000..269c7c96c9
--- /dev/null
+++ b/lib/snmp/test/snmp_agent_nfilter_test.erl
@@ -0,0 +1,78 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2004-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%
+%%
+
+%%----------------------------------------------------------------------
+%% Purpose:
+%%----------------------------------------------------------------------
+-module(snmp_agent_nfilter_test).
+
+%%----------------------------------------------------------------------
+%% Include files
+%%----------------------------------------------------------------------
+-include("test_server.hrl").
+-include("snmp_test_lib.hrl").
+
+
+%%----------------------------------------------------------------------
+%% External exports
+%%----------------------------------------------------------------------
+-export([
+ all/1,
+ init_per_testcase/2, fin_per_testcase/2
+ ]).
+
+%%----------------------------------------------------------------------
+%% Internal exports
+%%----------------------------------------------------------------------
+-export([
+ ]).
+
+%%----------------------------------------------------------------------
+%% Macros
+%%----------------------------------------------------------------------
+
+%%----------------------------------------------------------------------
+%% Records
+%%----------------------------------------------------------------------
+
+%%======================================================================
+%% External functions
+%%======================================================================
+
+init_per_testcase(_Case, Config) when is_list(Config) ->
+ Config.
+
+fin_per_testcase(_Case, Config) when is_list(Config) ->
+ Config.
+
+%%======================================================================
+%% Test case definitions
+%%======================================================================
+all(_) ->
+ ?SKIP(not_yet_implemented).
+
+
+%%======================================================================
+%% Test functions
+%%======================================================================
+
+
+%%======================================================================
+%% Internal functions
+%%======================================================================
diff --git a/lib/snmp/test/snmp_agent_test.erl b/lib/snmp/test/snmp_agent_test.erl
new file mode 100644
index 0000000000..53b35058e1
--- /dev/null
+++ b/lib/snmp/test/snmp_agent_test.erl
@@ -0,0 +1,6009 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2003-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%
+%%
+
+-module(snmp_agent_test).
+
+%% TODO
+%% * Test fault-tolerance (kill master etc)
+%%
+
+-compile(export_all).
+
+-define(application, snmp).
+
+-include_lib("kernel/include/file.hrl").
+-include("test_server.hrl").
+-include("snmp_test_lib.hrl").
+-define(SNMP_USE_V3, true).
+-include_lib("snmp/include/snmp_types.hrl").
+%% -include_lib("snmp/include/SNMP-COMMUNITY-MIB.hrl").
+%% -include_lib("snmp/include/SNMP-VIEW-BASED-ACM-MIB.hrl").
+%% -include_lib("snmp/include/SNMP-USER-BASED-SM-MIB.hrl").
+
+
+-define(klas1, [1,3,6,1,2,1,7]).
+-define(klas2, [1,3,6,1,2,1,9]).
+-define(klas3, [1,3,6,1,2,1,8,1]).
+-define(klas4, [1,3,6,1,2,1,8,4]).
+-define(sa, [1,3,6,1,4,1,193,2]).
+-define(system, [1,3,6,1,2,1,1]).
+-define(snmp, [1,3,6,1,2,1,11]).
+-define(snmpTraps, [1,3,6,1,6,3,1,1,5]).
+-define(ericsson, [1,3,6,1,4,1,193]).
+-define(testTrap, [1,3,6,1,2,1,15,0]).
+-define(xDescr, [1,3,6,1,2,1,17,1]).
+-define(xDescr2, [1,3,6,1,2,1,17,2]).
+
+-define(active, 1).
+-define(notInService, 2).
+-define(notReady, 3).
+-define(createAndGo, 4).
+-define(createAndWait, 5).
+-define(destroy, 6).
+
+-define(TRAP_UDP, 5000).
+
+-define(tooBigStr, "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").
+
+-define(str(X), snmp_pdus:bits_to_str(X)).
+
+-define(break(), begin io:format(user, "break at line ~w: pid: ~p\n",
+ [?LINE, self()]),
+ receive cont -> ok end
+ end).
+
+
+-define(v1_2(V1,V2),
+ case get(vsn) of
+ v1 -> V1;
+ _ -> V2
+ end).
+
+-define(v1_2_3(V1,V2,V3),
+ case get(vsn) of
+ v1 -> V1;
+ v2 -> V2;
+ _ -> V3
+ end).
+
+
+all(suite) ->
+ {req,
+ [
+ mnesia,
+ distribution,
+ {local_slave_nodes, 2},
+ {time, 360}
+ ],
+ [{conf, init_all, cases(), finish_all}]}.
+
+
+init_per_testcase(otp_7157_test = _Case, Config) when is_list(Config) ->
+ ?DBG("init_per_testcase -> entry with"
+ "~n Case: ~p"
+ "~n Config: ~p", [_Case, Config]),
+ Dog = ?WD_START(?MINS(1)),
+ [{watchdog, Dog}|Config];
+init_per_testcase(v2_inform_i = _Case, Config) when is_list(Config) ->
+ ?DBG("init_per_testcase -> entry with"
+ "~n Case: ~p"
+ "~n Config: ~p", [_Case, Config]),
+ Dog = ?WD_START(?MINS(10)),
+ [{watchdog, Dog}|Config];
+init_per_testcase(v3_inform_i = _Case, Config) when is_list(Config) ->
+ ?DBG("init_per_testcase -> entry with"
+ "~n Case: ~p"
+ "~n Config: ~p", [_Case, Config]),
+ Dog = ?WD_START(?MINS(10)),
+ [{watchdog, Dog}|Config];
+init_per_testcase(_Case, Config) when is_list(Config) ->
+ ?DBG("init_per_testcase -> entry with"
+ "~n Case: ~p"
+ "~n Config: ~p", [_Case, Config]),
+ Dog = ?WD_START(?MINS(6)),
+ [{watchdog, Dog}|Config].
+
+fin_per_testcase(_Case, Config) when is_list(Config) ->
+ ?DBG("fin_per_testcase -> entry with"
+ "~n Case: ~p"
+ "~n Config: ~p", [_Case, Config]),
+ Dog = ?config(watchdog, Config),
+ ?WD_STOP(Dog),
+ Config.
+
+cases() ->
+ case ?OSTYPE() of
+ vxworks ->
+ %% No crypto app, so skip v3 testcases
+ [
+ misc,
+ test_v1,
+ test_v2,
+ test_v1_v2,
+ test_multi_threaded,
+ mib_storage,
+ tickets
+ ];
+ _Else ->
+ [
+ misc,
+ test_v1,
+ test_v2,
+ test_v1_v2,
+ test_v3,
+ test_multi_threaded,
+ mib_storage,
+ tickets
+ ]
+ end.
+
+
+%%%-----------------------------------------------------------------
+%%% The test case structure is as follows:
+%%%
+%%% init_all - starts mnesia,
+%%%
+%%% init_v1 - starts agent
+%%% simple
+%%% big - e.g. starts/stops subagent, load/unloads mibs
+%%% init_mul
+%%% mul_get
+%%% mul_set
+%%% <etc>
+%%% finish_mul
+%%% <etc>
+%%% finish_v1
+%%%
+%%% init_v2 - starts agent
+%%% finish_v2
+%%%
+%%% init_bilingual - starts agent
+%%% finish_bilingual
+%%%
+%%% finish_all
+%%%
+%%% There is still one problem with these testsuites. If one test
+%%% fails, it may not be possible to run some other cases, as it
+%%% may have e.g. created some row or loaded some table, that it
+%%% didn't undo (since it failed).
+%%%-----------------------------------------------------------------
+
+init_all(Conf) ->
+ ?DISPLAY_SUITE_INFO(),
+ snmp_agent_test_lib:init_all(Conf).
+
+finish_all(Conf) ->
+ snmp_agent_test_lib:finish_all(Conf).
+
+start_v1_agent(Config) ->
+ snmp_agent_test_lib:start_v1_agent(Config).
+
+start_v1_agent(Config, Opts) ->
+ snmp_agent_test_lib:start_v1_agent(Config, Opts).
+
+start_v2_agent(Config) ->
+ snmp_agent_test_lib:start_v2_agent(Config).
+
+start_v2_agent(Config, Opts) ->
+ snmp_agent_test_lib:start_v2_agent(Config, Opts).
+
+start_v3_agent(Config) ->
+ snmp_agent_test_lib:start_v3_agent(Config).
+
+start_v3_agent(Config, Opts) ->
+ snmp_agent_test_lib:start_v3_agent(Config, Opts).
+
+start_bilingual_agent(Config) ->
+ snmp_agent_test_lib:start_bilingual_agent(Config).
+
+start_multi_threaded_agent(Config) when is_list(Config) ->
+ snmp_agent_test_lib:start_mt_agent(Config).
+
+stop_agent(Config) ->
+ snmp_agent_test_lib:stop_agent(Config).
+
+
+create_tables(SaNode) ->
+ ?line {atomic, ok} = mnesia:create_table([{name, friendsTable2},
+ {ram_copies, [SaNode]},
+ {snmp, [{key, integer}]},
+ {attributes, [a1,a2,a3]}]),
+ ?line {atomic, ok} = mnesia:create_table([{name, kompissTable2},
+ {ram_copies, [SaNode]},
+ {snmp, [{key, integer}]},
+ {attributes, [a1,a2,a3]}]),
+ ?line {atomic, ok} = mnesia:create_table([{name, snmp_variables},
+ {attributes, [a1,a2]}]).
+
+delete_tables() ->
+ mnesia:delete_table(friendsTable2),
+ mnesia:delete_table(kompissTable2),
+ mnesia:delete_table(snmp_variables).
+
+%% Creation is done in runtime!
+delete_mib_storage_mnesia_tables() ->
+ mnesia:delete_table(snmpa_mib_data),
+ mnesia:delete_table(snmpa_mib_tree),
+ mnesia:delete_table(snmpa_symbolic_store).
+
+
+%%-----------------------------------------------------------------
+%% A test case is always one of:
+%% - v1 specific case
+%% - v2 specific case
+%% - v1 and v2 case
+%% All v1 specific cases are prefixed with v1_, and all v2 with
+%% v2_. E.g. v1_trap/v2_trap.
+%%
+%% All other cases are shared. However, the testserver uses the name
+%% of the case to generate a file for that case. The same case cannot
+%% be used in different configurations in the same suite. Therefore
+%% all these functions exists in two variants, the base function
+%% <base>, and a second version <base>_2. There may be several
+%% versions as well, <base>_N.
+%%-----------------------------------------------------------------
+mib_storage(suite) -> [
+ mib_storage_ets,
+ mib_storage_dets,
+ mib_storage_mnesia,
+ mib_storage_size_check_ets,
+ mib_storage_size_check_dets,
+ mib_storage_size_check_mnesia,
+ mib_storage_varm_dets,
+ mib_storage_varm_mnesia
+ ].
+
+mib_storage_ets(suite) -> {req, [], {conf, init_mib_storage_ets,
+ mib_storage_ets_cases(),
+ finish_mib_storage_ets}}.
+
+mib_storage_dets(suite) -> {req, [], {conf, init_mib_storage_dets,
+ mib_storage_dets_cases(),
+ finish_mib_storage_dets}}.
+
+mib_storage_mnesia(suite) -> {req, [], {conf, init_mib_storage_mnesia,
+ mib_storage_mnesia_cases(),
+ finish_mib_storage_mnesia}}.
+
+mib_storage_size_check_ets(suite) ->
+ {req, [], {conf,
+ init_size_check_mse,
+ mse_size_check_cases(),
+ finish_size_check_mse}}.
+
+mib_storage_size_check_dets(suite) ->
+ {req, [], {conf,
+ init_size_check_msd,
+ msd_size_check_cases(),
+ finish_size_check_msd}}.
+
+mib_storage_size_check_mnesia(suite) ->
+ {req, [], {conf,
+ init_size_check_msm,
+ msm_size_check_cases(),
+ finish_size_check_msm}}.
+
+mib_storage_varm_dets(suite) ->
+ {req, [], {conf,
+ init_varm_mib_storage_dets,
+ varm_mib_storage_dets_cases(),
+ finish_varm_mib_storage_dets}}.
+
+mib_storage_varm_mnesia(suite) ->
+ {req, [], {conf,
+ init_varm_mib_storage_mnesia,
+ varm_mib_storage_mnesia_cases(),
+ finish_varm_mib_storage_mnesia}}.
+
+mib_storage_ets_cases() ->
+ [
+ mse_simple,
+ mse_v1_processing,
+ mse_big,
+ mse_big2,
+ mse_loop_mib,
+ mse_api,
+ mse_sa_register,
+ mse_v1_trap,
+ mse_sa_error,
+ mse_next_across_sa,
+ mse_undo,
+ mse_standard_mib,
+ mse_community_mib,
+ mse_framework_mib,
+ mse_target_mib,
+ mse_notification_mib,
+ mse_view_based_acm_mib,
+ mse_sparse_table,
+ mse_me_of,
+ mse_mib_of].
+
+mib_storage_dets_cases() ->
+ [
+ msd_simple,
+ msd_v1_processing,
+ msd_big,
+ msd_big2,
+ msd_loop_mib,
+ msd_api,
+ msd_sa_register,
+ msd_v1_trap,
+ msd_sa_error,
+ msd_next_across_sa,
+ msd_undo,
+ msd_standard_mib,
+ msd_community_mib,
+ msd_framework_mib,
+ msd_target_mib,
+ msd_notification_mib,
+ msd_view_based_acm_mib,
+ msd_sparse_table,
+ msd_me_of,
+ msd_mib_of
+ ].
+
+mib_storage_mnesia_cases() ->
+ [
+ msm_simple,
+ msm_v1_processing,
+ msm_big,
+ msm_big2,
+ msm_loop_mib,
+ msm_api,
+ msm_sa_register,
+ msm_v1_trap,
+ msm_sa_error,
+ msm_next_across_sa,
+ msm_undo,
+ msm_standard_mib,
+ msm_community_mib,
+ msm_framework_mib,
+ msm_target_mib,
+ msm_notification_mib,
+ msm_view_based_acm_mib,
+ msm_sparse_table,
+ msm_me_of,
+ msm_mib_of
+ ].
+
+mse_size_check_cases() ->
+ [mse_size_check].
+
+msd_size_check_cases() ->
+ [msd_size_check].
+
+msm_size_check_cases() ->
+ [msm_size_check].
+
+varm_mib_storage_dets_cases() ->
+ [msd_varm_mib_start].
+
+varm_mib_storage_mnesia_cases() ->
+ [msm_varm_mib_start].
+
+init_mib_storage_ets(Config) when is_list(Config) ->
+ ?LOG("init_mib_storage_ets -> entry", []),
+ MibStorage = {snmp_mib_storage,ets},
+ init_ms(Config, [MibStorage]).
+
+init_mib_storage_dets(Config) when is_list(Config) ->
+ ?LOG("init_mib_storage_ets -> entry", []),
+ ?line AgentDir = ?GCONF(agent_dir, Config),
+ MibStorage = {snmp_mib_storage,{dets,AgentDir}},
+ init_ms(Config, [MibStorage]).
+
+init_mib_storage_mnesia(Config) when is_list(Config) ->
+ ?LOG("init_mib_storage_ets -> entry", []),
+ MibStorage = {snmp_mib_storage,{mnesia,[]}},
+ init_ms(Config, [MibStorage]).
+
+init_ms(Config, Opts) when is_list(Config) ->
+ ?LOG("init_mib_storage_ets -> entry", []),
+ ?line SaNode = ?GCONF(snmp_sa, Config),
+ ?line create_tables(SaNode),
+ ?line AgentDir = ?GCONF(agent_dir, Config),
+ ?line MgrDir = ?GCONF(mgr_dir, Config),
+ ?line Ip = ?GCONF(ip, Config),
+ ?line config([v1], MgrDir, AgentDir, tuple_to_list(Ip), tuple_to_list(Ip)),
+ MasterAgentVerbosity = {snmp_master_agent_verbosity, trace},
+ MibsVerbosity = {snmp_mibserver_verbosity, trace},
+ SymStoreVerbosity = {snmp_symbolic_store_verbosity, trace},
+ Opts1 = [MasterAgentVerbosity,MibsVerbosity,SymStoreVerbosity|Opts],
+ [{vsn, v1} | start_v1_agent(Config,Opts1)].
+
+init_size_check_mse(Config) when is_list(Config) ->
+ MibStorage = {snmp_mib_storage, ets},
+ init_size_check_ms(Config, [MibStorage]).
+
+init_size_check_msd(Config) when is_list(Config) ->
+ AgentDir = ?GCONF(agent_dir, Config),
+ MibStorage = {snmp_mib_storage, {dets, AgentDir}},
+ init_size_check_ms(Config, [MibStorage]).
+
+init_size_check_msm(Config) when is_list(Config) ->
+ MibStorage = {snmp_mib_storage, {mnesia,[]}},
+ init_size_check_ms(Config, [MibStorage]).
+
+init_size_check_ms(Config, Opts) when is_list(Config) ->
+ SaNode = ?GCONF(snmp_sa, Config),
+ %% We are using v3 here, so crypto must be supported or else...
+ case ?CRYPTO_START() of
+ ok ->
+ case ?CRYPTO_SUPPORT() of
+ {no, Reason} ->
+ ?SKIP({unsupported_encryption, Reason});
+ yes ->
+ ok
+ end;
+ {error, Reason} ->
+ ?SKIP({failed_starting_crypto, Reason})
+ end,
+ create_tables(SaNode),
+ AgentDir = ?GCONF(agent_dir, Config),
+ MgrDir = ?GCONF(mgr_dir, Config),
+ Ip = ?GCONF(ip, Config),
+ ?line ok =
+ config([v3], MgrDir, AgentDir, tuple_to_list(Ip), tuple_to_list(Ip)),
+ [{vsn, v3} | start_v3_agent(Config, Opts)].
+
+init_varm_mib_storage_dets(Config) when is_list(Config) ->
+ ?LOG("init_varm_mib_storage_dets -> entry", []),
+ ?line SaNode = ?GCONF(snmp_sa, Config),
+ ?line create_tables(SaNode),
+ ?line AgentDir = ?GCONF(agent_dir, Config),
+ ?line MgrDir = ?GCONF(mgr_dir, Config),
+ ?line Ip = ?GCONF(ip, Config),
+ ?line config([v1], MgrDir, AgentDir, tuple_to_list(Ip), tuple_to_list(Ip)),
+ MibStorage = {snmp_mib_storage,{dets,AgentDir}},
+ MasterAgentVerbosity = {snmp_master_agent_verbosity, trace},
+ MibsVerbosity = {snmp_mibserver_verbosity, trace},
+ SymStoreVerbosity = {snmp_symbolic_store_verbosity, trace},
+ Opts = [MibStorage,MasterAgentVerbosity,MibsVerbosity,SymStoreVerbosity],
+ [{vsn, v1}, {agent_opts,Opts} | Config].
+
+init_varm_mib_storage_mnesia(Config) when is_list(Config) ->
+ ?LOG("init_varm_mib_storage_mnesia -> entry", []),
+ ?line SaNode = ?GCONF(snmp_sa, Config),
+ ?line create_tables(SaNode),
+ ?line AgentDir = ?GCONF(agent_dir, Config),
+ ?line MgrDir = ?GCONF(mgr_dir, Config),
+ ?line Ip = ?GCONF(ip, Config),
+ ?line config([v1], MgrDir, AgentDir, tuple_to_list(Ip), tuple_to_list(Ip)),
+ MibStorage = {snmp_mib_storage,{mnesia,[]}},
+ MasterAgentVerbosity = {snmp_master_agent_verbosity, trace},
+ MibsVerbosity = {snmp_mibserver_verbosity, trace},
+ SymStoreVerbosity = {snmp_symbolic_store_verbosity, trace},
+ Opts = [MibStorage,MasterAgentVerbosity,MibsVerbosity,SymStoreVerbosity],
+ [{vsn, v1}, {agent_opts,Opts} | Config].
+
+finish_mib_storage_ets(Config) when is_list(Config) ->
+ ?LOG("finish_mib_storage_ets -> entry", []),
+ delete_tables(),
+ C1 = stop_agent(Config),
+ delete_files(C1),
+ C2 = lists:keydelete(vsn, 1, C1),
+ lists:keydelete(agent_opts, 1, C2).
+
+finish_mib_storage_dets(Config) when is_list(Config) ->
+ ?LOG("finish_mib_storage_dets -> entry", []),
+ delete_tables(),
+ C1 = stop_agent(Config),
+ delete_files(C1),
+ C2 = lists:keydelete(vsn, 1, C1),
+ lists:keydelete(agent_opts, 1, C2).
+
+finish_mib_storage_mnesia(Config) when is_list(Config) ->
+ ?LOG("finish_mib_storage_mnesia -> entry", []),
+ delete_tables(),
+ delete_mib_storage_mnesia_tables(),
+ C1 = stop_agent(Config),
+ delete_files(C1),
+ C2 = lists:keydelete(vsn, 1, C1),
+ lists:keydelete(agent_opts, 1, C2).
+
+finish_varm_mib_storage_dets(Config) when is_list(Config) ->
+ ?LOG("finish_varm_mib_storage_dets -> entry", []),
+ delete_tables(),
+ %% C1 = stop_agent(Config), % In case something went wrong...
+ delete_files(Config),
+ C2 = lists:keydelete(vsn, 1, Config),
+ lists:keydelete(agent_opts, 1, C2).
+
+finish_varm_mib_storage_mnesia(Config) when is_list(Config) ->
+ ?LOG("finish_varm_mib_storage_mnesia -> entry", []),
+ delete_tables(),
+ delete_mib_storage_mnesia_tables(),
+ %% C1 = stop_agent(Config), % In case something went wrong...
+ delete_files(Config),
+ C2 = lists:keydelete(vsn, 1, Config),
+ lists:keydelete(agent_opts, 1, C2).
+
+finish_size_check_mse(Config) when is_list(Config) ->
+ finish_size_check_ms(Config).
+
+finish_size_check_msd(Config) when is_list(Config) ->
+ finish_size_check_ms(Config).
+
+finish_size_check_msm(Config) when is_list(Config) ->
+ finish_size_check_ms(Config).
+
+finish_size_check_ms(Config) when is_list(Config) ->
+ delete_tables(),
+ C1 = stop_agent(Config),
+ delete_files(C1),
+ lists:keydelete(vsn, 1, C1).
+
+
+%% These are just interface functions to fool the test server
+mse_simple(X) -> ?P(mse_simple), simple(X).
+mse_v1_processing(X) -> ?P(mse_v1_processing), v1_processing(X).
+mse_big(X) -> ?P(mse_big), big(X).
+mse_big2(X) -> ?P(mse_big2), big2(X).
+mse_loop_mib(X) -> ?P(mse_loop_mib), loop_mib(X).
+mse_api(X) -> ?P(mse_api), api(X).
+mse_sa_register(X) -> ?P(mse_sa_register), sa_register(X).
+mse_v1_trap(X) -> ?P(mse_v1_trap), v1_trap(X).
+mse_sa_error(X) -> ?P(mse_sa_error), sa_error(X).
+mse_next_across_sa(X) -> ?P(mse_next_across_sa), next_across_sa(X).
+mse_undo(X) -> ?P(mse_undo), undo(X).
+mse_standard_mib(X) -> ?P(mse_standard_mib), snmp_standard_mib(X).
+mse_community_mib(X) -> ?P(mse_community_mib), snmp_community_mib(X).
+mse_framework_mib(X) -> ?P(mse_framework_mib), snmp_framework_mib(X).
+mse_target_mib(X) -> ?P(mse_target_mib), snmp_target_mib(X).
+mse_notification_mib(X) -> ?P(mse_notification_mib), snmp_notification_mib(X).
+mse_view_based_acm_mib(X) -> ?P(mse_view_based_acm_mib), snmp_view_based_acm_mib(X).
+mse_sparse_table(X) -> ?P(mse_sparse_table), sparse_table(X).
+mse_me_of(X) -> ?P(mse_me_of), ms_me_of(X).
+mse_mib_of(X) -> ?P(mse_mib_of), ms_mib_of(X).
+
+msd_simple(X) -> ?P(msd_simple), simple(X).
+msd_v1_processing(X) -> ?P(msd_v1_processing), v1_processing(X).
+msd_big(X) -> ?P(msd_big), big(X).
+msd_big2(X) -> ?P(msd_big2), big2(X).
+msd_loop_mib(X) -> ?P(msd_loop_mib), loop_mib(X).
+msd_api(X) -> ?P(msd_api), api(X).
+msd_sa_register(X) -> ?P(msd_sa_register), sa_register(X).
+msd_v1_trap(X) -> ?P(msd_v1_trap), v1_trap(X).
+msd_sa_error(X) -> ?P(msd_sa_error), sa_error(X).
+msd_next_across_sa(X) -> ?P(msd_next_across_sa), next_across_sa(X).
+msd_undo(X) -> ?P(msd_undo), undo(X).
+msd_standard_mib(X) -> ?P(msd_standard_mib), snmp_standard_mib(X).
+msd_community_mib(X) -> ?P(msd_community_mib), snmp_community_mib(X).
+msd_framework_mib(X) -> ?P(msd_framework_mib), snmp_framework_mib(X).
+msd_target_mib(X) -> ?P(msd_target_mib), snmp_target_mib(X).
+msd_notification_mib(X) -> ?P(msd_notification_mib), snmp_notification_mib(X).
+msd_view_based_acm_mib(X) -> ?P(msd_view_based_acm_mib), snmp_view_based_acm_mib(X).
+msd_sparse_table(X) -> ?P(msd_sparse_table), sparse_table(X).
+msd_me_of(X) -> ?P(msd_me_of), ms_me_of(X).
+msd_mib_of(X) -> ?P(msd_mib_of), ms_mib_of(X).
+
+msm_simple(X) -> ?P(msm_simple), simple(X).
+msm_v1_processing(X) -> ?P(msm_v1_processing), v1_processing(X).
+msm_big(X) -> ?P(msm_big2), big(X).
+msm_big2(X) -> ?P(msm_loop_mib), big2(X).
+msm_loop_mib(X) -> ?P(msm_loop_mib), loop_mib(X).
+msm_api(X) -> ?P(msm_api), api(X).
+msm_sa_register(X) -> ?P(msm_sa_register), sa_register(X).
+msm_v1_trap(X) -> ?P(msm_v1_trap), v1_trap(X).
+msm_sa_error(X) -> ?P(msm_sa_error), sa_error(X).
+msm_next_across_sa(X) -> ?P(msm_next_across_sa), next_across_sa(X).
+msm_undo(X) -> ?P(msm_undo), undo(X).
+msm_standard_mib(X) -> ?P(msm_standard_mib), snmp_standard_mib(X).
+msm_community_mib(X) -> ?P(msm_community_mib), snmp_community_mib(X).
+msm_framework_mib(X) -> ?P(msm_framework_mib), snmp_framework_mib(X).
+msm_target_mib(X) -> ?P(msm_target_mib), snmp_target_mib(X).
+msm_notification_mib(X) -> ?P(msm_notification_mib), snmp_notification_mib(X).
+msm_view_based_acm_mib(X) -> ?P(msm_view_based_acm_mib), snmp_view_based_acm_mib(X).
+msm_sparse_table(X) -> ?P(msm_sparse_table), sparse_table(X).
+msm_me_of(X) -> ?P(msm_me_of), ms_me_of(X).
+msm_mib_of(X) -> ?P(msm_mib_of), ms_mib_of(X).
+
+
+mse_size_check(X) -> ?P(mse_size_check), ms_size_check(X).
+msd_size_check(X) -> ?P(msd_size_check), ms_size_check(X).
+msm_size_check(X) -> ?P(msm_size_check), ms_size_check(X).
+
+msd_varm_mib_start(X) ->
+ ?P(msd_varm_mib_start),
+ varm_mib_start(X).
+
+msm_varm_mib_start(X) ->
+ %% <CONDITIONAL-SKIP>
+ Skippable = [win32],
+ Condition = fun() -> ?OS_BASED_SKIP(Skippable) end,
+ ?NON_PC_TC_MAYBE_SKIP(X, Condition),
+ %% </CONDITIONAL-SKIP>
+
+ ?P(msm_varm_mib_start),
+ varm_mib_start(X).
+
+ms_size_check(suite) -> [];
+ms_size_check(Config) when is_list(Config) ->
+ ?P(ms_size_check),
+ init_case(Config),
+ ?LOG("mib server size check...", []),
+
+ ?line load_master("Test2"),
+ ?line load_master("TestTrap"),
+ ?line load_master("TestTrapv2"),
+ ?line load_master_std("OTP-SNMPEA-MIB"),
+ ?line load_master_std("SNMP-COMMUNITY-MIB"),
+ ?line load_master_std("SNMP-FRAMEWORK-MIB"),
+ ?line load_master_std("SNMP-MPD-MIB"),
+ ?line load_master_std("SNMP-NOTIFICATION-MIB"),
+ ?line load_master_std("SNMP-TARGET-MIB"),
+ ?line load_master_std("SNMP-USER-BASED-SM-MIB"),
+ ?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"),
+ ?line load_master_std("SNMPv2-MIB"),
+ ?line load_master_std("SNMPv2-TM"),
+
+ ?SLEEP(2000),
+
+ ?line display_memory_usage(),
+
+ ?line unload_master("OTP-SNMPEA-MIB"),
+ ?line unload_master("SNMP-COMMUNITY-MIB"),
+ ?line unload_master("SNMP-FRAMEWORK-MIB"),
+ ?line unload_master("SNMP-MPD-MIB"),
+ ?line unload_master("SNMP-NOTIFICATION-MIB"),
+ ?line unload_master("SNMP-TARGET-MIB"),
+ ?line unload_master("SNMP-USER-BASED-SM-MIB"),
+ ?line unload_master("SNMP-VIEW-BASED-ACM-MIB"),
+ ?line unload_master("SNMPv2-MIB"),
+ ?line unload_master("SNMPv2-TM"),
+
+ ?line unload_master("TestTrapv2"),
+ ?line unload_master("TestTrap"),
+ ?line unload_master("Test2"),
+
+ ok.
+
+
+varm_mib_start(suite) -> [];
+varm_mib_start(Config) when is_list(Config) ->
+ ?P(varm_mib_start),
+ ?LOG("varm_mib_start -> entry", []),
+ init_case(Config),
+
+ %% Start the agent
+ Opts = ?GCONF(agent_opts, Config),
+ Config1 = start_v1_agent(Config, Opts),
+
+ %% Sleep some in order for the agent to start properly
+ ?DBG("varm_mib_start -> sleep some (before loading mobs)", []),
+ ?SLEEP(5000),
+
+ %% Load all the mibs
+ HardwiredMibs = loaded_mibs(),
+ ?DBG("varm_mib_start -> load all mibs", []),
+ ?line load_master_std("SNMP-COMMUNITY-MIB"),
+ ?line load_master_std("SNMP-FRAMEWORK-MIB"),
+ ?line load_master_std("SNMP-TARGET-MIB"),
+ ?line load_master_std("SNMP-NOTIFICATION-MIB"),
+
+ %% Unload the hardwired mibs
+ ?DBG("varm_mib_start -> sleep some (before unloading hardwired mibs)", []),
+ ?SLEEP(1000),
+ ?DBG("varm_mib_start -> unload (hardwired) mibs", []),
+ ?line unload_mibs(HardwiredMibs), %% unload hardwired
+
+ ?DBG("varm_mib_start -> sleep some (before stopping agent)", []),
+ ?SLEEP(1000),
+
+ %% Stop the agent (without deleting the stored files)
+ ?DBG("varm_mib_start -> stop the agent", []),
+ Config2 = stop_agent(Config1),
+
+ %% Sleep some in order for the agent to stop properly
+ ?DBG("varm_mib_start -> sleep some (before re-starting the agent)", []),
+ ?SLEEP(5000),
+
+ %% Start the agent (again)
+ ?DBG("varm_mib_start -> start the agent", []),
+ Config3 = start_v1_agent(Config2, Opts),
+
+ ?DBG("varm_mib_start -> sleep some (before starting tests)", []),
+ ?SLEEP(5000),
+
+ %% Perform the test(s)
+ ?DBG("varm_mib_start -> perform the tests", []),
+ try_test(snmp_community_mib),
+ try_test(snmp_framework_mib),
+ try_test(snmp_target_mib),
+ try_test(snmp_notification_mib),
+
+ %% Stop the agent (without deleting the stored files)
+ ?DBG("varm_mib_start -> stop the agent", []),
+ stop_agent(Config3),
+ ok.
+
+
+-define(snmpTrapCommunity_instance, [1,3,6,1,6,3,18,1,4,0]).
+-define(vacmViewSpinLock_instance, [1,3,6,1,6,3,16,1,5,1,0]).
+-define(usmStatsNotInTimeWindows_instance, [1,3,6,1,6,3,15,1,1,2,0]).
+
+ms_me_of(suite) -> [];
+ms_me_of(Config) when is_list(Config) ->
+ ?P(ms_me_of),
+ init_case(Config),
+
+ ?line load_master("Test2"),
+ ?line load_master("TestTrap"),
+ ?line load_master("TestTrapv2"),
+ ?line load_master_std("OTP-SNMPEA-MIB"),
+ ?line load_master_std("SNMP-COMMUNITY-MIB"),
+ ?line load_master_std("SNMP-FRAMEWORK-MIB"),
+ ?line load_master_std("SNMP-MPD-MIB"),
+ ?line load_master_std("SNMP-NOTIFICATION-MIB"),
+ ?line load_master_std("SNMP-TARGET-MIB"),
+ ?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"),
+
+ ?SLEEP(2000),
+
+ ?line display_memory_usage(),
+
+
+ ?DBG("ms_me_of -> find ~w from SNMP-COMMUNITY-MIB",
+ [?snmpTrapCommunity_instance]),
+ ?line ok = me_of(?snmpTrapCommunity_instance),
+
+ ?DBG("ms_me_of -> find ~w from SNMP-VIEW-BASED-ACM-MIB",
+ [?vacmViewSpinLock_instance]),
+ ?line ok = me_of(?vacmViewSpinLock_instance),
+
+ ?DBG("ms_me_of -> find ~w from SNMP-USER-BASED-SM-MIB",
+ [?usmStatsNotInTimeWindows_instance]),
+ ?line {error, _} = me_of(?usmStatsNotInTimeWindows_instance),
+
+
+ ?line unload_master("OTP-SNMPEA-MIB"),
+ ?line unload_master("SNMP-COMMUNITY-MIB"),
+ ?line unload_master("SNMP-FRAMEWORK-MIB"),
+ ?line unload_master("SNMP-MPD-MIB"),
+ ?line unload_master("SNMP-NOTIFICATION-MIB"),
+ ?line unload_master("SNMP-TARGET-MIB"),
+ ?line unload_master("SNMP-VIEW-BASED-ACM-MIB"),
+
+ ?line unload_master("TestTrapv2"),
+ ?line unload_master("TestTrap"),
+ ?line unload_master("Test2"),
+
+ ok.
+
+me_of(Oid) ->
+ case snmpa:me_of(Oid) of
+ {ok, #me{oid = Oid}} ->
+ ok;
+ {ok, #me{oid = OtherOid}} ->
+ case lists:reverse(Oid) of
+ [0|Rest] ->
+ case lists:reverse(Rest) of
+ OtherOid ->
+ ok;
+ AnotherOid ->
+ {error, {invalid_oid, Oid, AnotherOid}}
+ end;
+ _ ->
+ {error, {invalid_oid, Oid, OtherOid}}
+ end;
+ {error, Reason} ->
+ {error, Reason};
+ Else ->
+ {error, Else}
+ end.
+
+
+ms_mib_of(suite) -> [];
+ms_mib_of(Config) when is_list(Config) ->
+ ?P(ms_mib_of),
+ init_case(Config),
+
+ ?line load_master("Test2"),
+ ?line load_master("TestTrap"),
+ ?line load_master("TestTrapv2"),
+ ?line load_master_std("OTP-SNMPEA-MIB"),
+ ?line load_master_std("SNMP-COMMUNITY-MIB"),
+ ?line load_master_std("SNMP-FRAMEWORK-MIB"),
+ ?line load_master_std("SNMP-MPD-MIB"),
+ ?line load_master_std("SNMP-NOTIFICATION-MIB"),
+ ?line load_master_std("SNMP-TARGET-MIB"),
+ ?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"),
+
+ ?SLEEP(2000),
+
+ ?line display_memory_usage(),
+
+
+ ?DBG("ms_mib_of -> find ~w from SNMP-COMMUNITY-MIB",
+ [?snmpTrapCommunity_instance]),
+ ?line ok = mib_of(?snmpTrapCommunity_instance, 'SNMP-COMMUNITY-MIB'),
+
+ ?DBG("ms_mib_of -> find ~w from SNMP-VIEW-BASED-ACM-MIB",
+ [?vacmViewSpinLock_instance]),
+ ?line ok = mib_of(?vacmViewSpinLock_instance, 'SNMP-VIEW-BASED-ACM-MIB'),
+
+ ?DBG("ms_mib_of -> find ~w from SNMP-USER-BASED-SM-MIB",
+ [?usmStatsNotInTimeWindows_instance]),
+ ?line {error, _} = mib_of(?usmStatsNotInTimeWindows_instance,
+ 'SNMP-USER-BASED-SM-MIB'),
+
+
+ ?line unload_master("OTP-SNMPEA-MIB"),
+ ?line unload_master("SNMP-COMMUNITY-MIB"),
+ ?line unload_master("SNMP-FRAMEWORK-MIB"),
+ ?line unload_master("SNMP-MPD-MIB"),
+ ?line unload_master("SNMP-NOTIFICATION-MIB"),
+ ?line unload_master("SNMP-TARGET-MIB"),
+ ?line unload_master("SNMP-VIEW-BASED-ACM-MIB"),
+
+ ?line unload_master("TestTrapv2"),
+ ?line unload_master("TestTrap"),
+ ?line unload_master("Test2"),
+
+ ok.
+
+mib_of(Oid, ExpectedMibName) ->
+ ?DBG("mib_of -> entry with"
+ "~n Oid: ~p"
+ "~n ExpectedMibName: ~p", [Oid, ExpectedMibName]),
+ %% case snmpa:mib_of(Oid) of
+ MibOf = snmpa:mib_of(Oid),
+ ?DBG("mib_of -> MibOf: ~n~p", [MibOf]),
+ case MibOf of
+ {ok, ExpectedMibName} ->
+ ok;
+ {ok, OtherMibName} ->
+ {error, {invalid_mib, ExpectedMibName, OtherMibName}};
+ {error, Reason} ->
+ {error, Reason};
+ Else ->
+ ?DBG("mib_of -> Else: ~n~p", [Else]),
+ {error, Else}
+ end.
+
+
+misc(suite) ->
+ {req, [], {conf, init_misc, misc_cases(), finish_misc}}.
+
+init_misc(Config) ->
+ init_v1(Config).
+
+finish_misc(Config) ->
+ finish_v1(Config).
+
+misc_cases() ->
+ [
+ app_info,
+ info_test
+ ].
+
+app_info(suite) -> [];
+app_info(Config) when is_list(Config) ->
+ ?P(app_info),
+ SnmpDir = app_dir(snmp),
+ SslDir = app_dir(ssl),
+ CryptoDir = app_dir(crypto),
+ Attr = snmp:module_info(attributes),
+ AppVsn =
+ case lists:keysearch(app_vsn, 1, Attr) of
+ {value, {app_vsn, V}} ->
+ V;
+ false ->
+ "undefined"
+ end,
+ io:format("Root dir: ~s~n"
+ "SNMP: Application dir: ~s~n"
+ " Application ver: ~s~n"
+ "SSL: Application dir: ~s~n"
+ "CRYPTO: Application dir: ~s~n",
+ [code:root_dir(), SnmpDir, AppVsn, SslDir, CryptoDir]),
+ ok.
+
+app_dir(App) ->
+ case code:lib_dir(App) of
+ D when is_list(D) ->
+ filename:basename(D);
+ {error, _Reason} ->
+ "undefined"
+ end.
+
+
+test_v1(suite) -> {req, [], {conf, init_v1, v1_cases(), finish_v1}}.
+
+%v1_cases() -> [loop_mib];
+v1_cases() ->
+ [
+ simple,
+ db_notify_client,
+ v1_processing,
+ big,
+ big2,
+ loop_mib,
+ api,
+ subagent,
+ mnesia,
+ multiple_reqs,
+ sa_register,
+ v1_trap,
+ sa_error,
+ next_across_sa,
+ undo,
+ reported_bugs,
+ standard_mibs,
+ sparse_table,
+ cnt_64,
+ opaque,
+
+ change_target_addr_config
+ ].
+
+init_v1(Config) when is_list(Config) ->
+ ?line SaNode = ?config(snmp_sa, Config),
+ ?line create_tables(SaNode),
+ ?line AgentDir = ?config(agent_dir, Config),
+ ?line MgrDir = ?config(mgr_dir, Config),
+ ?line Ip = ?config(ip, Config),
+ ?line config([v1], MgrDir, AgentDir, tuple_to_list(Ip), tuple_to_list(Ip)),
+ [{vsn, v1} | start_v1_agent(Config)].
+
+finish_v1(Config) when is_list(Config) ->
+ delete_tables(),
+ C1 = stop_agent(Config),
+ delete_files(C1),
+ lists:keydelete(vsn, 1, C1).
+
+test_v2(suite) -> {req, [], {conf, init_v2, v2_cases(), finish_v2}}.
+
+v2_cases() ->
+ [
+ simple_2,
+ v2_processing,
+ big_2,
+ big2_2,
+ loop_mib_2,
+ api_2,
+ subagent_2,
+ mnesia_2,
+ multiple_reqs_2,
+ sa_register_2,
+ v2_trap,
+ v2_inform,
+ sa_error_2,
+ next_across_sa_2,
+ undo_2,
+ reported_bugs_2,
+ standard_mibs_2,
+ v2_types,
+ implied,
+ sparse_table_2,
+ cnt_64_2,
+ opaque_2,
+ v2_caps
+ ].
+
+init_v2(Config) when is_list(Config) ->
+ SaNode = ?config(snmp_sa, Config),
+ create_tables(SaNode),
+ AgentDir = ?config(agent_dir, Config),
+ MgrDir = ?config(mgr_dir, Config),
+ Ip = ?config(ip, Config),
+ config([v2], MgrDir, AgentDir, tuple_to_list(Ip), tuple_to_list(Ip)),
+ [{vsn, v2} | start_v2_agent(Config)].
+
+finish_v2(Config) when is_list(Config) ->
+ delete_tables(),
+ C1 = stop_agent(Config),
+ delete_files(C1),
+ lists:keydelete(vsn, 1, C1).
+
+test_v1_v2(suite) ->
+ {req, [], {conf, init_v1_v2, v1_v2_cases(), finish_v1_v2}}.
+
+v1_v2_cases() ->
+ [simple_bi].
+
+init_v1_v2(Config) when is_list(Config) ->
+ SaNode = ?config(snmp_sa, Config),
+ create_tables(SaNode),
+ AgentDir = ?config(agent_dir, Config),
+ MgrDir = ?config(mgr_dir, Config),
+ Ip = ?config(ip, Config),
+ config([v1,v2], MgrDir, AgentDir, tuple_to_list(Ip), tuple_to_list(Ip)),
+ [{vsn, bilingual} | start_bilingual_agent(Config)].
+
+finish_v1_v2(Config) when is_list(Config) ->
+ delete_tables(),
+ C1 = stop_agent(Config),
+ delete_files(C1),
+ lists:keydelete(vsn, 1, C1).
+
+test_v3(suite) -> {req, [], {conf, init_v3, v3_cases(), finish_v3}}.
+
+v3_cases() ->
+ [
+ simple_3,
+ v3_processing,
+ big_3,
+ big2_3,
+ api_3,
+ subagent_3,
+ mnesia_3,
+ loop_mib_3,
+ multiple_reqs_3,
+ sa_register_3,
+ v3_trap,
+ v3_inform,
+ sa_error_3,
+ next_across_sa_3,
+ undo_3,
+ reported_bugs_3,
+ standard_mibs_3,
+ v3_security,
+ v2_types_3,
+ implied_3,
+ sparse_table_3,
+ cnt_64_3,
+ opaque_3,
+ v2_caps_3
+ ].
+
+init_v3(Config) when is_list(Config) ->
+ %% Make sure crypto works, otherwise start_agent will fail
+ %% and we will be stuck with a bunch of mnesia tables for
+ %% the rest of this suite...
+ ?DBG("start_agent -> start crypto app",[]),
+ case os:type() of
+ vxworks ->
+ no_crypto;
+ _ ->
+ case ?CRYPTO_START() of
+ ok ->
+ case ?CRYPTO_SUPPORT() of
+ {no, Reason} ->
+ ?SKIP({unsupported_encryption, Reason});
+ yes ->
+ ok
+ end;
+ {error, Reason} ->
+ ?SKIP({failed_starting_crypto, Reason})
+ end
+ end,
+ SaNode = ?config(snmp_sa, Config),
+ create_tables(SaNode),
+ AgentDir = ?config(agent_dir, Config),
+ MgrDir = ?config(mgr_dir, Config),
+ Ip = ?config(ip, Config),
+ ?line ok = config([v3], MgrDir, AgentDir,
+ tuple_to_list(Ip), tuple_to_list(Ip)),
+ [{vsn, v3} | start_v3_agent(Config)].
+
+finish_v3(Config) when is_list(Config) ->
+ delete_tables(),
+ C1 = stop_agent(Config),
+ delete_files(C1),
+ lists:keydelete(vsn, 1, C1).
+
+test_multi_threaded(suite) ->
+ {req, [], {conf, init_mt, mt_cases(), finish_mt}}.
+
+mt_cases() ->
+ [multi_threaded, mt_trap].
+
+init_mt(Config) when is_list(Config) ->
+ SaNode = ?config(snmp_sa, Config),
+ create_tables(SaNode),
+ AgentDir = ?config(agent_dir, Config),
+ MgrDir = ?config(mgr_dir, Config),
+ Ip = ?config(ip, Config),
+ ?line ok =
+ config([v2], MgrDir, AgentDir, tuple_to_list(Ip), tuple_to_list(Ip)),
+ [{vsn, v2} | start_multi_threaded_agent(Config)].
+
+finish_mt(Config) when is_list(Config) ->
+ delete_tables(),
+ C1 = stop_agent(Config),
+ delete_files(C1),
+ lists:keydelete(vsn, 1, C1).
+
+%% This one *must* be run first in each case.
+init_case(Config) ->
+ snmp_agent_test_lib:init_case(Config).
+
+
+load_master(Mib) ->
+ ?DBG("load_master -> entry with"
+ "~n Mib: ~p", [Mib]),
+ snmpa:unload_mibs(snmp_master_agent, [Mib]), % Unload for safety
+ ok = snmpa:load_mibs(snmp_master_agent, [get(mib_dir) ++ Mib]).
+
+load_master_std(Mib) ->
+ ?DBG("load_master_std -> entry with"
+ "~n Mib: ~p", [Mib]),
+ snmpa:unload_mibs(snmp_master_agent, [Mib]), % Unload for safety
+ ok = snmpa:load_mibs(snmp_master_agent, [get(std_mib_dir) ++ Mib]).
+
+unload_master(Mib) ->
+ ?DBG("unload_master -> entry with"
+ "~n Mib: ~p", [Mib]),
+ ok = snmpa:unload_mibs(snmp_master_agent, [Mib]).
+
+loaded_mibs() ->
+ ?DBG("loaded_mibs -> entry",[]),
+ Info = snmpa:info(snmp_master_agent),
+ {value, {mib_server, MibInfo}} = lists:keysearch(mib_server, 1, Info),
+ {value, {loaded_mibs, Mibs}} = lists:keysearch(loaded_mibs, 1, MibInfo),
+ [atom_to_list(Mib) || {Mib,_,_} <- Mibs].
+
+unload_mibs(Mibs) ->
+ ?DBG("unload_mibs -> entry with"
+ "~n Mibs: ~p", [Mibs]),
+ ok = snmpa:unload_mibs(snmp_master_agent, Mibs).
+
+start_subagent(SaNode, RegTree, Mib) ->
+ snmp_agent_test_lib:start_subagent(SaNode, RegTree, Mib).
+
+stop_subagent(SA) ->
+ snmp_agent_test_lib:stop_subagent(SA).
+
+
+%%-----------------------------------------------------------------
+%% This function takes care of the old OTP-SNMPEA-MIB.
+%% Unfortunately, the testcases were written to use the data in the
+%% internal tables, and these table are now obsolete and not used
+%% by the agent. Therefore, we emulate them by using
+%% OLD-SNMPEA-MIB, which uses the default impl. of all tables.
+%%
+%% These two rows must exist in intCommunityTable
+%% {[147,214,36,45], "public", 2, readWrite}.
+%% {[147,214,36,45], "standard trap", 2, read}.
+%% (But with the manager's IP address)
+%%
+%%-----------------------------------------------------------------
+init_old() ->
+ snmpa_local_db:table_create_row(intCommunityTable,
+ get(mip) ++ [6 | "public"],
+ {get(mip), "public", 2, 2}),
+ snmpa_local_db:table_create_row(intCommunityTable,
+ get(mip) ++ [13 | "standard trap"],
+ {get(mip), "standard trap", 2, 1}),
+ snmpa_local_db:variable_set(intAgentIpAddress, [127,0,0,1]).
+
+
+
+simple(suite) -> [];
+simple(Config) when is_list(Config) ->
+ ?P(simple),
+ init_case(Config),
+
+ try_test(simple_standard_test).
+
+simple_2(X) -> ?P(simple_2), simple(X).
+
+simple_bi(suite) -> [];
+simple_bi(Config) when is_list(Config) ->
+ ?P(simple_bi),
+ init_case(Config),
+
+ put(vsn, v1), % First, try v1 manager
+ try_test(simple_standard_test),
+
+ put(vsn, v2), % Then, try v2 manager
+ try_test(simple_standard_test).
+
+simple_3(X) ->
+ ?P(simple_3), simple(X).
+
+big(suite) -> [];
+big(Config) when is_list(Config) ->
+ ?P(big),
+ %% put(sname, {?MODULE, big}),
+ %% put(verbosity, trace),
+
+ {SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ ?P1("Starting subagent..."),
+ ?line pong = net_adm:ping(SaNode),
+
+ ?line {ok, SA} = start_subagent(SaNode, ?klas1, "Klas1"),
+ ?DBG("big -> SA: ~p", [SA]),
+ ?line load_master("OLD-SNMPEA-MIB"),
+ ?line init_old(),
+
+ snmpa:dump_mibs(),
+ snmpa:dump_mibs("dumped_mibs.txt"),
+ io:format("Local DB: ~n~p~n", [snmpa_local_db:print()]),
+
+ try_test(big_test),
+
+ ?line stop_subagent(SA),
+ ?line unload_master("OLD-SNMPEA-MIB").
+
+big_2(X) -> ?P(big_2), big(X).
+
+big_3(X) -> ?P(big_3), big(X).
+
+
+big2(suite) -> [];
+big2(Config) when is_list(Config) ->
+ ?P(big2),
+ %% This is exactly the same tests as 'big', but with the
+ %% v2 equivalent of the mibs.
+ {SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ ?P1("Starting subagent..."),
+ ?line pong = net_adm:ping(SaNode),
+
+ ?line {ok, SA} = start_subagent(SaNode, ?klas1, "Klas1-v2"),
+ ?line load_master("OLD-SNMPEA-MIB-v2"),
+ ?line init_old(),
+ try_test(big_test),
+ ?line stop_subagent(SA),
+ ?line unload_master("OLD-SNMPEA-MIB-v2").
+
+big2_2(X) -> ?P(big2_2), big2(X).
+
+big2_3(X) -> ?P(big2_3), big2(X).
+
+
+multi_threaded(suite) -> [];
+multi_threaded(Config) when is_list(Config) ->
+ ?P(multi_threaded),
+ init_case(Config),
+
+ ?line load_master("Test1"),
+ try_test(multi_threaded_test),
+ ?line unload_master("Test1").
+
+mt_trap(suite) -> [];
+mt_trap(Config) when is_list(Config) ->
+ ?P(mt_trap),
+ init_case(Config),
+ MA = whereis(snmp_master_agent),
+
+ ?line load_master("Test1"),
+ ?line load_master("TestTrapv2"),
+ try_test(mt_trap_test, [MA]),
+ ?line unload_master("TestTrapv2"),
+ ?line unload_master("Test1").
+
+v2_types(suite) -> [];
+v2_types(Config) when is_list(Config) ->
+ ?P(v2_types),
+ init_case(Config),
+
+ ?line load_master("Test1"),
+ try_test(types_v2_test),
+ ?line unload_master("Test1").
+
+v2_types_3(X) -> ?P(v2_types_3), v2_types(X).
+
+
+implied(suite) -> [];
+implied(Config) when is_list(Config) ->
+ ?P(implied),
+ init_case(Config),
+ MA = whereis(snmp_master_agent),
+
+ ?line load_master("Test1"),
+ try_test(implied_test,[MA]),
+ ?line unload_master("Test1").
+
+implied_3(X) -> ?P(implied_3), implied(X).
+
+
+sparse_table(suite) -> [];
+sparse_table(Config) when is_list(Config) ->
+ ?P(sparse_table),
+ init_case(Config),
+
+ ?line load_master("Test1"),
+ try_test(sparse_table_test),
+ ?line unload_master("Test1").
+
+sparse_table_2(X) -> ?P(sparse_table_2), sparse_table(X).
+
+sparse_table_3(X) -> ?P(sparse_table_3), sparse_table(X).
+
+cnt_64(suite) -> [];
+cnt_64(Config) when is_list(Config) ->
+ ?P(cnt_64),
+ init_case(Config),
+ MA = whereis(snmp_master_agent),
+
+ ?line load_master("Test1"),
+ try_test(cnt_64_test, [MA]),
+ ?line unload_master("Test1").
+
+cnt_64_2(X) -> ?P(cnt_64_2), cnt_64(X).
+
+cnt_64_3(X) -> ?P(cnt_64_3), cnt_64(X).
+
+opaque(suite) -> [];
+opaque(Config) when is_list(Config) ->
+ ?P(opaque),
+ init_case(Config),
+
+ ?line load_master("Test1"),
+ try_test(opaque_test),
+ ?line unload_master("Test1").
+
+opaque_2(X) -> ?P(opaque_2), opaque(X).
+
+opaque_3(X) -> ?P(opaque_2), opaque(X).
+
+
+change_target_addr_config(suite) -> [];
+change_target_addr_config(Config) when is_list(Config) ->
+ ?P(change_target_addr_config),
+ ?LOG("change_target_addr_config -> entry",[]),
+ init_case(Config),
+
+ put(sname,snmp_suite),
+ put(verbosity,trace),
+
+ MA = whereis(snmp_master_agent),
+
+ ?LOG("change_target_addr_config -> load TestTrap",[]),
+ ?line load_master("TestTrap"),
+
+ ?LOG("change_target_addr_config -> set trace verbosity for local_db",[]),
+ ?line snmpa:verbosity(local_db,trace),
+
+ %% First send some traps that will arive att the original manager
+ ?LOG("change_target_addr_config -> send trap",[]),
+ try_test(ma_trap1, [MA]),
+
+ ?LOG("change_target_addr_config -> set silence verbosity for local_db",[]),
+ ?line snmpa:verbosity(local_db,silence),
+
+ %% Start new dummy listener
+ ?LOG("change_target_addr_config -> start dummy manager",[]),
+ ?line {ok,Pid,NewPort} = dummy_manager_start(MA),
+
+ %% Reconfigure
+ ?LOG("change_target_addr_config -> reconfigure",[]),
+ AgentDir = ?config(agent_dir, Config),
+ ?line rewrite_target_addr_conf(AgentDir, NewPort),
+ ?line snmp_target_mib:reconfigure(AgentDir),
+
+ %% Send the trap again
+ ?LOG("change_target_addr_config -> send trap again",[]),
+ catch dummy_manager_send_trap2(Pid),
+
+ ?LOG("change_target_addr_config -> await trap ack",[]),
+ catch dummy_manager_await_trap2_ack(),
+
+ ?LOG("change_target_addr_config -> stop dummy manager",[]),
+ ?line ok = dummy_manager_stop(Pid),
+
+ ?LOG("change_target_addr_config -> reset target address config",[]),
+ ?line reset_target_addr_conf(AgentDir),
+
+ ?LOG("change_target_addr_config -> unload TestTrap",[]),
+ ?line unload_master("TestTrap").
+
+
+dummy_manager_start(MA) ->
+ ?DBG("dummy_manager_start -> entry",[]),
+ Pid = spawn(get(mgr_node), ?MODULE,dummy_manager_init,[self(),MA]),
+ ?DBG("dummy_manager_start -> Pid: ~p",[Pid]),
+ await_dummy_manager_started(Pid).
+
+await_dummy_manager_started(Pid) ->
+ receive
+ {dummy_manager_started,Pid,Port} ->
+ ?DBG("dummy_manager_start -> acknowledge received with"
+ "~n Port: ~p",[Port]),
+ {ok,Pid,Port};
+ {'EXIT', Pid, Reason} ->
+ {error, Pid, Reason};
+ O ->
+ ?LOG("dummy_manager_start -> received unknown message:"
+ "~n ~p",[O]),
+ await_dummy_manager_started(Pid)
+ end.
+
+dummy_manager_stop(Pid) ->
+ ?DBG("dummy_manager_stop -> entry with Pid: ~p",[Pid]),
+ Pid ! stop,
+ receive
+ {dummy_manager_stopping, Pid} ->
+ ?DBG("dummy_manager_stop -> acknowledge received",[]),
+ ok
+ after 10000 ->
+ ?ERR("dummy_manager_stop -> timeout",[]),
+ timeout
+ end.
+
+dummy_manager_send_trap2(Pid) ->
+ ?DBG("dummy_manager_send_trap2 -> entry",[]),
+ Pid ! {send_trap,testTrap2}.
+
+dummy_manager_await_trap2_ack() ->
+ ?DBG("dummy_manager_await_trap2 -> entry",[]),
+ receive
+ {received_trap,Trap} ->
+ ?LOG("dummy_manager_await_trap2 -> received trap: ~p",[Trap]),
+ %% Note:
+ %% Without this sleep the v2_inform_i testcase failes! There
+ %% is no relation between these two test cases as far as I
+ %% able to figure out...
+ ?SLEEP(60000),
+ ok;
+ O ->
+ ?ERR("dummy_manager_await_trap2 -> unexpected message: ~p",[O]),
+ ok
+ after 10000 ->
+ ?ERR("dummy_manager_await_trap2 -> timeout",[]),
+ timeout
+ end.
+
+dummy_manager_init(Parent,MA) ->
+ ?DBG("dummy_manager_init -> entry with"
+ "~n Parent: ~p"
+ "~n MA: ~p",[Parent,MA]),
+ {ok,S} = gen_udp:open(0,[{recbuf,65535}]),
+ ?DBG("dummy_manager_init -> S: ~p",[S]),
+ {ok,Port} = inet:port(S),
+ ?DBG("dummy_manager_init -> Port: ~p",[Port]),
+ Parent ! {dummy_manager_started,self(),Port},
+ dummy_manager_loop(Parent,S,MA).
+
+dummy_manager_loop(P,S,MA) ->
+ ?LOG("dummy_manager_loop -> ready for receive",[]),
+ receive
+ {send_trap,Trap} ->
+ ?LOG("dummy_manager_loop -> received trap send request"
+ "~n Trap: ~p",[Trap]),
+ snmpa:send_trap(MA, Trap, "standard trap"),
+ dummy_manager_loop(P,S,MA);
+ {udp, _UdpId, Ip, UdpPort, Bytes} ->
+ ?LOG("dummy_manager_loop -> received upd message"
+ "~n from: ~p:~p"
+ "~n size: ~p",
+ [Ip, UdpPort, dummy_manager_message_sz(Bytes)]),
+ R = dummy_manager_handle_message(Bytes),
+ ?DBG("dummy_manager_loop -> R: ~p",[R]),
+ P ! R,
+ dummy_manager_loop(P,S,MA);
+ stop ->
+ ?DBG("dummy_manager_loop -> received stop request",[]),
+ P ! {dummy_manager_stopping, self()},
+ gen_udp:close(S),
+ exit(normal);
+ O ->
+ ?LOG("dummy_manager_loop -> received unknown message:"
+ "~n ~p",[O]),
+ dummy_manager_loop(P,S,MA)
+ end.
+
+dummy_manager_message_sz(B) when is_binary(B) ->
+ size(B);
+dummy_manager_message_sz(L) when is_list(L) ->
+ length(L);
+dummy_manager_message_sz(_) ->
+ undefined.
+
+dummy_manager_handle_message(Bytes) ->
+ case (catch snmp_pdus:dec_message(Bytes)) of
+ {'EXIT',Reason} ->
+ ?ERR("dummy_manager_handle_message -> "
+ "failed decoding message only:~n ~p",[Reason]),
+ {error,Reason};
+ M ->
+ ?DBG("dummy_manager_handle_message -> decoded message:"
+ "~n ~p",[M]),
+ {received_trap,M}
+ end.
+
+
+api(suite) -> [];
+api(Config) when is_list(Config) ->
+ ?P(api),
+ init_case(Config),
+
+ ?line load_master("OLD-SNMPEA-MIB"),
+ ?line init_old(),
+ try_test(api_test, [node()]),
+ ?line unload_master("OLD-SNMPEA-MIB").
+
+api_2(X) -> ?P(api_2), api(X).
+
+api_3(X) -> ?P(api_3), api(X).
+
+
+subagent(suite) -> [];
+subagent(Config) when is_list(Config) ->
+ ?P(subagent),
+ {SaNode, _MgrNode, MibDir} = init_case(Config),
+
+ ?line {ok, SA} = start_subagent(SaNode, ?klas1, "Klas1"),
+ try_test(load_test_sa),
+
+ ?P1("Testing unregister subagent..."),
+ MA = whereis(snmp_master_agent),
+ rpc:call(SaNode, snmp, unregister_subagent, [MA, SA]),
+ try_test(unreg_test),
+
+ ?P1("Loading previous subagent mib in master and testing..."),
+ ?line ok = snmpa:load_mibs(MA, [MibDir ++ "Klas1"]),
+ try_test(load_test),
+
+ ?P1("Unloading previous subagent mib in master and testing..."),
+ ?line ok = snmpa:unload_mibs(MA, [MibDir ++ "Klas1"]),
+ try_test(unreg_test),
+ ?P1("Testing register subagent..."),
+ rpc:call(SaNode, snmp, register_subagent,
+ [MA, ?klas1, SA]),
+ try_test(load_test_sa),
+
+ ?line stop_subagent(SA),
+ try_test(unreg_test).
+
+subagent_2(X) -> ?P(subagent_2), subagent(X).
+
+subagent_3(X) ->
+ %% <CONDITIONAL-SKIP>
+ Skippable = [{unix, [darwin]}],
+ Condition = fun() -> ?OS_BASED_SKIP(Skippable) end,
+ ?NON_PC_TC_MAYBE_SKIP(X, Condition),
+ %% </CONDITIONAL-SKIP>
+
+ ?P(subagent_3),
+ subagent(X).
+
+
+mnesia(suite) -> [];
+mnesia(Config) when is_list(Config) ->
+ ?P(mnesia),
+ {SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ ?P1("Starting subagent with mnesia impl..."),
+ {ok, SA} = start_subagent(SaNode, ?klas2, "Klas2"),
+ ?line load_master("OLD-SNMPEA-MIB"),
+ ?line init_old(),
+
+ try_test(big_test_2),
+
+ ?P1("Testing unregister subagent..."),
+ MA = whereis(snmp_master_agent),
+ rpc:call(SaNode, snmp, unregister_subagent, [MA, SA]),
+ try_test(unreg_test),
+ ?line unload_master("OLD-SNMPEA-MIB"),
+ ?line stop_subagent(SA).
+
+mnesia_2(X) -> ?P(mnesia_2), mnesia(X).
+
+mnesia_3(X) -> ?P(mnesia_3), mnesia(X).
+
+
+multiple_reqs(suite) ->
+ {req, [], {conf, init_mul, mul_cases(), finish_mul}}.
+
+mul_cases() ->
+ [mul_get, mul_get_err, mul_next, mul_next_err, mul_set_err].
+
+multiple_reqs_2(suite) ->
+ {req, [], {conf, init_mul, mul_cases_2(), finish_mul}}.
+
+multiple_reqs_3(_X) ->
+ {req, [], {conf, init_mul, mul_cases_3(), finish_mul}}.
+
+
+mul_cases_2() ->
+ [mul_get_2, mul_get_err_2, mul_next_2, mul_next_err_2, mul_set_err_2].
+
+
+mul_cases_3() ->
+ [mul_get_3, mul_get_err_3, mul_next_3, mul_next_err_3, mul_set_err_3].
+
+
+init_mul(Config) when is_list(Config) ->
+ {SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ ?line {ok, SA} = start_subagent(SaNode, ?klas1, "Klas1"),
+ ?line load_master("OLD-SNMPEA-MIB"),
+ ?line init_old(),
+ [{mul_sub, SA} | Config].
+
+finish_mul(Config) when is_list(Config) ->
+ init_case(Config),
+
+ SA = ?config(mul_sub, Config),
+
+ ?line unload_master("OLD-SNMPEA-MIB"),
+ ?line stop_subagent(SA),
+ lists:keydelete(mul_sub, 1, Config).
+
+mul_get(suite) -> [];
+mul_get(Config) when is_list(Config) ->
+ ?P(mul_get),
+ init_case(Config),
+
+ ?P1("Testing multiple get..."),
+ try_test(do_mul_get).
+
+mul_get_2(X) -> ?P(mul_get_2), mul_get(X).
+
+mul_get_3(X) -> ?P(mul_get_3), mul_get(X).
+
+
+mul_get_err(suite) -> [];
+mul_get_err(Config) when is_list(Config) ->
+ ?P(mul_get_err),
+ init_case(Config),
+
+ ?P1("Testing multiple get with error..."),
+ try_test(do_mul_get_err).
+
+mul_get_err_2(X) -> ?P(mul_get_err_2), mul_get_err(X).
+
+mul_get_err_3(X) -> ?P(mul_get_err_3), mul_get_err(X).
+
+
+mul_next(suite) -> [];
+mul_next(Config) when is_list(Config) ->
+ ?P(mul_next),
+ init_case(Config),
+
+ ?P1("Testing multiple next..."),
+ try_test(do_mul_next).
+
+mul_next_2(X) -> ?P(mul_next_2), mul_next(X).
+
+mul_next_3(X) -> ?P(mul_next_3), mul_next(X).
+
+
+mul_next_err(suite) -> [];
+mul_next_err(Config) when is_list(Config) ->
+ ?P(mul_next_err),
+ init_case(Config),
+
+ ?P1("Testing multiple next..."),
+ try_test(do_mul_next_err).
+
+mul_next_err_2(X) -> ?P(mul_next_err_2), mul_next_err(X).
+
+mul_next_err_3(X) -> ?P(mul_next_err_3), mul_next_err(X).
+
+
+mul_set(suite) -> [];
+mul_set(Config) when is_list(Config) ->
+ ?P(mul_set),
+ init_case(Config),
+
+ ?P1("Testing multiple set..."),
+ try_test(do_mul_set).
+
+mul_set_2(X) -> ?P(mul_set_2), mul_set(X).
+
+mul_set_3(X) -> ?P(mul_set_3), mul_set(X).
+
+
+mul_set_err(suite) -> [];
+mul_set_err(Config) when is_list(Config) ->
+ ?P(mul_set_err),
+ init_case(Config),
+
+ ?P1("Testing multiple set with error..."),
+ try_test(do_mul_set_err).
+
+mul_set_err_2(X) -> ?P(mul_set_err_2), mul_set_err(X).
+
+mul_set_err_3(X) -> ?P(mul_set_err_3), mul_set_err(X).
+
+
+sa_register(suite) -> [];
+sa_register(Config) when is_list(Config) ->
+ ?P(sa_register),
+ {SaNode, _MgrNode, MibDir} = init_case(Config),
+
+ ?DBG("sa_register -> start subagent", []),
+ ?P1("start subagent..."),
+ ?line {ok, SA} = start_subagent(SaNode, ?klas1, "Klas1"),
+
+ ?DBG("sa_register -> unregister subagent", []),
+ ?P1("Testing unregister subagent (2)..."),
+ MA = whereis(snmp_master_agent),
+ rpc:call(SaNode, snmp, unregister_subagent, [MA, ?klas1]),
+ try_test(unreg_test),
+
+ ?P1("Unloading Klas1..."),
+ ?DBG("sa_register -> unload mibs", []),
+ snmpa:unload_mibs(SA, [MibDir ++ "Klas1"]),
+
+ ?P1("Loading SA-MIB..."),
+ ?DBG("sa_register -> unload mibs", []),
+ snmpa:load_mibs(SA, [MibDir ++ "SA-MIB"]),
+
+ ?P1("register subagent..."),
+ ?DBG("sa_register -> register subagent", []),
+ rpc:call(SaNode, snmp, register_subagent, [MA, ?sa, SA]),
+
+ try_test(sa_mib),
+
+ ?P1("stop subagent..."),
+ ?DBG("sa_register -> stop subagent", []),
+ ?line stop_subagent(SA).
+
+sa_register_2(X) -> ?P(sa_register_2), sa_register(X).
+
+sa_register_3(X) -> ?P(sa_register_3), sa_register(X).
+
+
+v1_trap(suite) -> [];
+v1_trap(Config) when is_list(Config) ->
+ ?P(v1_trap),
+ trap1(Config).
+
+trap1(Config) ->
+ {SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ ?P1("start subagent..."),
+ ?line {ok, SA} = start_subagent(SaNode, ?sa, "SA-MIB"),
+
+ ?P1("Testing trap sending from master agent..."),
+ MA = whereis(snmp_master_agent),
+
+ ?P1("load TestTrap & TestTrapv2..."),
+ ?line load_master("TestTrap"),
+ ?line load_master("TestTrapv2"),
+
+ ?P1("Testing trap sending from master-agent..."),
+ try_test(ma_trap1, [MA]),
+ try_test(ma_trap2, [MA]),
+ try_test(ma_v2_2_v1_trap, [MA]),
+ try_test(ma_v2_2_v1_trap2, [MA]),
+
+ ?P1("Testing trap sending from subagent..."),
+ try_test(sa_trap1, [SA]),
+ try_test(sa_trap2, [SA]),
+ try_test(sa_trap3, [SA]),
+
+ ?P1("unload TestTrap & TestTrapv2..."),
+ ?line unload_master("TestTrap"),
+ ?line unload_master("TestTrapv2"),
+
+ ?P1("stop subagent..."),
+ ?line stop_subagent(SA).
+
+v2_trap(suite) -> [];
+v2_trap(Config) when is_list(Config) ->
+ ?P(v2_trap),
+ trap2(Config).
+
+trap2(Config) ->
+ {SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ ?P1("start subagent..."),
+ ?line {ok, SA} = start_subagent(SaNode, ?sa, "SA-MIB"),
+
+ ?P1("Testing trap sending from master agent..."),
+ MA = whereis(snmp_master_agent),
+
+ ?P1("load TestTrap & TestTrapv2..."),
+ ?line load_master("TestTrap"),
+ ?line load_master("TestTrapv2"),
+
+ ?P1("Testing trap sending from master-agent..."),
+ try_test(ma_v2_trap1, [MA]),
+ try_test(ma_v2_trap2, [MA]),
+ try_test(ma_v1_2_v2_trap, [MA]),
+ try_test(ma_v1_2_v2_trap2, [MA]),
+
+ try_test(sa_mib),
+
+ ?P1("Testing trap sending from subagent..."),
+ try_test(sa_v1_2_v2_trap1, [SA]),
+ try_test(sa_v1_2_v2_trap2, [SA]),
+ try_test(sa_v1_2_v2_trap3, [SA]),
+
+ ?P1("unload TestTrap & TestTrapv2..."),
+ ?line unload_master("TestTrap"),
+ ?line unload_master("TestTrapv2"),
+
+ ?P1("stop subagent..."),
+ ?line stop_subagent(SA).
+
+v3_trap(suite) -> [];
+v3_trap(Config) when is_list(Config) ->
+ %% <CONDITIONAL-SKIP>
+ Skippable = [{unix, [darwin]}],
+ Condition = fun() -> ?OS_BASED_SKIP(Skippable) end,
+ ?NON_PC_TC_MAYBE_SKIP(Config, Condition),
+ %% </CONDITIONAL-SKIP>
+
+ ?P(v3_trap),
+ trap2(Config).
+
+v2_inform(suite) ->
+ {req, [], {conf, init_v2_inform, [v2_inform_i], finish_v2_inform}}.
+
+v3_inform(_X) ->
+ %% v2_inform(X).
+ {req, [], {conf, init_v3_inform, [v3_inform_i], finish_v3_inform}}.
+
+init_v2_inform(Config) when is_list(Config) ->
+ _Dir = ?config(agent_dir, Config),
+ %% snmp_internal_mib:configure(Dir),
+ Config.
+
+init_v3_inform(X) ->
+ init_v2_inform(X).
+
+finish_v2_inform(Config) when is_list(Config) ->
+ _Dir = ?config(agent_dir, Config),
+ %% snmp_internal_mib:configure(Dir),
+ Config.
+
+finish_v3_inform(X) ->
+ finish_v2_inform(X).
+
+
+
+v2_inform_i(suite) -> [];
+v2_inform_i(Config) when is_list(Config) ->
+ ?P(v2_inform_i),
+ inform_i(Config).
+
+inform_i(Config) ->
+ init_case(Config),
+
+ MA = whereis(snmp_master_agent),
+
+ ?P1("load TestTrap & TestTrapv2..."),
+ ?line load_master("TestTrap"),
+ ?line load_master("TestTrapv2"),
+
+ ?P1("Testing inform sending from master agent... "
+ "~nNOTE! This test takes a few minutes (10) to complete."),
+
+ try_test(ma_v2_inform1, [MA]),
+ try_test(ma_v2_inform2, [MA]),
+ try_test(ma_v2_inform3, [MA]),
+
+ ?P1("unload TestTrap & TestTrapv2..."),
+ ?line unload_master("TestTrap"),
+ ?line unload_master("TestTrapv2").
+
+v3_inform_i(X) ->
+ %% <CONDITIONAL-SKIP>
+ Skippable = [{unix, [darwin]}],
+ Condition = fun() -> ?OS_BASED_SKIP(Skippable) end,
+ ?NON_PC_TC_MAYBE_SKIP(X, Condition),
+ %% </CONDITIONAL-SKIP>
+
+ ?P(v3_inform_i),
+ inform_i(X).
+
+
+sa_error(suite) -> [];
+sa_error(Config) when is_list(Config) ->
+ ?P(sa_error),
+ {SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ ?P1("load OLD-SNMPEA-MIB..."),
+ ?line load_master("OLD-SNMPEA-MIB"),
+ ?line init_old(),
+
+ ?P1("start subagent..."),
+ ?line {ok, SA} = start_subagent(SaNode, ?sa, "SA-MIB"),
+
+ ?P1("Testing sa bad value (is_set_ok)..."),
+ try_test(sa_errs_bad_value),
+
+ ?P1("Testing sa gen err (set)..."),
+ try_test(sa_errs_gen_err),
+
+ ?P1("Testing too big..."),
+ try_test(sa_too_big),
+
+ ?P1("unload OLD-SNMPEA-MIB..."),
+ ?line unload_master("OLD-SNMPEA-MIB"),
+
+ ?P1("stop subagent..."),
+ stop_subagent(SA).
+
+sa_error_2(X) ->
+ ?P(sa_error_2),
+ sa_error(X).
+
+sa_error_3(X) ->
+ %% <CONDITIONAL-SKIP>
+ Skippable = [{unix, [darwin]}],
+ Condition = fun() -> ?OS_BASED_SKIP(Skippable) end,
+ ?NON_PC_TC_MAYBE_SKIP(X, Condition),
+ %% </CONDITIONAL-SKIP>
+
+ ?P(sa_error_3),
+ sa_error(X).
+
+
+next_across_sa(suite) -> [];
+next_across_sa(Config) when is_list(Config) ->
+ ?P(next_across_sa),
+ {SaNode, _MgrNode, MibDir} = init_case(Config),
+ MA = whereis(snmp_master_agent),
+
+ ?P1("start subagent (1)..."),
+ ?line {ok, SA} = start_subagent(SaNode, ?sa, "SA-MIB"),
+
+ ?P1("Loading another subagent mib (Klas1)..."),
+ ?line ok = snmpa:load_mibs(SA, [MibDir ++ "Klas1"]),
+
+ ?P1("register subagent..."),
+ rpc:call(SaNode, snmp, register_subagent, [MA, ?klas1, SA]),
+
+ ?P1("Load test subagent..."),
+ try_test(load_test_sa),
+
+ ?P1("Testing next across subagent (endOfMibView from SA)..."),
+ try_test(next_across_sa),
+
+ ?P1("Unloading mib (Klas1)"),
+ snmpa:unload_mibs(SA, [MibDir ++ "Klas1"]),
+ rpc:call(SaNode, snmp, unregister_subagent, [MA, ?klas1]),
+ try_test(unreg_test),
+
+ ?P1("Starting another subagent (2) "),
+ ?line {ok, SA2} = start_subagent(SaNode, ?klas1, "Klas1"),
+ ?P1("Testing next across subagent (wrong prefix from SA)..."),
+ try_test(next_across_sa),
+
+ ?P1("stop subagent (1)..."),
+ stop_subagent(SA),
+
+ ?P1("stop subagent (2)..."),
+ stop_subagent(SA2).
+
+next_across_sa_2(X) ->
+ ?P(next_across_sa_2),
+ next_across_sa(X).
+
+next_across_sa_3(X) ->
+ %% <CONDITIONAL-SKIP>
+ Skippable = [{unix, [darwin]}],
+ Condition = fun() -> ?OS_BASED_SKIP(Skippable) end,
+ ?NON_PC_TC_MAYBE_SKIP(X, Condition),
+ %% </CONDITIONAL-SKIP>
+
+ ?P(next_across_sa_3),
+ next_across_sa(X).
+
+
+undo(suite) -> [];
+undo(Config) when is_list(Config) ->
+ ?P(undo),
+ {SaNode, _MgrNode, MibDir} = init_case(Config),
+
+ MA = whereis(snmp_master_agent),
+
+ ?P1("start subagent (1)..."),
+ ?line {ok, SA} = start_subagent(SaNode, ?sa, "SA-MIB"),
+
+ ?P1("Load Klas3 & Klas4..."),
+ ?line ok = snmpa:load_mibs(MA, [MibDir ++ "Klas3"]),
+ ?line ok = snmpa:load_mibs(MA, [MibDir ++ "Klas4"]),
+
+ ?P1("Testing undo phase at master agent..."),
+ try_test(undo_test),
+ try_test(api_test2),
+
+ ?P1("Unload Klas3..."),
+ ?line ok = snmpa:unload_mibs(MA, [MibDir ++ "Klas3"]),
+
+ ?P1("Testing bad return values from instrum. funcs..."),
+ try_test(bad_return),
+
+ ?P1("Unload Klas4..."),
+ ?line ok = snmpa:unload_mibs(MA, [MibDir ++ "Klas4"]),
+
+ ?P1("Testing undo phase at subagent..."),
+ ?line ok = snmpa:load_mibs(SA, [MibDir ++ "Klas3"]),
+ ?line ok = snmpa:load_mibs(SA, [MibDir ++ "Klas4"]),
+ ?line ok = snmpa:register_subagent(MA, ?klas3, SA),
+ ?line ok = snmpa:register_subagent(MA, ?klas4, SA),
+ try_test(undo_test),
+ try_test(api_test3),
+
+ ?P1("Testing undo phase across master/subagents..."),
+ try_test(undo_test),
+ try_test(api_test3),
+
+ ?P1("stop subagent..."),
+ stop_subagent(SA).
+
+undo_2(X) ->
+ ?P(undo_2),
+ undo(X).
+
+undo_3(X) ->
+ %% <CONDITIONAL-SKIP>
+ Skippable = [{unix, [darwin]}],
+ Condition = fun() -> ?OS_BASED_SKIP(Skippable) end,
+ ?NON_PC_TC_MAYBE_SKIP(X, Condition),
+ %% </CONDITIONAL-SKIP>
+
+ ?P(undo_3),
+ undo(X).
+
+%% Req. Test2
+v1_processing(suite) -> [];
+v1_processing(Config) when is_list(Config) ->
+ ?P(v1_processing),
+ ?DBG("v1_processing -> entry", []),
+ init_case(Config),
+
+ ?P1("Load Test2..."),
+ ?line load_master("Test2"),
+
+ try_test(v1_proc),
+
+ ?P1("Unload Test2..."),
+ ?line unload_master("Test2").
+
+%% Req. Test2
+v2_processing(suite) -> [];
+v2_processing(Config) when is_list(Config) ->
+ ?P(v2_processing),
+ init_case(Config),
+
+ ?P1("Load Test2..."),
+ ?line load_master("Test2"),
+
+ try_test(v2_proc),
+
+ ?P1("Unload Test2..."),
+ ?line unload_master("Test2").
+
+%% Req. Test2
+v3_processing(suite) -> [];
+v3_processing(Config) when is_list(Config) ->
+ ?P(v3_processing),
+ init_case(Config),
+
+ ?P1("Load Test2..."),
+ ?line load_master("Test2"),
+
+ try_test(v2_proc), % same as v2!
+
+ ?P1("Unload Test2..."),
+ ?line unload_master("Test2").
+
+
+%% We'll try get/set/trap and inform for all the auth & priv protocols.
+%% For informs, the mgr is auth-engine. The agent has to sync. This is
+%% accomplished by the first inform sent. That one will generate a
+%% report, which makes it in sync. The notification-generating
+%% application times out, and send again. This time it'll work.
+v3_security(suite) ->
+ [
+ v3_crypto_basic,
+ v3_md5_auth,
+ v3_sha_auth,
+ v3_des_priv
+ ].
+
+v3_crypto_basic(suite) -> [];
+v3_crypto_basic(_Config) ->
+ ?P(v3_crypto_basic),
+ EID = [0,0,0,0,0,0,0,0,0,0,0,2],
+ %% From rfc2274 appendix A.3.1
+ ?line KMd5_1 = snmp:passwd2localized_key(md5, "maplesyrup", EID),
+ ?line [16#52,16#6f,16#5e,16#ed,16#9f,16#cc,16#e2,16#6f,
+ 16#89,16#64,16#c2,16#93,16#07,16#87,16#d8,16#2b] =
+ KMd5_1,
+ %% From rfc2274 appendix A.3.2
+ ?line KSHA_1 = snmp:passwd2localized_key(sha, "maplesyrup", EID),
+ ?line [16#66,16#95,16#fe,16#bc,16#92,16#88,16#e3,16#62,16#82,16#23,
+ 16#5f,16#c7,16#15,16#1f,16#12,16#84,16#97,16#b3,16#8f,16#3f] =
+ KSHA_1,
+ %% From rfc2274, appendix A.5.1
+ ?line KMd5_2 = snmp:passwd2localized_key(md5, "newsyrup", EID),
+ ?line [16#00,16#00,16#00,16#00,16#00,16#00,16#00,16#00,
+ 16#00,16#00,16#00,16#00,16#00,16#00,16#00,16#00,
+ 16#88,16#05,16#61,16#51,16#41,16#67,16#6c,16#c9,
+ 16#19,16#61,16#74,16#e7,16#42,16#a3,16#25,16#51] =
+ snmp_user_based_sm_mib:mk_key_change(md5, KMd5_1, KMd5_2, 16,
+ [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]),
+ %% From rfc2274, appendix A.5.2
+ ?line KSHA_2 = snmp:passwd2localized_key(sha, "newsyrup", EID),
+ ?line [16#00,16#00,16#00,16#00,16#00,16#00,16#00,16#00,
+ 16#00,16#00,16#00,16#00,16#00,16#00,16#00,16#00,
+ 16#00,16#00,16#00,16#00,16#9c,16#10,16#17,16#f4,
+ 16#fd,16#48,16#3d,16#2d,16#e8,16#d5,16#fa,16#db,
+ 16#f8,16#43,16#92,16#cb,16#06,16#45,16#70,16#51] =
+ snmp_user_based_sm_mib:mk_key_change(sha, KSHA_1, KSHA_2, 20,
+ [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]),
+ KSHA_1t = lists:sublist(KSHA_1, 16),
+ KSHA_2t = lists:sublist(KSHA_2, 16),
+ ?line [16#00,16#00,16#00,16#00,16#00,16#00,16#00,16#00,
+ 16#00,16#00,16#00,16#00,16#00,16#00,16#00,16#00,
+ 16#7e,16#f8,16#d8,16#a4,16#c9,16#cd,16#b2,16#6b,
+ 16#47,16#59,16#1c,16#d8,16#52,16#ff,16#88,16#b5] =
+ snmp_user_based_sm_mib:mk_key_change(sha, KSHA_1t, KSHA_2t, 16,
+ [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]),
+
+ %% Try with correct random
+ ?line Kc1 = snmp_user_based_sm_mib:mk_key_change(md5, KMd5_1, KMd5_2),
+ ?line KMd5_2 = snmp_user_based_sm_mib:extract_new_key(md5, KMd5_1, Kc1),
+ ?line Kc2 = snmp_user_based_sm_mib:mk_key_change(sha, KSHA_1, KSHA_2),
+ ?line KSHA_2 = snmp_user_based_sm_mib:extract_new_key(sha, KSHA_1, Kc2),
+ ok.
+
+
+
+v3_md5_auth(suite) -> [];
+v3_md5_auth(Config) when is_list(Config) ->
+ ?P(v3_md5_auth),
+ init_case(Config),
+
+ ?P1("Testing MD5 authentication...takes a few seconds..."),
+
+ AgentDir = ?config(agent_dir, Config),
+ ?line rewrite_target_params_conf(AgentDir, "authMD5", authNoPriv),
+ ?line snmp_target_mib:reconfigure(AgentDir),
+
+ MA = whereis(snmp_master_agent),
+
+ ?line load_master("Test2"),
+ ?line load_master("TestTrap"),
+ ?line load_master("TestTrapv2"),
+
+ try_test(v3_sync, [[{v2_proc, []},
+ {ma_v2_trap1, [MA]},
+ {v3_inform_sync, [MA]}]],
+ [{sec_level, authNoPriv}, {user, "authMD5"}]),
+
+ ?line unload_master("TestTrapv2"),
+ ?line unload_master("TestTrap"),
+ ?line unload_master("Test2"),
+ ?line reset_target_params_conf(AgentDir).
+
+v3_sha_auth(suite) -> [];
+v3_sha_auth(Config) when is_list(Config) ->
+ ?P(v3_sha_auth),
+ init_case(Config),
+
+ ?P1("Testing SHA authentication...takes a few seconds..."),
+
+ AgentDir = ?config(agent_dir, Config),
+ ?line rewrite_target_params_conf(AgentDir, "authSHA", authNoPriv),
+ ?line snmp_target_mib:reconfigure(AgentDir),
+
+ MA = whereis(snmp_master_agent),
+
+ ?line load_master("Test2"),
+ ?line load_master("TestTrap"),
+ ?line load_master("TestTrapv2"),
+
+ try_test(v3_sync, [[{v2_proc, []},
+ {ma_v2_trap1, [MA]},
+ {v3_inform_sync, [MA]}]],
+ [{sec_level, authNoPriv}, {user, "authSHA"}]),
+
+ ?line unload_master("TestTrapv2"),
+ ?line unload_master("TestTrap"),
+ ?line unload_master("Test2"),
+ ?line reset_target_params_conf(AgentDir).
+
+v3_des_priv(suite) -> [];
+v3_des_priv(Config) when is_list(Config) ->
+ ?P(v3_des_priv),
+ init_case(Config),
+
+ ?P1("Testing DES encryption...takes a few seconds..."),
+
+ AgentDir = ?config(agent_dir, Config),
+ ?line rewrite_target_params_conf(AgentDir, "privDES", authPriv),
+ ?line snmp_target_mib:reconfigure(AgentDir),
+
+ MA = whereis(snmp_master_agent),
+
+ snmp_user_based_sm_mib:usmUserTable(print),
+
+ ?line load_master("Test2"),
+ ?line load_master("TestTrap"),
+ ?line load_master("TestTrapv2"),
+
+ try_test(v3_sync, [[{v2_proc, []},
+ {ma_v2_trap1, [MA]},
+ {v3_inform_sync, [MA]}]],
+ [{sec_level, authPriv}, {user, "privDES"}]),
+
+ ?line unload_master("TestTrapv2"),
+ ?line unload_master("TestTrap"),
+ ?line unload_master("Test2"),
+ ?line reset_target_params_conf(AgentDir).
+
+%% -define(usmStatsNotInTimeWindows_instance, [1,3,6,1,6,3,15,1,1,2,0]).
+
+%% Make sure mgr is in sync with agent
+v3_sync(Funcs) ->
+ ?DBG("v3_sync -> entry with Funcs: ~p",[Funcs]),
+ g([[sysDescr, 0]]),
+ expect(432, report, [{?usmStatsNotInTimeWindows_instance, any}]),
+ g([[sysDescr, 0]]),
+ expect(433, [{[sysDescr,0], any}]),
+ lists:foreach(fun({Func, Args}) -> apply(?MODULE, Func, Args) end, Funcs).
+
+v3_inform_sync(MA) ->
+ ?DBG("v3_sync -> entry with MA: ~p => Send notification",[MA]),
+ ?line snmpa:send_notification(MA, testTrapv22, no_receiver,
+ "standard inform", []),
+ %% Make sure agent is in sync with mgr...
+ ?DBG("v3_sync -> wait some time: ",[]),
+ ?SLEEP(20000), % more than 1500*10 in target_addr.conf
+ ?DBG("v3_sync -> await response",[]),
+ ?line expect(1, {inform, true},
+ [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?system ++ [0,1]}]).
+
+
+v2_caps(suite) -> [];
+v2_caps(Config) when is_list(Config) ->
+ ?P(v2_caps),
+ init_case(Config),
+
+ try_test(v2_caps_i, [node()]).
+
+v2_caps_3(X) -> ?P(v2_caps_3), v2_caps(X).
+
+
+v2_caps_i(Node) ->
+ ?line Idx = rpc:call(Node, snmp, add_agent_caps, [[1,2,3,4,5], "test cap"]),
+ g([[sysORID, Idx], [sysORDescr, Idx]]),
+ ?line expect(1, [{[sysORID, Idx], [1,2,3,4,5]},
+ {[sysORDescr, Idx], "test cap"}]),
+ ?line rpc:call(Node, snmp, del_agent_caps, [Idx]),
+ g([[sysORID, Idx]]),
+ ?line expect(2, [{[sysORID, Idx], noSuchInstance}]).
+
+
+%% Req. Test2
+v1_proc() ->
+ ?DBG("v1_proc -> entry", []),
+ %% According to RFC1157.
+ %% Template: <Section>:<list no>
+ v1_get_p(),
+ v1_get_next_p(),
+ v1_set_p().
+
+
+v1_get_p() ->
+ %% 4.1.2:1
+ g([[test2]]),
+ ?line expect(10, noSuchName, 1, [{[test2], 'NULL'}]),
+ g([[tDescr]]),
+ ?line expect(11, noSuchName, 1, [{[tDescr], 'NULL'}]),
+ g([[tDescr2,0]]),
+ ?line expect(12, noSuchName, 1, [{[tDescr2,0], 'NULL'}]),
+ g([[tDescr3,0]]),
+ ?line expect(131, noSuchName, 1, [{[tDescr3,0], 'NULL'}]),
+ g([[tDescr4,0]]),
+ ?line expect(132, noSuchName, 1, [{[tDescr4,0], 'NULL'}]),
+ g([[sysDescr, 0], [tDescr,0]]), % Outside mibview
+ ?line expect(14, noSuchName, 2, [{[sysDescr, 0], 'NULL'},
+ {[tDescr,0], 'NULL'}]),
+ g([[sysDescr,3]]),
+ ?line expect(15, noSuchName, 1, [{[sysDescr, 3], 'NULL'}]),
+
+ %% 4.1.2:2
+ g([[tTable]]),
+ ?line expect(20, noSuchName, 1, [{[tTable], 'NULL'}]),
+ g([[tEntry]]),
+ ?line expect(21, noSuchName, 1, [{[tEntry], 'NULL'}]),
+
+ %% 4.1.2:3
+ g([[tTooBig, 0]]),
+ ?line expect(30, tooBig, 0, [{[tTooBig, 0], 'NULL'}]),
+
+ %% 4.1.2:4
+ g([[tGenErr1, 0]]),
+ ?line expect(40, genErr, 1, [{[tGenErr1, 0], 'NULL'}]),
+ g([[tGenErr2, 0]]),
+ ?line expect(41, genErr, 1, [{[tGenErr2, 0], 'NULL'}]),
+ g([[sysDescr, 0], [tGenErr3, 0]]),
+ ?line expect(42, genErr, 2, [{[sysDescr, 0], 'NULL'},
+ {[tGenErr3, 0], 'NULL'}]).
+
+
+v1_get_next_p() ->
+ %% 4.1.3:1
+ gn([[1,3,7,1]]),
+ ?line expect(10, noSuchName, 1, [{[1,3,7,1], 'NULL'}]),
+ gn([[tDescr2]]),
+ ?line expect(11, tooBig, 0, any),
+
+ %% 4.1.3:2
+ gn([[tTooBig]]),
+ io:format("We currently don't handle tooBig correct!!!\n"),
+% ?line expect(20, tooBig, 0, [{[tTooBig], 'NULL'}]),
+ ?line expect(20, tooBig, 0, any),
+
+ %% 4.1.3:3
+ gn([[tGenErr1]]),
+% ?line expect(40, genErr, 1, [{[tGenErr1], 'NULL'}]),
+ ?line expect(40, genErr, 1, any),
+ gn([[tGenErr2]]),
+% ?line expect(41, genErr, 1, [{[tGenErr2], 'NULL'}]),
+ ?line expect(41, genErr, 1, any),
+ gn([[sysDescr], [tGenErr3]]),
+% ?line expect(42, genErr, 2, [{[sysDescr], 'NULL'},
+% {[tGenErr3], 'NULL'}]).
+ ?line expect(42, genErr, 2, any).
+
+v1_set_p() ->
+ %% 4.1.5:1
+ s([{[1,3,7,0], i, 4}]),
+ ?line expect(10, noSuchName, 1, [{[1,3,7,0], 4}]),
+ s([{[tDescr,0], s, "outside mibview"}]),
+ ?line expect(11, noSuchName, 1, [{[tDescr,0], "outside mibview"}]),
+ s([{[tDescr3,0], s, "read-only"}]),
+ ?line expect(12, noSuchName, 1, [{[tDescr3,0], "read-only"}]),
+ s([{[tDescr3], s, "noSuchObject"}]),
+ ?line expect(13, noSuchName, 1, [{[tDescr3], "noSuchObject"}]),
+ s([{[tDescr3,1], s, "noSuchInstance"}]),
+ ?line expect(14, noSuchName, 1, [{[tDescr3,1], "noSuchInstance"}]),
+ s([{[tDescr2,0], s, "inconsistentName"}]),
+ ?line expect(15, noSuchName, 1, [{[tDescr2,0], "inconsistentName"}]),
+
+ %% 4.1.5:2
+ s([{[tDescr2, 0], i, 4}]),
+ ?line expect(20, badValue, 1, [{[tDescr2, 0], 4}]),
+ s([{[tDescr2, 0], s, "badValue"}]),
+ ?line expect(21, badValue, 1, [{[tDescr2, 0], "badValue"}]),
+
+ %% 4.1.5:3
+ %% The standard is quite incorrect here. The resp pdu was too big. In
+ %% the resp pdu, we have the original vbs. In the tooBig pdu we still
+ %% have to original vbs => the tooBig pdu is too big as well!!! It
+ %% may not get it to the manager, unless the agent uses 'NULL' instead
+ %% of the std-like original value.
+ s([{[tTooBig, 0], s, ?tooBigStr}]),
+ %% according to std:
+% ?line expect(30, tooBig, 0, [{[tTooBig, 0], ?tooBigStr}]),
+ ?line expect(30, tooBig, 0, [{[tTooBig, 0], 'NULL'}]),
+
+ %% 4.1.5:4
+ s([{[tDescr2, 0], s, "is_set_ok_fail"}]),
+ ?line expect(40, genErr, 1, [{[tDescr2, 0], "is_set_ok_fail"}]),
+ s([{[tDescr2, 0], s, "commit_fail"}]),
+ ?line expect(41, genErr, 1, [{[tDescr2, 0], "commit_fail"}]).
+
+%% Req. Test2
+v2_proc() ->
+ %% According to RFC1905.
+ %% Template: <Section>:<list no>
+ ?DBG("v2_proc -> entry",[]),
+ v2_get_p(),
+ v2_get_next_p(),
+ v2_get_bulk_p(),
+ v2_set_p().
+
+v2_get_p() ->
+ %% 4.2.1:2
+ ?DBG("v2_get_p -> entry",[]),
+ g([[test2]]),
+ ?line expect(10, [{[test2], noSuchObject}]),
+ g([[tDescr]]),
+ ?line expect(11, [{[tDescr], noSuchObject}]),
+ g([[tDescr4,0]]),
+ ?line expect(12, [{[tDescr4,0], noSuchObject}]),
+ g([[sysDescr, 0], [tDescr,0]]), % Outside mibview
+ ?line expect(13, [{[sysDescr,0], "Erlang SNMP agent"},
+ {[tDescr,0], noSuchObject}]),
+ g([[tTable]]),
+ ?line expect(14, [{[tTable], noSuchObject}]),
+ g([[tEntry]]),
+ ?line expect(15, [{[tEntry], noSuchObject}]),
+
+ %% 4.2.1:3
+ g([[tDescr2,0]]), %% instrum ret noSuchName!!!
+ ?line expect(20, [{[tDescr2,0], noSuchInstance}]),
+ g([[tDescr3,0]]),
+ ?line expect(21, [{[tDescr3,0], noSuchInstance}]),
+ g([[sysDescr,3]]),
+ ?line expect(22, [{[sysDescr, 3], noSuchInstance}]),
+ g([[tIndex,1]]),
+ ?line expect(23, [{[tIndex, 1], noSuchInstance}]),
+
+ %% 4.2.1 - any other error: genErr
+ g([[tGenErr1, 0]]),
+ ?line expect(30, genErr, 1, [{[tGenErr1, 0], 'NULL'}]),
+ g([[tGenErr2, 0]]),
+ ?line expect(31, genErr, 1, [{[tGenErr2, 0], 'NULL'}]),
+ g([[sysDescr, 0], [tGenErr3, 0]]),
+ ?line expect(32, genErr, 2, [{[sysDescr, 0], 'NULL'},
+ {[tGenErr3, 0], 'NULL'}]),
+
+ %% 4.2.1 - tooBig
+ g([[tTooBig, 0]]),
+ ?line expect(40, tooBig, 0, []).
+
+
+v2_get_next_p() ->
+ %% 4.2.2:2
+ ?DBG("v2_get_next_p -> entry",[]),
+ gn([[1,3,7,1]]),
+ ?line expect(10, [{[1,3,7,1], endOfMibView}]),
+ gn([[sysDescr], [1,3,7,1]]),
+ ?line expect(11, [{[sysDescr, 0], "Erlang SNMP agent"},
+ {[1,3,7,1], endOfMibView}]),
+ gn([[tCnt2, 1]]),
+ ?line expect(12, [{[tCnt2,2], 100}]),
+ gn([[tCnt2, 2]]),
+ ?line expect(12, [{[tCnt2,2], endOfMibView}]),
+
+ %% 4.2.2 - any other error: genErr
+ gn([[tGenErr1]]),
+ ?line expect(20, genErr, 1, [{[tGenErr1], 'NULL'}]),
+ gn([[tGenErr2]]),
+ ?line expect(21, genErr, 1, [{[tGenErr2], 'NULL'}]),
+ gn([[sysDescr], [tGenErr3]]),
+ ?line expect(22, genErr, 2, [{[sysDescr], 'NULL'},
+ {[tGenErr3], 'NULL'}]),
+
+ %% 4.2.2 - tooBig
+ gn([[tTooBig]]),
+ ?line expect(20, tooBig, 0, []).
+
+v2_get_bulk_p() ->
+ %% 4.2.3
+ ?DBG("v2_get_bulk_p -> entry",[]),
+ gb(1, 1, []),
+ ?line expect(10, []),
+ gb(-1, 1, []),
+ ?line expect(11, []),
+ gb(-1, -1, []),
+ ?line expect(12, []),
+ gb(-1, -1, []),
+ ?line expect(13, []),
+ gb(2, 0, [[sysDescr], [1,3,7,1]]),
+ ?line expect(14, [{[sysDescr, 0], "Erlang SNMP agent"},
+ {[1,3,7,1], endOfMibView}]),
+ gb(1, 2, [[sysDescr], [1,3,7,1]]),
+ ?line expect(15, [{[sysDescr, 0], "Erlang SNMP agent"},
+ {[1,3,7,1], endOfMibView}]),
+ gb(0, 2, [[sysDescr], [1,3,7,1]]),
+ ?line expect(16, [{[sysDescr, 0], "Erlang SNMP agent"},
+ {[1,3,7,1], endOfMibView},
+ {[sysObjectID, 0], [1,2,3]},
+ {[1,3,7,1], endOfMibView}]),
+
+ gb(2, 2, [[sysDescr], [1,3,7,1], [sysDescr], [1,3,7,1]]),
+ ?line expect(17, [{[sysDescr, 0], "Erlang SNMP agent"},
+ {[1,3,7,1], endOfMibView},
+ {[sysDescr, 0], "Erlang SNMP agent"},
+ {[1,3,7,1], endOfMibView},
+ {[sysObjectID, 0], [1,2,3]},
+ {[1,3,7,1], endOfMibView}]),
+
+ gb(1, 2, [[sysDescr], [sysDescr], [tTooBig]]),
+ ?line expect(18, [{[sysDescr, 0], "Erlang SNMP agent"},
+ {[sysDescr, 0], "Erlang SNMP agent"}]),
+
+ gb(1,12, [[tDescr2], [sysDescr]]), % next one after tDescr2 is tTooBig.
+ ?line expect(19, []),
+
+ gb(2,2, [[sysDescr], [sysObjectID], [tGenErr1], [sysDescr]]),
+ ?line expect(20, genErr, 3, [{[sysDescr], 'NULL'},
+ {[sysObjectID], 'NULL'},
+ {[tGenErr1], 'NULL'},
+ {[sysDescr], 'NULL'}]),
+ gb(0, 2, [[tCnt2, 1]]),
+ ?line expect(21, [{[tCnt2,2], 100},
+ {[tCnt2,2], endOfMibView}]).
+
+
+v2_set_p() ->
+ %% 4.2.5:1
+ ?DBG("v2_set_p -> entry",[]),
+ s([{[1,3,7,0], i, 4}]),
+ ?line expect(10, noAccess, 1, [{[1,3,7,0], 4}]),
+ s([{[tDescr,0], s, "outside mibview"}]),
+ ?line expect(11, noAccess, 1, [{[tDescr,0], "outside mibview"}]),
+
+ %% 4.2.5:2
+ s([{[1,3,6,1,0], s, "noSuchObject"}]),
+ ?line expect(20, notWritable, 1, [{[1,3,6,1,0], "noSuchObject"}]),
+
+ %% 4.2.5:3
+ s([{[tDescr2, 0], i, 4}]),
+ ?line expect(30, wrongType, 1, [{[tDescr2, 0], 4}]),
+ s([{[tDescr2, 0], s, "badValue"}]),
+ ?line expect(31, badValue, 1, [{[tDescr2, 0], "badValue"}]),
+
+ %% 4.2.5:4
+ s([{[tStr, 0], s, ""}]),
+ ?line expect(40, wrongLength, 1, [{[tStr, 0], ""}]),
+ s([{[tStr, 0], s, "12345"}]),
+ ?line expect(40, wrongLength, 1, [{[tStr, 0], "12345"}]),
+
+ %% 4.2.5:5 - N/A
+
+ %% 4.2.5:6
+ s([{[tInt1, 0], i, 0}]),
+ ?line expect(60, wrongValue, 1, [{[tInt1, 0], 0}]),
+ s([{[tInt1, 0], i, 5}]),
+ ?line expect(61, wrongValue, 1, [{[tInt1, 0], 5}]),
+ s([{[tInt2, 0], i, 0}]),
+ ?line expect(62, wrongValue, 1, [{[tInt2, 0], 0}]),
+ s([{[tInt2, 0], i, 5}]),
+ ?line expect(63, wrongValue, 1, [{[tInt2, 0], 5}]),
+ s([{[tInt3, 0], i, 5}]),
+ ?line expect(64, wrongValue, 1, [{[tInt3, 0], 5}]),
+
+ %% 4.2.5:7
+ s([{[tDescrX, 1, 1], s, "noCreation"}]),
+ ?line expect(70, noCreation, 1, [{[tDescrX, 1, 1], "noCreation"}]),
+
+ %% 4.2.5:8
+ s([{[tDescrX, 1, 2], s, "inconsistentName"}]),
+ ?line expect(80, inconsistentName, 1,
+ [{[tDescrX, 1, 2], "inconsistentName"}]),
+
+ %% 4.2.5:9
+ s([{[tCnt, 1, 2], i, 5}]),
+ ?line expect(90, notWritable, 1, [{[tCnt, 1, 2], 5}]),
+ s([{[tDescr3,0], s, "read-only"}]),
+ ?line expect(90, notWritable, 1, [{[tDescr3,0], "read-only"}]),
+
+ %% 4.2.5:10
+ s([{[tDescr2,0], s, "inconsistentValue"}]),
+ ?line expect(100, inconsistentValue, 1,
+ [{[tDescr2,0], "inconsistentValue"}]),
+
+ %% 4.2.5:11
+ s([{[tDescr2,0], s, "resourceUnavailable"}]),
+ ?line expect(110, resourceUnavailable, 1,
+ [{[tDescr2,0],"resourceUnavailable"}]),
+
+ %% 4.2.5:12
+ s([{[tDescr2, 0], s, "is_set_ok_fail"}]),
+ ?line expect(120, genErr, 1, [{[tDescr2, 0], "is_set_ok_fail"}]).
+
+ %% commitFailed and undoFailed is tested by the 'undo' case.
+
+
+%% Req. OLD-SNMPEA-MIB
+table_test() ->
+ io:format("Testing simple get, next and set on communityTable...~n"),
+%% {[147,214,36,45], "public", 2, readWrite}.
+%% {[147,214,36,45], "standard trap", 2, read}.
+ Key1c3 = [intCommunityViewIndex,get(mip),is("public")],
+ Key2c3 = [intCommunityViewIndex,get(mip),is("standard trap")],
+ Key1c4 = [intCommunityAccess,get(mip),is("public")],
+ EndKey = [intCommunityEntry,[9],get(mip),is("public")],
+ gn([[intCommunityEntry]]),
+ ?line expect(7, [{Key1c3, 2}]),
+ gn([[intCommunityTable]]),
+ ?line expect(71, [{Key1c3, 2}]),
+ gn([[community]]),
+ ?line expect(72, [{Key1c3, 2}]),
+ gn([[otpSnmpeaMIB]]),
+ ?line expect(73, [{Key1c3, 2}]),
+ gn([[ericsson]]),
+ ?line expect(74, [{Key1c3, 2}]),
+ gn([Key1c3]),
+ ?line expect(8, [{Key2c3, 2}]),
+ gn([Key2c3]),
+ ?line expect(9, [{Key1c4, 2}]),
+ gn([EndKey]),
+ AgentIp = [intAgentIpAddress,0],
+ ?line expect(10, [{AgentIp, any}]),
+ g([Key1c3]),
+ ?line expect(11, [{Key1c3, 2}]),
+ g([EndKey]),
+ ?line ?v1_2(expect(12, noSuchName, 1, any),
+ expect(12, [{EndKey, noSuchObject}])),
+
+ io:format("Testing row creation/deletion on communityTable...~n"),
+ NewKeyc3 = [intCommunityViewIndex,get(mip),is("test")],
+ NewKeyc4 = [intCommunityAccess,get(mip),is("test")],
+ NewKeyc5 = [intCommunityStatus,get(mip),is("test")],
+ s([{NewKeyc5, ?createAndGo}]),
+ ?line expect(14, ?v1_2(badValue, inconsistentValue), 1,any),
+ s([{NewKeyc5, ?createAndGo}, {NewKeyc3, 2}, {NewKeyc4, 2}]),
+ ?line expect(15, [{NewKeyc5, ?createAndGo},{NewKeyc3, 2}, {NewKeyc4, 2}]),
+ g([NewKeyc4]),
+ ?line expect(16, [{NewKeyc4, 2}]),
+ s([{NewKeyc5, ?destroy}]),
+ ?line expect(17, [{NewKeyc5, ?destroy}]),
+ s([{NewKeyc4, 2}]),
+ ?line expect(18, ?v1_2(noSuchName, inconsistentName), 1,[{NewKeyc4, 2}]),
+ s([{NewKeyc5, ?createAndWait}]),
+ ?line expect(19, [{NewKeyc5, ?createAndWait}]),
+ g([NewKeyc5]),
+ ?line expect(20, [{NewKeyc5, ?notReady}]),
+ s([{NewKeyc4, 2}]),
+ ?line expect(21, [{NewKeyc4, 2}]),
+ g([NewKeyc5]),
+ ?line expect(22, [{NewKeyc5, ?notReady}]),
+ s([{NewKeyc3, 2}]),
+ ?line expect(23, [{NewKeyc3, 2}]),
+ g([NewKeyc5]),
+ ?line expect(24, [{NewKeyc5, ?notInService}]),
+ s([{NewKeyc5, ?active}]),
+ ?line expect(25, [{NewKeyc5, ?active}]),
+ s([{NewKeyc5, ?destroy}]),
+ ?line expect(26, [{NewKeyc5, ?destroy}]),
+ s([{NewKeyc3, 3}]),
+ ?line expect(27, ?v1_2(noSuchName, inconsistentName), 1,[{NewKeyc3, 3}]),
+ otp_1128().
+
+%% Req. system group
+simple_standard_test() ->
+ ?DBG("simple_standard_test -> entry",[]),
+ gn([[1,1]]),
+ ?line expect(1, [{[sysDescr,0], "Erlang SNMP agent"}]),
+ gn([[1,3]]),
+ ?line expect(11, [{[sysDescr,0], "Erlang SNMP agent"}]),
+ gn([[1,3,6]]),
+ ?line expect(12, [{[sysDescr,0], "Erlang SNMP agent"}]),
+ gn([[1,3,6,1]]),
+ ?line expect(13, [{[sysDescr,0], "Erlang SNMP agent"}]),
+ gn([[1,3,6,1,2]]),
+ ?line expect(14, [{[sysDescr,0], "Erlang SNMP agent"}]),
+ gn([[1,3,6,1,2,1]]),
+ ?line expect(15, [{[sysDescr,0], "Erlang SNMP agent"}]),
+ gn([[1,3,6,1,2,1,1]]),
+ ?line expect(16, [{[sysDescr,0], "Erlang SNMP agent"}]),
+ gn([[sysDescr]]),
+ ?line expect(17, [{[sysDescr,0], "Erlang SNMP agent"}]),
+ g([[sysDescr,0]]),
+ ?line expect(2, [{[sysDescr,0], "Erlang SNMP agent"}]),
+ g([[sysDescr]]),
+ ?line ?v1_2(expect(3, noSuchName, 1, any),
+ expect(3, [{[sysDescr], noSuchObject}])),
+ g([[1,6,7,0]]),
+ ?line ?v1_2(expect(41, noSuchName, 1, any),
+ expect(3, [{[1,6,7,0], noSuchObject}])),
+ gn([[1,13]]),
+ ?line ?v1_2(expect(4, noSuchName,1, any),
+ expect(4, [{[1,13], endOfMibView}])),
+ s([{[sysLocation, 0], "new_value"}]),
+ ?line expect(5, [{[sysLocation, 0], "new_value"}]),
+ g([[sysLocation, 0]]),
+ ?line expect(6, [{[sysLocation, 0], "new_value"}]),
+ io:format("Testing noSuchName and badValue...~n"),
+ s([{[sysServices,0], 3}]),
+ ?line expect(61, ?v1_2(noSuchName, notWritable), 1, any),
+ s([{[sysLocation, 0], i, 3}]),
+ ?line expect(62, ?v1_2(badValue, wrongType), 1, any),
+ ?DBG("simple_standard_test -> done",[]),
+ ok.
+
+%% This is run in the agent node
+db_notify_client(suite) -> [];
+db_notify_client(Config) when is_list(Config) ->
+ ?P(db_notify_client),
+ {SaNode, MgrNode, MibDir} = init_case(Config),
+ ?DBG("db_notify_client -> case initiated: "
+ "~n SaNode: ~p"
+ "~n MgrNode: ~p"
+ "~n MibDir: ~p", [SaNode, MgrNode, MibDir]),
+ ?DBG("db_notify_client -> maximize verbosity", []),
+ snmpa_local_db:verbosity(trace),
+ Self = self(),
+ ?DBG("db_notify_client -> register self (~p) notify client", [Self]),
+ snmpa_local_db:register_notify_client(self(),?MODULE),
+
+ %% This call (to the manager) will issue to set operations, so
+ %% we expect to receive to notify(insert) calls.
+ try_test(db_notify_client_test),
+
+ ?DBG("db_notify_client -> await first notify",[]),
+ receive
+ {db_notify_test_reply, insert} ->
+ ?DBG("db_notify_client -> first notify received",[]),
+ ok
+ after 10000 ->
+ ?FAIL({timeout, waiting_for_first_event})
+ end,
+
+ ?DBG("db_notify_client -> await second notify",[]),
+ receive
+ {db_notify_test_reply, insert} ->
+ ?DBG("db_notify_client -> second notify received",[]),
+ ok
+ after 10000 ->
+ ?FAIL({timeout, waiting_for_second_event})
+ end,
+
+ ?DBG("db_notify_client -> unregister self (~p) notify client", [Self]),
+ snmpa_local_db:unregister_notify_client(self()),
+ ?DBG("db_notify_client -> minimize verbosity", []),
+ snmpa_local_db:verbosity(silence),
+
+ ?DBG("db_notify_client -> done", []),
+ ok.
+
+
+%% This is run in the manager node
+db_notify_client_test() ->
+ ?DBG("set first new sysLocation",[]),
+ s([{[sysLocation, 0], "new_value"}]),
+ ?line expect(5, [{[sysLocation, 0], "new_value"}]),
+
+ ?DBG("set second new sysLocation",[]),
+ s([{[sysLocation, 0], "new_value"}]),
+ ?line expect(5, [{[sysLocation, 0], "new_value"}]).
+
+notify(Pid, What) ->
+ ?DBG("notify(~p,~p) -> called",[Pid,What]),
+ Pid ! {db_notify_test_reply, What}.
+
+
+%% Req: system group, OLD-SNMPEA-MIB, Klas1
+big_test() ->
+ %% put(sname, {?MODULE, big_test}),
+ %% put(verbosity, trace),
+
+ ?DBG("big_test -> testing simple next/get/set @ master agent...",[]),
+ simple_standard_test(),
+
+ ?DBG("big_test -> testing simple next/get/set @ subagent...",[]),
+ gn([[klas1]]),
+ ?line expect(1, [{[fname,0], ""}]),
+ g([[fname,0]]),
+ ?line expect(2, [{[fname,0], ""}]),
+ s([{[fname,0], s, "test set"}]),
+ ?line expect(3, [{[fname,0], "test set"}]),
+ g([[fname,0]]),
+ ?line expect(4, [{[fname,0], "test set"}]),
+
+ ?DBG("big_test -> "
+ "testing next from last instance in master to subagent...",[]),
+ gn([[?v1_2(sysServices, sysORLastChange),0]]),
+ ?line expect(5, [{[fname,0], "test set"}]),
+ gn([[1,1],
+ [?v1_2(sysServices, sysORLastChange),0]]),
+ ?line expect(51, [{[sysDescr,0], "Erlang SNMP agent"},
+ {[fname,0], "test set"}]),
+ s([{[fname,0], s, ""}]),
+ ?line expect(52, [{[fname,0], ""}]),
+
+ table_test(),
+
+ ?DBG("big_test -> adding one row in subagent table",[]),
+ _FTab = [friendsEntry],
+ s([{[friendsEntry, [2, 3]], s, "kompis3"},
+ {[friendsEntry, [3, 3]], i, ?createAndGo}]),
+ ?line expect(6, [{[friendsEntry, [2, 3]], "kompis3"},
+ {[friendsEntry, [3, 3]], ?createAndGo}]),
+ g([[friendsEntry, [2, 3]],
+ [friendsEntry, [3, 3]]]),
+ ?line expect(7, [{[friendsEntry, [2, 3]], "kompis3"},
+ {[friendsEntry, [3, 3]], ?active}]),
+ s([{[friendsEntry, [3, 3]], i, ?destroy}]),
+ ?line expect(8, [{[friendsEntry, [3, 3]], ?destroy}]),
+
+ otp_1131(),
+
+ ?DBG("big_test -> adding two rows in subagent table with special INDEX",
+ []),
+ s([{[kompissEntry, [1, 3]], s, "kompis3"},
+ {[kompissEntry, [2, 3]], i, ?createAndGo}]),
+ ?line expect(9, [{[kompissEntry, [1, 3]], "kompis3"},
+ {[kompissEntry, [2, 3]], ?createAndGo}]),
+ g([[kompissEntry, [1, 3]],
+ [kompissEntry, [2, 3]]]),
+ ?line expect(10, [{[kompissEntry, [1, 3]], "kompis3"},
+ {[kompissEntry, [2, 3]], ?active}]),
+ gn([[kompissEntry, [1]],
+ [kompissEntry, [2]]]),
+ ?line expect(11, [{[kompissEntry, [1, 3]], "kompis3"},
+ {[kompissEntry, [2, 3]], ?active}]),
+ s([{[kompissEntry, [1, 2]], s, "kompis3"},
+ {[kompissEntry, [2, 2]], i, ?createAndGo}]),
+ ?line expect(12, [{[kompissEntry, [1, 2]], "kompis3"},
+ {[kompissEntry, [2, 2]], ?createAndGo}]),
+ gn([[kompissEntry, [1, 1]],
+ [kompissEntry, [2, 1]]]),
+ ?line expect(13, [{[kompissEntry, [1, 2]], "kompis3"},
+ {[kompissEntry, [2, 2]], ?active}]),
+ s([{[kompissEntry, [2, 3]], i, ?destroy}]),
+ ?line expect(14, [{[kompissEntry, [2, 3]], ?destroy}]),
+ s([{[kompissEntry, [2, 2]], i, ?destroy}]),
+ ?line expect(15, [{[kompissEntry, [2, 2]], ?destroy}]),
+ ?DBG("big_test -> done",[]),
+ ok.
+
+%% Req. system group, Klas2, OLD-SNMPEA-MIB
+big_test_2() ->
+ ?P1("Testing simple next/get/set @ master agent (2)..."),
+ simple_standard_test(),
+
+ ?P1("Testing simple next/get/set @ subagent (2)..."),
+ gn([[klas2]]),
+ ?line expect(1, [{[fname2,0], ""}]),
+ g([[fname2,0]]),
+ ?line expect(2, [{[fname2,0], ""}]),
+ s([{[fname2,0], s, "test set"}]),
+ ?line expect(3, [{[fname2,0], "test set"}]),
+ g([[fname2,0]]),
+ ?line expect(4, [{[fname2,0], "test set"}]),
+
+ otp_1298(),
+
+ ?P1("Testing next from last object in master to subagent (2)..."),
+ gn([[?v1_2(sysServices, sysORLastChange),0]]),
+ ?line expect(5, [{[fname2,0], "test set"}]),
+ gn([[1,1],
+ [?v1_2(sysServices, sysORLastChange),0]]),
+ ?line expect(51, [{[sysDescr,0], "Erlang SNMP agent"},
+ {[fname2,0], "test set"}]),
+
+ table_test(),
+
+ ?P1("Adding one row in subagent table (2)"),
+ _FTab = [friendsEntry2],
+ s([{[friendsEntry2, [2, 3]], s, "kompis3"},
+ {[friendsEntry2, [3, 3]], i, ?createAndGo}]),
+ ?line expect(6, [{[friendsEntry2, [2, 3]], "kompis3"},
+ {[friendsEntry2, [3, 3]], ?createAndGo}]),
+ g([[friendsEntry2, [2, 3]],
+ [friendsEntry2, [3, 3]]]),
+ ?line expect(7, [{[friendsEntry2, [2, 3]], "kompis3"},
+ {[friendsEntry2, [3, 3]], ?active}]),
+ s([{[friendsEntry2, [3, 3]], i, ?destroy}]),
+ ?line expect(8, [{[friendsEntry2, [3, 3]], ?destroy}]),
+
+ ?P1("Adding two rows in subagent table with special INDEX (2)"),
+ s([{[kompissEntry2, [1, 3]], s, "kompis3"},
+ {[kompissEntry2, [2, 3]], i, ?createAndGo}]),
+ ?line expect(9, [{[kompissEntry2, [1, 3]], "kompis3"},
+ {[kompissEntry2, [2, 3]], ?createAndGo}]),
+ g([[kompissEntry2, [1, 3]],
+ [kompissEntry2, [2, 3]]]),
+ ?line expect(10, [{[kompissEntry2, [1, 3]], "kompis3"},
+ {[kompissEntry2, [2, 3]], ?active}]),
+ gn([[kompissEntry2, [1]],
+ [kompissEntry2, [2]]]),
+ ?line expect(11, [{[kompissEntry2, [1, 3]], "kompis3"},
+ {[kompissEntry2, [2, 3]], ?active}]),
+ s([{[kompissEntry2, [1, 2]], s, "kompis3"},
+ {[kompissEntry2, [2, 2]], i, ?createAndGo}]),
+ ?line expect(12, [{[kompissEntry2, [1, 2]], "kompis3"},
+ {[kompissEntry2, [2, 2]], ?createAndGo}]),
+ gn([[kompissEntry2, [1, 1]],
+ [kompissEntry2, [2, 1]]]),
+ ?line expect(13, [{[kompissEntry2, [1, 2]], "kompis3"},
+ {[kompissEntry2, [2, 2]], ?active}]),
+ s([{[kompissEntry2, [2, 3]], i, ?destroy}]),
+ ?line expect(14, [{[kompissEntry2, [2, 3]], ?destroy}]),
+ s([{[kompissEntry2, [2, 2]], i, ?destroy}]),
+ ?line expect(15, [{[kompissEntry2, [2, 2]], ?destroy}]),
+ ok.
+
+%% Req. Test1
+multi_threaded_test() ->
+ ?P1("Testing multi threaded agent..."),
+ g([[multiStr,0]]),
+ Pid = get_multi_pid(),
+ g([[sysUpTime,0]]),
+ ?line expect(1, [{[sysUpTime,0], any}]),
+ s([{[sysLocation, 0], s, "pelle"}]),
+ ?line expect(2, [{[sysLocation, 0], "pelle"}]),
+ Pid ! continue,
+ ?line expect(3, [{[multiStr,0], "ok"}]),
+
+ s([{[multiStr, 0], s, "block"}]),
+ Pid2 = get_multi_pid(),
+ g([[sysUpTime,0]]),
+ ?line expect(4, [{[sysUpTime,0], any}]),
+ g([[multiStr,0]]),
+ Pid3 = get_multi_pid(),
+ g([[sysUpTime,0]]),
+ ?line expect(5, [{[sysUpTime,0], any}]),
+ s([{[sysLocation, 0], s, "kalle"}]),
+ Pid3 ! continue,
+ ?line expect(6, [{[multiStr,0], "ok"}]),
+ Pid2 ! continue,
+ ?line expect(7, [{[multiStr,0], "block"}]),
+ ?line expect(8, [{[sysLocation,0], "kalle"}]).
+
+%% Req. Test1, TestTrapv2
+mt_trap_test(MA) ->
+ ?P1("Testing trap-sending with multi threaded agent..."),
+ ?DBG("mt_trap_test(01) -> issue testTrapv22 (standard trap)", []),
+ snmpa:send_trap(MA, testTrapv22, "standard trap"),
+ ?DBG("mt_trap_test(02) -> await v2trap", []),
+ ?line expect(1, v2trap, [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?system ++ [0,1]}]),
+
+ ?DBG("mt_trap_test(03) -> issue mtTrap (standard trap)", []),
+ snmpa:send_trap(MA, mtTrap, "standard trap"),
+ Pid = get_multi_pid(),
+ ?DBG("mt_trap_test(04) -> multi pid: ~p. Now request sysUpTime...", [Pid]),
+ g([[sysUpTime,0]]),
+
+ %% Previously (before OTP-6784) this was done at 09 below
+ %% when the test1:multiStr was actually executed by the
+ %% worker-process, but as of 4.9.4, this is now executed
+ %% my the master_agent-process...
+ ?DBG("mt_trap_test(05) -> send continue to multi-pid", []),
+ Pid ! continue,
+
+ ?DBG("mt_trap_test(06) -> await sysUpTime", []),
+ ?line expect(2, [{[sysUpTime,0], any}]),
+ ?DBG("mt_trap_test(07) -> issue testTrapv22 (standard trap)", []),
+ snmpa:send_trap(MA, testTrapv22, "standard trap"),
+ ?DBG("mt_trap_test(08) -> await v2trap", []),
+ ?line expect(3, v2trap, [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?system ++ [0,1]}]),
+
+ %% ?DBG("mt_trap_test(09) -> send continue to multi-pid", []),
+ %% Pid ! continue,
+
+ ?DBG("mt_trap_test(10) -> await v2trap", []),
+ ?line expect(4, v2trap, [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?testTrap ++ [2]},
+ {[multiStr,0], "ok"}]),
+ ?DBG("mt_trap_test(11) -> done", []),
+ ok.
+
+
+get_multi_pid() ->
+ get_multi_pid(10).
+get_multi_pid(0) ->
+ ?line ?FAIL(no_global_name);
+get_multi_pid(N) ->
+ ?SLEEP(1000),
+ case global:whereis_name(snmp_multi_tester) of
+ Pid when is_pid(Pid) -> Pid;
+ _ -> get_multi_pid(N-1)
+ end.
+
+%% Req. Test1
+types_v2_test() ->
+ ?P1("Testing v2 types..."),
+
+ s([{[bits1,0], 2#10}]),
+ ?line expect(1, [{[bits1,0], ?str(2#10)}]),
+ g([[bits1,0]]),
+ ?line expect(2, [{[bits1,0], ?str(2#101)}]),
+
+ s([{[bits2,0], 2#11000000110}]),
+ ?line expect(3, [{[bits2,0], ?str(2#11000000110)}]),
+ g([[bits2,0]]),
+ ?line expect(4, [{[bits2,0], ?str(2#11000000110)}]),
+
+ g([[bits3,0]]),
+ ?line expect(50, genErr, 1, any),
+
+ g([[bits4,0]]),
+ ?line expect(51, genErr, 1, any),
+
+ s([{[bits1,0], s, [2#10]}]),
+ ?line expect(6, ?v1_2(badValue, wrongValue), 1, any),
+
+ s([{[bits2,0], 2#11001001101010011}]),
+ ?line expect(7, ?v1_2(badValue, wrongValue), 1, any).
+
+
+%% Req. Test1
+implied_test(MA) ->
+ ?LOG("implied_test -> start",[]),
+ ?P1("Testing IMPLIED..."),
+
+ snmpa:verbosity(MA,trace),
+ snmpa:verbosity(MA,trace),
+
+ %% Create two rows, check that they are get-nexted in correct order.
+ Idx1 = "apa",
+ Idx2 = "qq",
+ ?DBG("implied_test -> (send) create row 1 '~s' in table 1",[Idx1]),
+ s([{[testStatus, Idx1], i, ?createAndGo}, {[testDescr, Idx1],s,"row 1"}]),
+ ?line expect(1, [{[testStatus, Idx1], ?createAndGo},
+ {[testDescr, Idx1], "row 1"}]),
+ ?DBG("implied_test -> (send) create row 2 '~s' in table 1",[Idx2]),
+ s([{[testStatus, Idx2], i, ?createAndGo}, {[testDescr, Idx2],s,"row 2"}]),
+ ?line expect(2, [{[testStatus, Idx2], ?createAndGo},
+ {[testDescr, Idx2], "row 2"}]),
+ ?DBG("implied_test -> get-next(testDescr)",[]),
+ gn([[testDescr]]),
+ ?line expect(3, [{[testDescr,Idx1], "row 1"}]),
+ ?DBG("implied_test -> get-next(testDescr) of row 1",[]),
+ gn([[testDescr,Idx1]]),
+ ?line expect(4, [{[testDescr,Idx2], "row 2"}]),
+
+ % Delete the rows
+ ?DBG("implied_test -> (send) delete row 1 '~s' from table 1",[Idx1]),
+ s([{[testStatus, Idx1], i, ?destroy}]),
+ ?line expect(5, [{[testStatus, Idx1], ?destroy}]),
+ ?DBG("implied_test -> (send) delete row 2 '~s' from table 1",[Idx2]),
+ s([{[testStatus, Idx2], i, ?destroy}]),
+ ?line expect(6, [{[testStatus, Idx2], ?destroy}]),
+
+ %% Try the same in other table
+ Idx3 = [1, "apa"],
+ Idx4 = [1, "qq"],
+ ?DBG("implied_test -> (send) create row 1 '~s' in table 2",[Idx3]),
+ s([{[testStatus2, Idx3], i, ?createAndGo}, {[testDescr2,Idx3],s,"row 1"}]),
+ ?line expect(1, [{[testStatus2, Idx3], ?createAndGo},
+ {[testDescr2, Idx3], "row 1"}]),
+ ?DBG("implied_test -> (send) create row 2 '~s' in table 2",[Idx4]),
+ s([{[testStatus2, Idx4], i, ?createAndGo}, {[testDescr2,Idx4],s,"row 2"}]),
+ ?line expect(2, [{[testStatus2, Idx4], ?createAndGo},
+ {[testDescr2, Idx4], "row 2"}]),
+ ?DBG("implied_test -> get-next(testDescr2)",[]),
+ gn([[testDescr2]]),
+ ?line expect(3, [{[testDescr2,Idx3], "row 1"}]),
+ ?DBG("implied_test -> get-next(testDescr2) of row 1",[]),
+ gn([[testDescr2,Idx3]]),
+ ?line expect(4, [{[testDescr2,Idx4], "row 2"}]),
+
+ % Delete the rows
+ ?DBG("implied_test -> (send) delete row 1 '~s' from table 2",[Idx3]),
+ s([{[testStatus2, Idx3], i, ?destroy}]),
+ ?line expect(5, [{[testStatus2, Idx3], ?destroy}]),
+ ?DBG("implied_test -> (send) delete row 2 '~s' from table 2",[Idx4]),
+ s([{[testStatus2, Idx4], i, ?destroy}]),
+ ?line expect(6, [{[testStatus2, Idx4], ?destroy}]),
+
+ snmpa:verbosity(MA,log),
+
+ ?LOG("implied_test -> done",[]).
+
+
+
+%% Req. Test1
+sparse_table_test() ->
+ ?P1("Testing sparse table..."),
+
+ %% Create two rows, check that they are get-nexted in correct order.
+ Idx1 = 1,
+ Idx2 = 2,
+ s([{[sparseStatus, Idx1], i, ?createAndGo},
+ {[sparseDescr, Idx1], s, "row 1"}]),
+ ?line expect(1, [{[sparseStatus, Idx1], ?createAndGo},
+ {[sparseDescr, Idx1], "row 1"}]),
+ s([{[sparseStatus, Idx2], i, ?createAndGo},
+ {[sparseDescr, Idx2], s, "row 2"}]),
+ ?line expect(2, [{[sparseStatus, Idx2], ?createAndGo},
+ {[sparseDescr, Idx2], "row 2"}]),
+ ?v1_2(gn([[sparseIndex], [sparseDescr,Idx1], [sparseDescr,Idx2],
+ [sparseStatus,Idx1], [sparseStatus,Idx2]]),
+ gb(0,5,[[sparseIndex]])),
+ ?line expect(3, [{[sparseDescr,Idx1], "row 1"},
+ {[sparseDescr,Idx2], "row 2"},
+ {[sparseStatus,Idx1], ?active},
+ {[sparseStatus,Idx2], ?active},
+ {[sparseStr,0], "slut"}]),
+ % Delete the rows
+ s([{[sparseStatus, Idx1], i, ?destroy}]),
+ ?line expect(4, [{[sparseStatus, Idx1], ?destroy}]),
+ s([{[sparseStatus, Idx2], i, ?destroy}]),
+ ?line expect(5, [{[sparseStatus, Idx2], ?destroy}]).
+
+
+%% Req. Test1
+cnt_64_test(MA) ->
+ ?LOG("start cnt64 test (~p)",[MA]),
+ snmpa:verbosity(MA, trace),
+ ?LOG("start cnt64 test",[]),
+ ?P1("Testing Counter64, and at the same time, "
+ "RowStatus is not last column"),
+
+ ?DBG("get cnt64",[]),
+ g([[cnt64,0]]),
+ ?DBG("await response",[]),
+ ?line ?v1_2(expect(1, noSuchName, 1, any),
+ expect(1, [{[cnt64,0],18446744073709551615}])),
+ ?DBG("get-next cnt64",[]),
+ gn([[cnt64]]),
+ ?DBG("await response",[]),
+ ?line ?v1_2(expect(2, [{[cnt64Str,0], "after cnt64"}]),
+ expect(2, [{[cnt64,0],18446744073709551615}])),
+ ?DBG("send cntTrap",[]),
+ snmpa:send_trap(MA,cntTrap,"standard trap",[
+ {sysContact, "pelle"},
+ {cnt64, 10},
+ {sysLocation, "here"}
+ ]),
+ ?DBG("await response",[]),
+ ?line ?v1_2(expect(3, trap, [test], 6, 1, [{[sysContact,0], "pelle"},
+ {[sysLocation,0], "here"}]),
+ expect(3, v2trap, [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?testTrap ++ [1]},
+ {[sysContact,0], "pelle"},
+ {[cnt64,0], 10},
+ {[sysLocation,0], "here"}])),
+
+ %% Create two rows, check that they are get-nexted in correct order.
+ Idx1 = 1,
+ Idx2 = 2,
+ ?DBG("create row (cntStatus): ~p",[Idx1]),
+ s([{[cntStatus, Idx1], i, ?createAndGo}]),
+ ?DBG("await response",[]),
+ ?line expect(1, [{[cntStatus, Idx1], ?createAndGo}]),
+ ?DBG("create row (cntStatus): ~p",[Idx2]),
+ s([{[cntStatus, Idx2], i, ?createAndGo}]),
+ ?DBG("await response",[]),
+ ?line expect(2, [{[cntStatus, Idx2], ?createAndGo}]),
+
+ ?DBG("get-next (cntIndex)",[]),
+ gn([[cntIndex]]),
+ ?DBG("await response",[]),
+ ?line ?v1_2(expect(3, [{[cntStatus,Idx1], ?active}]),
+ expect(3, [{[cntCnt,Idx1], 0}])),
+ % Delete the rows
+ ?DBG("delete row (cntStatus): ~p",[Idx1]),
+ s([{[cntStatus, Idx1], i, ?destroy}]),
+ ?DBG("await response",[]),
+ ?line expect(4, [{[cntStatus, Idx1], ?destroy}]),
+ ?DBG("delete row (cntStatus): ~p",[Idx2]),
+ s([{[cntStatus, Idx2], i, ?destroy}]),
+ ?DBG("await response",[]),
+ ?line expect(5, [{[cntStatus, Idx2], ?destroy}]),
+ catch snmpa:verbosity(MA,log),
+ ?DBG("done",[]),
+ ok.
+
+%% Req. Test1
+opaque_test() ->
+ ?P1("Testing Opaque datatype..."),
+ g([[opaqueObj,0]]),
+ ?line expect(1, [{[opaqueObj,0], "opaque-data"}]).
+
+%% Req. OLD-SNMPEA-MIB
+api_test(MaNode) ->
+ ?line {value, OID} = rpc:call(MaNode, snmp, name_to_oid,
+ [intAgentIpAddress]),
+ ?line {value, intAgentIpAddress} = rpc:call(MaNode, snmp,
+ oid_to_name, [OID]),
+ ?line false = rpc:call(MaNode, snmp, name_to_oid, [intAgentIpAddres]),
+ ?line false = rpc:call(MaNode, snmp, oid_to_name,
+ [[1,5,32,3,54,3,3,34,4]]),
+ ?line {value, 2} = rpc:call(MaNode, snmp, enum_to_int,
+ [intViewType, excluded]),
+ ?line {value, excluded} = rpc:call(MaNode, snmp, int_to_enum,
+ [intViewType, 2]),
+ ?line false = rpc:call(MaNode, snmp, enum_to_int, [intViewType, exclude]),
+ ?line false = rpc:call(MaNode, snmp, enum_to_int,
+ [intAgentIpAddress, exclude]),
+ ?line false = rpc:call(MaNode, snmp, enum_to_int,
+ [intAgentIpAddre, exclude]),
+ ?line false = rpc:call(MaNode, snmp, int_to_enum, [intViewType, 3]),
+ ?line false = rpc:call(MaNode, snmp, int_to_enum, [intAgentIpAddress, 2]),
+ ?line false = rpc:call(MaNode, snmp, int_to_enum, [intAgentIpAddre, 2]),
+ ?line {value, active} = rpc:call(MaNode, snmp,
+ int_to_enum, ['RowStatus', ?active]),
+ ?line {value, ?destroy} = rpc:call(MaNode, snmp,
+ enum_to_int, ['RowStatus', destroy]),
+ ?line false = rpc:call(MaNode, snmp,
+ enum_to_int, ['RowStatus', xxxdestroy]),
+ ?line false = rpc:call(MaNode, snmp,
+ enum_to_int, ['xxRowStatus', destroy]),
+ ?line false = rpc:call(MaNode, snmp, int_to_enum, ['RowStatus', 25]),
+ ?line false = rpc:call(MaNode, snmp, int_to_enum, ['xxRowStatus', 1]),
+ ?line case snmp:date_and_time() of
+ List when is_list(List), length(List) == 8 -> ok;
+ List when is_list(List), length(List) == 11 -> ok
+ end.
+
+%% Req. Klas3
+api_test2() ->
+ g([[fname3,0]]),
+ ?line expect(1, [{[fname3,0], "ok"}]),
+ g([[fname4,0]]),
+ ?line expect(2, [{[fname4,0], 1}]).
+
+api_test3() ->
+ g([[fname3,0]]),
+ ?line expect(1, [{[fname3,0], "ok"}]).
+
+
+unreg_test() ->
+ gn([[?v1_2(sysServices, sysORLastChange),0]]),
+ ?line expect(1, [{[snmpInPkts, 0], any}]).
+
+load_test() ->
+ gn([[?v1_2(sysServices, sysORLastChange),0]]),
+ ?line expect(1, [{[fname,0], ""}]).
+
+%% Req. Klas1
+load_test_sa() ->
+ gn([[?v1_2(sysServices,sysORLastChange), 0]]),
+ ?line expect(1, [{[fname,0], any}]).
+
+%% Req. system group, Klas1, OLD-SNMPEA-MIB
+do_mul_get() ->
+ Key1c3 = [intCommunityEntry,[3],get(mip),is("public")],
+ Key1c4 = [intCommunityEntry,[4],get(mip),is("public")],
+ s([{[fname,0], s, "test set"}]),
+ ?line expect(3, [{[fname,0], "test set"}]),
+ g([[sysDescr,0], Key1c4, [fname,0],Key1c3,
+ [sysName,0]]),
+ ?line expect(1, [{[sysDescr,0], "Erlang SNMP agent"},
+ {Key1c4, 2},
+ {[fname,0], "test set"},
+ {Key1c3, 2},
+ {[sysName,0], "test"}]),
+ g([[1,3,7,1], Key1c4, [sysDescr,0], [1,3,7,2], Key1c3, [sysDescr,0]]),
+ ?line ?v1_2(expect(2, noSuchName, [1,4], any),
+ expect(2, [{[1,3,7,1], noSuchObject},
+ {Key1c4, 2},
+ {[sysDescr,0], "Erlang SNMP agent"},
+ {[1,3,7,2], noSuchObject},
+ {Key1c3, 2},
+ {[sysDescr,0], "Erlang SNMP agent"}])).
+
+%% Req. v1, system group, Klas1, OLD-SNMPEA-MIB, *ej* Klas3.
+do_mul_get_err() ->
+ Key1c3 = [intCommunityEntry,[3],get(mip),is("public")],
+ Key1c4 = [intCommunityEntry,[4],get(mip),is("public")],
+ s([{[fname,0], s, "test set"}]),
+ ?line expect(3, [{[fname,0], "test set"}]),
+ g([[sysDescr,0],Key1c4,[fname,0], Key1c3, [sysName,2]]),
+ ?line ?v1_2(expect(1, noSuchName, 5, any),
+ expect(1, [{[sysDescr,0], "Erlang SNMP agent"},
+ {Key1c4, 2},
+ {[fname,0], "test set"},
+ {Key1c3, 2},
+ {[sysName,2], noSuchInstance}])),
+ g([[sysDescr,0],Key1c4,[fname3,0], Key1c3, [sysName,1]]),
+ ?line ?v1_2(expect(1, noSuchName, [3,5], any),
+ expect(1, [{[sysDescr,0], "Erlang SNMP agent"},
+ {Key1c4, 2},
+ {[fname3,0], noSuchObject},
+ {Key1c3, 2},
+ {[sysName,1], noSuchInstance}])).
+
+
+%% Req. system group, Klas1, OLD-SNMPEA-MIB
+do_mul_next() ->
+ Key1c3s = [intCommunityEntry,[3],get(mip),is("publi")],
+ Key1c4s = [intCommunityEntry,[4],get(mip),is("publi")],
+ Key1c3 = [intCommunityEntry,[3],get(mip),is("public")],
+ Key1c4 = [intCommunityEntry,[4],get(mip),is("public")],
+ s([{[fname,0], s, "test set"}]),
+ ?line expect(3, [{[fname,0], "test set"}]),
+ gn([[sysDescr], Key1c4s, [fname],Key1c3s,[sysName]]),
+ ?line expect(1, [{[sysDescr,0], "Erlang SNMP agent"},
+ {Key1c4, 2}, {[fname,0], "test set"},
+ {Key1c3, 2}, {[sysName,0], "test"}]).
+
+%% Req. system group, Klas1, OLD-SNMPEA-MIB
+do_mul_next_err() ->
+ Key1c3s = [intCommunityEntry,[3],get(mip),is("publi")],
+ Key1c4s = [intCommunityEntry,[4],get(mip),is("publi")],
+ Key1c3 = [intCommunityEntry,[3],get(mip),is("public")],
+ Key1c4 = [intCommunityEntry,[4],get(mip),is("public")],
+ s([{[fname,0], s, "test set"}]),
+ ?line expect(3, [{[fname,0], "test set"}]),
+ gn([[sysDescr], Key1c4s, [1,3,6,999], [fname],[1,3,90], Key1c3s,[sysName]]),
+ ?line ?v1_2(expect(1, noSuchName, [3,5], any),
+ expect(1, [{[sysDescr,0], "Erlang SNMP agent"},
+ {Key1c4, 2},
+ {[1,3,6,999], endOfMibView},
+ {[fname,0], "test set"},
+ {[1,3,90], endOfMibView},
+ {Key1c3, 2},
+ {[sysName,0], "test"}])).
+
+
+%% Req. system group, Klas1, OLD-SNMPEA-MIB
+do_mul_set() ->
+ ?P1("Adding one row in subagent table, and one in master table"),
+ NewKeyc3 = [intCommunityEntry,[3],get(mip),is("test")],
+ NewKeyc4 = [intCommunityEntry,[4],get(mip),is("test")],
+ NewKeyc5 = [intCommunityEntry,[5],get(mip),is("test")],
+ s([{[friendsEntry, [2, 3]], "kompis3"},
+ {NewKeyc3, 2},
+ {[sysLocation,0], "new_value"},
+ {NewKeyc5, ?createAndGo},
+ {NewKeyc4, 2},
+ {[friendsEntry, [3, 3]], ?createAndGo}]),
+ ?line expect(1, [{[friendsEntry, [2, 3]], "kompis3"},
+ {NewKeyc3, 2},
+ {[sysLocation,0], "new_value"},
+ {NewKeyc5, ?createAndGo},
+ {NewKeyc4, 2},
+ {[friendsEntry, [3, 3]], ?createAndGo}]),
+ g([[friendsEntry, [2, 3]],
+ [sysLocation,0],
+ [friendsEntry, [3, 3]]]),
+ ?line expect(2, [{[friendsEntry, [2, 3]], "kompis3"},
+ {[sysLocation,0], "new_value"},
+ {[friendsEntry, [3, 3]], ?active}]),
+ g([NewKeyc4]),
+ ?line expect(3, [{NewKeyc4, 2}]),
+ s([{[friendsEntry, [3, 3]], ?destroy},
+ {NewKeyc5, ?destroy}]),
+ ?line expect(4, [{[friendsEntry, [3, 3]], ?destroy},
+ {NewKeyc5, ?destroy}]).
+
+%% Req. system group, Klas1, OLD-SNMPEA-MIB
+do_mul_set_err() ->
+ NewKeyc3 = [intCommunityEntry,[3],get(mip),is("test")],
+ NewKeyc4 = [intCommunityEntry,[4],get(mip),is("test")],
+ NewKeyc5 = [intCommunityEntry,[5],get(mip),is("test")],
+ ?P1("Adding one row in subagent table, and one in master table"),
+ s([{[friendsEntry, [2, 3]], s, "kompis3"},
+ {NewKeyc3, 2},
+ {[sysUpTime,0], 45}, % sysUpTime (readOnly)
+ {NewKeyc5, ?createAndGo},
+ {NewKeyc4, 2},
+ {[friendsEntry, [3, 3]], ?createAndGo}]),
+ ?line expect(1, ?v1_2(noSuchName, notWritable), 3, any),
+ g([[friendsEntry, [2, 3]]]),
+ ?line ?v1_2(expect(2, noSuchName, 1, any),
+ expect(2, [{[friendsEntry, [2,3]], noSuchInstance}])),
+ g([NewKeyc4]),
+ ?line ?v1_2(expect(3, noSuchName, 1, any),
+ expect(3, [{NewKeyc4, noSuchInstance}])).
+
+%% Req. SA-MIB
+sa_mib() ->
+ g([[sa, [2,0]]]),
+ ?line expect(1, [{[sa, [2,0]], 3}]),
+ s([{[sa, [1,0]], s, "sa_test"}]),
+ ?line expect(2, [{[sa, [1,0]], "sa_test"}]).
+
+ma_trap1(MA) ->
+ snmpa:send_trap(MA, testTrap2, "standard trap"),
+ ?line expect(1, trap, [system], 6, 1, [{[system, [4,0]],
+ "{mbj,eklas}@erlang.ericsson.se"}]),
+ snmpa:send_trap(MA, testTrap1, "standard trap"),
+ ?line expect(2, trap, [1,2,3] , 1, 0, [{[system, [4,0]],
+ "{mbj,eklas}@erlang.ericsson.se"}]).
+
+ma_trap2(MA) ->
+ snmpa:send_trap(MA,testTrap2,"standard trap",[{sysContact,"pelle"}]),
+ ?line expect(3, trap, [system], 6, 1, [{[system, [4,0]], "pelle"}]).
+
+ma_v2_2_v1_trap(MA) ->
+ snmpa:send_trap(MA,testTrapv22,"standard trap",[{sysContact,"pelle"}]),
+ ?line expect(3, trap, [system], 6, 1, [{[system, [4,0]], "pelle"}]).
+
+ma_v2_2_v1_trap2(MA) ->
+ snmpa:send_trap(MA,linkUp,"standard trap",[{ifIndex, [1], 1},
+ {ifAdminStatus, [1], 1},
+ {ifOperStatus, [1], 2}]),
+ ?line expect(3, trap, [1,2,3], 3, 0, [{[ifIndex, 1], 1},
+ {[ifAdminStatus, 1], 1},
+ {[ifOperStatus, 1], 2}]).
+
+sa_trap1(SA) ->
+ snmpa:send_trap(SA, saTrap, "standard trap"),
+ ?line expect(4, trap, [ericsson], 6, 1, [{[system, [4,0]],
+ "{mbj,eklas}@erlang.ericsson.se"},
+ {[sa, [1,0]], "sa_test"}]).
+
+sa_trap2(SA) ->
+ snmpa:send_trap(SA, saTrap, "standard trap",[{sysContact,"pelle"}]),
+ ?line expect(5, trap, [ericsson], 6, 1, [{[system, [4,0]],
+ "pelle"},
+ {[sa, [1,0]], "sa_test"}]).
+
+sa_trap3(SA) ->
+ snmpa:send_trap(SA, saTrap2, "standard trap",
+ [{intViewSubtree, [4], [1,2,3,4]}]),
+ ?line expect(6, trap, [ericsson], 6, 2, [{[system, [4,0]],
+ "{mbj,eklas}@erlang.ericsson.se"},
+ {[sa, [1,0]], "sa_test"},
+ {[intViewSubtree,4],[1,2,3,4]}]).
+
+ma_v2_trap1(MA) ->
+ ?DBG("ma_v2_traps -> entry with MA = ~p => "
+ "send standard trap: testTrapv22",[MA]),
+ snmpa:send_trap(MA, testTrapv22, "standard trap"),
+ ?line expect(1, v2trap, [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?system ++ [0,1]}]),
+ ?DBG("ma_v2_traps -> send standard trap: testTrapv21",[]),
+ snmpa:send_trap(MA, testTrapv21, "standard trap"),
+ ?line expect(2, v2trap, [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?snmp ++ [1]}]).
+
+ma_v2_trap2(MA) ->
+ snmpa:send_trap(MA,testTrapv22,"standard trap",[{sysContact,"pelle"}]),
+ ?line expect(3, v2trap, [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?system ++ [0,1]},
+ {[system, [4,0]], "pelle"}]).
+
+%% Note: This test case takes a while... actually a couple of minutes.
+ma_v2_inform1(MA) ->
+ ?DBG("ma_v2_inform1 -> entry with"
+ "~n MA = ~p => "
+ "~n send notification: testTrapv22", [MA]),
+
+ CmdExpectInform =
+ fun(No, Response) ->
+ expect(No,
+ {inform, Response},
+ [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?system ++ [0,1]}])
+ end,
+
+ CmdExp =
+ fun(ok) ->
+ ok;
+ ({ok, Val}) ->
+ ?DBG("ma_v2_inform -> [cmd2] Val: ~p", [Val]),
+ ok;
+ ({error, Id, Extra}) ->
+ {error, {unexpected, Id, Extra}};
+ (Error) ->
+ Error
+ end,
+
+ Cmd01 =
+ fun() ->
+ snmpa:send_notification(MA, testTrapv22, no_receiver,
+ "standard inform", []),
+ ok
+ end,
+ Cmd02 =
+ fun() ->
+ Res = CmdExpectInform(1, true),
+ CmdExp(Res)
+ end,
+
+ Tag03 = tag11,
+ Cmd03 =
+ fun() ->
+ snmpa:send_notification(MA, testTrapv22, {Tag03, self()},
+ "standard inform", []),
+ ok
+ end,
+ Cmd04 =
+ fun() ->
+ Res = CmdExpectInform(2, true),
+ CmdExp(Res)
+ end,
+ CmdSnmpTargets =
+ fun(T) ->
+ receive
+ {snmp_targets, T, [Addr]} ->
+ ?DBG("ma_v2_inform1 -> "
+ "received expected snmp_targets "
+ "~n with receiver: ~p",[Addr]),
+ ok;
+ {snmp_targets, T, Addrs} ->
+ ?ERR("ma_v2_inform1 -> "
+ "received unexpected snmp_targets"
+ "~n with receivers: ~n ~p",[Addrs]),
+ {error, {bad_addrs, Addrs}}
+ after
+ 5000 ->
+ ?ERR("ma_v2_inform1 -> "
+ "timeout awaiting snmp_targets [~w]",[T]),
+ {error, snmp_targets_timeout}
+ end
+ end,
+ Cmd05 = fun() -> CmdSnmpTargets(Tag03) end,
+ Cmd06 =
+ fun() ->
+ receive
+ {snmp_notification, Tag03, {got_response, Addr}} ->
+ ?DBG("ma_v2_inform1 -> "
+ "received expected snmp_notification "
+ "[with manager response] from: ~n ~p",[Addr]),
+ ok;
+ {snmp_notification, Tag03, {no_response, Addr}} ->
+ ?ERR("ma_v2_inform1 -> "
+ "received unexpected snmp_notification "
+ "[without manager response] from: ~n ~p",
+ [Addr]),
+ {error, no_response}
+ after
+ 20000 ->
+ ?ERR("ma_v2_inform1 -> "
+ "timeout awaiting snmp_notification [~p]",
+ [Tag03]),
+ {error, snmp_notification_timeout}
+ end
+ end,
+
+ Tag07 = tag12,
+ Cmd07 =
+ fun() ->
+ snmpa:send_notification(MA, testTrapv22, {Tag07, self()},
+ "standard inform", []),
+ ok
+ end,
+ Cmd08 =
+ fun() ->
+ Res = CmdExpectInform(3, false),
+ CmdExp(Res)
+ end,
+ Cmd09 =
+ fun() ->
+ CmdSnmpTargets(Tag07)
+ end,
+ Cmd10 =
+ fun() ->
+ receive
+ {snmp_notification, Tag07, {got_response, Addr}} ->
+ ?ERR("ma_v2_inform1 -> "
+ "received unexpected snmp_notification "
+ "[with manager response] from: ~n ~p", [Addr]),
+ {error, got_response};
+ {snmp_notification, Tag07, {no_response, Addr}} ->
+ ?DBG("ma_v2_inform1 -> "
+ "received expected snmp_notification "
+ "[without manager response] from: ~n ~p",
+ [Addr]),
+ ok
+ after
+ 240000 ->
+ ?ERR("ma_v2_inform1 -> "
+ "timeout awaiting snmp_notification [~p]",
+ [Tag07]),
+ {error, snmp_notification_timeout}
+ end
+ end,
+
+ Commands =
+ [
+ { 1, "Send notification [no receiver]", Cmd01},
+ { 2, "Expect inform [send response]", Cmd02},
+ { 3, "Send notification [tag1]", Cmd03},
+ { 4, "Expect inform [send response]", Cmd04},
+ { 5, "Expect snmp_targets message [from trap sender]", Cmd05},
+ { 6, "Expect snmp_notification [got_response] message [from trap sender]", Cmd06},
+ { 7, "Send notification [tag2]", Cmd07},
+ { 8, "Expect inform [don't send response]", Cmd08},
+ { 9, "Expect snmp_targets message [from trap sender]", Cmd09},
+ {10, "Expect snmp_notification [no_response] message [from trap sender]", Cmd10}
+ ],
+
+ command_handler(Commands).
+
+
+%% Note: This test case takes a while... actually a couple of minutes.
+ma_v2_inform2(MA) ->
+ ?DBG("ma_v2_inform2 -> entry with"
+ "~n MA = ~p => "
+ "~n send notification: testTrapv22", [MA]),
+
+ CmdExpectInform =
+ fun(No, Response) ->
+ expect(No,
+ {inform, Response},
+ [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?system ++ [0,1]}])
+ end,
+
+ CmdExp =
+ fun(ok) ->
+ ok;
+ ({ok, Val}) ->
+ ?DBG("ma_v2_inform -> [cmd2] Val: ~p", [Val]),
+ ok;
+ ({error, Id, Extra}) ->
+ {error, {unexpected, Id, Extra}};
+ (Error) ->
+ Error
+ end,
+
+ %% Await callback(s)
+ CmdAwaitDeliveryCallback =
+ fun(Kind, Ref, Tag) ->
+ io:format("CmdAwaitDeliveryCallback -> entry with"
+ "~n Kind: ~p"
+ "~n Ref: ~p"
+ "~n Tag: ~p"
+ "~n", [Kind, Ref, Tag]),
+ receive
+ {Kind, Ref, ok} ->
+ io:format("CmdAwaitDeliveryCallback(~p,~p) -> received expected result: ok"
+ "~n", [Tag, Ref]),
+ ok;
+ {Kind, Ref, Error} ->
+ io:format("CmdAwaitDeliveryCallback(~p,~p) -> received unexpected result: "
+ "~n Error: ~p"
+ "~n", [Tag, Ref, Error]),
+ {error, {unexpected_response, Error}}
+ after
+ 240000 ->
+ ?ERR("ma_v2_inform2 -> "
+ "timeout awaiting got_response for snmp_notification [~p]",
+ [Tag]),
+ {error, snmp_notification_timeout}
+ end
+ end,
+
+ Tag11 = tag21,
+ Ref11 = make_ref(),
+ Extra11 = [{tag, Tag11},
+ {ref, Ref11},
+ {recv, self()},
+ {targets, []},
+ {address, dummy},
+ {expected_delivery_result, got_response}],
+ Recv11 = #snmpa_notification_delivery_info{tag = Tag11,
+ mod = ?MODULE,
+ extra = Extra11},
+ Cmd11 =
+ fun() ->
+ snmpa:send_notification(MA, testTrapv22,
+ Recv11,
+ "standard inform", []),
+ ok
+ end,
+ Cmd12 =
+ fun() ->
+ Res = CmdExpectInform(4, true),
+ CmdExp(Res)
+ end,
+
+ Cmd13 = fun() -> CmdAwaitDeliveryCallback(targets, Ref11, Tag11) end,
+ Cmd14 = fun() -> CmdAwaitDeliveryCallback(info, Ref11, Tag11) end,
+
+ Commands =
+ [
+ {11, "Send notification [tag3]", Cmd11},
+ {12, "Expect notification message [tag3]", Cmd12},
+ {13, "Expect targets message [tag3]", Cmd13},
+ {14, "Expect notification response message [tag3]", Cmd14}
+ ],
+
+ command_handler(Commands).
+
+
+%% Note: This test case takes a while... actually a couple of minutes.
+ma_v2_inform3(MA) ->
+ ?DBG("ma_v2_inform3 -> entry with"
+ "~n MA = ~p => "
+ "~n send notification: testTrapv22", [MA]),
+
+ CmdExpectInform =
+ fun(No, Response) ->
+ expect(No,
+ {inform, Response},
+ [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?system ++ [0,1]}])
+ end,
+
+ CmdExp =
+ fun(ok) ->
+ ok;
+ ({ok, Val}) ->
+ ?DBG("ma_v2_inform3 -> [cmd2] Val: ~p", [Val]),
+ ok;
+ ({error, Id, Extra}) ->
+ {error, {unexpected, Id, Extra}};
+ (Error) ->
+ Error
+ end,
+
+ %% Await callback(s)
+ CmdAwaitDeliveryCallback =
+ fun(Kind, Ref, Tag) ->
+ io:format("CmdAwaitDeliveryCallback -> entry with"
+ "~n Kind: ~p"
+ "~n Ref: ~p"
+ "~n Tag: ~p"
+ "~n", [Kind, Ref, Tag]),
+ receive
+ {Kind, Ref, ok} ->
+ io:format("CmdAwaitDeliveryCallback(~p,~p) -> received expected result: ok"
+ "~n", [Tag, Ref]),
+ ok;
+ {Kind, Ref, Error} ->
+ io:format("CmdAwaitDeliveryCallback(~p,~p) -> received unexpected result: "
+ "~n Error: ~p"
+ "~n", [Tag, Ref, Error]),
+ {error, {unexpected_response, Error}}
+ after
+ 240000 ->
+ ?ERR("ma_v2_inform3 -> "
+ "timeout awaiting got_response for snmp_notification [~p]",
+ [Tag]),
+ {error, snmp_notification_timeout}
+ end
+ end,
+
+ Tag15 = tag31,
+ Ref15 = make_ref(),
+ Extra15 = [{tag, Tag15},
+ {ref, Ref15},
+ {recv, self()},
+ {targets, []},
+ {address, dummy},
+ {expected_delivery_result, no_response}],
+ Recv15 = #snmpa_notification_delivery_info{tag = Tag15,
+ mod = ?MODULE,
+ extra = Extra15},
+ Cmd15 =
+ fun() ->
+ snmpa:send_notification(MA, testTrapv22,
+ Recv15,
+ "standard inform", []),
+ ok
+ end,
+ Cmd16 =
+ fun() ->
+ Res = CmdExpectInform(5, false),
+ CmdExp(Res)
+ end,
+
+ Cmd17 = fun() -> CmdAwaitDeliveryCallback(targets, Ref15, Tag15) end,
+ Cmd18 = fun() -> CmdAwaitDeliveryCallback(info, Ref15, Tag15) end,
+
+ Commands =
+ [
+ {15, "Send notification [tag31]", Cmd15},
+ {16, "Expect notification message [tag31]", Cmd16},
+ {17, "Expect targets message [tag31]", Cmd17},
+ {18, "Expect notification (no) response message [tag31]", Cmd18}
+ ],
+
+ command_handler(Commands).
+
+
+delivery_targets(Tag, Addresses, Extra) ->
+ io:format("~w:delivery_targets -> entry with"
+ "~n Tag: ~p"
+ "~n Addresses: ~p"
+ "~n Extra: ~p"
+ "~n", [?MODULE, Tag, Addresses, Extra]),
+ {value, {_, Pid}} = lists:keysearch(recv, 1, Extra),
+ {value, {_, Ref}} = lists:keysearch(ref, 1, Extra),
+ case lists:keysearch(tag, 1, Extra) of
+ {value, {_, Tag}} ->
+ Pid ! {targets, Ref, ok};
+ {value, {_, OtherTag}} ->
+ Pid ! {targets, Ref, {error, {wrong_tag, Tag, OtherTag}}}
+ end,
+ ok.
+
+delivery_info(Tag, Address, DeliveryResult, Extra) ->
+ io:format("~w:delivery_info -> entry with"
+ "~n Tag: ~p"
+ "~n Address: ~p"
+ "~n DeliveryResult: ~p"
+ "~n Extra: ~p"
+ "~n", [?MODULE, Tag, Address, DeliveryResult, Extra]),
+ {value, {_, Pid}} = lists:keysearch(recv, 1, Extra),
+ {value, {_, Ref}} = lists:keysearch(ref, 1, Extra),
+ case lists:keysearch(tag, 1, Extra) of
+ {value, {_, Tag}} ->
+ Pid ! {info, Ref, ok};
+ {value, {_, OtherTag}} ->
+ Pid ! {info, Ref, {error, {wrong_tag, Tag, OtherTag}}}
+ end,
+ ok.
+
+
+command_handler([]) ->
+ ok;
+command_handler([{No, Desc, Cmd}|Rest]) ->
+ ?LOG("command_handler -> command ~w: ~n ~s", [No, Desc]),
+ case (catch Cmd()) of
+ ok ->
+ ?LOG("command_handler -> ~w: ok",[No]),
+ command_handler(Rest);
+ {error, Reason} ->
+ ?ERR("command_handler -> ~w error: ~n~p",[No, Reason]),
+ ?line ?FAIL(Reason);
+ Error ->
+ ?ERR("command_handler -> ~w unexpected: ~n~p",[No, Error]),
+ ?line ?FAIL({unexpected_command_result, Error})
+ end.
+
+
+ma_v1_2_v2_trap(MA) ->
+ snmpa:send_trap(MA,linkDown,"standard trap",[{ifIndex, [1], 1}]),
+ ?line expect(2, v2trap, [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?snmpTraps ++ [3]},
+ {[ifIndex, 1], 1},
+ {[snmpTrapEnterprise, 0], [1,2,3]}]).
+
+
+ma_v1_2_v2_trap2(MA) ->
+ snmpa:send_trap(MA,testTrap2,"standard trap",[{sysContact,"pelle"}]),
+ ?line expect(3, v2trap, [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?system ++ [0,1]},
+ {[system, [4,0]], "pelle"},
+ {[snmpTrapEnterprise, 0], ?system}]).
+
+
+sa_v1_2_v2_trap1(SA) ->
+ snmpa:send_trap(SA, saTrap, "standard trap"),
+ ?line expect(4, v2trap, [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?ericsson ++ [0, 1]},
+ {[system, [4,0]],
+ "{mbj,eklas}@erlang.ericsson.se"},
+ {[sa, [1,0]], "sa_test"},
+ {[snmpTrapEnterprise, 0], ?ericsson}]).
+
+sa_v1_2_v2_trap2(SA) ->
+ snmpa:send_trap(SA, saTrap, "standard trap",[{sysContact,"pelle"}]),
+ ?line expect(4, v2trap, [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?ericsson ++ [0, 1]},
+ {[system, [4,0]], "pelle"},
+ {[sa, [1,0]], "sa_test"},
+ {[snmpTrapEnterprise, 0], ?ericsson}]).
+
+
+sa_v1_2_v2_trap3(SA) ->
+ snmpa:send_trap(SA, saTrap2, "standard trap",
+ [{intViewSubtree, [4], [1,2,3,4]}]),
+ ?line expect(4, v2trap, [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?ericsson ++ [0, 2]},
+ {[system, [4,0]],
+ "{mbj,eklas}@erlang.ericsson.se"},
+ {[sa, [1,0]], "sa_test"},
+ {[intViewSubtree,4],[1,2,3,4]},
+ {[snmpTrapEnterprise, 0], ?ericsson}]).
+
+
+%% Req. SA-MIB, OLD-SNMPEA-MIB
+sa_errs_bad_value() ->
+ NewKeyc3 = [intCommunityEntry,[3],get(mip),is("test")],
+ NewKeyc4 = [intCommunityEntry,[4],get(mip),is("test")],
+ NewKeyc5 = [intCommunityEntry,[5],get(mip),is("test")],
+ s([{NewKeyc3, 2},
+ {[sa, [2,0]], 5}, % badValue (i is_set_ok)
+ {NewKeyc5, ?createAndGo},
+ {NewKeyc4, 2}]),
+ ?line expect(1, badValue, 2, any),
+ s([{NewKeyc3, 2},
+ {[sa, [2,0]], 6}, % wrongValue (i is_set_ok)
+ {NewKeyc5, ?createAndGo},
+ {NewKeyc4, 2}]),
+ ?line expect(1, ?v1_2(badValue, wrongValue), 2, any),
+ g([NewKeyc4]),
+ ?line ?v1_2(expect(2, noSuchName, 1, any),
+ expect(2, [{NewKeyc4, noSuchInstance}])).
+
+%% Req. SA-MIB, OLD-SNMPEA-MIB
+sa_errs_gen_err() ->
+ NewKeyc3 = [intCommunityEntry,[3],get(mip),is("test")],
+ NewKeyc4 = [intCommunityEntry,[4],get(mip),is("test")],
+ NewKeyc5 = [intCommunityEntry,[5],get(mip),is("test")],
+ s([{NewKeyc3, 2},{NewKeyc4, 2},
+ {NewKeyc5, ?createAndGo}, {[sa, [3,0]], 5}]),
+ ?line expect(1, genErr, 4, any),
+% The row might have been added; we don't know.
+% (as a matter of fact we do - it is added, because the agent
+% first sets its own vars, and then th SAs. Lets destroy it.
+ s([{NewKeyc5, ?destroy}]),
+ ?line expect(2, [{NewKeyc5, ?destroy}]).
+
+%% Req. SA-MIB, OLD-SNMPEA-MIB
+sa_too_big() ->
+ g([[sa, [4,0]]]),
+ ?line expect(1, tooBig).
+
+%% Req. Klas1, system group, snmp group (v1/v2)
+next_across_sa() ->
+ gn([[sysDescr],[klas1,5]]),
+ ?line expect(1, [{[sysDescr,0], "Erlang SNMP agent"},
+ {[snmpInPkts, 0], any}]).
+
+%% snmp_test_mgr:s([{[fStatus3, 1], 4}, {[fname3,0], "ok"}]). -> noError
+%% snmp_test_mgr:s([{[fStatus3, 1], 4}, {[fname3,0], "hoj"}]). -> {badValue, 2}
+%% snmp_test_mgr:s([{[fStatus3, 3], 4}, {[fname3,0], "hoj"}]). -> {genErr, 1}
+%% snmp_test_mgr:s([{[fStatus3, 4], 4}, {[fname3,0], "ok"}]). -> {genErr, 1}
+%% snmp_test_mgr:s([{[fStatus3, 4], 4}, {[fname3,0], "ufail"}]). -> {genErr, 1}
+%% snmp_test_mgr:s([{[fStatus3, 1], 4}, {[fname3,0], "xfail"}]). -> {genErr, 2}
+%% Req. Klas3, Klas4
+undo_test() ->
+ s([{[fStatus3, 1], 4}, {[fname3,0], "ok"}]),
+ ?line expect(1, [{[fStatus3, 1], 4}, {[fname3,0], "ok"}]),
+ s([{[fStatus3, 1], 4}, {[fname3,0], "hoj"}]),
+ ?line expect(2, ?v1_2(badValue, inconsistentValue), 2, any),
+ s([{[fStatus3, 3], 4}, {[fname3,0], "hoj"}]),
+ ?line expect(3, ?v1_2(genErr, undoFailed), 1, any),
+ s([{[fStatus3, 4], 4}, {[fname3,0], "ok"}]),
+ ?line expect(4, ?v1_2(genErr, commitFailed), 1, any),
+% unfortunatly we don't know if we'll get undoFailed or commitFailed.
+% it depends on which order the agent traverses the varbind list.
+% s([{[fStatus3, 4], 4}, {[fname3,0], "ufail"}]),
+% ?line expect(5, ?v1_2(genErr, undoFailed), 1, any),
+ s([{[fStatus3, 1], 4}, {[fname3,0], "xfail"}]),
+ ?line expect(6, genErr, 2, any).
+
+%% Req. Klas3, Klas4
+bad_return() ->
+ g([[fStatus4,4],
+ [fName4,4]]),
+ ?line expect(4, genErr, 2, any),
+ g([[fStatus4,5],
+ [fName4,5]]),
+ ?line expect(5, genErr, 1, any),
+ g([[fStatus4,6],
+ [fName4,6]]),
+ ?line expect(6, genErr, 2, any),
+ gn([[fStatus4,7],
+ [fName4,7]]),
+ ?line expect(7, genErr, 2, any),
+ gn([[fStatus4,8],
+ [fName4,8]]),
+ ?line expect(8, genErr, 1, any),
+ gn([[fStatus4,9],
+ [fName4,9]]),
+ ?line expect(9, genErr, 2, any).
+
+
+%%%-----------------------------------------------------------------
+%%% Test the implementation of standard mibs.
+%%% We should *at least* try to GET all variables, just to make
+%%% sure the instrumentation functions work.
+%%% Note that many of the functions in the standard mib is
+%%% already tested by the normal tests.
+%%%-----------------------------------------------------------------
+standard_mibs(suite) ->
+ [
+ snmp_standard_mib,
+ snmp_community_mib,
+ snmp_framework_mib,
+ snmp_target_mib,
+ snmp_notification_mib,
+ snmp_view_based_acm_mib
+ ].
+
+standard_mibs_2(suite) ->
+ [
+ snmpv2_mib_2,
+ snmp_community_mib_2,
+ snmp_framework_mib_2,
+ snmp_target_mib_2,
+ snmp_notification_mib_2,
+ snmp_view_based_acm_mib_2
+ ].
+
+standard_mibs_3(suite) ->
+ [
+ snmpv2_mib_3,
+ snmp_framework_mib_3,
+ snmp_mpd_mib_3,
+ snmp_target_mib_3,
+ snmp_notification_mib_3,
+ snmp_view_based_acm_mib_3,
+ snmp_user_based_sm_mib_3
+ ].
+
+%%-----------------------------------------------------------------
+%% For this test, the agent is configured for v1.
+%% o Test the counters and control objects in SNMP-STANDARD-MIB
+%%-----------------------------------------------------------------
+snmp_standard_mib(suite) -> [];
+snmp_standard_mib(Config) when is_list(Config) ->
+ ?P(snmp_standard_mib),
+ init_case(Config),
+ ?DBG("snmp_standard_mib -> std_mib_init", []),
+ try_test(std_mib_init),
+
+ ?DBG("snmp_standard_mib -> std_mib_a", []),
+ InBadVsns = try_test(std_mib_a),
+ put(vsn, v2),
+ ?DBG("snmp_standard_mib -> std_mib_read", []),
+ try_test(std_mib_read),
+ put(vsn, v1),
+
+ ?DBG("snmp_standard_mib -> std_mib_b (~w)", [InBadVsns]),
+ Bad = try_test(std_mib_b, [InBadVsns]),
+ ?DBG("snmp_standard_mib -> std_mib_read (community: 'bad community')", []),
+ try_test(std_mib_read, [], [{community, "bad community"}]),
+ ?DBG("snmp_standard_mib -> std_mib_write (community: 'public')", []),
+ try_test(std_mib_write, [], [{community, "public"}]),
+ ?DBG("snmp_standard_mib -> std_mib_asn_err", []),
+ try_test(std_mib_asn_err),
+ ?DBG("snmp_standard_mib -> std_mib_c (~w)", [Bad]),
+ try_test(std_mib_c, [Bad]),
+ ?DBG("snmp_standard_mib -> std_mib_a", []),
+ try_test(standard_mib_a),
+
+ ?DBG("snmp_standard_mib -> std_mib_finish", []),
+ try_test(std_mib_finish),
+ ?DBG("snmp_standard_mib -> std_mib_test_finish", []),
+ try_test(standard_mib_test_finish, [], [{community, "bad community"}]).
+
+%% Req. SNMP-STANDARD-MIB
+standard_mib_a() ->
+ ?line [OutPkts] = get_req(2, [[snmpOutPkts,0]]),
+ ?line [OutPkts2] = get_req(3, [[snmpOutPkts,0]]),
+ ?line OutPkts2 = OutPkts + 1,
+ %% There are some more counters we could test here, but it's not that
+ %% important, since they are removed from SNMPv2-MIB.
+ ok.
+
+%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB
+std_mib_init() ->
+ %% disable authentication failure traps. (otherwise w'd get many of
+ %% them - this is also a test to see that it works).
+ s([{[snmpEnableAuthenTraps,0], 2}]),
+ ?line expect(1, [{[snmpEnableAuthenTraps, 0], 2}]).
+
+%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB
+std_mib_finish() ->
+ %% enable again
+ s([{[snmpEnableAuthenTraps,0], 1}]),
+ ?line expect(1, [{[snmpEnableAuthenTraps, 0], 1}]).
+
+%% Req. SNMP-STANDARD-MIB
+standard_mib_test_finish() ->
+ %% force a authenticationFailure
+ std_mib_write(),
+ %% check that we got a trap
+ ?line expect(2, trap, [1,2,3], 4, 0, []).
+
+%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB
+std_mib_read() ->
+ ?DBG("std_mib_read -> entry", []),
+ g([[sysUpTime,0]]), % try a bad <something>; msg dropped, no reply
+ ?DBG("std_mib_read -> await timeout (i.e. no reply)", []),
+ ?line expect(1, timeout). % make sure we don't get a trap!
+
+
+%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB
+std_mib_write() ->
+ ?DBG("std_mib_write -> entry", []),
+ s([{[sysLocation, 0], "new_value"}]).
+
+%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB
+std_mib_asn_err() ->
+ snmp_test_mgr:send_bytes([48,99,67,12,0,0,0,0,0,0,5]).
+
+%%-----------------------------------------------------------------
+%% For this test, the agent is configured for v2 and v3.
+%% o Test the counters and control objects in SNMPv2-MIB
+%%-----------------------------------------------------------------
+snmpv2_mib_2(suite) -> [];
+snmpv2_mib_2(Config) when is_list(Config) ->
+ ?P(snmpv2_mib_2),
+ ?LOG("snmpv2_mib_2 -> start",[]),
+ init_case(Config),
+
+ ?DBG("snmpv2_mib_2 -> standard mib init",[]),
+ try_test(std_mib_init),
+
+ ?DBG("snmpv2_mib_2 -> get number of (so far) bad versions",[]),
+ InBadVsns = try_test(std_mib_a),
+
+ ?DBG("snmpv2_mib_2 -> make a bad version read",[]),
+ put(vsn, v1),
+ try_test(std_mib_read),
+
+ ?DBG("snmpv2_mib_2 -> bad version read",[]),
+ put(vsn, v2),
+ Bad = try_test(std_mib_b, [InBadVsns]),
+
+ ?DBG("snmpv2_mib_2 -> read with bad community",[]),
+ try_test(std_mib_read, [], [{community, "bad community"}]),
+
+ ?DBG("snmpv2_mib_2 -> write with public community",[]),
+ try_test(std_mib_write, [], [{community, "public"}]),
+
+ ?DBG("snmpv2_mib_2 -> asn err",[]),
+ try_test(std_mib_asn_err),
+
+ ?DBG("snmpv2_mib_2 -> check counters",[]),
+ try_test(std_mib_c, [Bad]),
+
+ ?DBG("snmpv2_mib_2 -> get som counters",[]),
+ try_test(snmpv2_mib_a),
+
+ ?DBG("snmpv2_mib_2 -> enable auth traps, and await some",[]),
+ try_test(std_mib_finish),
+
+ ?DBG("snmpv2_mib_2 -> force auth failure, and await trap, "
+ "then disable auth traps",[]),
+ try_test(snmpv2_mib_test_finish, [], [{community, "bad community"}]),
+
+ ?LOG("snmpv2_mib_2 -> done",[]).
+
+%% Req. SNMPv2-MIB
+snmpv2_mib_3(suite) -> [];
+snmpv2_mib_3(Config) when is_list(Config) ->
+ %% <CONDITIONAL-SKIP>
+ Skippable = [{unix, [darwin]}],
+ Condition = fun() -> ?OS_BASED_SKIP(Skippable) end,
+ ?NON_PC_TC_MAYBE_SKIP(Config, Condition),
+ %% </CONDITIONAL-SKIP>
+
+ ?P(snmpv2_mib_3),
+ init_case(Config),
+
+ InBadVsns = try_test(std_mib_a),
+ put(vsn, v1),
+ try_test(std_mib_read),
+ put(vsn, v3),
+ _Bad = try_test(std_mib_b, [InBadVsns]),
+ try_test(snmpv2_mib_a),
+
+ try_test(std_mib_finish).
+
+-define(authenticationFailure, [1,3,6,1,6,3,1,1,5,5]).
+
+%% Req. SNMPv2-MIB
+snmpv2_mib_test_finish() ->
+ %% force a authenticationFailure
+ ?DBG("ma_v2_inform -> write to std mib",[]),
+ std_mib_write(),
+
+ %% check that we got a trap
+ ?DBG("ma_v2_inform -> await trap",[]),
+ ?line expect(2, v2trap, [{[sysUpTime,0], any},
+ {[snmpTrapOID,0], ?authenticationFailure}]),
+
+ %% and the the inform
+ ?DBG("ma_v2_inform -> await inform",[]),
+ ?line expect(2, {inform,true}, [{[sysUpTime,0], any},
+ {[snmpTrapOID,0],?authenticationFailure}]).
+
+%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB
+std_mib_a() ->
+ ?line [InPkts] = get_req(2, [[snmpInPkts,0]]),
+ ?line [InPkts2] = get_req(3, [[snmpInPkts,0]]),
+ ?line InPkts2 = InPkts + 1,
+
+ ?line [InBadVsns] = get_req(4, [[snmpInBadVersions,0]]),
+ InBadVsns.
+
+%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB
+std_mib_b(InBadVsns) ->
+ ?line [InBadVsns2] = get_req(1, [[snmpInBadVersions,0]]),
+ ?line InBadVsns2 = InBadVsns + 1,
+ ?line [InPkts] = get_req(2, [[snmpInPkts,0]]),
+ ?line [InPkts2] = get_req(3, [[snmpInPkts,0]]),
+ ?line InPkts2 = InPkts + 1,
+ ?line [InBadCommunityNames, InBadCommunityUses, InASNErrs] =
+ get_req(4, [[snmpInBadCommunityNames,0],
+ [snmpInBadCommunityUses,0],
+ [snmpInASNParseErrs, 0]]),
+ {InBadCommunityNames, InBadCommunityUses, InASNErrs}.
+
+%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB
+std_mib_c({InBadCommunityNames, InBadCommunityUses, InASNErrs}) ->
+ ?line [InBadCommunityNames2, InBadCommunityUses2, InASNErrs2] =
+ get_req(1, [[snmpInBadCommunityNames,0],
+ [snmpInBadCommunityUses,0],
+ [snmpInASNParseErrs, 0]]),
+ ?line InBadCommunityNames2 = InBadCommunityNames + 1,
+ ?line InBadCommunityUses2 = InBadCommunityUses + 1,
+ ?line InASNErrs2 = InASNErrs + 1.
+
+%% Req. SNMPv2-MIB
+snmpv2_mib_a() ->
+ ?line [SetSerial] = get_req(2, [[snmpSetSerialNo,0]]),
+ s([{[snmpSetSerialNo,0], SetSerial}, {[sysLocation, 0], "val2"}]),
+ ?line expect(3, [{[snmpSetSerialNo,0], SetSerial},
+ {[sysLocation, 0], "val2"}]),
+ s([{[sysLocation, 0], "val3"}, {[snmpSetSerialNo,0], SetSerial}]),
+ ?line expect(4, inconsistentValue, 2,
+ [{[sysLocation, 0], "val3"},
+ {[snmpSetSerialNo,0], SetSerial}]),
+ ?line ["val2"] = get_req(5, [[sysLocation,0]]).
+
+
+%%-----------------------------------------------------------------
+%% o Bad community uses/name is tested already
+%% in SNMPv2-MIB and STANDARD-MIB.
+%% o Test add/deletion of rows.
+%%-----------------------------------------------------------------
+snmp_community_mib(suite) -> [];
+snmp_community_mib(Config) when is_list(Config) ->
+ ?P(snmp_community_mib),
+ init_case(Config),
+ ?line load_master_std("SNMP-COMMUNITY-MIB"),
+ try_test(snmp_community_mib),
+ ?line unload_master("SNMP-COMMUNITY-MIB").
+
+snmp_community_mib_2(X) -> ?P(snmp_community_mib_2), snmp_community_mib(X).
+
+%% Req. SNMP-COMMUNITY-MIB
+snmp_community_mib() ->
+ ?INF("NOT YET IMPLEMENTED", []),
+ nyi.
+
+%%-----------------------------------------------------------------
+%% o Test engine boots / time
+%%-----------------------------------------------------------------
+snmp_framework_mib(suite) -> [];
+snmp_framework_mib(Config) when is_list(Config) ->
+ ?P(snmp_framework_mib),
+ init_case(Config),
+ ?line load_master_std("SNMP-FRAMEWORK-MIB"),
+ try_test(snmp_framework_mib),
+ ?line unload_master("SNMP-FRAMEWORK-MIB").
+
+snmp_framework_mib_2(X) -> ?P(snmp_framework_mib_2), snmp_framework_mib(X).
+
+snmp_framework_mib_3(suite) -> [];
+snmp_framework_mib_3(Config) when is_list(Config) ->
+ ?P(snmp_framework_mib_3),
+ init_case(Config),
+ try_test(snmp_framework_mib).
+
+
+%% Req. SNMP-FRAMEWORK-MIB
+snmp_framework_mib() ->
+ ?line ["agentEngine"] = get_req(1, [[snmpEngineID,0]]),
+ ?line [EngineTime] = get_req(2, [[snmpEngineTime,0]]),
+ ?SLEEP(5000),
+ ?line [EngineTime2] = get_req(3, [[snmpEngineTime,0]]),
+ ?DBG("snmp_framework_mib -> time(s): "
+ "~n EngineTime 1 = ~p"
+ "~n EngineTime 2 = ~p", [EngineTime, EngineTime2]),
+ if
+ (EngineTime+7) < EngineTime2 ->
+ ?line ?FAIL({too_large_diff, EngineTime, EngineTime2});
+ (EngineTime+4) > EngineTime2 ->
+ ?line ?FAIL({too_large_diff, EngineTime, EngineTime2});
+ true ->
+ ok
+ end,
+ ?line case get_req(4, [[snmpEngineBoots,0]]) of
+ [Boots] when is_integer(Boots) ->
+ ok;
+ Else ->
+ ?FAIL(Else)
+ end,
+ ok.
+
+%%-----------------------------------------------------------------
+%% o Test the counters
+%%-----------------------------------------------------------------
+snmp_mpd_mib_3(suite) -> [];
+snmp_mpd_mib_3(Config) when is_list(Config) ->
+ %% <CONDITIONAL-SKIP>
+ Skippable = [{unix, [darwin]}],
+ Condition = fun() -> ?OS_BASED_SKIP(Skippable) end,
+ ?NON_PC_TC_MAYBE_SKIP(Config, Condition),
+ %% </CONDITIONAL-SKIP>
+
+ ?P(snmp_mpd_mib_3),
+ init_case(Config),
+ UnknownPDUHs = try_test(snmp_mpd_mib_a),
+ try_test(snmp_mpd_mib_b, [], [{context_engine_id, "bad engine"}]),
+ try_test(snmp_mpd_mib_c, [UnknownPDUHs]).
+
+
+%% Req. SNMP-MPD-MIB
+snmp_mpd_mib_a() ->
+ ?line [UnknownSecs, InvalidMsgs] =
+ get_req(1, [[snmpUnknownSecurityModels,0],
+ [snmpInvalidMsgs,0]]),
+ Pdu = #pdu{type = 'get-request',
+ request_id = 23,
+ error_status = noError,
+ error_index = 0,
+ varbinds = []},
+ SPdu = #scopedPdu{contextEngineID = "agentEngine",
+ contextName = "",
+ data = Pdu},
+ ?line SPDUBytes = snmp_pdus:enc_scoped_pdu(SPdu),
+ V3Hdr1 = #v3_hdr{msgID = 21,
+ msgMaxSize = 484,
+ msgFlags = [7],
+ msgSecurityModel = 23, % bad sec model
+ msgSecurityParameters = []},
+ V3Hdr2 = #v3_hdr{msgID = 21,
+ msgMaxSize = 484,
+ msgFlags = [6], % bad flag combination
+ msgSecurityModel = 3,
+ msgSecurityParameters = []},
+ Message1 = #message{version = 'version-3', vsn_hdr = V3Hdr1,
+ data = SPDUBytes},
+ Message2 = #message{version = 'version-3', vsn_hdr = V3Hdr2,
+ data = SPDUBytes},
+ ?line MsgBytes1 = snmp_pdus:enc_message_only(Message1),
+ ?line MsgBytes2 = snmp_pdus:enc_message_only(Message2),
+ snmp_test_mgr:send_bytes(MsgBytes1),
+ snmp_test_mgr:send_bytes(MsgBytes2),
+
+ ?line [UnknownSecs2, InvalidMsgs2, UnknownPDUHs] =
+ get_req(1, [[snmpUnknownSecurityModels,0],
+ [snmpInvalidMsgs,0],
+ [snmpUnknownPDUHandlers, 0]]),
+ ?line UnknownSecs2 = UnknownSecs + 1,
+ ?line InvalidMsgs2 = InvalidMsgs + 1,
+ UnknownPDUHs.
+
+-define(snmpUnknownPDUHandlers_instance, [1,3,6,1,6,3,11,2,1,3,0]).
+snmp_mpd_mib_b() ->
+ g([[sysUpTime,0]]),
+ ?line expect(1, report, [{?snmpUnknownPDUHandlers_instance, any}]).
+
+
+snmp_mpd_mib_c(UnknownPDUHs) ->
+ ?line [UnknownPDUHs2] = get_req(1, [[snmpUnknownPDUHandlers, 0]]),
+ ?line UnknownPDUHs2 = UnknownPDUHs + 1.
+
+
+snmp_target_mib(suite) -> [];
+snmp_target_mib(Config) when is_list(Config) ->
+ ?P(snmp_target_mib),
+ init_case(Config),
+ ?line load_master_std("SNMP-TARGET-MIB"),
+ try_test(snmp_target_mib),
+ ?line unload_master("SNMP-TARGET-MIB").
+
+snmp_target_mib_2(X) -> ?P(snmp_target_mib_2), snmp_target_mib(X).
+
+snmp_target_mib_3(X) -> ?P(snmp_target_mib_3), snmp_target_mib(X).
+
+snmp_target_mib() ->
+ ?INF("NOT YET IMPLEMENTED", []),
+ nyi.
+
+snmp_notification_mib(suite) -> [];
+snmp_notification_mib(Config) when is_list(Config) ->
+ ?P(snmp_notification_mib),
+ init_case(Config),
+ ?line load_master_std("SNMP-NOTIFICATION-MIB"),
+ try_test(snmp_notification_mib),
+ ?line unload_master("SNMP-NOTIFICATION-MIB").
+
+snmp_notification_mib_2(X) -> ?P(snmp_notification_mib_2),
+ snmp_notification_mib(X).
+
+snmp_notification_mib_3(X) -> ?P(snmp_notification_mib_3),
+ snmp_notification_mib(X).
+
+snmp_notification_mib() ->
+ ?INF("NOT YET IMPLEMENTED", []),
+ nyi.
+
+%%-----------------------------------------------------------------
+%% o add/delete views and try them
+%% o try boundaries
+%%-----------------------------------------------------------------
+snmp_view_based_acm_mib(suite) -> [];
+snmp_view_based_acm_mib(Config) when is_list(Config) ->
+ ?P(snmp_view_based_acm_mib),
+ init_case(Config),
+
+ ?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"),
+ ?line load_master("Test2"),
+ snmp_view_based_acm_mib(),
+ ?line unload_master("Test2"),
+ ?line unload_master("SNMP-VIEW-BASED-ACM-MIB").
+
+snmp_view_based_acm_mib_2(X) ->
+ ?P(snmp_view_based_acm_mib_2),
+ snmp_view_based_acm_mib(X).
+
+snmp_view_based_acm_mib_3(X) ->
+ %% <CONDITIONAL-SKIP>
+ Skippable = [{unix, [darwin]}],
+ Condition = fun() -> ?OS_BASED_SKIP(Skippable) end,
+ ?NON_PC_TC_MAYBE_SKIP(X, Condition),
+ %% </CONDITIONAL-SKIP>
+
+ ?P(snmp_view_based_acm_mib_3),
+ snmp_view_based_acm_mib(X).
+
+snmp_view_based_acm_mib() ->
+ snmpa:verbosity(net_if,trace),
+ snmpa:verbosity(master_agent,trace),
+ ?LOG("start snmp_view_based_acm_mib test",[]),
+ %% The user "no-rights" is present in USM, and is mapped to security
+ %% name 'no-rights", which is not present in VACM.
+ %% So, we'll add rights for it, try them and delete them.
+ %% We'll give "no-rights" write access to tDescr.0 and read access
+ %% to tDescr2.0
+ %% These are the options we'll use to the mgr
+ Opts = [{user, "no-rights"}, {community, "no-rights"}],
+ %% Find the valid secmodel, and one invalid secmodel.
+ {SecMod, InvSecMod} =
+ case get(vsn) of
+ v1 -> {?SEC_V1, ?SEC_V2C};
+ v2 -> {?SEC_V2C, ?SEC_USM};
+ v3 -> {?SEC_USM, ?SEC_V1}
+ end,
+ ?DBG("assign rights for 'no-rights'",[]),
+ ?line try_test(use_no_rights, [], Opts),
+
+ %% Now, add a mapping from "no-rights" -> "no-rights-group"
+ GRow1Status = [vacmSecurityToGroupStatus,[SecMod, 9,"no-rights"]],
+ GRow1 =
+ [{[vacmGroupName, [SecMod, 9,"no-rights"]], "no-rights-group"},
+ {GRow1Status, ?createAndGo}],
+ ?DBG("set '~p'",[GRow1]),
+ ?line try_test(do_set, [GRow1]),
+
+ ?DBG("assign rights for 'no-rights'",[]),
+ ?line try_test(use_no_rights, [], Opts),
+
+ %% Create a mapping for another sec model, and make sure it dosn't
+ %% give us access
+ GRow2Status = [vacmSecurityToGroupStatus,[InvSecMod, 9,"no-rights"]],
+ GRow2 = [{[vacmGroupName, [InvSecMod, 9, "no-rights"]], "initial"},
+ {GRow2Status, ?createAndGo}],
+
+ ?DBG("set '~p'",[GRow2]),
+ ?line try_test(do_set, [GRow2]),
+
+ ?DBG("assign rights for 'no-rights'",[]),
+ ?line try_test(use_no_rights, [], Opts),
+
+ %% Delete that row
+ ?line try_test(del_row, [GRow2Status]),
+
+ RVName = "rv_name",
+ WVName = "wv_name",
+
+ %% Access row
+ ARow1Idx = [15 | "no-rights-group"] ++ [0, ?SEC_ANY, 1],
+ ARow1Status = [vacmAccessStatus, ARow1Idx],
+ ARow1 = [{[vacmAccessContextMatch, ARow1Idx], 1},
+ {[vacmAccessReadViewName, ARow1Idx], RVName},
+ {[vacmAccessWriteViewName, ARow1Idx], WVName},
+ {ARow1Status, ?createAndGo}],
+
+ %% This access row would give acces, if InvSecMod was valid.
+ ARow2Idx = [15 | "no-rights-group"] ++ [0, InvSecMod, 1],
+ ARow2Status = [vacmAccessStatus, ARow2Idx],
+ ARow2 = [{[vacmAccessContextMatch, ARow2Idx], 1},
+ {[vacmAccessReadViewName, ARow2Idx], "internet"},
+ {[vacmAccessWriteViewName, ARow2Idx], "internet"},
+ {ARow2Status, ?createAndGo}],
+
+ ?line try_test(do_set, [ARow2]),
+
+ ?line try_test(use_no_rights, [], Opts),
+
+ %% Delete that row
+ ?line try_test(del_row, [ARow2Status]),
+
+
+ %% Add valid row
+ ?line try_test(do_set, [ARow1]),
+
+ ?line try_test(use_no_rights, [], Opts),
+
+ %% Create the view family
+ VRow1Idx = mk_ln(RVName) ++ mk_ln(?xDescr), % object access
+ VRow2Idx = mk_ln(RVName) ++ mk_ln(?xDescr2 ++ [0]), % instance access
+ VRow3Idx = mk_ln(WVName) ++ mk_ln(?xDescr), % object access
+ VRow4Idx = mk_ln(WVName) ++ mk_ln(?xDescr ++ [0]), % instance access
+ VRow1Status = [vacmViewTreeFamilyStatus, VRow1Idx],
+ VRow2Status = [vacmViewTreeFamilyStatus, VRow2Idx],
+ VRow3Status = [vacmViewTreeFamilyStatus, VRow3Idx],
+ VRow4Status = [vacmViewTreeFamilyStatus, VRow4Idx],
+
+ ?line try_test(add_row, [VRow1Status]),
+ ?line try_test(add_row, [VRow2Status]),
+ ?line try_test(add_row, [VRow3Status]),
+
+ %% We're supposed to have access now...
+ ?line try_test(use_rights, [], Opts),
+
+ %% Change Row3 to Row4
+ ?line try_test(del_row, [VRow3Status]),
+ ?line try_test(add_row, [VRow4Status]),
+
+ %% We should still have access...
+ ?line try_test(use_rights, [], Opts),
+
+ %% Delete rows
+ ?line try_test(del_row, [GRow1Status]),
+
+ ?line try_test(use_no_rights, [], Opts),
+
+ %% Delete rest of rows
+ ?line try_test(del_row, [ARow1Status]),
+ ?line try_test(del_row, [VRow1Status]),
+ ?line try_test(del_row, [VRow2Status]),
+ ?line try_test(del_row, [VRow4Status]),
+
+ ?line try_test(use_no_rights, [], Opts),
+ snmpa:verbosity(master_agent,log).
+
+do_set(Row) ->
+ s(Row),
+ expect(1, Row).
+
+add_row(RowStatus) ->
+ s([{RowStatus, ?createAndGo}]),
+ expect(1, [{RowStatus, ?createAndGo}]).
+
+del_row(RowStatus) ->
+ s([{RowStatus, ?destroy}]),
+ expect(1, [{RowStatus, ?destroy}]).
+
+
+
+use_no_rights() ->
+ g([[xDescr,0]]),
+ ?v1_2_3(expect(11, noSuchName, 1, any),
+ expect(12, [{[xDescr,0], noSuchObject}]),
+ expect(13, authorizationError, 1, any)),
+ g([[xDescr2,0]]),
+ ?v1_2_3(expect(21, noSuchName, 1, any),
+ expect(22, [{[xDescr2,0], noSuchObject}]),
+ expect(23, authorizationError, 1, any)),
+ gn([[xDescr]]),
+ ?v1_2_3(expect(31, noSuchName, 1, any),
+ expect(32, [{[xDescr], endOfMibView}]),
+ expect(33, authorizationError, 1, any)),
+ s([{[xDescr,0], "tryit"}]),
+ ?v1_2_3(expect(41, noSuchName, 1, any),
+ expect(42, noAccess, 1, any),
+ expect(43, authorizationError, 1, any)).
+
+
+use_rights() ->
+ g([[xDescr,0]]),
+ expect(1, [{[xDescr,0], any}]),
+ g([[xDescr2,0]]),
+ expect(2, [{[xDescr2,0], any}]),
+ s([{[xDescr,0], "tryit"}]),
+ expect(3, noError, 0, any),
+ g([[xDescr,0]]),
+ expect(4, [{[xDescr,0], "tryit"}]).
+
+mk_ln(X) ->
+ [length(X) | X].
+
+%%-----------------------------------------------------------------
+%% o add/delete users and try them
+%% o test all secLevels
+%% o test all combinations of protocols
+%% o try bad ops; check counters
+%%-----------------------------------------------------------------
+snmp_user_based_sm_mib_3(suite) -> [];
+snmp_user_based_sm_mib_3(Config) when is_list(Config) ->
+ %% <CONDITIONAL-SKIP>
+ Skippable = [{unix, [darwin]}],
+ Condition = fun() -> ?OS_BASED_SKIP(Skippable) end,
+ ?NON_PC_TC_MAYBE_SKIP(Config, Condition),
+ %% </CONDITIONAL-SKIP>
+
+ ?P(snmp_user_based_sm_mib_3),
+ init_case(Config),
+
+ _AgentDir = ?config(agent_dir, Config),
+ ?line load_master_std("SNMP-USER-BASED-SM-MIB"),
+
+ %% The newUser used here already has VACM access.
+
+ %% Add a new user in the simplest way; just createAndGo
+ try_test(v3_sync, [[{usm_add_user1, []}]],
+ [{sec_level, authPriv}, {user, "privDES"}]),
+
+ %% Try to use the new user
+ ?line load_master("Test2"),
+ try_test(v3_sync, [[{usm_use_user, []}]],
+ [{sec_level, authPriv}, {user, "newUser"}]),
+ ?line unload_master("Test2"),
+
+ ShaKey1 = snmp:passwd2localized_key(sha, "new sha password", "agentEngine"),
+ DesKey1 = lists:sublist(ShaKey1, 16),
+
+ %% Change the new user's keys - 1
+ try_test(v3_sync, [[{usm_key_change1, [ShaKey1, DesKey1]}]],
+ [{sec_level, authPriv}, {user, "newUser"}]),
+
+ %% Try to use the new keys
+ MgrDir = ?config(mgr_dir, Config),
+ ?line rewrite_usm_mgr(MgrDir, ShaKey1, DesKey1),
+ ?line load_master("Test2"),
+ try_test(v3_sync, [[{usm_use_user, []}]],
+ [{sec_level, authPriv}, {user, "newUser"}]),
+ ?line unload_master("Test2"),
+
+ ShaKey2 = snmp:passwd2localized_key(sha, "newer password", "agentEngine"),
+ DesKey2 = lists:sublist(ShaKey2, 16),
+
+ %% Change the new user's keys - 2
+ ?line try_test(v3_sync,
+ [[{usm_key_change2, [ShaKey1, DesKey1, ShaKey2, DesKey2]}]],
+ [{sec_level, authPriv}, {user, "newUser"}]),
+
+ %% Try to use the new keys
+ reset_usm_mgr(MgrDir),
+ ?line rewrite_usm_mgr(MgrDir, ShaKey2, DesKey2),
+ ?line load_master("Test2"),
+ ?line try_test(v3_sync, [[{usm_use_user, []}]],
+ [{sec_level, authPriv}, {user, "newUser"}]),
+ ?line unload_master("Test2"),
+ reset_usm_mgr(MgrDir),
+
+ %% Change the new user's keys - 3
+ ?line try_test(v3_sync,
+ [[{usm_key_change3, [ShaKey2, DesKey2, ShaKey1, DesKey1]}]],
+ [{sec_level, authPriv}, {user, "privDES"}]),
+
+ %% Try to use the new keys
+ ?line rewrite_usm_mgr(MgrDir, ShaKey1, DesKey1),
+ ?line load_master("Test2"),
+ try_test(v3_sync, [[{usm_use_user, []}]],
+ [{sec_level, authPriv}, {user, "newUser"}]),
+ ?line unload_master("Test2"),
+ reset_usm_mgr(MgrDir),
+
+ %% Try some read requests
+ ?line try_test(v3_sync, [[{usm_read, []}]],
+ [{sec_level, authPriv}, {user, "privDES"}]),
+
+ %% Delete the new user
+ ?line try_test(v3_sync, [[{usm_del_user, []}]],
+ [{sec_level, authPriv}, {user, "privDES"}]),
+
+ %% Try some bad requests
+ ?line try_test(v3_sync, [[{usm_bad, []}]],
+ [{sec_level, authPriv}, {user, "privDES"}]),
+
+ ?line unload_master("SNMP-USER-BASED-SM-MIB").
+
+-define(usmUserSecurityName, [1,3,6,1,6,3,15,1,2,2,1,3]).
+
+usm_add_user1() ->
+ NewRowIndex = [11,"agentEngine", 7, "newUser"],
+ RowPointer = ?usmUserSecurityName ++ [11|"agentEngine"] ++ [7|"privDES"],
+ Vbs1 = [{[usmUserCloneFrom, NewRowIndex], RowPointer},
+ {[usmUserStatus, NewRowIndex], ?createAndGo}],
+ ?line s(Vbs1),
+ ?line expect(1, Vbs1),
+ ok.
+
+usm_use_user() ->
+ v2_proc().
+
+
+%% Change own public keys
+usm_key_change1(ShaKey, DesKey) ->
+ NewRowIndex = [11,"agentEngine", 7, "newUser"],
+ ShaKeyChange = snmp_user_based_sm_mib:mk_key_change(sha,
+ "passwd_shaxxxxxxxxxx",
+ ShaKey),
+ DesKeyChange = snmp_user_based_sm_mib:mk_key_change(sha,
+ "passwd_desxxxxxx",
+ DesKey),
+ Vbs1 = [{[usmUserAuthKeyChange, NewRowIndex], ShaKeyChange},
+ {[usmUserPrivKeyChange, NewRowIndex], DesKeyChange}],
+ s(Vbs1),
+ ?line expect(1, Vbs1).
+
+%% Change own private keys
+usm_key_change2(OldShaKey, OldDesKey, ShaKey, DesKey) ->
+ NewRowIndex = [11,"agentEngine", 7, "newUser"],
+ ShaKeyChange = snmp_user_based_sm_mib:mk_key_change(sha,
+ OldShaKey,
+ ShaKey),
+ DesKeyChange = snmp_user_based_sm_mib:mk_key_change(sha,
+ OldDesKey,
+ DesKey),
+ Vbs1 = [{[usmUserOwnAuthKeyChange, NewRowIndex], ShaKeyChange},
+ {[usmUserOwnPrivKeyChange, NewRowIndex], DesKeyChange}],
+ s(Vbs1),
+ ?line expect(1, Vbs1).
+
+%% Change other's public keys
+usm_key_change3(OldShaKey, OldDesKey, ShaKey, DesKey) ->
+ NewRowIndex = [11,"agentEngine", 7, "newUser"],
+ ShaKeyChange = snmp_user_based_sm_mib:mk_key_change(sha,
+ OldShaKey,
+ ShaKey),
+ DesKeyChange = snmp_user_based_sm_mib:mk_key_change(sha,
+ OldDesKey,
+ DesKey),
+ Vbs1 = [{[usmUserOwnAuthKeyChange, NewRowIndex], ShaKeyChange}],
+ s(Vbs1),
+ ?line expect(1, noAccess, 1, any),
+ Vbs2 = [{[usmUserOwnPrivKeyChange, NewRowIndex], DesKeyChange}],
+ s(Vbs2),
+ ?line expect(2, noAccess, 1, any),
+
+
+ Vbs3 = [{[usmUserAuthKeyChange, NewRowIndex], ShaKeyChange},
+ {[usmUserPrivKeyChange, NewRowIndex], DesKeyChange}],
+ s(Vbs3),
+ ?line expect(1, Vbs3).
+
+usm_read() ->
+ NewRowIndex = [11,"agentEngine", 7, "newUser"],
+ ?line g([[usmUserSecurityName, NewRowIndex],
+ [usmUserCloneFrom, NewRowIndex],
+ [usmUserAuthKeyChange, NewRowIndex],
+ [usmUserOwnAuthKeyChange, NewRowIndex],
+ [usmUserPrivKeyChange, NewRowIndex],
+ [usmUserOwnPrivKeyChange, NewRowIndex]]),
+ ?line expect(1,
+ [{[usmUserSecurityName, NewRowIndex], "newUser"},
+ {[usmUserCloneFrom, NewRowIndex], [0,0]},
+ {[usmUserAuthKeyChange, NewRowIndex], ""},
+ {[usmUserOwnAuthKeyChange, NewRowIndex], ""},
+ {[usmUserPrivKeyChange, NewRowIndex], ""},
+ {[usmUserOwnPrivKeyChange, NewRowIndex], ""}]),
+ ok.
+
+
+
+usm_del_user() ->
+ NewRowIndex = [11,"agentEngine", 7, "newUser"],
+ Vbs1 = [{[usmUserStatus, NewRowIndex], ?destroy}],
+ ?line s(Vbs1),
+ ?line expect(1, Vbs1),
+ ok.
+
+-define(usmUserCloneFrom, [1,3,6,1,6,3,15,1,2,2,1,4]).
+
+-define(usmNoAuthProtocol, [1,3,6,1,6,3,10,1,1,1]).
+
+-define(usmHMACMD5AuthProtocol, [1,3,6,1,6,3,10,1,1,2]).
+
+-define(usmHMACSHAAuthProtocol, [1,3,6,1,6,3,10,1,1,3]).
+
+-define(usmNoPrivProtocol, [1,3,6,1,6,3,10,1,2,1]).
+
+-define(usmDESPrivProtocol, [1,3,6,1,6,3,10,1,2,2]).
+
+usm_bad() ->
+ NewRowIndex = [11,"agentEngine", 7, "newUser"],
+ RowPointer1 = ?usmUserSecurityName ++ [11|"agentEngine"] ++ [7|"privDOS"],
+ Vbs1 = [{[usmUserCloneFrom, NewRowIndex], RowPointer1},
+ {[usmUserStatus, NewRowIndex], ?createAndGo}],
+ ?line s(Vbs1),
+ ?line expect(1, inconsistentName, 1, any),
+
+ RowPointer2 = ?usmUserCloneFrom ++ [11|"agentEngine"] ++ [7|"privDES"],
+ Vbs2 = [{[usmUserCloneFrom, NewRowIndex], RowPointer2},
+ {[usmUserStatus, NewRowIndex], ?createAndGo}],
+ ?line s(Vbs2),
+ ?line expect(2, wrongValue, 1, any),
+
+ RowPointer3 = ?usmUserSecurityName ++ [11|"agentEngine"] ++ [7|"privDES"],
+ Vbs3 = [{[usmUserCloneFrom, NewRowIndex], RowPointer3},
+ {[usmUserStatus, NewRowIndex], ?createAndGo}],
+ ?line s(Vbs3),
+ ?line expect(3, Vbs3),
+ ?line s([{[usmUserAuthProtocol, NewRowIndex], ?usmNoAuthProtocol}]),
+ ?line expect(4, inconsistentValue, 1, any),
+ ?line s([{[usmUserAuthProtocol, NewRowIndex], ?usmHMACMD5AuthProtocol}]),
+ ?line expect(5, inconsistentValue, 1, any),
+ ?line s([{[usmUserAuthProtocol, NewRowIndex], ?usmDESPrivProtocol}]),
+ ?line expect(6, wrongValue, 1, any),
+ ?line s([{[usmUserPrivProtocol, NewRowIndex], ?usmHMACSHAAuthProtocol}]),
+ ?line expect(7, wrongValue, 1, any),
+
+ Vbs4 = [{[usmUserStatus, NewRowIndex], ?destroy}],
+ ?line s(Vbs4),
+ ?line expect(1, Vbs4),
+
+ ok.
+
+
+%%-----------------------------------------------------------------
+%% Loop through entire MIB, to make sure that all instrum. funcs
+%% works.
+%% Load all std mibs that are not loaded by default.
+%%-----------------------------------------------------------------
+loop_mib(suite) -> [];
+loop_mib(Config) when is_list(Config) ->
+ ?P(loop_mib),
+ ?LOG("loop_mib -> initiate case",[]),
+ %% snmpa:verbosity(master_agent,debug),
+ %% snmpa:verbosity(mib_server,info),
+ {SaNode, MgrNode, MibDir} = init_case(Config),
+ ?DBG("loop_mib -> ~n"
+ "\tSaNode: ~p~n"
+ "\tMgrNode: ~p~n"
+ "\tMibDir: ~p",[SaNode, MgrNode, MibDir]),
+ ?DBG("loop_mib -> load mib SNMP-COMMUNITY-MIB",[]),
+ ?line load_master_std("SNMP-COMMUNITY-MIB"),
+ ?DBG("loop_mib -> load mib SNMP-MPD-MIB",[]),
+ ?line load_master_std("SNMP-MPD-MIB"),
+ ?DBG("loop_mib -> load mib SNMP-TARGET-MIB",[]),
+ ?line load_master_std("SNMP-TARGET-MIB"),
+ ?DBG("loop_mib -> load mib SNMP-NOTIFICATION-MIB",[]),
+ ?line load_master_std("SNMP-NOTIFICATION-MIB"),
+ ?DBG("loop_mib -> load mib SNMP-FRAMEWORK-MIB",[]),
+ ?line load_master_std("SNMP-FRAMEWORK-MIB"),
+ ?DBG("loop_mib -> load mib SNMP-VIEW-BASED-ACM-MIB",[]),
+ ?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"),
+ ?DBG("loop_mib -> try",[]),
+ try_test(loop_mib_1),
+ ?DBG("loop_mib -> unload mib SNMP-COMMUNITY-MIB",[]),
+ ?line unload_master("SNMP-COMMUNITY-MIB"),
+ ?DBG("loop_mib -> unload mib SNMP-MPD-MIB",[]),
+ ?line unload_master("SNMP-MPD-MIB"),
+ ?DBG("loop_mib -> unload mib SNMP-TARGET-MIB",[]),
+ ?line unload_master("SNMP-TARGET-MIB"),
+ ?DBG("loop_mib -> unload mib SNMP-NOTIFICATION-MIB",[]),
+ ?line unload_master("SNMP-NOTIFICATION-MIB"),
+ ?DBG("loop_mib -> unload mib SNMP-FRAMEWORK-MIB",[]),
+ ?line unload_master("SNMP-FRAMEWORK-MIB"),
+ ?DBG("loop_mib -> unload mib SNMP-VIEW-BASED-ACM-MIB",[]),
+ ?line unload_master("SNMP-VIEW-BASED-ACM-MIB"),
+ %% snmpa:verbosity(master_agent,log),
+ %% snmpa:verbosity(mib_server,silence),
+ ?LOG("loop_mib -> done",[]).
+
+
+loop_mib_2(suite) -> [];
+loop_mib_2(Config) when is_list(Config) ->
+ ?P(loop_mib_2),
+ ?LOG("loop_mib_2 -> initiate case",[]),
+ {SaNode, MgrNode, MibDir} = init_case(Config),
+ ?DBG("loop_mib_2 -> ~n"
+ "\tSaNode: ~p~n"
+ "\tMgrNode: ~p~n"
+ "\tMibDir: ~p",[SaNode, MgrNode, MibDir]),
+ ?DBG("loop_mib_2 -> load mibs",[]),
+ ?line load_master_std("SNMP-COMMUNITY-MIB"),
+ ?line load_master_std("SNMP-MPD-MIB"),
+ ?line load_master_std("SNMP-TARGET-MIB"),
+ ?line load_master_std("SNMP-NOTIFICATION-MIB"),
+ ?line load_master_std("SNMP-FRAMEWORK-MIB"),
+ ?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"),
+ try_test(loop_mib_2),
+ ?DBG("loop_mib_2 -> unload mibs",[]),
+ ?line unload_master("SNMP-COMMUNITY-MIB"),
+ ?line unload_master("SNMP-MPD-MIB"),
+ ?line unload_master("SNMP-TARGET-MIB"),
+ ?line unload_master("SNMP-NOTIFICATION-MIB"),
+ ?line unload_master("SNMP-FRAMEWORK-MIB"),
+ ?line unload_master("SNMP-VIEW-BASED-ACM-MIB"),
+ ?LOG("loop_mib_2 -> done",[]).
+
+
+loop_mib_3(suite) -> [];
+loop_mib_3(Config) when is_list(Config) ->
+ ?P(loop_mib_3),
+ ?LOG("loop_mib_3 -> initiate case",[]),
+ {SaNode, MgrNode, MibDir} = init_case(Config),
+ ?DBG("loop_mib_3 -> ~n"
+ "\tSaNode: ~p~n"
+ "\tMgrNode: ~p~n"
+ "\tMibDir: ~p",[SaNode, MgrNode, MibDir]),
+ ?DBG("loop_mib_3 -> load mibs",[]),
+ ?line load_master_std("SNMP-TARGET-MIB"),
+ ?line load_master_std("SNMP-NOTIFICATION-MIB"),
+ ?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"),
+ ?line load_master_std("SNMP-USER-BASED-SM-MIB"),
+
+ try_test(loop_mib_2),
+
+ ?DBG("loop_mib_3 -> unload mibs",[]),
+ ?line unload_master("SNMP-TARGET-MIB"),
+ ?line unload_master("SNMP-NOTIFICATION-MIB"),
+ ?line unload_master("SNMP-VIEW-BASED-ACM-MIB"),
+ ?line unload_master("SNMP-USER-BASED-SM-MIB"),
+ ?LOG("loop_mib_3 -> done",[]).
+
+
+%% Req. As many mibs all possible
+loop_mib_1() ->
+ ?DBG("loop_mib_1 -> entry",[]),
+ N = loop_it_1([1,1], 0),
+ io:format(user, "found ~w varibles\n", [N]),
+ ?line N = if N < 100 -> 100;
+ true -> N
+ end.
+
+
+loop_it_1(Oid, N) ->
+ ?DBG("loop_it_1 -> entry with~n"
+ "\tOid: ~p~n"
+ "\tN: ~p",[Oid,N]),
+ case get_next_req([Oid]) of
+ #pdu{type = 'get-response',
+ error_status = noError,
+ error_index = 0,
+ varbinds = [#varbind{oid = NOid,
+ value = Value}]} when NOid > Oid ->
+ ?DBG("loop_it_1 -> "
+ "~n NOid: ~p"
+ "~n Value: ~p",[NOid, Value]),
+ ?line [Value2] = get_req(1, [NOid]), % must not be same
+ ?DBG("loop_it_1 -> "
+ "~n Value2: ~p",[Value2]),
+ loop_it_1(NOid, N+1);
+
+ #pdu{type = 'get-response',
+ error_status = noError,
+ error_index = 0,
+ varbinds = Vbs} ->
+ exit({unexpected_vbs, ?LINE, Vbs});
+
+ #pdu{type = 'get-response',
+ error_status = noSuchName,
+ error_index = 1,
+ varbinds = [_]} ->
+ ?DBG("loop_it_1 -> done: ~p",[N]),
+ N;
+
+ #pdu{type = 'get-response',
+ error_status = Err,
+ error_index = Idx,
+ varbinds = Vbs} ->
+ exit({unexpected_pdu, ?LINE, Err, Idx, Vbs});
+
+ #pdu{type = Type,
+ error_status = Err,
+ error_index = Idx,
+ varbinds = Vbs} ->
+ exit({unexpected_pdu, ?LINE, Type, Err, Idx, Vbs});
+
+ {error, Reason} ->
+ exit({error, Reason, ?LINE})
+ end.
+
+
+%% Req. As many mibs all possible
+loop_mib_2() ->
+ ?DBG("loop_mib_1 -> entry",[]),
+ N = loop_it_2([1,1], 0),
+ io:format(user, "found ~w varibles\n", [N]),
+ ?line N = if N < 100 -> 100;
+ true -> N
+ end.
+
+
+loop_it_2(Oid, N) ->
+ ?DBG("loop_it_2 -> entry with"
+ "~n Oid: ~p"
+ "~n N: ~p",[Oid, N]),
+ case get_next_req([Oid]) of
+ #pdu{type = 'get-response',
+ error_status = noError,
+ error_index = 0,
+ varbinds = [#varbind{oid = NOid, value = endOfMibView}]} ->
+ ?DBG("loop_it_2 -> "
+ "~n NOid: ~p",[NOid]),
+ N;
+
+ #pdu{type = 'get-response',
+ error_status = noError,
+ error_index = 0,
+ varbinds = [#varbind{oid = NOid,
+ value = Value}]} when NOid > Oid ->
+ ?DBG("loop_it_2 -> "
+ "~n NOid: ~p"
+ "~n Value: ~p",[NOid, Value]),
+ ?line [Value2] = get_req(1, [NOid]), % must not be same
+ ?DBG("loop_it_2 -> "
+ "~n Value2: ~p",[Value2]),
+ loop_it_2(NOid, N+1);
+
+ #pdu{type = 'get-response',
+ error_status = noError,
+ error_index = 0,
+ varbinds = Vbs} ->
+ exit({unexpected_pdu, ?LINE,
+ [{varbinds, Vbs},
+ {get_next_oid, Oid},
+ {counter, N}]});
+
+ #pdu{type = 'get-response',
+ error_status = ES,
+ error_index = EI,
+ varbinds = Vbs} ->
+ exit({unexpected_pdu, ?LINE,
+ [{error_status, ES},
+ {error_index, EI},
+ {varbinds, Vbs},
+ {get_next_oid, Oid},
+ {counter, N}]});
+
+ #pdu{type = Type,
+ error_status = ES,
+ error_index = EI,
+ varbinds = Vbs} ->
+ exit({unexpected_pdu, ?LINE,
+ [{type, Type},
+ {error_status, ES},
+ {error_index, EI},
+ {varbinds, Vbs},
+ {get_next_oid, Oid},
+ {counter, N}]});
+
+ {error, Reason} ->
+ exit({unexpected_result, ?LINE,
+ [{reason, Reason},
+ {get_next_oid, Oid},
+ {counter, N}]})
+
+ end.
+
+
+%%%-----------------------------------------------------------------
+%%% Testing of reported bugs and other tickets.
+%%%-----------------------------------------------------------------
+
+reported_bugs(suite) ->
+ [
+ otp_1128,
+ otp_1129,
+ otp_1131,
+ otp_1162,
+ otp_1222,
+ otp_1298,
+ otp_1331,
+ otp_1338,
+ otp_1342,
+ otp_2776,
+ otp_2979,
+ otp_3187,
+ otp_3725
+ ].
+
+reported_bugs_2(suite) ->
+ [
+ otp_1128_2,
+ otp_1129_2,
+ otp_1131_2,
+ otp_1162_2,
+ otp_1222_2,
+ otp_1298_2,
+ otp_1331_2,
+ otp_1338_2,
+ otp_1342_2,
+ otp_2776_2,
+ otp_2979_2,
+ otp_3187_2
+ ].
+
+reported_bugs_3(suite) ->
+ [
+ otp_1128_3,
+ otp_1129_3,
+ otp_1131_3,
+ otp_1162_3,
+ otp_1222_3,
+ otp_1298_3,
+ otp_1331_3,
+ otp_1338_3,
+ otp_1342_3,
+ otp_2776_3,
+ otp_2979_3,
+ otp_3187_3,
+ otp_3542
+ ].
+
+
+%% These are (ticket) test cases where the initiation has to be done
+%% individually.
+tickets(suite) ->
+ [
+ otp_4394,
+ otp_7157
+ ].
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-1128
+%% Slogan: Bug in handling of createAndWait set-requests.
+%%-----------------------------------------------------------------
+otp_1128(suite) -> [];
+otp_1128(Config) when is_list(Config) ->
+ ?P(otp_1128),
+ init_case(Config),
+
+ ?line load_master("OLD-SNMPEA-MIB"),
+ ?line init_old(),
+ try_test(otp_1128),
+ ?line unload_master("OLD-SNMPEA-MIB").
+
+otp_1128_2(X) -> ?P(otp_1128_2), otp_1128(X).
+
+otp_1128_3(X) -> ?P(otp_1128_3), otp_1128(X).
+
+otp_1128() ->
+ io:format("Testing bug reported in ticket OTP-1128...~n"),
+
+ NewKeyc3 = [intCommunityViewIndex,get(mip),is("test")],
+ NewKeyc4 = [intCommunityAccess,get(mip),is("test")],
+ NewKeyc5 = [intCommunityStatus,get(mip),is("test")],
+
+ s([{NewKeyc5, ?createAndWait}, {NewKeyc4, 2}]),
+ ?line expect(28, [{NewKeyc5, ?createAndWait}, {NewKeyc4, 2}]),
+ g([NewKeyc5]),
+ ?line expect(29, [{NewKeyc5, ?notReady}]),
+ s([{NewKeyc5, ?active}, {NewKeyc3, 2}]),
+ ?line expect(30, [{NewKeyc5, ?active}, {NewKeyc3, 2}]),
+ g([NewKeyc5]),
+ ?line expect(31, [{NewKeyc5, ?active}]),
+ s([{NewKeyc5, ?destroy}]),
+ ?line expect(32, [{NewKeyc5, ?destroy}]).
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-1129, OTP-1169
+%% Slogan: snmpa:int_to_enum crashes on bad oids
+%%-----------------------------------------------------------------
+otp_1129(suite) -> [];
+otp_1129(Config) when is_list(Config) ->
+ ?P(otp_1129),
+ init_case(Config),
+ ?line load_master("Klas3"),
+ try_test(otp_1129_i, [node()]),
+ ?line unload_master("Klas3").
+
+otp_1129_2(X) -> ?P(otp_1129_2), otp_1129(X).
+
+otp_1129_3(X) -> ?P(otp_1129_3), otp_1129(X).
+
+otp_1129_i(MaNode) ->
+ io:format("Testing bug reported in ticket OTP-1129...~n"),
+ false = rpc:call(MaNode, snmp, int_to_enum, [iso, 1]),
+ false = rpc:call(MaNode, snmp, int_to_enum, [isox, 1]).
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-1131
+%% Slogan: Agent crashes / erlang node halts if RowIndex in a
+%% setrequest is of bad type, e.g. an INDEX {INTEGER},
+%% and RowIdenx [3,2].
+%%-----------------------------------------------------------------
+otp_1131(suite) -> [];
+otp_1131(Config) when is_list(Config) ->
+ ?P(otp_1131),
+ init_case(Config),
+
+ ?line load_master("Klas1"),
+ try_test(otp_1131),
+ ?line unload_master("Klas1").
+
+otp_1131_2(X) -> ?P(otp_1131_2), otp_1131(X).
+
+otp_1131_3(X) ->
+ %% <CONDITIONAL-SKIP>
+ Skippable = [{unix, [darwin]}],
+ Condition = fun() -> ?OS_BASED_SKIP(Skippable) end,
+ ?NON_PC_TC_MAYBE_SKIP(X, Condition),
+ %% </CONDITIONAL-SKIP>
+
+ ?P(otp_1131_3),
+ otp_1131(X).
+
+otp_1131() ->
+ io:format("Testing bug reported in ticket OTP-1131...~n"),
+ s([{[friendsEntry, [2, 3, 1]], s, "kompis3"},
+ {[friendsEntry, [3, 3, 1]], i, ?createAndGo}]),
+ ?line expect(1, ?v1_2(noSuchName, noCreation), 2, any).
+
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-1162
+%% Slogan: snmp_agent can't handle wrongValue from instrum.func
+%%-----------------------------------------------------------------
+otp_1162(suite) -> [];
+otp_1162(Config) when is_list(Config) ->
+ ?P(otp_1162),
+ {SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?line {ok, SA} = start_subagent(SaNode, ?sa, "SA-MIB"),
+ try_test(otp_1162),
+ stop_subagent(SA).
+
+otp_1162_2(X) -> ?P(otp_1162_2), otp_1162(X).
+
+otp_1162_3(X) -> ?P(otp_1162_3), otp_1162(X).
+
+otp_1162() ->
+ s([{[sa, [2,0]], 6}]), % wrongValue (i is_set_ok)
+ ?line expect(1, ?v1_2(badValue, wrongValue), 1, any).
+
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-1222
+%% Slogan: snmp agent crash if faulty index is returned from instrum
+%%-----------------------------------------------------------------
+otp_1222(suite) -> [];
+otp_1222(Config) when is_list(Config) ->
+ ?P(otp_1222),
+ init_case(Config),
+ ?line load_master("Klas3"),
+ ?line load_master("Klas4"),
+ try_test(otp_1222),
+ ?line unload_master("Klas3"),
+ ?line unload_master("Klas4").
+
+otp_1222_2(X) -> ?P(otp_1222_2), otp_1222(X).
+
+otp_1222_3(X) -> ?P(otp_1222_3), otp_1222(X).
+
+otp_1222() ->
+ io:format("Testing bug reported in ticket OTP-1222...~n"),
+ s([{[fStatus4,1], 4}, {[fName4,1], 1}]),
+ ?line expect(1, genErr, 0, any),
+ s([{[fStatus4,2], 4}, {[fName4,2], 1}]),
+ ?line expect(2, genErr, 0, any).
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-1298
+%% Slogan: Negative INTEGER values are treated as positive.
+%%-----------------------------------------------------------------
+otp_1298(suite) -> [];
+otp_1298(Config) when is_list(Config) ->
+ ?P(otp_1298),
+ init_case(Config),
+
+ ?line load_master("Klas2"),
+ try_test(otp_1298),
+ ?line unload_master("Klas2").
+
+otp_1298_2(X) -> ?P(otp_1298_2), otp_1298(X).
+
+otp_1298_3(X) -> ?P(otp_1298_3), otp_1298(X).
+
+otp_1298() ->
+ io:format("Testing bug reported in ticket OTP-1298...~n"),
+ s([{[fint,0], -1}]),
+ ?line expect(1298, [{[fint,0], -1}]).
+
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-1331
+%% Slogan: snmp_generic should return noError when deleting non-ex row
+%%-----------------------------------------------------------------
+otp_1331(suite) -> [];
+otp_1331(Config) when is_list(Config) ->
+ ?P(otp_1331),
+ init_case(Config),
+ ?line load_master("OLD-SNMPEA-MIB"),
+ ?line init_old(),
+ try_test(otp_1331),
+ ?line unload_master("OLD-SNMPEA-MIB").
+
+otp_1331_2(X) -> ?P(otp_1331_2), otp_1331(X).
+
+otp_1331_3(X) -> ?P(otp_1331_3), otp_1331(X).
+
+otp_1331() ->
+ NewKeyc5 = [intCommunityStatus,[127,32,0,0],is("test")],
+ s([{NewKeyc5, ?destroy}]),
+ ?line expect(1, [{NewKeyc5, ?destroy}]).
+
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-1338
+%% Slogan: snmp bug in initialisation of default values for mnesia tabs
+%%-----------------------------------------------------------------
+otp_1338(suite) -> [];
+otp_1338(Config) when is_list(Config) ->
+ ?P(otp_1338),
+ init_case(Config),
+
+ ?line load_master("Klas2"),
+ try_test(otp_1338),
+ ?line unload_master("Klas2").
+
+otp_1338_2(X) -> ?P(otp_1338_2), otp_1338(X).
+
+otp_1338_3(X) -> ?P(otp_1338_3), otp_1338(X).
+
+otp_1338() ->
+ s([{[kStatus2, 7], i, ?createAndGo}]),
+ ?line expect(1, [{[kStatus2, 7], ?createAndGo}]),
+ g([[kName2, 7]]),
+ ?line expect(2, [{[kName2, 7], "JJJ"}]).
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-1342
+%% Slogan: default impl of snmp table can't handle bad index access,
+%% Set when INDEX is read-write gets into an infinite loop!
+%%-----------------------------------------------------------------
+otp_1342(suite) -> [];
+otp_1342(Config) when is_list(Config) ->
+ ?P(otp_1342),
+ init_case(Config),
+ ?line load_master("Klas4"),
+ try_test(otp_1342),
+ ?line unload_master("Klas4").
+
+otp_1342_2(X) -> ?P(otp_1342_2), otp_1342(X).
+
+otp_1342_3(X) -> ?P(otp_1342_3), otp_1342(X).
+
+otp_1342() ->
+ s([{[fIndex5, 1], i, 1},
+ {[fName5, 1], i, 3},
+ {[fStatus5, 1], i, ?createAndGo}]),
+ ?line expect(1, ?v1_2(noSuchName, noCreation), 3, any).
+
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-1366
+%% Slogan: snmp traps not sent to all managers
+%% Note: NYI! We need a way to tell the test server that we need
+%% mgrs on two different machines.
+%%-----------------------------------------------------------------
+otp_1366(suite) -> [];
+otp_1366(Config) when is_list(Config) ->
+ ?P(otp_1366),
+ init_case(Config),
+ ?line load_master("OLD-SNMPEA-MIB"),
+ ?line init_old(),
+ try_test(otp_1366),
+ ?line unload_master("OLD-SNMPEA-MIB").
+
+otp_1366_2(X) -> ?P(otp_1366_2), otp_1366(X).
+
+otp_1366_3(X) -> ?P(otp_1366_3), otp_1366(X).
+
+otp_1366() ->
+ ?INF("NOT YET IMPLEMENTED", []),
+ 'NYI'.
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-2776
+%% Slogan: snmp:validate_date_and_time() fails when time is 00:00
+%%-----------------------------------------------------------------
+otp_2776(suite) -> [];
+otp_2776(Config) when is_list(Config) ->
+ ?P(otp_2776),
+ init_case(Config),
+ try_test(otp_2776).
+
+otp_2776_2(X) -> ?P(otp_2776_2), otp_2776(X).
+
+otp_2776_3(X) -> ?P(otp_2776_3), otp_2776(X).
+
+otp_2776() ->
+ io:format("Testing bug reported in ticket OTP-2776...~n"),
+
+ Dt01_valid = [19,98,9,1,1,0,23,0,43,0,0],
+ Dt02_valid = [19,98,9,1,0,0,0,0,43,0,0], % This is what is fixed: 00:00
+ Dt03_valid = [19,98,2,28,1,0,23,0,43,0,0],
+ Dt04_invalid = [19,98,2,29,1,0,23,0,43,0,0],
+ Dt05_valid = [19,96,2,29,1,0,23,0,43,0,0],
+ Dt06_valid = [20,0,2,29,1,0,23,0,43,0,0],
+ Dt07_invalid = [19,96,2,30,1,0,23,0,43,0,0], % This is also fixed: 30/2
+ Dt08_valid = [19,98,4,30,1,0,23,0,43,0,0],
+ Dt09_invalid = [19,98,4,31,1,0,23,0,43,0,0], % This is also fixed: 31/4
+ Dt10_invalid = [],
+ Dt11_invalid = [kalle,hobbe],
+ L = [{ 1, true, Dt01_valid},
+ { 2, true, Dt02_valid},
+ { 3, true, Dt03_valid},
+ { 4, false, Dt04_invalid},
+ { 5, true, Dt05_valid},
+ { 6, true, Dt06_valid},
+ { 7, false, Dt07_invalid},
+ { 8, true, Dt08_valid},
+ { 9, false, Dt09_invalid},
+ {10, false, Dt10_invalid},
+ {11, false, Dt11_invalid}],
+
+ ?line ok = validate_dat(L).
+
+
+validate_dat(L) -> validate_dat(L,[]).
+
+validate_dat([],V) ->
+ Fun = fun({_,X}) -> case X of
+ ok -> false;
+ _ -> true
+ end
+ end,
+ validate_dat1( lists:reverse( lists:filter(Fun,V) ) );
+validate_dat([{Id,E,Dat}|T],V) ->
+ validate_dat(T,[validate_dat2(Id,E,Dat) | V]).
+
+validate_dat1([]) -> ok;
+validate_dat1(L) -> {error,L}.
+
+validate_dat2(Id, E, Dat) ->
+ Res = case {E,snmp:validate_date_and_time(Dat)} of
+ {E,E} -> ok;
+ {E,A} -> {E,A}
+ end,
+ {Id, Res}.
+
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-2979
+%% Slogan: get-next on more than 1 column in an empty table
+%% returns bad response.
+%%-----------------------------------------------------------------
+otp_2979(suite) -> [];
+otp_2979(Config) when is_list(Config) ->
+ ?P(otp_2979),
+ init_case(Config),
+ ?line load_master("Test1"),
+ ?line init_old(),
+ try_test(otp_2979),
+ ?line unload_master("Test1").
+
+otp_2979_2(X) -> ?P(otp_2979_2), otp_2979(X).
+
+otp_2979_3(X) -> ?P(otp_2979_3), otp_2979(X).
+
+otp_2979() ->
+ gn([[sparseDescr], [sparseStatus]]),
+ ?line expect(1, [{[sparseStr,0], "slut"},
+ {[sparseStr,0], "slut"}]).
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-3187
+%% Slogan: get-next on vacmAccessTable for colums > 5 returns
+%% endOfTable - should return value.
+%%-----------------------------------------------------------------
+otp_3187(suite) -> [];
+otp_3187(Config) when is_list(Config) ->
+ ?P(otp_3187),
+ init_case(Config),
+ ?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"),
+ otp_3187(),
+ ?line unload_master("SNMP-VIEW-BASED-ACM-MIB").
+
+otp_3187_2(X) -> ?P(otp_3187_2), otp_3187(X).
+
+otp_3187_3(X) -> ?P(otp_3187_3), otp_3187(X).
+
+otp_3187() ->
+ ?line Elements =
+ snmp_view_based_acm_mib:vacmAccessTable(get_next,[],[4,5,6]),
+ lists:foreach(fun(E) ->
+ ?line if E == endOfTable ->
+ ?FAIL(endOfTable);
+ true -> ok
+ end
+ end, Elements).
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-3542
+%% Slogan:
+%%-----------------------------------------------------------------
+otp_3542(suite) -> [];
+otp_3542(Config) when is_list(Config) ->
+ ?P(otp_3542),
+ init_case(Config),
+ try_test(otp_3542).
+
+otp_3542() ->
+ io:format("SNMP v3 discovery...~n"),
+ ?line Res = snmp_test_mgr:d(),
+ io:format("SNMP v3 discovery result: ~p~n",[Res]).
+
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-3725
+%% Slogan: Slow response time on snmpa:int_to_enum
+%%-----------------------------------------------------------------
+otp_3725(suite) -> [];
+otp_3725(Config) when is_list(Config) ->
+ ?P(otp_3725),
+ init_case(Config),
+
+ ?line load_master("OLD-SNMPEA-MIB"),
+ ?line init_old(),
+ try_test(otp_3725_test, [node()]),
+ ?line unload_master("OLD-SNMPEA-MIB").
+
+%% Req. OLD-SNMPEA-MIB
+otp_3725_test(MaNode) ->
+ io:format("Testing feature requested in ticket OTP-3725...~n"),
+ ?line rpc:call(MaNode,snmpa,verbosity,[symbolic_store,trace]),
+ ?line Db = rpc:call(MaNode,snmp,get_symbolic_store_db,[]),
+ ?DBG("otp_3725_test -> Db = ~p",[Db]),
+
+ ?line {value, OID} = rpc:call(MaNode, snmp, name_to_oid,
+ [Db, intAgentIpAddress]),
+ ?DBG("otp_3725_test -> name_to_oid for ~p: ~p",[intAgentIpAddress,OID]),
+ ?line {value, intAgentIpAddress} = rpc:call(MaNode, snmp, oid_to_name,
+ [Db,OID]),
+ ?DBG("otp_3725_test -> oid_to_name for ~p: ~p",[OID,intAgentIpAddress]),
+ ?line false = rpc:call(MaNode, snmp, name_to_oid, [Db, intAgentIpAddres]),
+ ?line false = rpc:call(MaNode, snmp, oid_to_name,
+ [Db, [1,5,32,3,54,3,3,34,4]]),
+ ?line {value, 2} = rpc:call(MaNode, snmp, enum_to_int,
+ [Db, intViewType, excluded]),
+ ?line {value, excluded} = rpc:call(MaNode, snmp, int_to_enum,
+ [Db, intViewType, 2]),
+ ?line false = rpc:call(MaNode, snmp, enum_to_int,
+ [Db, intViewType, exclude]),
+ ?line false = rpc:call(MaNode, snmp, enum_to_int,
+ [Db, intAgentIpAddress, exclude]),
+ ?line false = rpc:call(MaNode, snmp, enum_to_int,
+ [Db, intAgentIpAddre, exclude]),
+ ?line false = rpc:call(MaNode, snmp, int_to_enum, [Db, intViewType, 3]),
+ ?line false = rpc:call(MaNode, snmp, int_to_enum,
+ [Db, intAgentIpAddress, 2]),
+ ?line false = rpc:call(MaNode, snmp, int_to_enum,
+ [Db, intAgentIpAddre, 2]),
+ ?line {value, active} = rpc:call(MaNode, snmp, int_to_enum,
+ [Db, 'RowStatus', ?active]),
+ ?line {value, ?destroy} = rpc:call(MaNode, snmp, enum_to_int,
+ [Db, 'RowStatus', destroy]),
+ ?line false = rpc:call(MaNode, snmp, enum_to_int,
+ [Db, 'RowStatus', xxxdestroy]),
+ ?line false = rpc:call(MaNode, snmp, enum_to_int,
+ [Db, 'xxRowStatus', destroy]),
+ ?line false = rpc:call(MaNode, snmp, int_to_enum, [Db, 'RowStatus', 25]),
+ ?line false = rpc:call(MaNode, snmp, int_to_enum, [Db, 'xxRowStatus', 1]),
+ ok.
+
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-4394
+%% Slogan: Target mib tag list check invalid
+%%-----------------------------------------------------------------
+
+
+otp_4394(suite) -> {req, [], {conf,
+ init_otp_4394,
+ [otp_4394_test],
+ finish_otp_4394}}.
+
+init_otp_4394(Config) when is_list(Config) ->
+ ?DBG("init_otp_4394 -> entry with"
+ "~n Config: ~p", [Config]),
+ ?line AgentDir = ?config(agent_dir, Config),
+ ?line MgrDir = ?config(mgr_dir, Config),
+ ?line Ip = ?config(ip, Config),
+ ?line otp_4394_config(AgentDir, MgrDir, Ip),
+ MasterAgentVerbosity = {master_agent_verbosity, trace},
+ NetIfVerbosity = {net_if_verbosity, trace},
+ Opts = [MasterAgentVerbosity,NetIfVerbosity],
+ [{vsn, v1} | start_v1_agent(Config,Opts)].
+
+otp_4394_config(AgentDir, MgrDir, Ip0) ->
+ ?DBG("otp_4394_config -> entry with"
+ "~n AgentDir: ~p"
+ "~n MgrDir: ~p"
+ "~n Ip0: ~p", [AgentDir, MgrDir, Ip0]),
+ Vsn = [v1],
+ Ip = tuple_to_list(Ip0),
+ ?line snmp_config:write_agent_snmp_files(AgentDir, Vsn, Ip,
+ ?TRAP_UDP, Ip, 4000,
+ "OTP-4394 test"),
+ ?line case update_usm(Vsn, AgentDir) of
+ true ->
+ ?line copy_file(filename:join(AgentDir, "usm.conf"),
+ filename:join(MgrDir, "usm.conf")),
+ ?line update_usm_mgr(Vsn, MgrDir);
+ false ->
+ ?line ok
+ end,
+ C1 = {"a", "all-rights", "initial", "", "pc"},
+ C2 = {"c", "secret", "secret_name", "", "secret_tag"},
+ ?line write_community_conf(AgentDir, [C1, C2]),
+ ?line update_vacm(Vsn, AgentDir),
+ Ta1 = {"shelob v1",
+ [134,138,177,177], 5000, 1500, 3, %% Anv�nd Ip och modda
+ "pc1",
+ "target_v1", "",
+ %% [255,255,255,255,0,0],
+ [],
+ 2048},
+ Ta2 = {"bifur v1",
+ [134,138,177,75], 5000, 1500, 3, %% Anv�nd Ip
+ "pc2",
+ "target_v1", "",
+ %% [255,255,255,255,0,0],
+ [], 2048},
+ ?line write_target_addr_conf(AgentDir, [Ta1, Ta2]),
+ ?line write_target_params_conf(AgentDir, Vsn),
+ ?line write_notify_conf(AgentDir),
+ ok.
+
+
+
+finish_otp_4394(Config) when is_list(Config) ->
+ ?DBG("finish_otp_4394 -> entry", []),
+ C1 = stop_agent(Config),
+ delete_files(C1),
+ erase(mgr_node),
+ lists:keydelete(vsn, 1, C1).
+
+otp_4394_test(suite) -> [];
+otp_4394_test(Config) ->
+ ?P(otp_4394_test),
+ ?DBG("otp_4394_test -> entry", []),
+ init_case(Config),
+ try_test(otp_4394_test1),
+ ?DBG("otp_4394_test -> done", []),
+ ok.
+
+otp_4394_test1() ->
+ ?DBG("otp_4394_test1 -> entry", []),
+ gn([[1,1]]),
+ Res =
+ case snmp_test_mgr:expect(1, [{[sysDescr,0], "Erlang SNMP agent"}]) of
+ %% {error, 1, {"?",[]}, {"~w",[timeout]}}
+ {error, 1, _, {_, [timeout]}} ->
+ ?DBG("otp_4394_test1 -> expected result: timeout", []),
+ ok;
+ Else ->
+ Else
+ end,
+ ?DBG("otp_4394_test1 -> done with: ~p", [Res]),
+ Res.
+
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-7157
+%% Slogan: Target mib tag list check invalid
+%%-----------------------------------------------------------------
+
+
+otp_7157(suite) ->
+ {req, [], {conf,
+ init_otp_7157,
+ [otp_7157_test],
+ finish_otp_7157}}.
+
+init_otp_7157(Config) when is_list(Config) ->
+ %% <CONDITIONAL-SKIP>
+ Skippable = [win32],
+ Condition = fun() -> ?OS_BASED_SKIP(Skippable) end,
+ ?NON_PC_TC_MAYBE_SKIP(Config, Condition),
+ %% </CONDITIONAL-SKIP>
+
+ ?DBG("init_otp_7157 -> entry with"
+ "~n Config: ~p", [Config]),
+ ?line AgentDir = ?config(agent_dir, Config),
+ ?line MgrDir = ?config(mgr_dir, Config),
+ ?line Ip = ?config(ip, Config),
+ ?line config([v2], MgrDir, AgentDir, tuple_to_list(Ip), tuple_to_list(Ip)),
+ MasterAgentVerbosity = {master_agent_verbosity, trace},
+ NetIfVerbosity = {net_if_verbosity, trace},
+ Opts = [MasterAgentVerbosity, NetIfVerbosity],
+ [{vsn, v2} | start_v2_agent(Config, Opts)].
+
+
+finish_otp_7157(Config) when is_list(Config) ->
+ ?DBG("finish_otp_7157 -> entry", []),
+ C1 = stop_agent(Config),
+ delete_files(C1),
+ erase(mgr_node),
+ lists:keydelete(vsn, 1, C1).
+
+otp_7157_test(suite) -> [];
+otp_7157_test(Config) ->
+ ?P(otp_7157_test),
+ ?DBG("otp_7157_test -> entry", []),
+ init_case(Config),
+ MA = whereis(snmp_master_agent),
+ ?line load_master("Test1"),
+ try_test(otp_7157_test1, [MA]),
+ ?line unload_master("Test1"),
+ ?DBG("otp_7157_test -> done", []),
+ ok.
+
+%% ts:run(snmp, snmp_agent_test, [batch]).
+otp_7157_test1(MA) ->
+ ?LOG("start otp_7157_test1 test (~p)",[MA]),
+ snmpa:verbosity(MA, trace),
+ ?LOG("start otp_7157_test1 test",[]),
+ ?P1("Testing that varbinds in traps/notifications are not reordered"),
+
+ ?DBG("send cntTrap",[]),
+ snmpa:send_trap(MA, cntTrap, "standard trap"),
+
+ ?DBG("await response",[]),
+ %% We don't really care about the values, just the vb order.
+ ?line ok = expect(1, v2trap, [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], any},
+ {[sysContact, 0], any},
+ {[cnt64, 0], any},
+ {[sysLocation, 0], any}]),
+
+ ?DBG("done", []),
+ ok.
+
+
+
+%%-----------------------------------------------------------------
+%% Slogan: info test
+%%-----------------------------------------------------------------
+
+info_test(suite) -> [];
+info_test(Config) when is_list(Config) ->
+ ?P(info_test),
+ init_case(Config),
+
+ ?line load_master("OLD-SNMPEA-MIB"),
+ ?line init_old(),
+ try_test(info_test1, [node()]),
+ ?line unload_master("OLD-SNMPEA-MIB").
+
+info_test1(MaNode) ->
+ ?line Info = rpc:call(MaNode, snmpa, info, []),
+ ?DBG("info_test1 -> Info: ~n~p", [Info]),
+ Keys = [vsns,
+ stats_counters,
+ {agent, [process_memory, db_memory]},
+ {net_if, [process_memory, port_info, reqs]},
+ {note_store, [process_memory, db_memory]},
+ {symbolic_store, [process_memory, db_memory]},
+ {local_db, [process_memory, db_memory]},
+ {mib_server, [process_memory,
+ loaded_mibs,
+ subagents,
+ tree_size_bytes,
+ db_memory]}],
+ verify_info(Info, Keys),
+ OldInfo = snmpa:old_info_format(Info),
+ ?DBG("info_test1 -> OldInfo: ~n~p", [OldInfo]),
+ verify_old_info(OldInfo),
+ ok.
+
+verify_info([], []) ->
+ ok;
+verify_info([], Keys) ->
+ ?FAIL({remaining_info_keys, Keys});
+verify_info(Info0, [Key|Keys]) ->
+ Info = verify_info1(Info0, Key),
+ verify_info(Info, Keys).
+
+verify_info1(Info0, Key) when is_atom(Key) ->
+ case lists:keydelete(Key, 1, Info0) of
+ Info0 ->
+ ?FAIL({missing_info, Key});
+ Info ->
+ Info
+ end;
+verify_info1(Info0, {Key, SubKeys}) when is_atom(Key) andalso is_list(SubKeys) ->
+ case lists:keysearch(Key, 1, Info0) of
+ false ->
+ ?FAIL({missing_info, Key});
+ {value, {Key, SubInfo}} ->
+ case verify_subinfo(SubInfo, SubKeys) of
+ ok ->
+ lists:keydelete(Key, 1, Info0);
+ {error, MissingSubKeyOrKeys} ->
+ ?FAIL({missing_info, {Key, MissingSubKeyOrKeys}})
+ end
+ end.
+
+verify_subinfo(_, []) ->
+ ok;
+verify_subinfo([], Keys) ->
+ {error, Keys};
+verify_subinfo(Info0, [Key|Keys]) ->
+ case lists:keydelete(Key, 1, Info0) of
+ Info0 ->
+ {error, Key};
+ Info ->
+ verify_subinfo(Info, Keys)
+ end.
+
+verify_old_info(Info) ->
+ Keys = [vsns, subagents, loaded_mibs,
+ tree_size_bytes, process_memory, db_memory],
+ verify_old_info(Keys, Info).
+
+verify_old_info([], _) ->
+ ok;
+verify_old_info([Key|Keys], Info) ->
+ case lists:keymember(Key, 1, Info) of
+ true ->
+ verify_old_info(Keys, Info);
+ false ->
+ ?FAIL({missing_old_info, Key})
+ end.
+
+%% string used in index
+is(S) -> [length(S) | S].
+
+try_test(Func) ->
+ snmp_agent_test_lib:try_test(?MODULE, Func).
+
+try_test(Func, A) ->
+ snmp_agent_test_lib:try_test(?MODULE, Func, A).
+
+try_test(Func, A, Opts) ->
+ snmp_agent_test_lib:try_test(?MODULE, Func, A, Opts).
+
+
+%% Test manager wrapperfunctions:
+g(Oids) -> snmp_test_mgr:g(Oids).
+gn() -> snmp_test_mgr:gn().
+gn(OidsOrN) -> snmp_test_mgr:gn(OidsOrN).
+gb(NR, MR, Oids) -> snmp_test_mgr:gb(NR, MR, Oids).
+s(VAV) -> snmp_test_mgr:s(VAV).
+
+expect(A, B) -> snmp_agent_test_lib:expect(A, B).
+expect(A, B, C) -> snmp_agent_test_lib:expect(A, B, C).
+expect(A, B, C, D) -> snmp_agent_test_lib:expect(A, B, C, D).
+expect(A, B, C, D, E, F) -> snmp_agent_test_lib:expect(A, B, C, D, E, F).
+
+get_req(Id, Vars) ->
+ snmp_agent_test_lib:get_req(Id, Vars).
+
+get_next_req(Vars) ->
+ snmp_agent_test_lib:get_next_req(Vars).
+
+
+start_node(Name) ->
+ snmp_agent_test_lib:start_node(Name).
+
+stop_node(Node) ->
+ snmp_agent_test_lib:stop_node(Node).
+
+
+%%%-----------------------------------------------------------------
+%%% Configuration
+%%%-----------------------------------------------------------------
+delete_files(Config) ->
+ snmp_agent_test_lib:delete_files(Config).
+
+config(Vsns, MgrDir, AgentDir, MIp, AIp) ->
+ snmp_agent_test_lib:config(Vsns, MgrDir, AgentDir, MIp, AIp).
+
+update_usm(Vsns, Dir) ->
+ snmp_agent_test_lib:update_usm(Vsns, Dir).
+
+update_usm_mgr(Vsns, Dir) ->
+ snmp_agent_test_lib:update_usm_mgr(Vsns, Dir).
+
+rewrite_usm_mgr(Dir, ShaKey, DesKey) ->
+ snmp_agent_test_lib:rewrite_usm_mgr(Dir, ShaKey, DesKey).
+
+reset_usm_mgr(Dir) ->
+ snmp_agent_test_lib:reset_usm_mgr(Dir).
+
+update_community(Vsns, DIr) ->
+ snmp_agent_test_lib:update_community(Vsns, DIr).
+
+update_vacm(Vsn, Dir) ->
+ snmp_agent_test_lib:update_vacm(Vsn, Dir).
+
+write_community_conf(Dir, Conf) ->
+ snmp_agent_test_lib:write_community_conf(Dir, Conf).
+
+write_target_addr_conf(Dir, Conf) ->
+ snmp_agent_test_lib:write_target_addr_conf(Dir, Conf).
+
+write_target_addr_conf(Dir, ManagerIp, UDP, Vsns) ->
+ snmp_agent_test_lib:write_target_addr_conf(Dir, ManagerIp, UDP, Vsns).
+
+rewrite_target_addr_conf(Dir, NewPort) ->
+ snmp_agent_test_lib:rewrite_target_addr_conf(Dir, NewPort).
+
+
+reset_target_addr_conf(Dir) ->
+ snmp_agent_test_lib:reset_target_addr_conf(Dir).
+
+write_target_params_conf(Dir, Vsns) ->
+ snmp_agent_test_lib:write_target_params_conf(Dir, Vsns).
+
+rewrite_target_params_conf(Dir, SecName, SecLevel) ->
+ snmp_agent_test_lib:rewrite_target_params_conf(Dir, SecName, SecLevel).
+
+reset_target_params_conf(Dir) ->
+ snmp_agent_test_lib:reset_target_params_conf(Dir).
+
+write_notify_conf(Dir) ->
+ snmp_agent_test_lib:write_notify_conf(Dir).
+
+write_view_conf(Dir) ->
+ snmp_agent_test_lib:write_view_conf(Dir).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+copy_file(From, To) ->
+ snmp_agent_test_lib:copy_file(From, To).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+display_memory_usage() ->
+ Info = snmpa:info(snmp_master_agent),
+ AMU = display_agent_memory_uasge(Info),
+ NIMU = display_net_if_memory_usage(Info),
+ NSMU = display_note_store_memory_usage(Info),
+ SSMU = display_symbolic_store_memory_usage(Info),
+ LDBMU = display_local_db_memory_usage(Info),
+ MSMU = display_mib_server_memory_usage(Info),
+ ?INF("Memory usage: ~n" ++
+ AMU ++ NIMU ++ NSMU ++ SSMU ++ LDBMU ++ MSMU, []),
+ ok.
+
+display_agent_memory_uasge(Info) ->
+ AgentInfo = lists_key1search(agent, Info),
+ ProcMem =
+ lists_key1search([process_memory,master_agent], AgentInfo),
+ WProcMem =
+ lists_key1search([process_memory,worker], AgentInfo),
+ SWProcMem =
+ lists_key1search([process_memory,set_worker], AgentInfo),
+ TabSize =
+ lists_key1search([db_memory,agent], AgentInfo),
+ CCSize =
+ lists_key1search([db_memory,community_cache], AgentInfo),
+ VacmSize =
+ lists_key1search([db_memory,vacm], AgentInfo),
+ lists:flatten(
+ io_lib:format(" Agent memory usage: "
+ "~n Master process memory size: ~p"
+ "~n Worker process memory size: ~p"
+ "~n Set-worker process memory size: ~p"
+ "~n Agent tab size: ~p"
+ "~n Community cache size: ~p"
+ "~n Vacm tab size: ~p"
+ "~n",
+ [ProcMem, WProcMem, SWProcMem,
+ TabSize, CCSize, VacmSize])).
+
+display_net_if_memory_usage(Info) ->
+ NiInfo = lists_key1search(net_if, Info),
+ ProcMem = lists_key1search(process_memory, NiInfo),
+ lists:flatten(
+ io_lib:format(" Net if memory usage: "
+ "~n Process memory size: ~p"
+ "~n",[ProcMem])).
+
+display_note_store_memory_usage(Info) ->
+ NsInfo = lists_key1search(note_store, Info),
+ ProcMem = lists_key1search([process_memory,notes], NsInfo),
+ ProcTmrMem = lists_key1search([process_memory,timer], NsInfo),
+ TabSize = lists_key1search([db_memory,notes], NsInfo),
+ lists:flatten(
+ io_lib:format(" Note store memory usage: "
+ "~n Notes process memory size: ~p"
+ "~n Timer process memory size: ~p"
+ "~n Notes tab size: ~p"
+ "~n",
+ [ProcMem, ProcTmrMem, TabSize])).
+
+ display_symbolic_store_memory_usage(Info) ->
+ SsInfo = lists_key1search(symbolic_store, Info),
+ ProcMem = lists_key1search(process_memory, SsInfo),
+ DbMem = lists_key1search(db_memory, SsInfo),
+ lists:flatten(
+ io_lib:format(" Symbolic store memory usage: "
+ "~n Process memory size: ~p"
+ "~n DB size: ~p"
+ "~n",
+ [ProcMem, DbMem])).
+
+display_local_db_memory_usage(Info) ->
+ LdInfo = lists_key1search(local_db, Info),
+ ProcMem = lists_key1search(process_memory, LdInfo),
+ EtsSize = lists_key1search([db_memory,ets], LdInfo),
+ DetsSize = lists_key1search([db_memory,dets], LdInfo),
+ lists:flatten(
+ io_lib:format(" Local DB memory usage: "
+ "~n Process memory size: ~p"
+ "~n DB [ets] size: ~p"
+ "~n DB [dets] size: ~p"
+ "~n",
+ [ProcMem, EtsSize, DetsSize])).
+
+display_mib_server_memory_usage(Info) ->
+ MibInfo = lists_key1search(mib_server, Info),
+ ProcMem = lists_key1search(process_memory, MibInfo),
+ TreeSize = lists_key1search(tree_size_bytes, MibInfo),
+ MibDbSize = lists_key1search([db_memory,mib], MibInfo),
+ NodeDbSize = lists_key1search([db_memory,node], MibInfo),
+ TreeDbSize = lists_key1search([db_memory,tree], MibInfo),
+ lists:flatten(
+ io_lib:format(" MIB server memory usage: "
+ "~n Process memory size: ~p"
+ "~n Tree size: ~p"
+ "~n Mib db size: ~p"
+ "~n Node db size: ~p"
+ "~n Tree db size: ~p"
+ "~n",
+ [ProcMem, TreeSize, MibDbSize, NodeDbSize, TreeDbSize])).
+
+lists_key1search([], Res) ->
+ Res;
+lists_key1search([Key|Keys], List) when is_atom(Key) andalso is_list(List) ->
+ case lists:keysearch(Key, 1, List) of
+ {value, {Key, Val}} ->
+ lists_key1search(Keys, Val);
+ false ->
+ undefined
+ end;
+lists_key1search(Key, List) when is_atom(Key) ->
+ case lists:keysearch(Key, 1, List) of
+ {value, {Key, Val}} ->
+ Val;
+ false ->
+ undefined
+ end.
+
+
+regs() ->
+ lists:sort(registered()).
+
diff --git a/lib/snmp/test/snmp_agent_test_lib.erl b/lib/snmp/test/snmp_agent_test_lib.erl
new file mode 100644
index 0000000000..31b375efa9
--- /dev/null
+++ b/lib/snmp/test/snmp_agent_test_lib.erl
@@ -0,0 +1,1480 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2005-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%
+%%
+
+-module(snmp_agent_test_lib).
+
+
+-export([
+ start_v1_agent/1, start_v1_agent/2,
+ start_v2_agent/1, start_v2_agent/2,
+ start_v3_agent/1, start_v3_agent/2,
+ start_bilingual_agent/1, start_bilingual_agent/2,
+ start_mt_agent/1, start_mt_agent/2,
+ stop_agent/1,
+
+ start_sup/0, stop_sup/2,
+ start_subagent/3, stop_subagent/1,
+ start_sub_sup/1, start_sub_sup/2,
+
+ start_node/1, stop_node/1,
+
+ load_master/1, load_master_std/1, unload_master/1,
+ loaded_mibs/0, unload_mibs/1,
+
+ get_req/2, get_next_req/1,
+
+ config/5,
+ delete_files/1,
+ copy_file/2,
+ update_usm/2,
+ update_usm_mgr/2, rewrite_usm_mgr/3, reset_usm_mgr/1,
+ update_community/2,
+ update_vacm/2,
+ write_community_conf/2,
+ write_target_addr_conf/2, write_target_addr_conf/4,
+ rewrite_target_addr_conf/2, reset_target_addr_conf/1,
+ write_target_params_conf/2, rewrite_target_params_conf/3,
+ reset_target_params_conf/1,
+ write_notify_conf/1, write_view_conf/1,
+
+ display_memory_usage/0,
+
+ init_all/1, finish_all/1,
+ init_case/1,
+ try_test/2, try_test/3, try_test/4,
+ expect/2, expect/3, expect/4, expect/6,
+
+ regs/0,
+ rpc/3
+ ]).
+
+%% Internal exports
+-export([wait/5, run/4]).
+
+-include_lib("kernel/include/file.hrl").
+-include("test_server.hrl").
+-include("snmp_test_lib.hrl").
+-define(SNMP_USE_V3, true).
+-include_lib("snmp/include/snmp_types.hrl").
+
+-define(TRAP_UDP, 5000).
+
+-define(v1_2(V1,V2),
+ case get(vsn) of
+ v1 -> V1;
+ _ -> V2
+ end).
+
+-define(v1_2_3(V1,V2,V3),
+ case get(vsn) of
+ v1 -> V1;
+ v2 -> V2;
+ _ -> V3
+ end).
+
+
+%%%-----------------------------------------------------------------
+%%% The test case structure is as follows:
+%%%
+%%% init_all - starts mnesia,
+%%%
+%%% init_v1 - starts agent
+%%% simple
+%%% big - e.g. starts/stops subagent, load/unloads mibs
+%%% init_mul
+%%% mul_get
+%%% mul_set
+%%% <etc>
+%%% finish_mul
+%%% <etc>
+%%% finish_v1
+%%%
+%%% init_v2 - starts agent
+%%% finish_v2
+%%%
+%%% init_bilingual - starts agent
+%%% finish_bilingual
+%%%
+%%% finish_all
+%%%
+%%% There is still one problem with these testsuites. If one test
+%%% fails, it may not be possible to run some other cases, as it
+%%% may have e.g. created some row or loaded some table, that it
+%%% didn't undo (since it failed).
+%%%-----------------------------------------------------------------
+
+init_all(Config0) when is_list(Config0) ->
+ ?LOG("init_all -> entry with"
+ "~n Config0: ~p",[Config0]),
+
+ %% --
+ %% Fix config:
+ %%
+
+ DataDir0 = ?config(data_dir, Config0),
+ DataDir1 = filename:split(filename:absname(DataDir0)),
+ [_|DataDir2] = lists:reverse(DataDir1),
+ DataDir3 = filename:join(lists:reverse(DataDir2) ++ [?snmp_test_data]),
+ Config1 = lists:keydelete(data_dir, 1, Config0),
+ Config = [{data_dir, DataDir3 ++ "/"}|Config1],
+
+ %% --
+ %% Start nodes
+ %%
+
+ ?line {ok, SaNode} = start_node(snmp_sa),
+ ?line {ok, MgrNode} = start_node(snmp_mgr),
+
+
+ %% --
+ %% Create necessary files
+ %%
+
+ PrivDir = ?config(priv_dir, Config),
+ ?DBG("init_all -> PrivDir ~p", [PrivDir]),
+
+ TopDir = filename:join(PrivDir, snmp_agent_test),
+ case file:make_dir(TopDir) of
+ ok ->
+ ok;
+ {error, eexist} ->
+ ok;
+ Error ->
+ ?FAIL({failed_creating_subsuite_top_dir, Error})
+ end,
+
+ DataDir = ?config(data_dir, Config),
+ ?DBG("init_all -> DataDir ~p", [DataDir]),
+
+ ?line ok = file:make_dir(MgrDir = filename:join(TopDir, "mgr_dir/")),
+ ?DBG("init_all -> MgrDir ~p", [MgrDir]),
+
+ ?line ok = file:make_dir(AgentDir = filename:join(TopDir, "agent_dir/")),
+ ?DBG("init_all -> AgentDir ~p", [AgentDir]),
+
+ ?line ok = file:make_dir(SaDir = filename:join(TopDir, "sa_dir/")),
+ ?DBG("init_all -> SaDir ~p", [SaDir]),
+
+
+ %% --
+ %% Start and initiate mnesia
+ %%
+
+ ?DBG("init_all -> load application mnesia", []),
+ ?line ok = application:load(mnesia),
+
+ ?DBG("init_all -> load application mnesia on node ~p", [SaNode]),
+ ?line ok = rpc:call(SaNode, application, load, [mnesia]),
+
+ ?DBG("init_all -> application mnesia: set_env dir",[]),
+ ?line application_controller:set_env(mnesia, dir,
+ filename:join(TopDir, "Mnesia1")),
+
+ ?DBG("init_all -> application mnesia: set_env dir on node ~p",[SaNode]),
+ ?line rpc:call(SaNode, application_controller, set_env,
+ [mnesia, dir, filename:join(TopDir, "Mnesia2")]),
+
+ ?DBG("init_all -> create mnesia schema",[]),
+ ?line ok = mnesia:create_schema([SaNode, node()]),
+
+ ?DBG("init_all -> start application mnesia",[]),
+ ?line ok = application:start(mnesia),
+
+ ?DBG("init_all -> start application mnesia on ~p",[SaNode]),
+ ?line ok = rpc:call(SaNode, application, start, [mnesia]),
+ Ip = ?LOCALHOST(),
+ [{snmp_sa, SaNode},
+ {snmp_mgr, MgrNode},
+ {agent_dir, AgentDir ++ "/"},
+ {mgr_dir, MgrDir ++ "/"},
+ {sa_dir, SaDir ++ "/"},
+ {mib_dir, DataDir},
+ {ip, Ip} |
+ Config].
+
+
+finish_all(Config) when is_list(Config) ->
+ SaNode = ?config(snmp_sa, Config),
+ MgrNode = ?config(snmp_mgr, Config),
+ stop_node(SaNode),
+ stop_node(MgrNode),
+ application:stop(mnesia).
+
+
+%% --- This one *must* be run first in each case ---
+
+init_case(Config) when is_list(Config) ->
+ ?DBG("init_case -> entry with"
+ "~n Config: ~p", [Config]),
+ SaNode = ?config(snmp_sa, Config),
+ MgrNode = ?config(snmp_mgr, Config),
+ MasterNode = node(),
+
+ SaHost = ?HOSTNAME(SaNode),
+ MgrHost = ?HOSTNAME(MgrNode),
+ MasterHost = ?HOSTNAME(MasterNode),
+ {ok, MasterIP} = snmp_misc:ip(MasterHost),
+ {ok, MIP} = snmp_misc:ip(MgrHost),
+ {ok, SIP} = snmp_misc:ip(SaHost),
+
+
+ put(mgr_node, MgrNode),
+ put(sa_node, SaNode),
+ put(master_node, MasterNode),
+ put(sa_host, SaHost),
+ put(mgr_host, MgrHost),
+ put(master_host, MasterHost),
+ put(mip, tuple_to_list(MIP)),
+ put(masterip, tuple_to_list(MasterIP)),
+ put(sip, tuple_to_list(SIP)),
+
+ MibDir = ?config(mib_dir, Config),
+ put(mib_dir, MibDir),
+ StdM = filename:join(code:priv_dir(snmp), "mibs") ++ "/",
+ put(std_mib_dir, StdM),
+
+ MgrDir = ?config(mgr_dir, Config),
+ put(mgr_dir, MgrDir),
+
+ put(vsn, ?config(vsn, Config)),
+ ?DBG("init_case -> exit with"
+ "~n MasterNode: ~p"
+ "~n SaNode: ~p"
+ "~n MgrNode: ~p"
+ "~n MibDir: ~p", [MasterNode, SaNode, MgrNode, MibDir]),
+ {SaNode, MgrNode, MibDir}.
+
+
+%%%--------------------------------------------------
+%%% Used to test the standard mib with our
+%%% configuration.
+%%%--------------------------------------------------
+
+try_test(Mod, Func) ->
+ call(get(mgr_node), ?MODULE, run, [Mod, Func, [], []]).
+
+try_test(Mod, Func, A) ->
+ call(get(mgr_node), ?MODULE, run, [Mod, Func, A, []]).
+
+try_test(Mod, Func, A, Opts) ->
+ call(get(mgr_node), ?MODULE, run, [Mod, Func, A, Opts]).
+
+call(N,M,F,A) ->
+ ?DBG("call -> entry with~n"
+ " N: ~p~n"
+ " M: ~p~n"
+ " F: ~p~n"
+ " A: ~p~n"
+ " when~n"
+ " get(): ~p",
+ [N,M,F,A,get()]),
+ spawn(N, ?MODULE, wait, [self(),get(),M,F,A]),
+ receive
+ {done, {'EXIT', Rn}, Loc} ->
+ ?DBG("call -> done with exit: "
+ "~n Rn: ~p"
+ "~n Loc: ~p", [Rn, Loc]),
+ put(test_server_loc, Loc),
+ exit(Rn);
+ {done, Ret, Zed} ->
+ ?DBG("call -> done:"
+ "~n Ret: ~p"
+ "~n Zed: ~p", [Ret, Zed]),
+ Ret
+ end.
+
+wait(From, Env, M, F, A) ->
+ ?DBG("wait -> entry with"
+ "~n From: ~p"
+ "~n Env: ~p"
+ "~n M: ~p"
+ "~n F: ~p"
+ "~n A: ~p", [From, Env, M, F, A]),
+ lists:foreach(fun({K,V}) -> put(K,V) end, Env),
+ Rn = (catch apply(M, F, A)),
+ ?DBG("wait -> Rn: ~n~p", [Rn]),
+ From ! {done, Rn, get(test_server_loc)},
+ exit(Rn).
+
+run(Mod, Func, Args, Opts) ->
+ ?DBG("run -> entry with"
+ "~n Mod: ~p"
+ "~n Func: ~p"
+ "~n Args: ~p"
+ "~n Opts: ~p", [Mod, Func, Args, Opts]),
+ M = get(mib_dir),
+ Dir = get(mgr_dir),
+ User = snmp_misc:get_option(user, Opts, "all-rights"),
+ SecLevel = snmp_misc:get_option(sec_level, Opts, noAuthNoPriv),
+ EngineID = snmp_misc:get_option(engine_id, Opts, "agentEngine"),
+ CtxEngineID = snmp_misc:get_option(context_engine_id, Opts, EngineID),
+ Community = snmp_misc:get_option(community, Opts, "all-rights"),
+ ?DBG("run -> start crypto app",[]),
+ Crypto = case os:type() of
+ vxworks ->
+ no_crypto;
+ _ ->
+ ?CRYPTO_START()
+ end,
+ ?DBG("run -> Crypto: ~p", [Crypto]),
+ catch snmp_test_mgr:stop(), % If we had a running mgr from a failed case
+ StdM = filename:join(code:priv_dir(snmp), "mibs") ++ "/",
+ Vsn = get(vsn),
+ ?DBG("run -> config:"
+ "~n M: ~p"
+ "~n Vsn: ~p"
+ "~n Dir: ~p"
+ "~n User: ~p"
+ "~n SecLevel: ~p"
+ "~n EngineID: ~p"
+ "~n CtxEngineID: ~p"
+ "~n Community: ~p"
+ "~n StdM: ~p",
+ [M,Vsn,Dir,User,SecLevel,EngineID,CtxEngineID,Community,StdM]),
+ case snmp_test_mgr:start([%% {agent, snmp_test_lib:hostname()},
+ {packet_server_debug,true},
+ {debug,true},
+ {agent, get(master_host)},
+ {agent_udp, 4000},
+ {trap_udp, 5000},
+ {recbuf,65535},
+ quiet,
+ Vsn,
+ {community, Community},
+ {user, User},
+ {sec_level, SecLevel},
+ {engine_id, EngineID},
+ {context_engine_id, CtxEngineID},
+ {dir, Dir},
+ {mibs, mibs(StdM, M)}]) of
+ {ok, _Pid} ->
+ case (catch apply(Mod, Func, Args)) of
+ {'EXIT', Reason} ->
+ catch snmp_test_mgr:stop(),
+ ?FAIL({apply_failed, {Mod, Func, Args}, Reason});
+ Res ->
+ catch snmp_test_mgr:stop(),
+ Res
+ end;
+ Err ->
+ io:format("Error starting manager: ~p\n", [Err]),
+ catch snmp_test_mgr:stop(),
+ ?line ?FAIL({mgr_start, Err})
+ end.
+
+
+%% ---------------------------------------------------------------
+%% --- ---
+%% --- Start the agent ---
+%% --- ---
+%% ---------------------------------------------------------------
+
+start_v1_agent(Config) when is_list(Config) ->
+ start_agent(Config, [v1]).
+
+start_v1_agent(Config, Opts) when is_list(Config) andalso is_list(Opts) ->
+ start_agent(Config, [v1], Opts).
+
+start_v2_agent(Config) when is_list(Config) ->
+ start_agent(Config, [v2]).
+
+start_v2_agent(Config, Opts) when is_list(Config) andalso is_list(Opts) ->
+ start_agent(Config, [v2], Opts).
+
+start_v3_agent(Config) when is_list(Config) ->
+ start_agent(Config, [v3]).
+
+start_v3_agent(Config, Opts) when is_list(Config) andalso is_list(Opts) ->
+ start_agent(Config, [v3], Opts).
+
+start_bilingual_agent(Config) when is_list(Config) ->
+ start_agent(Config, [v1,v2]).
+
+start_bilingual_agent(Config, Opts) when is_list(Config) andalso is_list(Opts) ->
+ start_agent(Config, [v1,v2], Opts).
+
+start_mt_agent(Config) when is_list(Config) ->
+ start_agent(Config, [v2], [{snmp_multi_threaded, true}]).
+
+start_mt_agent(Config, Opts) when is_list(Config) andalso is_list(Opts) ->
+ start_agent(Config, [v2], [{snmp_multi_threaded, true}|Opts]).
+
+start_agent(Config, Vsns) ->
+ start_agent(Config, Vsns, []).
+start_agent(Config, Vsns, Opts) ->
+ ?LOG("start_agent -> entry (~p) with"
+ "~n Config: ~p"
+ "~n Vsns: ~p"
+ "~n Opts: ~p",[node(), Config, Vsns, Opts]),
+
+ ?line AgentDir = ?config(agent_dir, Config),
+ ?line SaNode = ?config(snmp_sa, Config),
+
+%% AgentConfig =
+%% [{agent_type, master},
+%% %% {multi_threaded, MultiT},
+%% %% {priority, Prio},
+%% %% {error_report_mod, ErrorReportMod},
+%% {versions, Vsns},
+%% {db_dir, AgentDir},
+%% %% {db_init_error, DbInitError},
+%% %% {set_mechanism, SetModule},
+%% %% {authentication_service, AuthModule},
+%% {audit_trail_log, [{type, read_write},
+%% {dir, AgentDir},
+%% {size, {10240, 10}},
+%% {repair, true}]},
+%% {config, [{verbosity, info},
+%% {dir, AgentDir},
+%% {force_load, false}]},
+%% {mibs, Mibs},
+%% %% {mib_storage, MibStorage},
+%% {local_db, []},
+%% {mib_server, []},
+%% {symbolic_store, []},
+%% {note_store, []},
+%% {net_if, []},
+%% %% {supervisor, SupOpts}
+%% ],
+
+ app_env_init(vsn_init(Vsns) ++
+ [{audit_trail_log, read_write_log},
+ {audit_trail_log_dir, AgentDir},
+ {audit_trail_log_size, {10240, 10}},
+ {force_config_reload, false},
+ {snmp_agent_type, master},
+ {snmp_config_dir, AgentDir},
+ {snmp_db_dir, AgentDir},
+ {snmp_local_db_auto_repair, true},
+ {snmp_local_db_verbosity, log},
+ {snmp_master_agent_verbosity, trace},
+ {snmp_supervisor_verbosity, trace},
+ {snmp_mibserver_verbosity, log},
+ {snmp_symbolic_store_verbosity, log},
+ {snmp_note_store_verbosity, log},
+ {snmp_net_if_verbosity, trace}],
+ Opts),
+
+
+ process_flag(trap_exit,true),
+
+ {ok, AppSup} = snmp_app_sup:start_link(),
+ unlink(AppSup),
+ ?DBG("start_agent -> snmp app supervisor: ~p",[AppSup]),
+
+ ?DBG("start_agent -> start master agent (old style)",[]),
+ ?line Sup = start_sup(),
+
+ ?DBG("start_agent -> unlink from supervisor",[]),
+ ?line unlink(Sup),
+ ?line SaDir = ?config(sa_dir, Config),
+ ?DBG("start_agent -> (rpc) start sub on ~p",[SaNode]),
+ ?line {ok, Sub} = start_sub_sup(SaNode, SaDir),
+ ?DBG("start_agent -> done",[]),
+ ?line [{snmp_sup, {Sup, self()}}, {snmp_sub, Sub} | Config].
+
+
+vsn_init(Vsn) ->
+ vsn_init([v1,v2,v3], Vsn, []).
+
+vsn_init([], _Vsn, Acc) ->
+ Acc;
+vsn_init([V|Vsns], Vsn, Acc) ->
+ case lists:member(V, Vsn) of
+ true ->
+ vsn_init(Vsns, Vsn, [{V, true}|Acc]);
+ false ->
+ vsn_init(Vsns, Vsn, [{V, false}|Acc])
+ end.
+
+app_env_init(Env0, Opts) ->
+ ?DBG("app_env_init -> unload snmp",[]),
+ ?line application:unload(snmp),
+ ?DBG("app_env_init -> load snmp",[]),
+ ?line application:load(snmp),
+ ?DBG("app_env_init -> initiate (snmp) application env",[]),
+ F1 = fun({Key, Val} = New, Acc0) ->
+ ?DBG("app_env_init -> "
+ "updating setting ~p to ~p", [Key, Val]),
+ case lists:keyreplace(Key, 1, Acc0, New) of
+ Acc0 ->
+ [New|Acc0];
+ Acc ->
+ Acc
+ end
+ end,
+ Env = lists:foldr(F1, Env0, Opts),
+ ?DBG("app_env_init -> Env: ~p",[Env]),
+ F2 = fun({Key,Val}) ->
+ ?DBG("app_env_init -> setting ~p to ~p",[Key, Val]),
+ application_controller:set_env(snmp, Key, Val)
+ end,
+ lists:foreach(F2, Env).
+
+
+stop_agent(Config) when is_list(Config) ->
+ ?LOG("stop_agent -> entry with"
+ "~n Config: ~p",[Config]),
+
+ {Sup, Par} = ?config(snmp_sup, Config),
+ ?DBG("stop_agent -> attempt to stop (sup) ~p"
+ "~n Sup: ~p"
+ "~n Par: ~p",
+ [Sup,
+ (catch process_info(Sup)),
+ (catch process_info(Par))]),
+
+ Info = agent_info(Sup),
+ ?DBG("stop_agent -> Agent info: "
+ "~n ~p", [Info]),
+
+ stop_sup(Sup, Par),
+
+ {Sup2, Par2} = ?config(snmp_sub, Config),
+ ?DBG("stop_agent -> attempt to stop (sub) ~p"
+ "~n Sup2: ~p"
+ "~n Par2: ~p",
+ [Sup2,
+ (catch process_info(Sup2)),
+ (catch process_info(Par2))]),
+ stop_sup(Sup2, Par2),
+
+ ?DBG("stop_agent -> done - now cleanup config", []),
+ C1 = lists:keydelete(snmp_sup, 1, Config),
+ lists:keydelete(snmp_sub, 1, C1).
+
+
+start_sup() ->
+ case (catch snmpa_app:start(normal)) of
+ {ok, S} ->
+ ?DBG("start_agent -> started, Sup: ~p",[S]),
+ S;
+
+ Else ->
+ ?DBG("start_agent -> unknown result: ~n~p",[Else]),
+ %% Get info about the apps we depend on
+ ?FAIL({start_failed,Else, ?IS_MNESIA_RUNNING()})
+ end.
+
+stop_sup(Pid, _) when (node(Pid) =:= node()) ->
+ case (catch process_info(Pid)) of
+ PI when is_list(PI) ->
+ ?LOG("stop_sup -> attempt to stop ~p", [Pid]),
+ Ref = erlang:monitor(process, Pid),
+ exit(Pid, kill),
+ await_stopped(Pid, Ref);
+ {'EXIT', _Reason} ->
+ ?LOG("stop_sup -> ~p not running", [Pid]),
+ ok
+ end;
+stop_sup(Pid, _) ->
+ ?LOG("stop_sup -> attempt to stop ~p", [Pid]),
+ Ref = erlang:monitor(process, Pid),
+ ?LOG("stop_sup -> Ref: ~p", [Ref]),
+ %% Pid ! {'EXIT', Parent, shutdown}, % usch
+ exit(Pid, kill),
+ await_stopped(Pid, Ref).
+
+await_stopped(Pid, Ref) ->
+ receive
+ {'DOWN', Ref, process, Pid, _Reason} ->
+ ?DBG("received down message for ~p", [Pid]),
+ ok
+ after 10000 ->
+ ?INF("await_stopped -> timeout for ~p",[Pid]),
+ erlang:demonitor(Ref),
+ ?FAIL({failed_stop,Pid})
+ end.
+
+
+%% --- start subagent supervisor ---
+
+start_sub_sup(Node, Dir) ->
+ rpc:call(Node, ?MODULE, start_sub_sup, [Dir]).
+
+start_sub_sup(Dir) ->
+ ?DBG("start_sub -> entry",[]),
+ Opts = [{db_dir, Dir},
+ {supervisor, [{verbosity, trace}]}],
+ {ok, P} = snmpa_supervisor:start_sub_sup(Opts),
+ unlink(P),
+ {ok, {P, self()}}.
+
+
+%% --- start and stop subagents ---
+
+start_subagent(SaNode, RegTree, Mib) ->
+ ?DBG("start_subagent -> entry with"
+ "~n SaNode: ~p"
+ "~n RegTree: ~p"
+ "~n Mib: ~p", [SaNode, RegTree, Mib]),
+ MA = whereis(snmp_master_agent),
+ ?DBG("start_subagent -> MA: ~p", [MA]),
+ MibDir = get(mib_dir),
+ Mib1 = join(MibDir,Mib),
+ Mod = snmpa_supervisor,
+ Func = start_sub_agent,
+ Args = [MA, RegTree, [Mib1]],
+ case rpc:call(SaNode, Mod, Func, Args) of
+ {ok, SA} ->
+ ?DBG("start_subagent -> SA: ~p", [SA]),
+ {ok, SA};
+ Error ->
+ ?FAIL({subagent_start_failed, SaNode, Error, [MA, RegTree, Mib1]})
+ end.
+
+stop_subagent(SA) ->
+ ?DBG("stop_subagent -> entry with"
+ "~n SA: ~p", [SA]),
+ rpc:call(node(SA), snmpa_supervisor, stop_sub_agent, [SA]).
+
+
+mibs(StdMibDir,MibDir) ->
+ [join(StdMibDir, ?v1_2("STANDARD-MIB.bin", "SNMPv2-MIB.bin")),
+ join(MibDir, "OLD-SNMPEA-MIB.bin"),
+ join(StdMibDir, "SNMP-FRAMEWORK-MIB"),
+ join(StdMibDir, "SNMP-MPD-MIB"),
+ join(StdMibDir, "SNMP-VIEW-BASED-ACM-MIB"),
+ join(StdMibDir, "SNMP-USER-BASED-SM-MIB"),
+ join(StdMibDir, "SNMP-TARGET-MIB"),
+ join(StdMibDir, "SNMP-NOTIFICATION-MIB"),
+ join(MibDir, "Klas1.bin"),
+ join(MibDir, "Klas2.bin"),
+ join(MibDir, "Klas3.bin"),
+ join(MibDir, "Klas4.bin"),
+ join(MibDir, "SA-MIB.bin"),
+ join(MibDir, "TestTrap.bin"),
+ join(MibDir, "Test1.bin"),
+ join(MibDir, "Test2.bin"),
+ join(MibDir, "TestTrapv2.bin")].
+
+join(D,F) ->
+ filename:join(D,F).
+
+
+%% --- various mib load/unload functions ---
+
+load_master(Mib) ->
+ ?DBG("load_master -> entry with"
+ "~n Mib: ~p", [Mib]),
+ snmpa:unload_mibs(snmp_master_agent, [Mib]), % Unload for safety
+ ok = snmpa:load_mibs(snmp_master_agent, [get(mib_dir) ++ Mib]).
+
+load_master_std(Mib) ->
+ ?DBG("load_master_std -> entry with"
+ "~n Mib: ~p", [Mib]),
+ snmpa:unload_mibs(snmp_master_agent, [Mib]), % Unload for safety
+ ok = snmpa:load_mibs(snmp_master_agent, [get(std_mib_dir) ++ Mib]).
+
+unload_master(Mib) ->
+ ?DBG("unload_master -> entry with"
+ "~n Mib: ~p", [Mib]),
+ ok = snmpa:unload_mibs(snmp_master_agent, [Mib]).
+
+loaded_mibs() ->
+ ?DBG("loaded_mibs -> entry",[]),
+ Info = snmpa:info(snmp_master_agent),
+ {value, {loaded_mibs, Mibs}} = lists:keysearch(loaded_mibs, 1, Info),
+ [atom_to_list(Mib) || {Mib,_,_} <- Mibs].
+
+unload_mibs(Mibs) ->
+ ?DBG("unload_mibs -> entry with"
+ "~n Mibs: ~p", [Mibs]),
+ ok = snmpa:unload_mibs(snmp_master_agent, Mibs).
+
+
+agent_info(Sup) ->
+ ?DBG("agent_info -> entry with"
+ "~n Sup: ~p", [Sup]),
+ rpc:call(node(Sup), snmpa, info, []).
+
+
+%% ---
+
+expect(Id, A) ->
+ Fun = fun() -> do_expect(A) end,
+ expect2(Id, Fun).
+
+expect(Id, A, B) ->
+ Fun = fun() -> do_expect(A, B) end,
+ expect2(Id, Fun).
+
+expect(Id, A, B, C) ->
+ Fun = fun() -> do_expect(A, B, C) end,
+ expect2(Id, Fun).
+
+expect(Id, A, B, C, D, E) ->
+ Fun = fun() -> do_expect(A, B, C, D, E) end,
+ expect2(Id, Fun).
+
+expect2(Id, F) ->
+ io:format("~w:expect2 -> entry with"
+ "~n Id: ~w"
+ "~n", [?MODULE, Id]),
+ case F() of
+ {error, Reason} ->
+ {error, Id, Reason};
+ Else ->
+ io:format("~w:expect2 -> "
+ "~n Id: ~w"
+ "~n Else: ~p"
+ "~n", [?MODULE, Id, Else]),
+ Else
+ end.
+
+
+%% ----------------------------------------------------------------------
+
+get_timeout() ->
+ get_timeout(os:type()).
+
+get_timeout(vxworks) -> 7000;
+get_timeout(_) -> 3500.
+
+receive_pdu(To) ->
+ receive
+ {snmp_pdu, PDU} when is_record(PDU, pdu) ->
+ PDU
+ after To ->
+ {error, timeout}
+ end.
+
+receive_trap(To) ->
+ receive
+ {snmp_pdu, PDU} when is_record(PDU, trappdu) ->
+ PDU
+ after To ->
+ {error, timeout}
+ end.
+
+
+do_expect(Expect) when is_atom(Expect) ->
+ do_expect({Expect, get_timeout()});
+
+do_expect({any_pdu, To})
+ when is_integer(To) orelse (To =:= infinity) ->
+ io:format("~w:do_expect(any_pdu) -> entry with"
+ "~n To: ~w"
+ "~n", [?MODULE, To]),
+ receive_pdu(To);
+
+do_expect({any_trap, To}) ->
+ io:format("~w:do_expect(any_trap) -> entry with"
+ "~n To: ~w"
+ "~n", [?MODULE, To]),
+ receive_trap(To);
+
+do_expect({timeout, To}) ->
+ io:format("~w:do_expect(timeout) -> entry with"
+ "~n To: ~w"
+ "~n", [?MODULE, To]),
+ receive
+ X ->
+ {error, {unexpected, X}}
+ after
+ To ->
+ ok
+ end;
+
+do_expect({Err, To})
+ when is_atom(Err) andalso (is_integer(To) orelse (To =:= infinity)) ->
+ do_expect({{error, Err}, To});
+
+do_expect({error, Err}) when is_atom(Err) ->
+ Check = fun(_, R) -> R end,
+ do_expect2(Check, any, Err, any, any, get_timeout());
+do_expect({{error, Err}, To}) ->
+ Check = fun(_, R) -> R end,
+ do_expect2(Check, any, Err, any, any, To);
+
+%% exp_varbinds() -> [exp_varbind()]
+%% exp_varbind() -> any | {Oid, any} | {Oid, Value}
+%% Oid -> [integer()]
+%% Value -> term()
+%% ExpVBs -> exp_varbinds() | {VbsCondition, exp_varbinds()}
+do_expect(ExpVBs) ->
+ Check = fun(_, R) -> R end,
+ do_expect2(Check, 'get-response', noError, 0, ExpVBs, get_timeout()).
+
+
+do_expect(v2trap, ExpVBs) ->
+ Check = fun(_, R) -> R end,
+ do_expect2(Check, 'snmpv2-trap', noError, 0, ExpVBs, get_timeout());
+
+
+do_expect(report, ExpVBs) ->
+ Check = fun(_, R) -> R end,
+ do_expect2(Check, 'report', noError, 0, ExpVBs, get_timeout());
+
+
+do_expect(inform, ExpVBs) ->
+ do_expect({inform, true}, ExpVBs);
+
+do_expect({inform, false}, ExpVBs) ->
+ io:format("~w:do_expect(inform, false) -> entry with"
+ "~n ExpVBs: ~p"
+ "~n", [?MODULE, ExpVBs]),
+ Check = fun(_, R) -> R end,
+ do_expect2(Check, 'inform-request', noError, 0, ExpVBs, get_timeout());
+
+do_expect({inform, true}, ExpVBs) ->
+ io:format("~w:do_expect(inform, true) -> entry with"
+ "~n ExpVBs: ~p"
+ "~n", [?MODULE, ExpVBs]),
+ Check =
+ fun(PDU, ok) ->
+ RespPDU = PDU#pdu{type = 'get-response',
+ error_status = noError,
+ error_index = 0},
+ snmp_test_mgr:rpl(RespPDU),
+ ok;
+ (_, Err) ->
+ Err
+ end,
+ do_expect2(Check, 'inform-request', noError, 0, ExpVBs, get_timeout());
+
+do_expect({inform, {error, EStat, EIdx}}, ExpVBs)
+ when is_atom(EStat) andalso is_integer(EIdx) ->
+ Check =
+ fun(PDU, ok) ->
+ RespPDU = PDU#pdu{type = 'get-response',
+ error_status = EStat,
+ error_index = EIdx},
+ snmp_test_mgr:rpl(RespPDU),
+ ok;
+ (_, Err) ->
+ Err
+ end,
+ do_expect2(Check, 'inform-request', noError, 0, ExpVBs, get_timeout()).
+
+
+do_expect(Err, Idx, ExpVBs) ->
+ do_expect(Err, Idx, ExpVBs, get_timeout()).
+
+do_expect(Err, Idx, ExpVBs, To)
+ when is_atom(Err) andalso
+ (is_integer(Idx) orelse is_list(Idx) orelse (Idx == any)) ->
+ Check = fun(_, R) -> R end,
+ do_expect2(Check, 'get-response', Err, Idx, ExpVBs, To).
+
+
+do_expect(Type, Enterp, Generic, Specific, ExpVBs) ->
+ do_expect(Type, Enterp, Generic, Specific, ExpVBs, 3500).
+
+do_expect(trap, Enterp, Generic, Specific, ExpVBs, To) ->
+ io:format("~w:do_expect(trap) -> entry with"
+ "~n Enterp: ~w"
+ "~n Generic: ~w"
+ "~n Specific: ~w"
+ "~n ExpVBs: ~w"
+ "~n To: ~w"
+ "~nwhen"
+ "~n Time: ~w"
+ "~n", [?MODULE, Enterp, Generic, Specific, ExpVBs, To, t()]),
+ PureE = purify_oid(Enterp),
+ case receive_trap(To) of
+ #trappdu{enterprise = PureE,
+ generic_trap = Generic,
+ specific_trap = Specific,
+ varbinds = VBs} ->
+ check_vbs(purify_oids(ExpVBs), VBs);
+
+ #trappdu{enterprise = Ent2,
+ generic_trap = G2,
+ specific_trap = Spec2,
+ varbinds = VBs} ->
+ {error, {unexpected_trap,
+ {PureE, Generic, Specific, ExpVBs},
+ {Ent2, G2, Spec2, VBs}}};
+
+ Error ->
+ Error
+ end.
+
+
+do_expect2(Check, Type, Err, Idx, ExpVBs, To)
+ when is_function(Check) andalso
+ is_atom(Type) andalso
+ is_atom(Err) andalso
+ (is_integer(Idx) orelse is_list(Idx) orelse (Idx =:= any)) andalso
+ (is_list(ExpVBs) orelse (ExpVBs =:= any)) andalso
+ (is_integer(To) orelse (To =:= infinity)) ->
+
+ io:format("~w:do_expect2 -> entry with"
+ "~n Type: ~w"
+ "~n Err: ~w"
+ "~n Idx: ~w"
+ "~n ExpVBs: ~w"
+ "~n To: ~w"
+ "~nwhen"
+ "~n Time: ~w"
+ "~n", [?MODULE, Type, Err, Idx, ExpVBs, To, t()]),
+
+ case receive_pdu(To) of
+
+ #pdu{type = Type,
+ error_status = Err,
+ error_index = Idx} when ExpVBs =:= any ->
+ ok;
+
+ #pdu{type = Type,
+ request_id = ReqId,
+ error_status = Err2,
+ error_index = Idx} when ExpVBs =:= any ->
+ {error, {unexpected_error_status, Err, Err2, ReqId}};
+
+ #pdu{error_status = Err} when (Type =:= any) andalso
+ (Idx =:= any) andalso
+ (ExpVBs =:= any) ->
+ ok;
+
+ #pdu{request_id = ReqId,
+ error_status = Err2} when (Type =:= any) andalso
+ (Idx =:= any) andalso
+ (ExpVBs =:= any) ->
+ {error, {unexpected_error_status, Err, Err2, ReqId}};
+
+ #pdu{type = Type,
+ error_status = Err} when (Idx =:= any) andalso
+ (ExpVBs =:= any) ->
+ ok;
+
+ #pdu{type = Type,
+ request_id = ReqId,
+ error_status = Err2} when (Idx =:= any) andalso
+ (ExpVBs =:= any) ->
+ {error, {unexpected_error_status, Err, Err2, ReqId}};
+
+ #pdu{type = Type,
+ request_id = ReqId,
+ error_status = Err,
+ error_index = EI} when is_list(Idx) andalso (ExpVBs =:= any) ->
+ case lists:member(EI, Idx) of
+ true ->
+ ok;
+ false ->
+ {error, {unexpected_error_index, EI, Idx, ReqId}}
+ end;
+
+ #pdu{type = Type,
+ request_id = ReqId,
+ error_status = Err2,
+ error_index = EI} when is_list(Idx) andalso (ExpVBs =:= any) ->
+ case lists:member(EI, Idx) of
+ true ->
+ {error, {unexpected_error_status, Err, Err2, ReqId}};
+ false ->
+ {error, {unexpected_error, {Err, Idx}, {Err2, EI}, ReqId}}
+ end;
+
+ #pdu{type = Type2,
+ request_id = ReqId,
+ error_status = Err2,
+ error_index = Idx2} when ExpVBs =:= any ->
+ {error,
+ {unexpected_pdu,
+ {Type, Err, Idx}, {Type2, Err2, Idx2}, ReqId}};
+
+ #pdu{type = Type,
+ error_status = Err,
+ error_index = Idx,
+ varbinds = VBs} = PDU ->
+ Check(PDU, check_vbs(purify_oids(ExpVBs), VBs));
+
+ #pdu{type = Type,
+ error_status = Err,
+ varbinds = VBs} = PDU when Idx =:= any ->
+ Check(PDU, check_vbs(purify_oids(ExpVBs), VBs));
+
+ #pdu{type = Type,
+ request_id = ReqId,
+ error_status = Err,
+ error_index = EI,
+ varbinds = VBs} = PDU when is_list(Idx) ->
+ PureVBs = purify_oids(ExpVBs),
+ case lists:member(EI, Idx) of
+ true ->
+ Check(PDU, check_vbs(PureVBs, VBs));
+ false ->
+ {error, {unexpected_error_index, Idx, EI, ReqId}}
+ end;
+
+ #pdu{type = Type2,
+ request_id = ReqId,
+ error_status = Err2,
+ error_index = Idx2,
+ varbinds = VBs2} ->
+ {error,
+ {unexpected_pdu,
+ {Type, Err, Idx, purify_oids(ExpVBs)},
+ {Type2, Err2, Idx2, VBs2},
+ ReqId}};
+
+ Error ->
+ Error
+ end.
+
+
+
+check_vbs([], []) ->
+ ok;
+check_vbs(Exp, []) ->
+ {error, {to_few_vbs, Exp}};
+check_vbs([], VBs) ->
+ {error, {to_many_vbs, VBs}};
+check_vbs([any|Exp], [_|VBs]) ->
+ check_vbs(Exp, VBs);
+check_vbs([{Oid, any}|Exp], [#varbind{oid = Oid}|VBs]) ->
+ check_vbs(Exp, VBs);
+check_vbs([{Oid, Val}|Exp], [#varbind{oid = Oid, value = Val}|VBs]) ->
+ check_vbs(Exp, VBs);
+check_vbs([{Oid, Val1}|_], [#varbind{oid = Oid, value = Val2}|_]) ->
+ {error, {unexpected_vb_value, Oid, Val1, Val2}};
+check_vbs([{Oid1, _}|_], [#varbind{oid = Oid2}|_]) ->
+ {error, {unexpected_vb_oid, Oid1, Oid2}}.
+
+
+purify_oids({VbsCondition, VBs})
+ when ((VbsCondition =:= true) orelse (VbsCondition =:= false)) andalso
+ is_list(VBs) ->
+ {VbsCondition, do_purify_oids(VBs)};
+purify_oids(VBs) when is_list(VBs) ->
+ do_purify_oids(VBs).
+
+do_purify_oids([]) ->
+ [];
+do_purify_oids([{XOid, Q}|T]) ->
+ [{purify_oid(XOid), Q} | do_purify_oids(T)].
+
+
+purify_oid(Oid) ->
+ io:format("~w:purify_oid -> entry with"
+ "~n Oid: ~w"
+ "~n",
+ [?MODULE, Oid]),
+ case (catch snmp_test_mgr:purify_oid(Oid)) of
+ {error, Reason} ->
+ io:format("~w:purify_oid -> error: "
+ "~n Reason: ~p"
+ "~n",
+ [?MODULE, Reason]),
+ exit({malformed_oid, Reason});
+ {ok, Oid2} when is_list(Oid2) ->
+ io:format("~w:purify_oid -> ok: "
+ "~n Oid2: ~p"
+ "~n",
+ [?MODULE, Oid2]),
+ Oid2;
+ Error ->
+ io:format("~w:purify_oid -> unexpected return value: "
+ "~n Error: ~p"
+ "~n",
+ [?MODULE, Error]),
+ exit({unexpected_purify_result, Error})
+
+ end.
+
+
+%% ----------------------------------------------------------------------
+
+get_req(Id, Vars) ->
+ ?DBG("get_req -> entry with"
+ "~n Id: ~p"
+ "~n Vars: ~p",[Id,Vars]),
+ snmp_test_mgr:g(Vars),
+ ?DBG("get_req -> await response",[]),
+ case snmp_test_mgr:get_response(Id, Vars) of
+ {ok, Val} ->
+ ?DBG("get_req -> response: ~p",[Val]),
+ Val;
+ {error, _, {ExpFmt, ExpArg}, {ActFmt, ActArg}} ->
+ ?DBG("get_req -> error for ~p: "
+ "~n " ++ ExpFmt ++
+ "~n " ++ ActFmt,
+ [Id] ++ ExpArg ++ ActArg),
+ exit({unexpected_response, ExpArg, ActArg});
+ Error ->
+ ?DBG("get_req -> error: ~n~p",[Error]),
+ exit({unknown, Error})
+ end.
+
+
+get_next_req(Vars) ->
+ ?DBG("get_next_req -> entry with"
+ "~n Vars: ~p",[Vars]),
+ snmp_test_mgr:gn(Vars),
+ ?DBG("get_next_req -> await response",[]),
+ Response = snmp_test_mgr:receive_response(),
+ ?DBG("get_next_req -> response: ~p",[Response]),
+ Response.
+
+
+%% --- start and stop nodes ---
+
+start_node(Name) ->
+ ?LOG("start_node -> entry with"
+ "~n Name: ~p"
+ "~n when"
+ "~n hostname of this node: ~p",
+ [Name, list_to_atom(?HOSTNAME(node()))]),
+ Pa = filename:dirname(code:which(?MODULE)),
+ ?DBG("start_node -> Pa: ~p",[Pa]),
+
+ Args = case init:get_argument('CC_TEST') of
+ {ok, [[]]} ->
+ " -pa /clearcase/otp/libraries/snmp/ebin ";
+ {ok, [[Path]]} ->
+ " -pa " ++ Path;
+ error ->
+ ""
+ end,
+ %% Do not use start_link!!! (the proc that calls this one is tmp)
+ ?DBG("start_node -> Args: ~p~n",[Args]),
+ A = Args ++ " -pa " ++ Pa,
+ case (catch ?START_NODE(Name, A)) of
+ {ok, Node} ->
+ %% Tell the test_server to not clean up things it never started.
+ ?DBG("start_node -> Node: ~p",[Node]),
+ {ok, Node};
+ Else ->
+ ?ERR("start_node -> failed with(other): Else: ~p",[Else]),
+ ?line ?FAIL(Else)
+ end.
+
+
+stop_node(Node) ->
+ ?LOG("stop_node -> Node: ~p",[Node]),
+ rpc:cast(Node, erlang, halt, []).
+
+
+%%%-----------------------------------------------------------------
+%%% Configuration
+%%%-----------------------------------------------------------------
+
+config(Vsns, MgrDir, AgentDir, MIp, AIp) ->
+ ?line snmp_config:write_agent_snmp_files(AgentDir, Vsns, MIp,
+ ?TRAP_UDP, AIp, 4000,
+ "test"),
+ ?line case update_usm(Vsns, AgentDir) of
+ true ->
+ ?line copy_file(filename:join(AgentDir, "usm.conf"),
+ filename:join(MgrDir, "usm.conf")),
+ ?line update_usm_mgr(Vsns, MgrDir);
+ false ->
+ ?line ok
+ end,
+ ?line update_community(Vsns, AgentDir),
+ ?line update_vacm(Vsns, AgentDir),
+ ?line write_target_addr_conf(AgentDir, MIp, ?TRAP_UDP, Vsns),
+ ?line write_target_params_conf(AgentDir, Vsns),
+ ?line write_notify_conf(AgentDir),
+ ok.
+
+delete_files(Config) ->
+ Dir = ?config(agent_dir, Config),
+ {ok, List} = file:list_dir(Dir),
+ lists:foreach(fun(FName) -> file:delete(filename:join(Dir, FName)) end,
+ List).
+
+update_usm(Vsns, Dir) ->
+ case lists:member(v3, Vsns) of
+ true ->
+ Conf = [{"agentEngine", "all-rights", "all-rights", zeroDotZero,
+ usmNoAuthProtocol, "", "",
+ usmNoPrivProtocol, "", "", "", "", ""},
+
+ {"agentEngine", "no-rights", "no-rights", zeroDotZero,
+ usmNoAuthProtocol, "", "",
+ usmNoPrivProtocol, "", "", "", "", ""},
+
+ {"agentEngine", "authMD5", "authMD5", zeroDotZero,
+ usmHMACMD5AuthProtocol, "", "",
+ usmNoPrivProtocol, "", "", "", "passwd_md5xxxxxx", ""},
+
+ {"agentEngine", "authSHA", "authSHA", zeroDotZero,
+ usmHMACSHAAuthProtocol, "", "",
+ usmNoPrivProtocol, "", "", "",
+ "passwd_shaxxxxxxxxxx", ""},
+
+ {"agentEngine", "privDES", "privDES", zeroDotZero,
+ usmHMACSHAAuthProtocol, "", "",
+ usmDESPrivProtocol, "", "", "",
+ "passwd_shaxxxxxxxxxx", "passwd_desxxxxxx"},
+
+ {"mgrEngine", "all-rights", "all-rights", zeroDotZero,
+ usmNoAuthProtocol, "", "",
+ usmNoPrivProtocol, "", "", "", "", ""},
+
+ {"mgrEngine", "no-rights", "no-rights", zeroDotZero,
+ usmNoAuthProtocol, "", "",
+ usmNoPrivProtocol, "", "", "", "", ""},
+
+ {"mgrEngine", "authMD5", "authMD5", zeroDotZero,
+ usmHMACMD5AuthProtocol, "", "",
+ usmNoPrivProtocol, "", "", "", "passwd_md5xxxxxx", ""},
+
+ {"mgrEngine", "authSHA", "authSHA", zeroDotZero,
+ usmHMACSHAAuthProtocol, "", "",
+ usmNoPrivProtocol, "", "", "",
+ "passwd_shaxxxxxxxxxx", ""},
+
+ {"mgrEngine", "privDES", "privDES", zeroDotZero,
+ usmHMACSHAAuthProtocol, "", "",
+ usmDESPrivProtocol, "", "", "",
+ "passwd_shaxxxxxxxxxx", "passwd_desxxxxxx"}],
+ ?line ok = snmp_config:update_agent_usm_config(Dir, Conf),
+ true;
+ false ->
+ false
+ end.
+
+update_usm_mgr(Vsns, Dir) ->
+ case lists:member(v3, Vsns) of
+ true ->
+ Conf = [{"agentEngine", "newUser", "newUser", zeroDotZero,
+ usmHMACSHAAuthProtocol, "", "",
+ usmDESPrivProtocol, "", "", "",
+ "passwd_shaxxxxxxxxxx", "passwd_desxxxxxx"},
+
+ {"mgrEngine", "newUser", "newUser", zeroDotZero,
+ usmHMACSHAAuthProtocol, "", "",
+ usmDESPrivProtocol, "", "", "",
+ "passwd_shaxxxxxxxxxx", "passwd_desxxxxxx"}],
+
+ ?line ok = snmp_config:update_agent_usm_config(Dir, Conf),
+ true;
+ false ->
+ false
+ end.
+
+rewrite_usm_mgr(Dir, ShaKey, DesKey) ->
+ ?line ok = file:rename(filename:join(Dir,"usm.conf"),
+ filename:join(Dir,"usm.old")),
+ Conf = [{"agentEngine", "newUser", "newUser", zeroDotZero,
+ usmHMACSHAAuthProtocol, "", "",
+ usmDESPrivProtocol, "", "", "", ShaKey, DesKey},
+ {"mgrEngine", "newUser", "newUser", zeroDotZero,
+ usmHMACSHAAuthProtocol, "", "",
+ usmDESPrivProtocol, "", "", "", ShaKey, DesKey}],
+ ok = snmp_config:write_agent_usm_config(Dir, "", Conf).
+
+reset_usm_mgr(Dir) ->
+ ?line ok = file:rename(filename:join(Dir,"usm.old"),
+ filename:join(Dir,"usm.conf")).
+
+
+update_community([v3], _Dir) ->
+ ok;
+update_community(_, Dir) ->
+ Conf = [{"no-rights", "no-rights", "no-rights", "", ""}],
+ ?line ok = snmp_config:update_agent_community_config(Dir, Conf).
+
+
+-define(tDescr_instance, [1,3,6,1,2,1,16,1,0]).
+update_vacm(_Vsn, Dir) ->
+ Conf = [{vacmSecurityToGroup, usm, "authMD5", "initial"},
+ {vacmSecurityToGroup, usm, "authSHA", "initial"},
+ {vacmSecurityToGroup, usm, "privDES", "initial"},
+ {vacmSecurityToGroup, usm, "newUser", "initial"},
+ {vacmViewTreeFamily, "internet", ?tDescr_instance,
+ excluded, null}],
+ ?line ok = snmp_config:update_agent_vacm_config(Dir, Conf).
+
+
+write_community_conf(Dir, Conf) ->
+ snmp_config:write_agent_community_config(Dir, "", Conf).
+
+write_target_addr_conf(Dir, Conf) ->
+ snmp_config:write_agent_target_addr_config(Dir, "", Conf).
+
+write_target_addr_conf(Dir, ManagerIp, UDP, Vsns) ->
+ snmp_config:write_agent_snmp_target_addr_conf(Dir, ManagerIp, UDP, Vsns).
+
+rewrite_target_addr_conf(Dir, NewPort) ->
+ ?DBG("rewrite_target_addr_conf -> entry with"
+ "~n NewPort: ~p", [NewPort]),
+ TAFile = filename:join(Dir, "target_addr.conf"),
+ case file:read_file_info(TAFile) of
+ {ok, _} -> ok;
+ {error, R} -> ?ERR("failure reading file info of "
+ "target address config file: ~p",[R]),
+ ok
+ end,
+
+ ?line [TrapAddr|Addrs] =
+ snmp_conf:read(TAFile,
+ fun(R) -> rewrite_target_addr_conf_check(R) end),
+
+ ?DBG("rewrite_target_addr_conf -> TrapAddr: ~p",[TrapAddr]),
+
+ NewAddrs = [rewrite_target_addr_conf2(NewPort,TrapAddr)|Addrs],
+
+ ?DBG("rewrite_target_addr_conf -> NewAddrs: ~p",[NewAddrs]),
+
+ ?line ok = file:rename(filename:join(Dir,"target_addr.conf"),
+ filename:join(Dir,"target_addr.old")),
+
+ ?line ok = snmp_config:write_agent_target_addr_config(Dir, "", NewAddrs).
+
+rewrite_target_addr_conf_check(O) ->
+ {ok,O}.
+
+rewrite_target_addr_conf2(NewPort,{Name,Ip,_Port,Timeout,Retry,
+ "std_trap",EngineId}) ->
+ ?LOG("rewrite_target_addr_conf2 -> entry with std_trap",[]),
+ {Name,Ip,NewPort,Timeout,Retry,"std_trap",EngineId};
+rewrite_target_addr_conf2(_NewPort,O) ->
+ ?LOG("rewrite_target_addr_conf2 -> entry with "
+ "~n O: ~p",[O]),
+ O.
+
+reset_target_addr_conf(Dir) ->
+ ?line ok = file:rename(filename:join(Dir,"target_addr.old"),
+ filename:join(Dir,"target_addr.conf")).
+
+write_target_params_conf(Dir, Vsns) ->
+ F = fun(v1) -> {"target_v1", v1, v1, "all-rights", noAuthNoPriv};
+ (v2) -> {"target_v2", v2c, v2c, "all-rights", noAuthNoPriv};
+ (v3) -> {"target_v3", v3, usm, "all-rights", noAuthNoPriv}
+ end,
+ Conf = [F(Vsn) || Vsn <- Vsns],
+ snmp_config:write_agent_target_params_config(Dir, "", Conf).
+
+rewrite_target_params_conf(Dir, SecName, SecLevel)
+ when is_list(SecName) andalso is_atom(SecLevel) ->
+ ?line ok = file:rename(filename:join(Dir,"target_params.conf"),
+ filename:join(Dir,"target_params.old")),
+ Conf = [{"target_v3", v3, usm, SecName, SecLevel}],
+ snmp_config:write_agent_target_params_config(Dir, "", Conf).
+
+reset_target_params_conf(Dir) ->
+ ?line ok = file:rename(filename:join(Dir,"target_params.old"),
+ filename:join(Dir,"target_params.conf")).
+
+write_notify_conf(Dir) ->
+ Conf = [{"standard trap", "std_trap", trap},
+ {"standard inform", "std_inform", inform}],
+ snmp_config:write_agent_notify_config(Dir, "", Conf).
+
+write_view_conf(Dir) ->
+ Conf = [{2, [1,3,6], included, null},
+ {2, ?tDescr_instance, excluded, null}],
+ snmp_config:write_agent_view_config(Dir, "", Conf).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+copy_file(From, To) ->
+ {ok, Bin} = file:read_file(From),
+ ok = file:write_file(To, Bin).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+display_memory_usage() ->
+ Info = snmpa:info(snmp_master_agent),
+ TreeSize = key1search(tree_size_bytes, Info),
+ ProcMem = key1search(process_memory, Info),
+ MibDbSize = key1search([db_memory,mib], Info),
+ NodeDbSize = key1search([db_memory,node], Info),
+ TreeDbSize = key1search([db_memory,tree], Info),
+ ?INF("Memory usage: "
+ "~n Tree size: ~p"
+ "~n Process memory size: ~p"
+ "~n Mib db size: ~p"
+ "~n Node db size: ~p"
+ "~n Tree db size: ~p",
+ [TreeSize, ProcMem, MibDbSize, NodeDbSize, TreeDbSize]).
+
+key1search([], Res) ->
+ Res;
+key1search([Key|Keys], List) when is_atom(Key) andalso is_list(List) ->
+ case lists:keysearch(Key, 1, List) of
+ {value, {Key, Val}} ->
+ key1search(Keys, Val);
+ false ->
+ undefined
+ end;
+key1search(Key, List) when is_atom(Key) ->
+ case lists:keysearch(Key, 1, List) of
+ {value, {Key, Val}} ->
+ Val;
+ false ->
+ undefined
+ end.
+
+
+regs() ->
+ lists:sort(registered()).
+
+
+rpc(Node, F, A) ->
+ rpc:call(Node, snmpa, F, A).
+
+
+%% await_pdu(To) ->
+%% await_response(To, pdu).
+%%
+%% await_trap(To) ->
+%% await_response(To, trap).
+%%
+%% await_any(To) ->
+%% await_response(To, any).
+%%
+%%
+%% await_response(To, What) ->
+%% await_response(To, What, []).
+%%
+%% await_response(To, What, Stuff) when is_integer(To) andalso (To >= 0) ->
+%% T = t(),
+%% receive
+%% {snmp_pdu, PDU} when is_record(Trap, pdu) andalso (What =:= pdu) ->
+%% {ok, PDU};
+%% {snmp_pdu, Trap} is_when record(Trap, trappdu) andalso (What =:= trap) ->
+%% {ok, Trap};
+%% Any when What =:= any ->
+%% {ok, Any};
+%% Any ->
+%% %% Recalc time
+%% NewTo = To - (t() - T)
+%% await_reponse(NewTo, What, [{NewTo, Any}|Stuff])
+%% after To ->
+%% {error, {timeout, Stuff}}
+%% end;
+%% await_response(_, Stuff) ->
+%% {error, {timeout, Stuff}}.
+%%
+%%
+%% t() ->
+%% {A,B,C} = erlang:now(),
+%% A*1000000000+B*1000+(C div 1000).
+%%
+%%
+%% timeout() ->
+%% timeout(os:type()).
+%%
+%% timeout(vxworks) -> 7000;
+%% timeout(_) -> 3500.
+
+
+%% Time in milli seconds
+t() ->
+ {A,B,C} = erlang:now(),
+ A*1000000000+B*1000+(C div 1000).
diff --git a/lib/snmp/test/snmp_agent_v1_test.erl b/lib/snmp/test/snmp_agent_v1_test.erl
new file mode 100644
index 0000000000..52ac6cf58f
--- /dev/null
+++ b/lib/snmp/test/snmp_agent_v1_test.erl
@@ -0,0 +1,2673 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2005-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%
+%%
+
+-module(snmp_agent_v1_test).
+
+%% TODO
+%% * Test fault-tolerance (kill master etc)
+%%
+
+-export([]).
+
+-define(application, snmp).
+
+-include_lib("kernel/include/file.hrl").
+-include("test_server.hrl").
+-include("snmp_test_lib.hrl").
+-define(SNMP_USE_V3, true).
+-include_lib("snmp/include/snmp_types.hrl").
+
+
+-define(klas1, [1,3,6,1,2,1,7]).
+-define(klas2, [1,3,6,1,2,1,9]).
+-define(klas3, [1,3,6,1,2,1,8,1]).
+-define(klas4, [1,3,6,1,2,1,8,4]).
+-define(sa, [1,3,6,1,4,1,193,2]).
+-define(system, [1,3,6,1,2,1,1]).
+-define(snmp, [1,3,6,1,2,1,11]).
+-define(snmpTraps, [1,3,6,1,6,3,1,1,5]).
+-define(ericsson, [1,3,6,1,4,1,193]).
+-define(testTrap, [1,3,6,1,2,1,15,0]).
+-define(xDescr, [1,3,6,1,2,1,17,1]).
+-define(xDescr2, [1,3,6,1,2,1,17,2]).
+
+-define(active, 1).
+-define(notInService, 2).
+-define(notReady, 3).
+-define(createAndGo, 4).
+-define(createAndWait, 5).
+-define(destroy, 6).
+
+-define(TRAP_UDP, 5000).
+
+-define(tooBigStr, "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").
+
+
+%% -- test manager defines --
+-define(MGR, snmp_test_mgr).
+-define(GN(X), ?MGR:gn(X)).
+-define(G(X), ?MGR:g(X)).
+-define(S(X), ?MGR:s(X)).
+-define(GB(X), ?MGR:gb(X)).
+-define(SEND_BYTES(X), ?MGR:send_bytes(X)).
+
+%% -- agent test lib defines --
+-define(LIB, snmp_agent_test_lib).
+-define(INIT_CASE(X), ?LIB:init_case(X)).
+-define(TRY_TEST1(A), ?LIB:try_test(A)).
+-define(TRY_TEST2(A, B), ?LIB:try_test(A, B)).
+-define(TRY_TEST3(A, B, C), ?LIB:try_test(A, B, C)).
+-define(START_SA(A, B, C), ?LIB:start_subagent(A, B, C)).
+-define(STOP_SA(A), ?LIB:stop_subagent(A)).
+-define(P1(C), ?LIB:p(C)).
+-define(P2(F), ?LIB:p(F,[])).
+-define(P3(F,A), ?LIB:p(F,A)).
+-define(RPC(N, F, A), ?LIB:rpc(N, F, A)).
+
+
+-define(v1_2(V1,V2),
+ case get(vsn) of
+ v1 -> V1;
+ _ -> V2
+ end).
+
+-define(v1_2_3(V1,V2,V3),
+ case get(vsn) of
+ v1 -> V1;
+ v2 -> V2;
+ _ -> V3
+ end).
+
+all(suite) -> {req,
+ [mnesia, distribution,
+ {local_slave_nodes, 2}, {time, 360}],
+ [{conf, init, cases(), finish}]}.
+
+init_per_testcase(_Case, Config) when list(Config) ->
+ Dog = ?t:timetrap(?t:minutes(6)),
+ [{watchdog, Dog}|Config].
+
+fin_per_testcase(_Case, Config) when list(Config) ->
+ Dog = ?config(watchdog, Config),
+ ?t:timetrap_cancel(Dog),
+ Config.
+
+cases() ->
+ [simple,
+ db_notify_client,
+ processing,
+ big,
+ big2,
+ %% implied,
+ loop_mib,
+ api,
+ subagent,
+ mnesia,
+ multiple_reqs,
+ sa_register,
+ v1_trap,
+ sa_error,
+ next_across_sa,
+ undo,
+ standard_mibs,
+ sparse_table,
+ cnt_64,
+ opaque,
+ %% opaque].
+
+ change_target_addr_config,
+
+ reported_bugs,
+ tickets
+ ].
+
+
+init(Config) ->
+ init_all(Config),
+ init_v1(Config).
+
+finish(Config) ->
+ finish_v1(Config),
+ finish_all(Config).
+
+init_v1(Config) when list(Config) ->
+ ?line SaNode = ?config(snmp_sa, Config),
+ ?line create_tables(SaNode),
+ ?line AgentDir = ?config(agent_dir, Config),
+ ?line MgrDir = ?config(mgr_dir, Config),
+ ?line Ip = ?config(ip, Config),
+ ?line config([v1], MgrDir, AgentDir, tuple_to_list(Ip), tuple_to_list(Ip)),
+ [{vsn, v1} | start_v1_agent(Config)].
+
+finish_v1(Config) when list(Config) ->
+ delete_tables(),
+ C1 = stop_agent(Config),
+ delete_files(C1),
+ lists:keydelete(vsn, 1, C1).
+
+
+%%-----------------------------------------------------------------
+%% This function takes care of the old OTP-SNMPEA-MIB.
+%% Unfortunately, the testcases were written to use the data in the
+%% internal tables, and these table are now obsolete and not used
+%% by the agent. Therefore, we emulate them by using
+%% OLD-SNMPEA-MIB, which uses the default impl. of all tables.
+%%
+%% These two rows must exist in intCommunityTable
+%% {[147,214,36,45], "public", 2, readWrite}.
+%% {[147,214,36,45], "standard trap", 2, read}.
+%% (But with the manager's IP address)
+%%
+%%-----------------------------------------------------------------
+init_old() ->
+ snmpa_local_db:table_create_row(intCommunityTable,
+ get(mip) ++ [6 | "public"],
+ {get(mip), "public", 2, 2}),
+ snmpa_local_db:table_create_row(intCommunityTable,
+ get(mip) ++ [13 | "standard trap"],
+ {get(mip), "standard trap", 2, 1}),
+ snmpa_local_db:variable_set(intAgentIpAddress, [127,0,0,1]).
+
+
+%% =========================================================================
+%%
+%% C A S E S
+%%
+%% =========================================================================
+
+%% -- simple --
+
+simple(suite) -> [];
+simple(Config) when list(Config) ->
+ ?P1(simple),
+ ?INIT_CASE(Config),
+
+ ?TRY_TEST1(simple_standard_test).
+
+simple_standard_test() ->
+ ?DBG("simple_standard_test -> entry",[]),
+ ?GN([[1,1]]),
+ ?line expect(1, [{[sysDescr,0], "Erlang SNMP agent"}]),
+
+ ?GN([[1,3]]),
+ ?line expect(11, [{[sysDescr,0], "Erlang SNMP agent"}]),
+
+ ?GN([[1,3,6]]),
+ ?line expect(12, [{[sysDescr,0], "Erlang SNMP agent"}]),
+
+ ?GN([[1,3,6,1]]),
+ ?line expect(13, [{[sysDescr,0], "Erlang SNMP agent"}]),
+
+ ?GN([[1,3,6,1,2]]),
+ ?line expect(14, [{[sysDescr,0], "Erlang SNMP agent"}]),
+
+ ?GN([[1,3,6,1,2,1]]),
+ ?line expect(15, [{[sysDescr,0], "Erlang SNMP agent"}]),
+
+ ?GN([[1,3,6,1,2,1,1]]),
+ ?line expect(16, [{[sysDescr,0], "Erlang SNMP agent"}]),
+
+ ?GN([[sysDescr]]),
+ ?line expect(17, [{[sysDescr,0], "Erlang SNMP agent"}]),
+
+ ?G([[sysDescr,0]]),
+ ?line expect(2, [{[sysDescr,0], "Erlang SNMP agent"}]),
+
+ ?G([[sysDescr]]),
+ ?line ?v1_2(expect(3, noSuchName, 1, any),
+ expect(3, [{[sysDescr], noSuchObject}])),
+
+ ?G([[1,6,7,0]]),
+ ?line ?v1_2(expect(41, noSuchName, 1, any),
+ expect(3, [{[1,6,7,0], noSuchObject}])),
+
+ ?GN([[1,13]]),
+ ?line ?v1_2(expect(4, noSuchName,1, any),
+ expect(4, [{[1,13], endOfMibView}])),
+
+ ?S([{[sysLocation, 0], "new_value"}]),
+ ?line expect(5, [{[sysLocation, 0], "new_value"}]),
+
+ ?G([[sysLocation, 0]]),
+ ?line expect(6, [{[sysLocation, 0], "new_value"}]),
+
+ io:format("Testing noSuchName and badValue...~n"),
+ ?S([{[sysServices,0], 3}]),
+ ?line expect(61, ?v1_2(noSuchName, notWritable), 1, any),
+
+ ?S([{[sysLocation, 0], i, 3}]),
+ ?line expect(62, ?v1_2(badValue, wrongType), 1, any),
+ ?DBG("simple_standard_test -> done",[]),
+ ok.
+
+
+%% -- db_notify_client --
+
+%% This is run in the agent node
+db_notify_client(suite) -> [];
+db_notify_client(Config) when list(Config) ->
+ ?P1(db_notify_client),
+ {SaNode, MgrNode, MibDir} = ?INIT_CASE(Config),
+ ?DBG("~n\tSaNode: ~p~n\tMgrNode: ~p~n\tMibDir: ~p",
+ [SaNode,MgrNode,MibDir]),
+ snmpa_local_db:register_notify_client(self(),?MODULE),
+
+ %% This call (the manager) will issue to set operations, so
+ %% we expect to receive to notify(insert) calls.
+ ?TRY_TEST1(db_notify_client_test),
+
+ ?DBG("await first notify",[]),
+ receive
+ {db_notify_test_reply,insert} -> ?DBG("first notify received",[]),ok
+ end,
+
+ ?DBG("await second notify",[]),
+ receive
+ {db_notify_test_reply,insert} -> ?DBG("second notify received",[]),ok
+ end,
+
+ snmpa_local_db:unregister_notify_client(self()).
+
+
+%% This is run in the manager node
+db_notify_client_test() ->
+ ?DBG("set first new sysLocation",[]),
+ ?S([{[sysLocation, 0], "new_value"}]),
+ ?line expect(5, [{[sysLocation, 0], "new_value"}]),
+
+ ?DBG("set second new sysLocation",[]),
+ ?S([{[sysLocation, 0], "new_value"}]),
+ ?line expect(5, [{[sysLocation, 0], "new_value"}]).
+
+notify(Pid,What) ->
+ ?DBG("notify(~p,~p) -> called",[Pid,What]),
+ Pid ! {db_notify_test_reply,What}.
+
+
+%% -- processing --
+
+%% Req. Test2
+processing(suite) -> [];
+processing(Config) when list(Config) ->
+ ?P1(processing),
+ ?INIT_CASE(Config),
+
+ ?line load_master("Test2"),
+ ?TRY_TEST1(v1_proc),
+ ?line unload_master("Test2").
+
+v1_proc() ->
+ ?DBG("v1_proc -> entry", []),
+ %% According to RFC1157.
+ %% Template: <Section>:<list no>
+ v1_get_p(),
+ v1_get_next_p(),
+ v1_set_p().
+
+v1_get_p() ->
+ %% 4.1.2:1
+ ?G([[test2]]),
+ ?line expect(10, noSuchName, 1, [{[test2], 'NULL'}]),
+ ?G([[tDescr]]),
+ ?line expect(11, noSuchName, 1, [{[tDescr], 'NULL'}]),
+ ?G([[tDescr2,0]]),
+ ?line expect(12, noSuchName, 1, [{[tDescr2,0], 'NULL'}]),
+ ?G([[tDescr3,0]]),
+ ?line expect(131, noSuchName, 1, [{[tDescr3,0], 'NULL'}]),
+ ?G([[tDescr4,0]]),
+ ?line expect(132, noSuchName, 1, [{[tDescr4,0], 'NULL'}]),
+ ?G([[sysDescr, 0], [tDescr,0]]), % Outside mibview
+ ?line expect(14, noSuchName, 2, [{[sysDescr, 0], 'NULL'},
+ {[tDescr,0], 'NULL'}]),
+ ?G([[sysDescr,3]]),
+ ?line expect(15, noSuchName, 1, [{[sysDescr, 3], 'NULL'}]),
+
+ %% 4.1.2:2
+ ?G([[tTable]]),
+ ?line expect(20, noSuchName, 1, [{[tTable], 'NULL'}]),
+ ?G([[tEntry]]),
+ ?line expect(21, noSuchName, 1, [{[tEntry], 'NULL'}]),
+
+ %% 4.1.2:3
+ ?G([[tTooBig, 0]]),
+ ?line expect(30, tooBig, 0, [{[tTooBig, 0], 'NULL'}]),
+
+ %% 4.1.2:4
+ ?G([[tGenErr1, 0]]),
+ ?line expect(40, genErr, 1, [{[tGenErr1, 0], 'NULL'}]),
+ ?G([[tGenErr2, 0]]),
+ ?line expect(41, genErr, 1, [{[tGenErr2, 0], 'NULL'}]),
+ ?G([[sysDescr, 0], [tGenErr3, 0]]),
+ ?line expect(42, genErr, 2, [{[sysDescr, 0], 'NULL'},
+ {[tGenErr3, 0], 'NULL'}]).
+
+v1_get_next_p() ->
+ %% 4.1.3:1
+ ?GN([[1,3,7,1]]),
+ ?line expect(10, noSuchName, 1, [{[1,3,7,1], 'NULL'}]),
+
+ ?GN([[tDescr2]]),
+ ?line expect(11, tooBig, 0, any),
+
+ %% 4.1.3:2
+ ?GN([[tTooBig]]),
+ io:format("We currently don't handle tooBig correct!!!\n"),
+ %% ?line expect(20, tooBig, 0, [{[tTooBig], 'NULL'}]),
+ ?line expect(20, tooBig, 0, any),
+
+ %% 4.1.3:3
+ ?GN([[tGenErr1]]),
+ %% ?line expect(40, genErr, 1, [{[tGenErr1], 'NULL'}]),
+ ?line expect(40, genErr, 1, any),
+
+ ?GN([[tGenErr2]]),
+ %% ?line expect(41, genErr, 1, [{[tGenErr2], 'NULL'}]),
+ ?line expect(41, genErr, 1, any),
+
+ ?GN([[sysDescr], [tGenErr3]]),
+ %% ?line expect(42, genErr, 2, [{[sysDescr], 'NULL'},
+ %% {[tGenErr3], 'NULL'}]).
+ ?line expect(42, genErr, 2, any).
+
+v1_set_p() ->
+ %% 4.1.5:1
+ ?S([{[1,3,7,0], i, 4}]),
+ ?line expect(10, noSuchName, 1, [{[1,3,7,0], 4}]),
+
+ ?S([{[tDescr,0], s, "outside mibview"}]),
+ ?line expect(11, noSuchName, 1, [{[tDescr,0], "outside mibview"}]),
+
+ ?S([{[tDescr3,0], s, "read-only"}]),
+ ?line expect(12, noSuchName, 1, [{[tDescr3,0], "read-only"}]),
+
+ ?S([{[tDescr3], s, "noSuchObject"}]),
+ ?line expect(13, noSuchName, 1, [{[tDescr3], "noSuchObject"}]),
+
+ ?S([{[tDescr3,1], s, "noSuchInstance"}]),
+ ?line expect(14, noSuchName, 1, [{[tDescr3,1], "noSuchInstance"}]),
+
+ ?S([{[tDescr2,0], s, "inconsistentName"}]),
+ ?line expect(15, noSuchName, 1, [{[tDescr2,0], "inconsistentName"}]),
+
+ %% 4.1.5:2
+ ?S([{[tDescr2, 0], i, 4}]),
+ ?line expect(20, badValue, 1, [{[tDescr2, 0], 4}]),
+
+ ?S([{[tDescr2, 0], s, "badValue"}]),
+ ?line expect(21, badValue, 1, [{[tDescr2, 0], "badValue"}]),
+
+ %% 4.1.5:3
+ %% The standard is quite incorrect here. The resp pdu was too big. In
+ %% the resp pdu, we have the original vbs. In the tooBig pdu we still
+ %% have to original vbs => the tooBig pdu is too big as well!!! It
+ %% may not get it to the manager, unless the agent uses 'NULL' instead
+ %% of the std-like original value.
+ ?S([{[tTooBig, 0], s, ?tooBigStr}]),
+ %% according to std:
+ %% ?line expect(30, tooBig, 0, [{[tTooBig, 0], ?tooBigStr}]),
+ ?line expect(30, tooBig, 0, [{[tTooBig, 0], 'NULL'}]),
+
+ %% 4.1.5:4
+ ?S([{[tDescr2, 0], s, "is_set_ok_fail"}]),
+ ?line expect(40, genErr, 1, [{[tDescr2, 0], "is_set_ok_fail"}]),
+
+ ?S([{[tDescr2, 0], s, "commit_fail"}]),
+ ?line expect(41, genErr, 1, [{[tDescr2, 0], "commit_fail"}]).
+
+
+%% -- big --
+
+big(suite) -> [];
+big(Config) when list(Config) ->
+ ?P1(big),
+ {SaNode, _MgrNode, _MibDir} = ?INIT_CASE(Config),
+
+ p("Starting subagent..."),
+ ?line pong = net_adm:ping(SaNode),
+
+ ?line {ok, SA} = ?START_SA(SaNode, ?klas1, "Klas1"),
+ ?DBG("big -> SA: ~p", [SA]),
+ ?line load_master("OLD-SNMPEA-MIB"),
+ ?line init_old(),
+
+ ?TRY_TEST1(big_test),
+
+ ?line ?STOP_SA(SA),
+ ?line unload_master("OLD-SNMPEA-MIB").
+
+%% Req: system group, OLD-SNMPEA-MIB, Klas1
+big_test() ->
+ ?DBG("big_test -> testing simple next/get/set @ master agent...",[]),
+ simple_standard_test(),
+
+ ?DBG("big_test -> testing simple next/get/set @ subagent...",[]),
+ ?GN([[klas1]]),
+ ?line expect(1, [{[fname,0], ""}]),
+
+ ?G([[fname,0]]),
+ ?line expect(2, [{[fname,0], ""}]),
+
+ ?S([{[fname,0], s, "test set"}]),
+ ?line expect(3, [{[fname,0], "test set"}]),
+
+ ?G([[fname,0]]),
+ ?line expect(4, [{[fname,0], "test set"}]),
+
+ ?DBG("big_test -> "
+ "testing next from last instance in master to subagent...",[]),
+ ?GN([[?v1_2(sysServices, sysORLastChange),0]]),
+ ?line expect(5, [{[fname,0], "test set"}]),
+
+ ?GN([[1,1],
+ [?v1_2(sysServices, sysORLastChange),0]]),
+ ?line expect(51, [{[sysDescr,0], "Erlang SNMP agent"},
+ {[fname,0], "test set"}]),
+ ?S([{[fname,0], s, ""}]),
+ ?line expect(52, [{[fname,0], ""}]),
+
+ table_test(),
+
+ ?DBG("big_test -> adding one row in subagent table",[]),
+ _FTab = [friendsEntry],
+ ?S([{[friendsEntry, [2, 3]], s, "kompis3"},
+ {[friendsEntry, [3, 3]], i, ?createAndGo}]),
+ ?line expect(6, [{[friendsEntry, [2, 3]], "kompis3"},
+ {[friendsEntry, [3, 3]], ?createAndGo}]),
+
+ ?G([[friendsEntry, [2, 3]],
+ [friendsEntry, [3, 3]]]),
+ ?line expect(7, [{[friendsEntry, [2, 3]], "kompis3"},
+ {[friendsEntry, [3, 3]], ?active}]),
+
+ ?S([{[friendsEntry, [3, 3]], i, ?destroy}]),
+ ?line expect(8, [{[friendsEntry, [3, 3]], ?destroy}]),
+
+ otp_1131(),
+
+ ?DBG("big_test -> adding two rows in subagent table with special INDEX",
+ []),
+ ?S([{[kompissEntry, [1, 3]], s, "kompis3"},
+ {[kompissEntry, [2, 3]], i, ?createAndGo}]),
+ ?line expect(9, [{[kompissEntry, [1, 3]], "kompis3"},
+ {[kompissEntry, [2, 3]], ?createAndGo}]),
+
+ ?G([[kompissEntry, [1, 3]],
+ [kompissEntry, [2, 3]]]),
+ ?line expect(10, [{[kompissEntry, [1, 3]], "kompis3"},
+ {[kompissEntry, [2, 3]], ?active}]),
+
+ ?GN([[kompissEntry, [1]],
+ [kompissEntry, [2]]]),
+ ?line expect(11, [{[kompissEntry, [1, 3]], "kompis3"},
+ {[kompissEntry, [2, 3]], ?active}]),
+
+ ?S([{[kompissEntry, [1, 2]], s, "kompis3"},
+ {[kompissEntry, [2, 2]], i, ?createAndGo}]),
+ ?line expect(12, [{[kompissEntry, [1, 2]], "kompis3"},
+ {[kompissEntry, [2, 2]], ?createAndGo}]),
+
+ ?GN([[kompissEntry, [1, 1]],
+ [kompissEntry, [2, 1]]]),
+ ?line expect(13, [{[kompissEntry, [1, 2]], "kompis3"},
+ {[kompissEntry, [2, 2]], ?active}]),
+
+ ?S([{[kompissEntry, [2, 3]], i, ?destroy}]),
+ ?line expect(14, [{[kompissEntry, [2, 3]], ?destroy}]),
+
+ ?S([{[kompissEntry, [2, 2]], i, ?destroy}]),
+ ?line expect(15, [{[kompissEntry, [2, 2]], ?destroy}]),
+ ?DBG("big_test -> done",[]),
+ ok.
+
+
+%% Req. system group, Klas2, OLD-SNMPEA-MIB
+big_test_2() ->
+ ?P1(big_test_2),
+
+ ?P2("Testing simple next/get/set @ master agent (2)..."),
+ simple_standard_test(),
+
+ p("Testing simple next/get/set @ subagent (2)..."),
+ ?GN([[klas2]]),
+ ?line expect(1, [{[fname2,0], ""}]),
+
+ ?G([[fname2,0]]),
+ ?line expect(2, [{[fname2,0], ""}]),
+
+ ?S([{[fname2,0], s, "test set"}]),
+ ?line expect(3, [{[fname2,0], "test set"}]),
+
+ ?G([[fname2,0]]),
+ ?line expect(4, [{[fname2,0], "test set"}]),
+
+ otp_1298(),
+
+ ?P2("Testing next from last object in master to subagent (2)..."),
+ ?GN([[?v1_2(sysServices, sysORLastChange),0]]),
+ ?line expect(5, [{[fname2,0], "test set"}]),
+
+ ?GN([[1,1],
+ [?v1_2(sysServices, sysORLastChange),0]]),
+ ?line expect(51, [{[sysDescr,0], "Erlang SNMP agent"},
+ {[fname2,0], "test set"}]),
+
+ table_test(),
+
+ ?P2("Adding one row in subagent table (2)"),
+ ?S([{[friendsEntry2, [2, 3]], s, "kompis3"},
+ {[friendsEntry2, [3, 3]], i, ?createAndGo}]),
+ ?line expect(6, [{[friendsEntry2, [2, 3]], "kompis3"},
+ {[friendsEntry2, [3, 3]], ?createAndGo}]),
+
+ ?G([[friendsEntry2, [2, 3]],
+ [friendsEntry2, [3, 3]]]),
+ ?line expect(7, [{[friendsEntry2, [2, 3]], "kompis3"},
+ {[friendsEntry2, [3, 3]], ?active}]),
+
+ ?S([{[friendsEntry2, [3, 3]], i, ?destroy}]),
+ ?line expect(8, [{[friendsEntry2, [3, 3]], ?destroy}]),
+
+ ?P2("Adding two rows in subagent table with special INDEX (2)"),
+ ?S([{[kompissEntry2, [1, 3]], s, "kompis3"},
+ {[kompissEntry2, [2, 3]], i, ?createAndGo}]),
+ ?line expect(9, [{[kompissEntry2, [1, 3]], "kompis3"},
+ {[kompissEntry2, [2, 3]], ?createAndGo}]),
+ ?G([[kompissEntry2, [1, 3]],
+ [kompissEntry2, [2, 3]]]),
+ ?line expect(10, [{[kompissEntry2, [1, 3]], "kompis3"},
+ {[kompissEntry2, [2, 3]], ?active}]),
+ ?GN([[kompissEntry2, [1]],
+ [kompissEntry2, [2]]]),
+ ?line expect(11, [{[kompissEntry2, [1, 3]], "kompis3"},
+ {[kompissEntry2, [2, 3]], ?active}]),
+
+ ?S([{[kompissEntry2, [1, 2]], s, "kompis3"},
+ {[kompissEntry2, [2, 2]], i, ?createAndGo}]),
+ ?line expect(12, [{[kompissEntry2, [1, 2]], "kompis3"},
+ {[kompissEntry2, [2, 2]], ?createAndGo}]),
+
+ ?GN([[kompissEntry2, [1, 1]],
+ [kompissEntry2, [2, 1]]]),
+ ?line expect(13, [{[kompissEntry2, [1, 2]], "kompis3"},
+ {[kompissEntry2, [2, 2]], ?active}]),
+
+ ?S([{[kompissEntry2, [2, 3]], i, ?destroy}]),
+ ?line expect(14, [{[kompissEntry2, [2, 3]], ?destroy}]),
+
+ ?S([{[kompissEntry2, [2, 2]], i, ?destroy}]),
+ ?line expect(15, [{[kompissEntry2, [2, 2]], ?destroy}]),
+ ok.
+
+
+%% -- bug2 --
+
+big2(suite) -> [];
+big2(Config) when list(Config) ->
+ ?P1(big2),
+ %% This is exactly the same tests as 'big', but with the
+ %% v2 equivalent of the mibs.
+ {SaNode, _MgrNode, _MibDir} = ?INIT_CASE(Config),
+
+ ?P2("Starting subagent..."),
+ ?line pong = net_adm:ping(SaNode),
+
+ ?line {ok, SA} = ?START_SA(SaNode, ?klas1, "Klas1-v2"),
+ ?line load_master("OLD-SNMPEA-MIB-v2"),
+ ?line init_old(),
+
+ ?TRY_TEST1(big_test),
+
+ ?line ?STOP_SUBAGENT(SA),
+ ?line unload_master("OLD-SNMPEA-MIB-v2").
+
+
+implied(suite) -> [];
+implied(Config) when list(Config) ->
+ ?P1(implied),
+ ?INIT_CASE(Config),
+
+ ?line load_master("Test1"),
+
+ ?TRY_TEST2(implied_test,[whereis(snmp_master_agent)]),
+
+ ?line unload_master("Test1").
+
+%% Req. Test1
+implied_test(MA) ->
+ ?LOG("implied_test -> start",[]),
+
+ snmpa:verbosity(MA,trace),
+ snmpa:verbosity(MA,trace),
+
+ %% Create two rows, check that they are get-nexted in correct order.
+ Idx1 = "apa",
+ Idx2 = "qq",
+
+ ?DBG("implied_test -> (send) create row 1 '~s' in table 1",[Idx1]),
+ ?S([{[testStatus, Idx1], i, ?createAndGo}, {[testDescr, Idx1],s,"row 1"}]),
+ ?line expect(1, [{[testStatus, Idx1], ?createAndGo},
+ {[testDescr, Idx1], "row 1"}]),
+ ?DBG("implied_test -> (send) create row 2 '~s' in table 1",[Idx2]),
+
+ ?S([{[testStatus, Idx2], i, ?createAndGo}, {[testDescr, Idx2],s,"row 2"}]),
+ ?line expect(2, [{[testStatus, Idx2], ?createAndGo},
+ {[testDescr, Idx2], "row 2"}]),
+ ?DBG("implied_test -> get-next(testDescr)",[]),
+
+ ?GN([[testDescr]]),
+ ?line expect(3, [{[testDescr,Idx1], "row 1"}]),
+ ?DBG("implied_test -> get-next(testDescr) of row 1",[]),
+
+ ?GN([[testDescr,Idx1]]),
+ ?line expect(4, [{[testDescr,Idx2], "row 2"}]),
+
+ % Delete the rows
+ ?DBG("implied_test -> (send) delete row 1 '~s' from table 1",[Idx1]),
+ ?S([{[testStatus, Idx1], i, ?destroy}]),
+ ?line expect(5, [{[testStatus, Idx1], ?destroy}]),
+
+ ?DBG("implied_test -> (send) delete row 2 '~s' from table 1",[Idx2]),
+ ?S([{[testStatus, Idx2], i, ?destroy}]),
+ ?line expect(6, [{[testStatus, Idx2], ?destroy}]),
+
+ %% Try the same in other table
+ Idx3 = [1, "apa"],
+ Idx4 = [1, "qq"],
+ ?DBG("implied_test -> (send) create row 1 '~s' in table 2",[Idx3]),
+ ?S([{[testStatus2, Idx3], i, ?createAndGo}, {[testDescr2,Idx3],s,"row 1"}]),
+ ?line expect(1, [{[testStatus2, Idx3], ?createAndGo},
+ {[testDescr2, Idx3], "row 1"}]),
+
+ ?DBG("implied_test -> (send) create row 2 '~s' in table 2",[Idx4]),
+ ?S([{[testStatus2, Idx4], i, ?createAndGo},
+ {[testDescr2,Idx4],s,"row 2"}]),
+ ?line expect(2, [{[testStatus2, Idx4], ?createAndGo},
+ {[testDescr2, Idx4], "row 2"}]),
+
+ ?DBG("implied_test -> get-next(testDescr2)",[]),
+ ?GN([[testDescr2]]),
+ ?line expect(3, [{[testDescr2,Idx3], "row 1"}]),
+ ?DBG("implied_test -> get-next(testDescr2) of row 1",[]),
+
+ ?GN([[testDescr2,Idx3]]),
+ ?line expect(4, [{[testDescr2,Idx4], "row 2"}]),
+
+ % Delete the rows
+ ?DBG("implied_test -> (send) delete row 1 '~s' from table 2",[Idx3]),
+ ?S([{[testStatus2, Idx3], i, ?destroy}]),
+ ?line expect(5, [{[testStatus2, Idx3], ?destroy}]),
+
+ ?DBG("implied_test -> (send) delete row 2 '~s' from table 2",[Idx4]),
+ ?S([{[testStatus2, Idx4], i, ?destroy}]),
+ ?line expect(6, [{[testStatus2, Idx4], ?destroy}]),
+
+ snmpa:verbosity(MA,log),
+
+ ?LOG("implied_test -> done",[]).
+
+
+%% -- loop_mib --
+
+%%-----------------------------------------------------------------
+%% Loop through entire MIB, to make sure that all instrum. funcs
+%% works.
+%% Load all std mibs that are not loaded by default.
+%%-----------------------------------------------------------------
+loop_mib(suite) -> [];
+loop_mib(Config) when list(Config) ->
+ ?P1(loop_mib),
+ %% snmpa:verbosity(master_agent,debug),
+ %% snmpa:verbosity(mib_server,info),
+ {SaNode, MgrNode, MibDir} = ?INIT_CASE(Config),
+ ?DBG("loop_mib -> "
+ "~n SaNode: ~p"
+ "~n MgrNode: ~p"
+ "~n MibDir: ~p", [SaNode, MgrNode, MibDir]),
+
+ ?DBG("loop_mib -> load mib SNMP-COMMUNITY-MIB",[]),
+ ?line load_master_std("SNMP-COMMUNITY-MIB"),
+ ?DBG("loop_mib -> load mib SNMP-MPD-MIB",[]),
+ ?line load_master_std("SNMP-MPD-MIB"),
+ ?DBG("loop_mib -> load mib SNMP-TARGET-MIB",[]),
+ ?line load_master_std("SNMP-TARGET-MIB"),
+ ?DBG("loop_mib -> load mib SNMP-NOTIFICATION-MIB",[]),
+ ?line load_master_std("SNMP-NOTIFICATION-MIB"),
+ ?DBG("loop_mib -> load mib SNMP-FRAMEWORK-MIB",[]),
+ ?line load_master_std("SNMP-FRAMEWORK-MIB"),
+ ?DBG("loop_mib -> load mib SNMP-VIEW-BASED-ACM-MIB",[]),
+ ?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"),
+ ?DBG("loop_mib -> try",[]),
+
+ ?TRY_TEST1(loop_mib),
+
+ ?DBG("loop_mib -> unload mib SNMP-COMMUNITY-MIB",[]),
+ ?line unload_master("SNMP-COMMUNITY-MIB"),
+ ?DBG("loop_mib -> unload mib SNMP-MPD-MIB",[]),
+ ?line unload_master("SNMP-MPD-MIB"),
+ ?DBG("loop_mib -> unload mib SNMP-TARGET-MIB",[]),
+ ?line unload_master("SNMP-TARGET-MIB"),
+ ?DBG("loop_mib -> unload mib SNMP-NOTIFICATION-MIB",[]),
+ ?line unload_master("SNMP-NOTIFICATION-MIB"),
+ ?DBG("loop_mib -> unload mib SNMP-FRAMEWORK-MIB",[]),
+ ?line unload_master("SNMP-FRAMEWORK-MIB"),
+ ?DBG("loop_mib -> unload mib SNMP-VIEW-BASED-ACM-MIB",[]),
+ ?line unload_master("SNMP-VIEW-BASED-ACM-MIB"),
+ %% snmpa:verbosity(master_agent,log),
+ %% snmpa:verbosity(mib_server,silence),
+ ?LOG("loop_mib -> done",[]).
+
+%% Req. As many mibs all possible
+loop_mib() ->
+ ?DBG("loop_mib -> entry",[]),
+ N = loop_it([1,1], 0),
+ ?P3("found ~w varibles\n", [N]),
+ ?line N = if N < 100 -> 100;
+ true -> N
+ end.
+
+loop_it(Oid, N) ->
+ ?DBG("loop_it -> entry with"
+ "~n Oid: ~p"
+ "~n N: ~p", [Oid,N]),
+ case get_next_req([Oid]) of
+ #pdu{type='get-response', error_status=noError, error_index=0,
+ varbinds=[#varbind{oid = NOid,value = Value}]} when NOid > Oid ->
+ ?DBG("loop_it -> "
+ "~n NOid: ~p"
+ "~n Value: ~p",[NOid,Value]),
+ ?line [Value2] = get_req(1, [NOid]), % must not be same
+ ?DBG("loop_it_1 -> "
+ "~n Value2: ~p",[Value2]),
+ loop_it(NOid, N+1);
+
+ #pdu{type='get-response', error_status=noSuchName, error_index=1,
+ varbinds=[_]} ->
+ ?DBG("loop_it -> done",[]),
+ N;
+
+ #pdu{type = Type, error_status = Err, error_index = Idx,
+ varbinds = Vbs} ->
+ exit({unexpected_pdu, ?LINE, Type, Err, Idx, Vbs})
+
+ end.
+
+
+%% -- api --
+
+api(suite) -> [];
+api(Config) when list(Config) ->
+ ?P1(api),
+ ?INIY_CASE(Config),
+
+ ?line load_master("OLD-SNMPEA-MIB"),
+ ?line init_old(),
+
+ ?TRY_TEST2(api_test, [node()]),
+
+ ?line unload_master("OLD-SNMPEA-MIB").
+
+%% Req. OLD-SNMPEA-MIB
+api_test(MaNode) ->
+ ?line {value, OID} = ?RPC(MaNode, name_to_oid, [intAgentIpAddress]),
+ ?line {value, intAgentIpAddress} = ?RPC(MaNode, oid_to_name, [OID]),
+ ?line false = ?RPC(MaNode, name_to_oid, [intAgentIpAddres]),
+ ?line false = ?RPC(MaNode, oid_to_name, [[1,5,32,3,54,3,3,34,4]]),
+ ?line {value, 2} = ?RPC(MaNode, enum_to_int, [intViewType, excluded]),
+ ?line {value, excluded} = ?RPC(MaNode, int_to_enum, [intViewType, 2]),
+ ?line false = ?RPC(MaNode, enum_to_int, [intViewType, exclude]),
+ ?line false = ?RPC(MaNode, enum_to_int, [intAgentIpAddress, exclude]),
+ ?line false = ?RPC(MaNode, enum_to_int, [intAgentIpAddre, exclude]),
+ ?line false = ?RPC(MaNode, int_to_enum, [intViewType, 3]),
+ ?line false = ?RPC(MaNode, int_to_enum, [intAgentIpAddress, 2]),
+ ?line false = ?RPC(MaNode, int_to_enum, [intAgentIpAddre, 2]),
+ ?line {value, active} = ?RPC(MaNode, int_to_enum, ['RowStatus', ?active]),
+ ?line {value, ?destroy} =
+ ?RPC(MaNode, enum_to_int, ['RowStatus', destroy]),
+ ?line false = ?RPC(MaNode, enum_to_int, ['RowStatus', xxxdestroy]),
+ ?line false = ?RPC(MaNode, enum_to_int, ['xxRowStatus', destroy]),
+ ?line false = ?RPC(MaNode, int_to_enum, ['RowStatus', 25]),
+ ?line false = ?RPC(MaNode, int_to_enum, ['xxRowStatus', 1]),
+ ?line case snmp:date_and_time() of
+ List when list(List), length(List) == 8 -> ok;
+ List when list(List), length(List) == 11 -> ok
+ end.
+
+
+%% -- subagent --
+
+subagent(suite) -> [];
+subagent(Config) when list(Config) ->
+ ?P1(subagent),
+ {SaNode, _MgrNode, MibDir} = ?INIT_CASE(Config),
+
+ ?line {ok, SA} = ?START_SA(SaNode, ?klas1, "Klas1"),
+
+ ?TRY_TEST1(load_test_sa),
+
+ ?P2("Testing unregister subagent [~w]...", [SA]),
+ MA = whereis(snmp_master_agent),
+ ?RPC(SaNode, unregister_subagent, [MA, SA]),
+ ?TRY_TEST1(unreg_test),
+
+ ?P2("Loading previous subagent mib in master and testing..."),
+ ?line ok = snmpa:load_mibs(MA, [MibDir ++ "Klas1"]),
+ ?TRY_TEST1(load_test),
+
+ ?P2("Unloading previous subagent mib in master and testing..."),
+ ?line ok = snmpa:unload_mibs(MA, [MibDir ++ "Klas1"]),
+
+ ?TRY_TEST1(unreg_test),
+
+ ?P2("Testing register subagent..."),
+ ?RPC(SaNode, register_subagent, [MA, ?klas1, SA]),
+ ?TRY_TEST1(load_test_sa),
+
+ ?line ?STOP_SA(SA),
+ ?TRY_TEST1(unreg_test).
+
+%% Req. Klas1
+load_test_sa() ->
+ ?GN([[?v1_2(sysServices,sysORLastChange), 0]]),
+ ?line expect(1, [{[fname,0], any}]).
+
+unreg_test() ->
+ ?GN([[?v1_2(sysServices, sysORLastChange),0]]),
+ ?line expect(1, [{[snmpInPkts, 0], any}]).
+
+load_test() ->
+ ?GN([[?v1_2(sysServices, sysORLastChange),0]]),
+ ?line expect(1, [{[fname,0], ""}]).
+
+
+%% -- mnesia --
+
+mnesia(suite) -> [];
+mnesia(Config) when list(Config) ->
+ {SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ p("Starting subagent with mnesia impl..."),
+ {ok, SA} = start_subagent(SaNode, ?klas2, "Klas2"),
+ ?line load_master("OLD-SNMPEA-MIB"),
+ ?line init_old(),
+
+ ?TRY_TEST1(big_test_2),
+
+ p("Testing unregister subagent..."),
+ MA = whereis(snmp_master_agent),
+ rpc:call(SaNode, snmp, unregister_subagent, [MA, SA]),
+ ?TRY_TEST1(unreg_test),
+ ?line unload_master("OLD-SNMPEA-MIB"),
+ ?line stop_subagent(SA).
+
+
+%% -- multiple_reqs --
+
+multiple_reqs(suite) ->
+ {req, [], {conf, init_mul, mul_cases(), finish_mul}}.
+
+mul_cases() ->
+ [mul_get, mul_get_err, mul_next, mul_next_err, mul_set_err].
+
+init_mul(Config) when list(Config) ->
+ {SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ ?line {ok, SA} = start_subagent(SaNode, ?klas1, "Klas1"),
+ ?line load_master("OLD-SNMPEA-MIB"),
+ ?line init_old(),
+ [{mul_sub, SA} | Config].
+
+finish_mul(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ SA = ?config(mul_sub, Config),
+
+ ?line unload_master("OLD-SNMPEA-MIB"),
+ ?line stop_subagent(SA),
+ lists:keydelete(mul_sub, 1, Config).
+
+
+%% -- mul_get --
+
+mul_get(suite) -> [];
+mul_get(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ p("Testing multiple get..."),
+ ?TRY_TEST1(do_mul_get).
+
+%% Req. system group, Klas1, OLD-SNMPEA-MIB
+do_mul_get() ->
+ Key1c3 = [intCommunityEntry,[3],get(mip),is("public")],
+ Key1c4 = [intCommunityEntry,[4],get(mip),is("public")],
+ s([{[fname,0], s, "test set"}]),
+ ?line expect(3, [{[fname,0], "test set"}]),
+ g([[sysDescr,0], Key1c4, [fname,0],Key1c3,
+ [sysName,0]]),
+ ?line expect(1, [{[sysDescr,0], "Erlang SNMP agent"},
+ {Key1c4, 2},
+ {[fname,0], "test set"},
+ {Key1c3, 2},
+ {[sysName,0], "test"}]),
+ g([[1,3,7,1], Key1c4, [sysDescr,0], [1,3,7,2], Key1c3, [sysDescr,0]]),
+ ?line ?v1_2(expect(2, noSuchName, [1,4], any),
+ expect(2, [{[1,3,7,1], noSuchObject},
+ {Key1c4, 2},
+ {[sysDescr,0], "Erlang SNMP agent"},
+ {[1,3,7,2], noSuchObject},
+ {Key1c3, 2},
+ {[sysDescr,0], "Erlang SNMP agent"}])).
+
+
+%% -- mul_get_err --
+
+mul_get_err(suite) -> [];
+mul_get_err(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ p("Testing multiple get with error..."),
+ ?TRY_TEST1(do_mul_get_err).
+
+%% Req. v1, system group, Klas1, OLD-SNMPEA-MIB, *ej* Klas3.
+do_mul_get_err() ->
+ Key1c3 = [intCommunityEntry,[3],get(mip),is("public")],
+ Key1c4 = [intCommunityEntry,[4],get(mip),is("public")],
+ s([{[fname,0], s, "test set"}]),
+ ?line expect(3, [{[fname,0], "test set"}]),
+ g([[sysDescr,0],Key1c4,[fname,0], Key1c3, [sysName,2]]),
+ ?line ?v1_2(expect(1, noSuchName, 5, any),
+ expect(1, [{[sysDescr,0], "Erlang SNMP agent"},
+ {Key1c4, 2},
+ {[fname,0], "test set"},
+ {Key1c3, 2},
+ {[sysName,2], noSuchInstance}])),
+ g([[sysDescr,0],Key1c4,[fname3,0], Key1c3, [sysName,1]]),
+ ?line ?v1_2(expect(1, noSuchName, [3,5], any),
+ expect(1, [{[sysDescr,0], "Erlang SNMP agent"},
+ {Key1c4, 2},
+ {[fname3,0], noSuchObject},
+ {Key1c3, 2},
+ {[sysName,1], noSuchInstance}])).
+
+
+%% -- mul_next --
+
+mul_next(suite) -> [];
+mul_next(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ p("Testing multiple next..."),
+ ?TRY_TEST1(do_mul_next).
+
+%% Req. system group, Klas1, OLD-SNMPEA-MIB
+do_mul_next() ->
+ Key1c3s = [intCommunityEntry,[3],get(mip),is("publi")],
+ Key1c4s = [intCommunityEntry,[4],get(mip),is("publi")],
+ Key1c3 = [intCommunityEntry,[3],get(mip),is("public")],
+ Key1c4 = [intCommunityEntry,[4],get(mip),is("public")],
+ s([{[fname,0], s, "test set"}]),
+ ?line expect(3, [{[fname,0], "test set"}]),
+ gn([[sysDescr], Key1c4s, [fname],Key1c3s,[sysName]]),
+ ?line expect(1, [{[sysDescr,0], "Erlang SNMP agent"},
+ {Key1c4, 2}, {[fname,0], "test set"},
+ {Key1c3, 2}, {[sysName,0], "test"}]).
+
+
+%% -- mul_next_err --
+
+mul_next_err(suite) -> [];
+mul_next_err(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ p("Testing multiple next..."),
+ ?TRY_TEST1(do_mul_next_err).
+
+%% Req. system group, Klas1, OLD-SNMPEA-MIB
+do_mul_next_err() ->
+ Key1c3s = [intCommunityEntry,[3],get(mip),is("publi")],
+ Key1c4s = [intCommunityEntry,[4],get(mip),is("publi")],
+ Key1c3 = [intCommunityEntry,[3],get(mip),is("public")],
+ Key1c4 = [intCommunityEntry,[4],get(mip),is("public")],
+ s([{[fname,0], s, "test set"}]),
+ ?line expect(3, [{[fname,0], "test set"}]),
+ gn([[sysDescr], Key1c4s, [1,3,6,999], [fname],[1,3,90], Key1c3s,[sysName]]),
+ ?line ?v1_2(expect(1, noSuchName, [3,5], any),
+ expect(1, [{[sysDescr,0], "Erlang SNMP agent"},
+ {Key1c4, 2},
+ {[1,3,6,999], endOfMibView},
+ {[fname,0], "test set"},
+ {[1,3,90], endOfMibView},
+ {Key1c3, 2},
+ {[sysName,0], "test"}])).
+
+
+%% -- mul_set --
+
+mul_set(suite) -> [];
+mul_set(Config) when list(Config) ->
+ ?P(mul_set),
+ ?INIT_CASE(Config),
+
+ ?TRY_TEST1(do_mul_set).
+
+%% Req. system group, Klas1, OLD-SNMPEA-MIB
+do_mul_set() ->
+ p("Adding one row in subagent table, and one in master table"),
+ NewKeyc3 = [intCommunityEntry,[3],get(mip),is("test")],
+ NewKeyc4 = [intCommunityEntry,[4],get(mip),is("test")],
+ NewKeyc5 = [intCommunityEntry,[5],get(mip),is("test")],
+ s([{[friendsEntry, [2, 3]], "kompis3"},
+ {NewKeyc3, 2},
+ {[sysLocation,0], "new_value"},
+ {NewKeyc5, ?createAndGo},
+ {NewKeyc4, 2},
+ {[friendsEntry, [3, 3]], ?createAndGo}]),
+ ?line expect(1, [{[friendsEntry, [2, 3]], "kompis3"},
+ {NewKeyc3, 2},
+ {[sysLocation,0], "new_value"},
+ {NewKeyc5, ?createAndGo},
+ {NewKeyc4, 2},
+ {[friendsEntry, [3, 3]], ?createAndGo}]),
+ g([[friendsEntry, [2, 3]],
+ [sysLocation,0],
+ [friendsEntry, [3, 3]]]),
+ ?line expect(2, [{[friendsEntry, [2, 3]], "kompis3"},
+ {[sysLocation,0], "new_value"},
+ {[friendsEntry, [3, 3]], ?active}]),
+ g([NewKeyc4]),
+ ?line expect(3, [{NewKeyc4, 2}]),
+ s([{[friendsEntry, [3, 3]], ?destroy},
+ {NewKeyc5, ?destroy}]),
+ ?line expect(4, [{[friendsEntry, [3, 3]], ?destroy},
+ {NewKeyc5, ?destroy}]).
+
+
+%% -- mul_set_err --
+
+mul_set_err(suite) -> [];
+mul_set_err(Config) when list(Config) ->
+ ?P(mul_set_err),
+ ?INIT_CASE(Config),
+
+ ?TRY_TEST1(do_mul_set_err).
+
+%% Req. system group, Klas1, OLD-SNMPEA-MIB
+do_mul_set_err() ->
+ NewKeyc3 = [intCommunityEntry,[3],get(mip),is("test")],
+ NewKeyc4 = [intCommunityEntry,[4],get(mip),is("test")],
+ NewKeyc5 = [intCommunityEntry,[5],get(mip),is("test")],
+ p("Adding one row in subagent table, and one in master table"),
+ s([{[friendsEntry, [2, 3]], s, "kompis3"},
+ {NewKeyc3, 2},
+ {[sysUpTime,0], 45}, % sysUpTime (readOnly)
+ {NewKeyc5, ?createAndGo},
+ {NewKeyc4, 2},
+ {[friendsEntry, [3, 3]], ?createAndGo}]),
+ ?line expect(1, ?v1_2(noSuchName, notWritable), 3, any),
+ g([[friendsEntry, [2, 3]]]),
+ ?line ?v1_2(expect(2, noSuchName, 1, any),
+ expect(2, [{[friendsEntry, [2,3]], noSuchInstance}])),
+ g([NewKeyc4]),
+ ?line ?v1_2(expect(3, noSuchName, 1, any),
+ expect(3, [{NewKeyc4, noSuchInstance}])).
+
+
+%% -- sa_register --
+
+sa_register(suite) -> [];
+sa_register(Config) when list(Config) ->
+ ?P1(sa_register),
+ {SaNode, _MgrNode, MibDir} = ?INIT_CASE(Config),
+
+ ?DBG("sa_register -> start subagent", []),
+ ?line {ok, SA} = start_subagent(SaNode, ?klas1, "Klas1"),
+
+ ?DBG("sa_register -> unregister subagent", []),
+ ?P2("Testing unregister subagent (2)..."),
+ MA = whereis(snmp_master_agent),
+ rpc:call(SaNode, snmp, unregister_subagent, [MA, ?klas1]),
+ ?TRY_TEST1(unreg_test),
+
+ ?P2("Loading SA-MIB..."),
+ ?DBG("sa_register -> unload mibs", []),
+ snmpa:unload_mibs(SA, [MibDir ++ "Klas1"]),
+ ?DBG("sa_register -> unload mibs", []),
+ snmpa:load_mibs(SA, [MibDir ++ "SA-MIB"]),
+ ?DBG("sa_register -> register subagent", []),
+ rpc:call(SaNode, snmp, register_subagent, [MA,?sa,SA]),
+ ?TRY_TEST1(sa_mib),
+
+ ?DBG("sa_register -> stop subagent", []),
+ ?line stop_subagent(SA).
+
+%% Req. SA-MIB
+sa_mib() ->
+ g([[sa, [2,0]]]),
+ ?line expect(1, [{[sa, [2,0]], 3}]),
+ s([{[sa, [1,0]], s, "sa_test"}]),
+ ?line expect(2, [{[sa, [1,0]], "sa_test"}]).
+
+
+%% -- v1_trap --
+
+v1_trap(suite) -> [];
+v1_trap(Config) when list(Config) ->
+ {SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ ?line {ok, SA} = start_subagent(SaNode, ?sa, "SA-MIB"),
+
+ p("Testing trap sending from master agent..."),
+ MA = whereis(snmp_master_agent),
+
+ ?line load_master("TestTrap"),
+ ?line load_master("TestTrapv2"),
+
+ ?TRY_TEST2(ma_trap1, [MA]),
+ ?TRY_TEST2(ma_trap2, [MA]),
+ ?TRY_TEST2(ma_v2_2_v1_trap, [MA]),
+ ?TRY_TEST2(ma_v2_2_v1_trap2, [MA]),
+
+ p("Testing trap sending from subagent..."),
+ ?TRY_TEST2(sa_trap1, [SA]),
+ ?TRY_TEST2(sa_trap2, [SA]),
+ ?TRY_TEST2(sa_trap3, [SA]),
+
+ ?line unload_master("TestTrap"),
+ ?line unload_master("TestTrapv2"),
+
+ ?line stop_subagent(SA).
+
+ma_trap1(MA) ->
+ snmpa:send_trap(MA, testTrap2, "standard trap"),
+ ?line expect(1, trap, [system], 6, 1, [{[system, [4,0]],
+ "{mbj,eklas}@erlang.ericsson.se"}]),
+ snmpa:send_trap(MA, testTrap1, "standard trap"),
+ ?line expect(2, trap, [1,2,3] , 1, 0, [{[system, [4,0]],
+ "{mbj,eklas}@erlang.ericsson.se"}]).
+
+ma_trap2(MA) ->
+ snmpa:send_trap(MA,testTrap2,"standard trap",[{sysContact,"pelle"}]),
+ ?line expect(3, trap, [system], 6, 1, [{[system, [4,0]], "pelle"}]).
+
+ma_v2_2_v1_trap(MA) ->
+ snmpa:send_trap(MA,testTrapv22,"standard trap",[{sysContact,"pelle"}]),
+ ?line expect(3, trap, [system], 6, 1, [{[system, [4,0]], "pelle"}]).
+
+ma_v2_2_v1_trap2(MA) ->
+ snmpa:send_trap(MA,linkUp,"standard trap",[{ifIndex, [1], 1},
+ {ifAdminStatus, [1], 1},
+ {ifOperStatus, [1], 2}]),
+ ?line expect(3, trap, [1,2,3], 3, 0, [{[ifIndex, 1], 1},
+ {[ifAdminStatus, 1], 1},
+ {[ifOperStatus, 1], 2}]).
+
+sa_trap1(SA) ->
+ snmpa:send_trap(SA, saTrap, "standard trap"),
+ ?line expect(4, trap, [ericsson], 6, 1, [{[system, [4,0]],
+ "{mbj,eklas}@erlang.ericsson.se"},
+ {[sa, [1,0]], "sa_test"}]).
+
+sa_trap2(SA) ->
+ snmpa:send_trap(SA, saTrap, "standard trap",[{sysContact,"pelle"}]),
+ ?line expect(5, trap, [ericsson], 6, 1, [{[system, [4,0]],
+ "pelle"},
+ {[sa, [1,0]], "sa_test"}]).
+
+sa_trap3(SA) ->
+ snmpa:send_trap(SA, saTrap2, "standard trap",
+ [{intViewSubtree, [4], [1,2,3,4]}]),
+ ?line expect(6, trap, [ericsson], 6, 2, [{[system, [4,0]],
+ "{mbj,eklas}@erlang.ericsson.se"},
+ {[sa, [1,0]], "sa_test"},
+ {[intViewSubtree,4],[1,2,3,4]}]).
+
+ma_v2_trap1(MA) ->
+ ?DBG("ma_v2_traps -> entry with MA = ~p => "
+ "send standard trap: testTrapv22",[MA]),
+ snmpa:send_trap(MA, testTrapv22, "standard trap"),
+ ?line expect(1, v2trap, [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?system ++ [0,1]}]),
+ ?DBG("ma_v2_traps -> send standard trap: testTrapv21",[]),
+ snmpa:send_trap(MA, testTrapv21, "standard trap"),
+ ?line expect(2, v2trap, [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?snmp ++ [1]}]).
+
+ma_v2_trap2(MA) ->
+ snmpa:send_trap(MA,testTrapv22,"standard trap",[{sysContact,"pelle"}]),
+ ?line expect(3, v2trap, [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?system ++ [0,1]},
+ {[system, [4,0]], "pelle"}]).
+
+ma_v1_2_v2_trap(MA) ->
+ snmpa:send_trap(MA,linkDown,"standard trap",[{ifIndex, [1], 1}]),
+ ?line expect(2, v2trap, [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?snmpTraps ++ [3]},
+ {[ifIndex, 1], 1},
+ {[snmpTrapEnterprise, 0], [1,2,3]}]).
+
+
+ma_v1_2_v2_trap2(MA) ->
+ snmpa:send_trap(MA,testTrap2,"standard trap",[{sysContact,"pelle"}]),
+ ?line expect(3, v2trap, [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?system ++ [0,1]},
+ {[system, [4,0]], "pelle"},
+ {[snmpTrapEnterprise, 0], ?system}]).
+
+
+sa_v1_2_v2_trap1(SA) ->
+ snmpa:send_trap(SA, saTrap, "standard trap"),
+ ?line expect(4, v2trap, [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?ericsson ++ [0, 1]},
+ {[system, [4,0]],
+ "{mbj,eklas}@erlang.ericsson.se"},
+ {[sa, [1,0]], "sa_test"},
+ {[snmpTrapEnterprise, 0], ?ericsson}]).
+
+sa_v1_2_v2_trap2(SA) ->
+ snmpa:send_trap(SA, saTrap, "standard trap",[{sysContact,"pelle"}]),
+ ?line expect(4, v2trap, [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?ericsson ++ [0, 1]},
+ {[system, [4,0]], "pelle"},
+ {[sa, [1,0]], "sa_test"},
+ {[snmpTrapEnterprise, 0], ?ericsson}]).
+
+
+sa_v1_2_v2_trap3(SA) ->
+ snmpa:send_trap(SA, saTrap2, "standard trap",
+ [{intViewSubtree, [4], [1,2,3,4]}]),
+ ?line expect(4, v2trap, [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?ericsson ++ [0, 2]},
+ {[system, [4,0]],
+ "{mbj,eklas}@erlang.ericsson.se"},
+ {[sa, [1,0]], "sa_test"},
+ {[intViewSubtree,4],[1,2,3,4]},
+ {[snmpTrapEnterprise, 0], ?ericsson}]).
+
+
+%% -- sa_error --
+
+sa_error(suite) -> [];
+sa_error(Config) when list(Config) ->
+ {SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ ?line load_master("OLD-SNMPEA-MIB"),
+ ?line init_old(),
+ ?line {ok, SA} = start_subagent(SaNode, ?sa, "SA-MIB"),
+
+ p("Testing sa bad value (is_set_ok)..."),
+ ?TRY_TEST1(sa_errs_bad_value),
+
+ p("Testing sa gen err (set)..."),
+ ?TRY_TEST1(sa_errs_gen_err),
+
+ p("Testing too big..."),
+ ?TRY_TEST1(sa_too_big),
+
+ ?line unload_master("OLD-SNMPEA-MIB"),
+ stop_subagent(SA).
+
+%% Req. SA-MIB, OLD-SNMPEA-MIB
+sa_errs_bad_value() ->
+ NewKeyc3 = [intCommunityEntry,[3],get(mip),is("test")],
+ NewKeyc4 = [intCommunityEntry,[4],get(mip),is("test")],
+ NewKeyc5 = [intCommunityEntry,[5],get(mip),is("test")],
+ s([{NewKeyc3, 2},
+ {[sa, [2,0]], 5}, % badValue (i is_set_ok)
+ {NewKeyc5, ?createAndGo},
+ {NewKeyc4, 2}]),
+ ?line expect(1, badValue, 2, any),
+ s([{NewKeyc3, 2},
+ {[sa, [2,0]], 6}, % wrongValue (i is_set_ok)
+ {NewKeyc5, ?createAndGo},
+ {NewKeyc4, 2}]),
+ ?line expect(1, ?v1_2(badValue, wrongValue), 2, any),
+ g([NewKeyc4]),
+ ?line ?v1_2(expect(2, noSuchName, 1, any),
+ expect(2, [{NewKeyc4, noSuchInstance}])).
+
+%% Req. SA-MIB, OLD-SNMPEA-MIB
+sa_errs_gen_err() ->
+ NewKeyc3 = [intCommunityEntry,[3],get(mip),is("test")],
+ NewKeyc4 = [intCommunityEntry,[4],get(mip),is("test")],
+ NewKeyc5 = [intCommunityEntry,[5],get(mip),is("test")],
+ s([{NewKeyc3, 2},{NewKeyc4, 2},
+ {NewKeyc5, ?createAndGo}, {[sa, [3,0]], 5}]),
+ ?line expect(1, genErr, 4, any),
+% The row might have been added; we don't know.
+% (as a matter of fact we do - it is added, because the agent
+% first sets its own vars, and then th SAs. Lets destroy it.
+ s([{NewKeyc5, ?destroy}]),
+ ?line expect(2, [{NewKeyc5, ?destroy}]).
+
+%% Req. SA-MIB, OLD-SNMPEA-MIB
+sa_too_big() ->
+ g([[sa, [4,0]]]),
+ ?line expect(1, tooBig).
+
+
+%% -- next_across_sa --
+
+next_across_sa(suite) -> [];
+next_across_sa(Config) when list(Config) ->
+ {SaNode, _MgrNode, MibDir} = init_case(Config),
+ MA = whereis(snmp_master_agent),
+
+ ?line {ok, SA} = start_subagent(SaNode, ?sa, "SA-MIB"),
+
+ p("Loading another subagent mib..."),
+ ?line ok = snmpa:load_mibs(SA, [MibDir ++ "Klas1"]),
+
+ rpc:call(SaNode, snmp, register_subagent, [MA, ?klas1, SA]),
+ ?TRY_TEST1(load_test_sa),
+
+ p("Testing next across subagent (endOfMibView from SA)..."),
+ ?TRY_TEST1(next_across_sa),
+
+ p("Unloading mib"),
+ snmpa:unload_mibs(SA, [MibDir ++ "Klas1"]),
+ rpc:call(SaNode, snmp, unregister_subagent, [MA, ?klas1]),
+ ?TRY_TEST1(unreg_test),
+
+ p("Starting another subagent"),
+ ?line {ok, SA2} = start_subagent(SaNode, ?klas1, "Klas1"),
+ p("Testing next across subagent (wrong prefix from SA)..."),
+ ?TRY_TEST1(next_across_sa),
+
+ stop_subagent(SA),
+ stop_subagent(SA2).
+
+%% Req. Klas1, system group, snmp group (v1/v2)
+next_across_sa() ->
+ gn([[sysDescr],[klas1,5]]),
+ ?line expect(1, [{[sysDescr,0], "Erlang SNMP agent"},
+ {[snmpInPkts, 0], any}]).
+
+
+%% -- undo --
+
+undo(suite) -> [];
+undo(Config) when list(Config) ->
+ {SaNode, _MgrNode, MibDir} = init_case(Config),
+ MA = whereis(snmp_master_agent),
+
+ ?line {ok, SA} = start_subagent(SaNode, ?sa, "SA-MIB"),
+
+ p("Testing undo phase at master agent..."),
+ ?line ok = snmpa:load_mibs(MA, [MibDir ++ "Klas3"]),
+ ?line ok = snmpa:load_mibs(MA, [MibDir ++ "Klas4"]),
+ ?TRY_TEST1(undo_test),
+ ?TRY_TEST1(api_test2),
+ ?line ok = snmpa:unload_mibs(MA, [MibDir ++ "Klas3"]),
+
+ p("Testing bad return values from instrum. funcs..."),
+ ?TRY_TEST1(bad_return),
+
+ ?line ok = snmpa:unload_mibs(MA, [MibDir ++ "Klas4"]),
+
+ p("Testing undo phase at subagent..."),
+ ?line ok = snmpa:load_mibs(SA, [MibDir ++ "Klas3"]),
+ ?line ok = snmpa:load_mibs(SA, [MibDir ++ "Klas4"]),
+ ?line ok = snmpa:register_subagent(MA, ?klas3, SA),
+ ?line ok = snmpa:register_subagent(MA, ?klas4, SA),
+ ?TRY_TEST1(undo_test),
+ ?TRY_TEST1(api_test3),
+
+ p("Testing undo phase across master/subagents..."),
+ ?TRY_TEST1(undo_test),
+ ?TRY_TEST1(api_test3),
+ stop_subagent(SA).
+
+%% snmp_test_mgr:s([{[fStatus3, 1], 4}, {[fname3,0], "ok"}]). -> noError
+%% snmp_test_mgr:s([{[fStatus3, 1], 4}, {[fname3,0], "hoj"}]). -> {badValue, 2}
+%% snmp_test_mgr:s([{[fStatus3, 3], 4}, {[fname3,0], "hoj"}]). -> {genErr, 1}
+%% snmp_test_mgr:s([{[fStatus3, 4], 4}, {[fname3,0], "ok"}]). -> {genErr, 1}
+%% snmp_test_mgr:s([{[fStatus3, 4], 4}, {[fname3,0], "ufail"}]). -> {genErr, 1}
+%% snmp_test_mgr:s([{[fStatus3, 1], 4}, {[fname3,0], "xfail"}]). -> {genErr, 2}
+%% Req. Klas3, Klas4
+undo_test() ->
+ s([{[fStatus3, 1], 4}, {[fname3,0], "ok"}]),
+ ?line expect(1, [{[fStatus3, 1], 4}, {[fname3,0], "ok"}]),
+ s([{[fStatus3, 1], 4}, {[fname3,0], "hoj"}]),
+ ?line expect(2, ?v1_2(badValue, inconsistentValue), 2, any),
+ s([{[fStatus3, 3], 4}, {[fname3,0], "hoj"}]),
+ ?line expect(3, ?v1_2(genErr, undoFailed), 1, any),
+ s([{[fStatus3, 4], 4}, {[fname3,0], "ok"}]),
+ ?line expect(4, ?v1_2(genErr, commitFailed), 1, any),
+ %% unfortunatly we don't know if we'll get undoFailed or commitFailed.
+ %% it depends on which order the agent traverses the varbind list.
+ %% s([{[fStatus3, 4], 4}, {[fname3,0], "ufail"}]),
+ %% ?line expect(5, ?v1_2(genErr, undoFailed), 1, any),
+ s([{[fStatus3, 1], 4}, {[fname3,0], "xfail"}]),
+ ?line expect(6, genErr, 2, any).
+
+%% Req. Klas3, Klas4
+bad_return() ->
+ g([[fStatus4,4],
+ [fName4,4]]),
+ ?line expect(4, genErr, 2, any),
+ g([[fStatus4,5],
+ [fName4,5]]),
+ ?line expect(5, genErr, 1, any),
+ g([[fStatus4,6],
+ [fName4,6]]),
+ ?line expect(6, genErr, 2, any),
+ gn([[fStatus4,7],
+ [fName4,7]]),
+ ?line expect(7, genErr, 2, any),
+ gn([[fStatus4,8],
+ [fName4,8]]),
+ ?line expect(8, genErr, 1, any),
+ gn([[fStatus4,9],
+ [fName4,9]]),
+ ?line expect(9, genErr, 2, any).
+
+
+%% -- standard_mibs --
+
+%%%-----------------------------------------------------------------
+%%% Test the implementation of standard mibs.
+%%% We should *at least* try to GET all variables, just to make
+%%% sure the instrumentation functions work.
+%%% Note that many of the functions in the standard mib is
+%%% already tested by the normal tests.
+%%%-----------------------------------------------------------------
+standard_mibs(suite) ->
+ [snmp_standard_mib,
+ snmp_community_mib,
+ snmp_framework_mib,
+ snmp_target_mib,
+ snmp_notification_mib,
+ snmp_view_based_acm_mib].
+
+
+%% -- snmp_standard_mib --
+
+%%-----------------------------------------------------------------
+%% For this test, the agent is configured for v1.
+%% o Test the counters and control objects in SNMP-STANDARD-MIB
+%%-----------------------------------------------------------------
+snmp_standard_mib(suite) -> [];
+snmp_standard_mib(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?DBG("snmp_standard_mib -> std_mib_init", []),
+ ?TRY_TEST1(std_mib_init),
+
+ ?DBG("snmp_standard_mib -> std_mib_a", []),
+ InBadVsns = ?TRY_TEST1(std_mib_a),
+ put(vsn, v2),
+ ?DBG("snmp_standard_mib -> std_mib_read", []),
+ ?TRY_TEST1(std_mib_read),
+ put(vsn, v1),
+
+ ?DBG("snmp_standard_mib -> std_mib_b (~w)", [InBadVsns]),
+ Bad = ?TRY_TEST2(std_mib_b, [InBadVsns]),
+ ?DBG("snmp_standard_mib -> std_mib_read (community: 'bad community')", []),
+ ?TRY_TEST3(std_mib_read, [], [{community, "bad community"}]),
+ ?DBG("snmp_standard_mib -> std_mib_write (community: 'public')", []),
+ ?TRY_TEST3(std_mib_write, [], [{community, "public"}]),
+ ?DBG("snmp_standard_mib -> std_mib_asn_err", []),
+ ?TRY_TEST1(std_mib_asn_err),
+ ?DBG("snmp_standard_mib -> std_mib_c (~w)", [Bad]),
+ ?TRY_TEST2(std_mib_c, [Bad]),
+ ?DBG("snmp_standard_mib -> std_mib_a", []),
+ ?TRY_TEST1(standard_mib_a),
+
+ ?DBG("snmp_standard_mib -> std_mib_finish", []),
+ ?TRY_TEST1(std_mib_finish),
+ ?DBG("snmp_standard_mib -> std_mib_test_finish", []),
+ ?TRY_TEST3(standard_mib_test_finish, [], [{community, "bad community"}]).
+
+%% Req. SNMP-STANDARD-MIB
+standard_mib_a() ->
+ ?line [OutPkts] = get_req(2, [[snmpOutPkts,0]]),
+ ?line [OutPkts2] = get_req(3, [[snmpOutPkts,0]]),
+ ?line OutPkts2 = OutPkts + 1,
+ %% There are some more counters we could test here, but it's not that
+ %% important, since they are removed from SNMPv2-MIB.
+ ok.
+
+%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB
+std_mib_init() ->
+ %% disable authentication failure traps. (otherwise w'd get many of
+ %% them - this is also a test to see that it works).
+ s([{[snmpEnableAuthenTraps,0], 2}]),
+ ?line expect(1, [{[snmpEnableAuthenTraps, 0], 2}]).
+
+%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB
+std_mib_finish() ->
+ %% enable again
+ s([{[snmpEnableAuthenTraps,0], 1}]),
+ ?line expect(1, [{[snmpEnableAuthenTraps, 0], 1}]).
+
+%% Req. SNMP-STANDARD-MIB
+standard_mib_test_finish() ->
+ %% force a authenticationFailure
+ std_mib_write(),
+ %% check that we got a trap
+ ?line expect(2, trap, [1,2,3], 4, 0, []).
+
+%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB
+std_mib_read() ->
+ ?DBG("std_mib_read -> entry", []),
+ g([[sysUpTime,0]]), % try a bad <something>; msg dropped, no reply
+ ?DBG("std_mib_read -> await timeout (i.e. no reply)", []),
+ ?line expect(1, timeout). % make sure we don't get a trap!
+
+
+%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB
+std_mib_write() ->
+ ?DBG("std_mib_write -> entry", []),
+ s([{[sysLocation, 0], "new_value"}]).
+
+%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB
+std_mib_asn_err() ->
+ ?SEND_BYTES([48,99,67,12,0,0,0,0,0,0,5]).
+
+%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB
+std_mib_a() ->
+ ?line [InPkts] = get_req(2, [[snmpInPkts,0]]),
+ ?line [InPkts2] = get_req(3, [[snmpInPkts,0]]),
+ ?line InPkts2 = InPkts + 1,
+
+ ?line [InBadVsns] = get_req(4, [[snmpInBadVersions,0]]),
+ InBadVsns.
+
+%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB
+std_mib_b(InBadVsns) ->
+ ?line [InBadVsns2] = get_req(1, [[snmpInBadVersions,0]]),
+ ?line InBadVsns2 = InBadVsns + 1,
+ ?line [InPkts] = get_req(2, [[snmpInPkts,0]]),
+ ?line [InPkts2] = get_req(3, [[snmpInPkts,0]]),
+ ?line InPkts2 = InPkts + 1,
+ ?line [InBadCommunityNames, InBadCommunityUses, InASNErrs] =
+ get_req(4, [[snmpInBadCommunityNames,0],
+ [snmpInBadCommunityUses,0],
+ [snmpInASNParseErrs, 0]]),
+ {InBadCommunityNames, InBadCommunityUses, InASNErrs}.
+
+%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB
+std_mib_c({InBadCommunityNames, InBadCommunityUses, InASNErrs}) ->
+ ?line [InBadCommunityNames2, InBadCommunityUses2, InASNErrs2] =
+ get_req(1, [[snmpInBadCommunityNames,0],
+ [snmpInBadCommunityUses,0],
+ [snmpInASNParseErrs, 0]]),
+ ?line InBadCommunityNames2 = InBadCommunityNames + 1,
+ ?line InBadCommunityUses2 = InBadCommunityUses + 1,
+ ?line InASNErrs2 = InASNErrs + 1.
+
+
+%% -- snmp_community_mib --
+
+%%-----------------------------------------------------------------
+%% o Bad community uses/name is tested already
+%% in SNMPv2-MIB and STANDARD-MIB.
+%% o Test add/deletion of rows.
+%%-----------------------------------------------------------------
+snmp_community_mib(suite) -> [];
+snmp_community_mib(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?line load_master_std("SNMP-COMMUNITY-MIB"),
+ ?TRY_TEST1(snmp_community_mib),
+ ?line unload_master("SNMP-COMMUNITY-MIB").
+
+snmp_community_mib_2(X) -> snmp_community_mib(X).
+
+%% Req. SNMP-COMMUNITY-MIB
+snmp_community_mib() ->
+ ?INF("NOT YET IMPLEMENTED", []),
+ nyi.
+
+
+%% -- snmp_framework_mib --
+
+%%-----------------------------------------------------------------
+%% o Test engine boots / time
+%%-----------------------------------------------------------------
+snmp_framework_mib(suite) -> [];
+snmp_framework_mib(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?line load_master_std("SNMP-FRAMEWORK-MIB"),
+ ?TRY_TEST1(snmp_framework_mib),
+ ?line unload_master("SNMP-FRAMEWORK-MIB").
+
+%% Req. SNMP-FRAMEWORK-MIB
+snmp_framework_mib() ->
+ ?line ["agentEngine"] = get_req(1, [[snmpEngineID,0]]),
+ ?line [EngineTime] = get_req(2, [[snmpEngineTime,0]]),
+ sleep(5000),
+ ?line [EngineTime2] = get_req(3, [[snmpEngineTime,0]]),
+ if
+ EngineTime+7 < EngineTime2 ->
+ ?line ?FAIL({too_large_diff, EngineTime, EngineTime2});
+ EngineTime+4 > EngineTime2 ->
+ ?line ?FAIL({too_large_diff, EngineTime, EngineTime2});
+ true -> ok
+ end,
+ ?line case get_req(4, [[snmpEngineBoots,0]]) of
+ [Boots] when integer(Boots) -> ok;
+ Else -> ?FAIL(Else)
+ end,
+ ok.
+
+
+%% -- snmp_target_mib --
+
+snmp_target_mib(suite) -> [];
+snmp_target_mib(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?line load_master_std("SNMP-TARGET-MIB"),
+ ?TRY_TEST1(snmp_target_mib),
+ ?line unload_master("SNMP-TARGET-MIB").
+
+snmp_target_mib() ->
+ ?INF("NOT YET IMPLEMENTED", []),
+ nyi.
+
+
+%% -- snmp_notification_mib --
+
+snmp_notification_mib(suite) -> [];
+snmp_notification_mib(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?line load_master_std("SNMP-NOTIFICATION-MIB"),
+ ?TRY_TEST1(snmp_notification_mib),
+ ?line unload_master("SNMP-NOTIFICATION-MIB").
+
+snmp_notification_mib() ->
+ ?INF("NOT YET IMPLEMENTED", []),
+ nyi.
+
+
+%% -- snmp_view_based_acm_mib --
+
+%%-----------------------------------------------------------------
+%% o add/delete views and try them
+%% o try boundaries
+%%-----------------------------------------------------------------
+snmp_view_based_acm_mib(suite) -> [];
+snmp_view_based_acm_mib(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"),
+ ?line load_master("Test2"),
+ snmp_view_based_acm_mib(),
+ ?line unload_master("Test2"),
+ ?line unload_master("SNMP-VIEW-BASED-ACM-MIB").
+
+snmp_view_based_acm_mib() ->
+ snmpa:verbosity(net_if,trace),
+ snmpa:verbosity(master_agent,trace),
+ ?LOG("start snmp_view_based_acm_mib test",[]),
+ %% The user "no-rights" is present in USM, and is mapped to security
+ %% name 'no-rights", which is not present in VACM.
+ %% So, we'll add rights for it, try them and delete them.
+ %% We'll give "no-rights" write access to tDescr.0 and read access
+ %% to tDescr2.0
+ %% These are the options we'll use to the mgr
+ Opts = [{user, "no-rights"}, {community, "no-rights"}],
+ %% Find the valid secmodel, and one invalid secmodel.
+ {SecMod, InvSecMod} =
+ case get(vsn) of
+ v1 -> {?SEC_V1, ?SEC_V2C};
+ v2 -> {?SEC_V2C, ?SEC_USM};
+ v3 -> {?SEC_USM, ?SEC_V1}
+ end,
+ ?DBG("assign rights for 'no-rights'",[]),
+ ?line ?TRY_TEST3(use_no_rights, [], Opts),
+
+ %% Now, add a mapping from "no-rights" -> "no-rights-group"
+ GRow1Status = [vacmSecurityToGroupStatus,[SecMod, 9,"no-rights"]],
+ GRow1 =
+ [{[vacmGroupName, [SecMod, 9,"no-rights"]], "no-rights-group"},
+ {GRow1Status, ?createAndGo}],
+ ?DBG("set '~p'",[GRow1]),
+ ?line ?TRY_TEST2(do_set, [GRow1]),
+
+ ?DBG("assign rights for 'no-rights'",[]),
+ ?line ?TRY_TEST3(use_no_rights, [], Opts),
+
+ %% Create a mapping for another sec model, and make sure it dosn't
+ %% give us access
+ GRow2Status = [vacmSecurityToGroupStatus,[InvSecMod, 9,"no-rights"]],
+ GRow2 = [{[vacmGroupName, [InvSecMod, 9, "no-rights"]], "initial"},
+ {GRow2Status, ?createAndGo}],
+
+ ?DBG("set '~p'",[GRow2]),
+ ?line ?TRY_TEST2(do_set, [GRow2]),
+
+ ?DBG("assign rights for 'no-rights'",[]),
+ ?line ?TRY_TEST3(use_no_rights, [], Opts),
+
+ %% Delete that row
+ ?line ?TRY_TEST2(del_row, [GRow2Status]),
+
+ RVName = "rv_name",
+ WVName = "wv_name",
+
+ %% Access row
+ ARow1Idx = [15 | "no-rights-group"] ++ [0, ?SEC_ANY, 1],
+ ARow1Status = [vacmAccessStatus, ARow1Idx],
+ ARow1 = [{[vacmAccessContextMatch, ARow1Idx], 1},
+ {[vacmAccessReadViewName, ARow1Idx], RVName},
+ {[vacmAccessWriteViewName, ARow1Idx], WVName},
+ {ARow1Status, ?createAndGo}],
+
+ %% This access row would give acces, if InvSecMod was valid.
+ ARow2Idx = [15 | "no-rights-group"] ++ [0, InvSecMod, 1],
+ ARow2Status = [vacmAccessStatus, ARow2Idx],
+ ARow2 = [{[vacmAccessContextMatch, ARow2Idx], 1},
+ {[vacmAccessReadViewName, ARow2Idx], "internet"},
+ {[vacmAccessWriteViewName, ARow2Idx], "internet"},
+ {ARow2Status, ?createAndGo}],
+
+ ?line ?TRY_TEST2(do_set, [ARow2]),
+
+ ?line ?TRY_TEST3(use_no_rights, [], Opts),
+
+ %% Delete that row
+ ?line ?TRY_TEST2(del_row, [ARow2Status]),
+
+
+ %% Add valid row
+ ?line ?TRY_TEST2(do_set, [ARow1]),
+
+ ?line ?TRY_TEST3(use_no_rights, [], Opts),
+
+ %% Create the view family
+ VRow1Idx = mk_ln(RVName) ++ mk_ln(?xDescr), % object access
+ VRow2Idx = mk_ln(RVName) ++ mk_ln(?xDescr2 ++ [0]), % instance access
+ VRow3Idx = mk_ln(WVName) ++ mk_ln(?xDescr), % object access
+ VRow4Idx = mk_ln(WVName) ++ mk_ln(?xDescr ++ [0]), % instance access
+ VRow1Status = [vacmViewTreeFamilyStatus, VRow1Idx],
+ VRow2Status = [vacmViewTreeFamilyStatus, VRow2Idx],
+ VRow3Status = [vacmViewTreeFamilyStatus, VRow3Idx],
+ VRow4Status = [vacmViewTreeFamilyStatus, VRow4Idx],
+
+ ?line ?TRY_TEST2(add_row, [VRow1Status]),
+ ?line ?TRY_TEST2(add_row, [VRow2Status]),
+ ?line ?TRY_TEST2(add_row, [VRow3Status]),
+
+ %% We're supposed to have access now...
+ ?line ?TRY_TEST3(use_rights, [], Opts),
+
+ %% Change Row3 to Row4
+ ?line ?TRY_TEST2(del_row, [VRow3Status]),
+ ?line ?TRY_TEST2(add_row, [VRow4Status]),
+
+ %% We should still have access...
+ ?line ?TRY_TEST3(use_rights, [], Opts),
+
+ %% Delete rows
+ ?line ?TRY_TEST2(del_row, [GRow1Status]),
+
+ ?line ?TRY_TEST3(use_no_rights, [], Opts),
+
+ %% Delete rest of rows
+ ?line ?TRY_TEST2(del_row, [ARow1Status]),
+ ?line ?TRY_TEST2(del_row, [VRow1Status]),
+ ?line ?TRY_TEST2(del_row, [VRow2Status]),
+ ?line ?TRY_TEST2(del_row, [VRow4Status]),
+
+ ?line ?TRY_TEST3(use_no_rights, [], Opts),
+ snmpa:verbosity(master_agent,log).
+
+do_set(Row) ->
+ s(Row),
+ expect(1, Row).
+
+add_row(RowStatus) ->
+ s([{RowStatus, ?createAndGo}]),
+ expect(1, [{RowStatus, ?createAndGo}]).
+
+del_row(RowStatus) ->
+ s([{RowStatus, ?destroy}]),
+ expect(1, [{RowStatus, ?destroy}]).
+
+
+
+use_no_rights() ->
+ g([[xDescr,0]]),
+ ?v1_2_3(expect(11, noSuchName, 1, any),
+ expect(12, [{[xDescr,0], noSuchObject}]),
+ expect(13, authorizationError, 1, any)),
+ g([[xDescr2,0]]),
+ ?v1_2_3(expect(21, noSuchName, 1, any),
+ expect(22, [{[xDescr2,0], noSuchObject}]),
+ expect(23, authorizationError, 1, any)),
+ gn([[xDescr]]),
+ ?v1_2_3(expect(31, noSuchName, 1, any),
+ expect(32, [{[xDescr], endOfMibView}]),
+ expect(33, authorizationError, 1, any)),
+ s([{[xDescr,0], "tryit"}]),
+ ?v1_2_3(expect(41, noSuchName, 1, any),
+ expect(42, noAccess, 1, any),
+ expect(43, authorizationError, 1, any)).
+
+
+use_rights() ->
+ g([[xDescr,0]]),
+ expect(1, [{[xDescr,0], any}]),
+ g([[xDescr2,0]]),
+ expect(2, [{[xDescr2,0], any}]),
+ s([{[xDescr,0], "tryit"}]),
+ expect(3, noError, 0, any),
+ g([[xDescr,0]]),
+ expect(4, [{[xDescr,0], "tryit"}]).
+
+
+%% -- sparse_table --
+
+sparse_table(suite) -> [];
+sparse_table(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = ?INIT_CASE(Config),
+
+ ?line load_master("Test1"),
+ ?TRY_TEST1(sparse_table_test),
+ ?line unload_master("Test1").
+
+%% Req. Test1
+sparse_table_test() ->
+ p("Testing sparse table..."),
+
+ %% Create two rows, check that they are get-nexted in correct order.
+ Idx1 = 1,
+ Idx2 = 2,
+ s([{[sparseStatus, Idx1], i, ?createAndGo},
+ {[sparseDescr, Idx1], s, "row 1"}]),
+ ?line expect(1, [{[sparseStatus, Idx1], ?createAndGo},
+ {[sparseDescr, Idx1], "row 1"}]),
+ s([{[sparseStatus, Idx2], i, ?createAndGo},
+ {[sparseDescr, Idx2], s, "row 2"}]),
+ ?line expect(2, [{[sparseStatus, Idx2], ?createAndGo},
+ {[sparseDescr, Idx2], "row 2"}]),
+ ?v1_2(gn([[sparseIndex], [sparseDescr,Idx1], [sparseDescr,Idx2],
+ [sparseStatus,Idx1], [sparseStatus,Idx2]]),
+ gb(0,5,[[sparseIndex]])),
+ ?line expect(3, [{[sparseDescr,Idx1], "row 1"},
+ {[sparseDescr,Idx2], "row 2"},
+ {[sparseStatus,Idx1], ?active},
+ {[sparseStatus,Idx2], ?active},
+ {[sparseStr,0], "slut"}]),
+ % Delete the rows
+ s([{[sparseStatus, Idx1], i, ?destroy}]),
+ ?line expect(4, [{[sparseStatus, Idx1], ?destroy}]),
+ s([{[sparseStatus, Idx2], i, ?destroy}]),
+ ?line expect(5, [{[sparseStatus, Idx2], ?destroy}]).
+
+
+%% -- cnt_64 --
+
+cnt_64(suite) -> [];
+cnt_64(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = ?INIT_CASE(Config),
+ MA = whereis(snmp_master_agent),
+
+ ?line load_master("Test1"),
+ ?TRY_TEST2(cnt_64_test, [MA]),
+ ?line unload_master("Test1").
+
+%% Req. Test1
+cnt_64_test(MA) ->
+ ?LOG("start cnt64 test (~p)",[MA]),
+ snmpa:verbosity(MA,trace),
+ ?LOG("start cnt64 test",[]),
+ p("Testing Counter64, and at the same time, RowStatus is not last column"),
+
+ ?DBG("get cnt64",[]),
+ g([[cnt64,0]]),
+ ?DBG("await response",[]),
+ ?line ?v1_2(expect(1, noSuchName, 1, any),
+ expect(1, [{[cnt64,0],18446744073709551615}])),
+ ?DBG("get-next cnt64",[]),
+ gn([[cnt64]]),
+ ?DBG("await response",[]),
+ ?line ?v1_2(expect(2, [{[cnt64Str,0], "after cnt64"}]),
+ expect(2, [{[cnt64,0],18446744073709551615}])),
+ ?DBG("send cntTrap",[]),
+ snmpa:send_trap(MA,cntTrap,"standard trap",[{sysContact,"pelle"},
+ {cnt64, 10},
+ {sysLocation, "here"}]),
+ ?DBG("await response",[]),
+ ?line ?v1_2(expect(3, trap, [test], 6, 1, [{[sysContact,0], "pelle"},
+ {[sysLocation,0], "here"}]),
+ expect(3, v2trap, [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?testTrap ++ [1]},
+ {[sysContact,0], "pelle"},
+ {[cnt64,0], 10},
+ {[sysLocation,0], "here"}])),
+
+ %% Create two rows, check that they are get-nexted in correct order.
+ Idx1 = 1,
+ Idx2 = 2,
+ ?DBG("create row (cntStatus): ~p",[Idx1]),
+ s([{[cntStatus, Idx1], i, ?createAndGo}]),
+ ?DBG("await response",[]),
+ ?line expect(1, [{[cntStatus, Idx1], ?createAndGo}]),
+ ?DBG("create row (cntStatus): ~p",[Idx2]),
+ s([{[cntStatus, Idx2], i, ?createAndGo}]),
+ ?DBG("await response",[]),
+ ?line expect(2, [{[cntStatus, Idx2], ?createAndGo}]),
+
+ ?DBG("get-next (cntIndex)",[]),
+ gn([[cntIndex]]),
+ ?DBG("await response",[]),
+ ?line ?v1_2(expect(3, [{[cntStatus,Idx1], ?active}]),
+ expect(3, [{[cntCnt,Idx1], 0}])),
+ % Delete the rows
+ ?DBG("delete row (cntStatus): ~p",[Idx1]),
+ s([{[cntStatus, Idx1], i, ?destroy}]),
+ ?DBG("await response",[]),
+ ?line expect(4, [{[cntStatus, Idx1], ?destroy}]),
+ ?DBG("delete row (cntStatus): ~p",[Idx2]),
+ s([{[cntStatus, Idx2], i, ?destroy}]),
+ ?DBG("await response",[]),
+ ?line expect(5, [{[cntStatus, Idx2], ?destroy}]),
+ catch snmpa:verbosity(MA,log),
+ ?DBG("done",[]),
+ ok.
+
+
+%% -- opaque --
+
+opaque(suite) -> [];
+opaque(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = ?INIT_CASE(Config),
+
+ ?line load_master("Test1"),
+ ?TRY_TEST1(opaque_test),
+ ?line unload_master("Test1").
+
+%% Req. Test1
+opaque_test() ->
+ p("Testing Opaque datatype..."),
+ g([[opaqueObj,0]]),
+ ?line expect(1, [{[opaqueObj,0], "opaque-data"}]).
+
+
+%% -- change_target_addr_config --
+
+change_target_addr_config(suite) -> [];
+change_target_addr_config(Config) when list(Config) ->
+ p("Testing changing target address config..."),
+ ?LOG("change_target_addr_config -> entry",[]),
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ put(sname,snmp_suite),
+ put(verbosity,trace),
+
+ MA = whereis(snmp_master_agent),
+
+ ?LOG("change_target_addr_config -> load TestTrap",[]),
+ ?line load_master("TestTrap"),
+
+ ?LOG("change_target_addr_config -> set trace verbosity for local_db",[]),
+ ?line snmpa:verbosity(local_db,trace),
+
+ %% First send some traps that will arive att the original manager
+ ?LOG("change_target_addr_config -> send trap",[]),
+ ?TRY_TEST2(ma_trap1, [MA]),
+
+ ?LOG("change_target_addr_config -> set silence verbosity for local_db",[]),
+ ?line snmpa:verbosity(local_db,silence),
+
+ %% Start new dummy listener
+ ?LOG("change_target_addr_config -> start dummy manager",[]),
+ ?line {ok,Pid,NewPort} = dummy_manager_start(MA),
+
+ %% Reconfigure
+ ?LOG("change_target_addr_config -> reconfigure",[]),
+ AgentDir = ?config(agent_dir, Config),
+ ?line rewrite_target_addr_conf(AgentDir, NewPort),
+ ?line snmp_target_mib:reconfigure(AgentDir),
+
+ %% Send the trap again
+ ?LOG("change_target_addr_config -> send trap again",[]),
+ catch dummy_manager_send_trap2(Pid),
+
+ ?LOG("change_target_addr_config -> await trap ack",[]),
+ catch dummy_manager_await_trap2_ack(),
+
+ ?LOG("change_target_addr_config -> stop dummy manager",[]),
+ ?line ok = dummy_manager_stop(Pid),
+
+ ?LOG("change_target_addr_config -> reset target address config",[]),
+ ?line reset_target_addr_conf(AgentDir),
+
+ ?LOG("change_target_addr_config -> unload TestTrap",[]),
+ ?line unload_master("TestTrap").
+
+
+dummy_manager_start(MA) ->
+ ?DBG("dummy_manager_start -> entry",[]),
+ Pid = spawn(get(mgr_node), ?MODULE,dummy_manager_init,[self(),MA]),
+ ?DBG("dummy_manager_start -> Pid: ~p",[Pid]),
+ await_dummy_manager_started(Pid).
+
+await_dummy_manager_started(Pid) ->
+ receive
+ {dummy_manager_started,Pid,Port} ->
+ ?DBG("dummy_manager_start -> acknowledge received with"
+ "~n Port: ~p",[Port]),
+ {ok,Pid,Port};
+ {'EXIT', Pid, Reason} ->
+ {error, Pid, Reason};
+ O ->
+ ?LOG("dummy_manager_start -> received unknown message:"
+ "~n ~p",[O]),
+ await_dummy_manager_started(Pid)
+ end.
+
+dummy_manager_stop(Pid) ->
+ ?DBG("dummy_manager_stop -> entry with Pid: ~p",[Pid]),
+ Pid ! stop,
+ receive
+ {dummy_manager_stopping, Pid} ->
+ ?DBG("dummy_manager_stop -> acknowledge received",[]),
+ ok
+ after 10000 ->
+ ?ERR("dummy_manager_stop -> timeout",[]),
+ timeout
+ end.
+
+dummy_manager_send_trap2(Pid) ->
+ ?DBG("dummy_manager_send_trap2 -> entry",[]),
+ Pid ! {send_trap,testTrap2}.
+
+dummy_manager_await_trap2_ack() ->
+ ?DBG("dummy_manager_await_trap2 -> entry",[]),
+ receive
+ {received_trap,Trap} ->
+ ?LOG("dummy_manager_await_trap2 -> received trap: ~p",[Trap]),
+ %% Note:
+ %% Without this sleep the v2_inform_i testcase failes! There
+ %% is no relation between these two test cases as far as I
+ %% able to figure out...
+ sleep(60000),
+ ok;
+ O ->
+ ?ERR("dummy_manager_await_trap2 -> unexpected message: ~p",[O]),
+ ok
+ after 10000 ->
+ ?ERR("dummy_manager_await_trap2 -> timeout",[]),
+ timeout
+ end.
+
+dummy_manager_init(Parent,MA) ->
+ ?DBG("dummy_manager_init -> entry with"
+ "~n Parent: ~p"
+ "~n MA: ~p",[Parent,MA]),
+ {ok,S} = gen_udp:open(0,[{recbuf,65535}]),
+ ?DBG("dummy_manager_init -> S: ~p",[S]),
+ {ok,Port} = inet:port(S),
+ ?DBG("dummy_manager_init -> Port: ~p",[Port]),
+ Parent ! {dummy_manager_started,self(),Port},
+ dummy_manager_loop(Parent,S,MA).
+
+dummy_manager_loop(P,S,MA) ->
+ ?LOG("dummy_manager_loop -> ready for receive",[]),
+ receive
+ {send_trap,Trap} ->
+ ?LOG("dummy_manager_loop -> received trap send request"
+ "~n Trap: ~p",[Trap]),
+ snmpa:send_trap(MA, Trap, "standard trap"),
+ dummy_manager_loop(P,S,MA);
+ {udp, _UdpId, Ip, UdpPort, Bytes} ->
+ ?LOG("dummy_manager_loop -> received upd message"
+ "~n from: ~p:~p"
+ "~n size: ~p",
+ [Ip, UdpPort, dummy_manager_message_sz(Bytes)]),
+ R = dummy_manager_handle_message(Bytes),
+ ?DBG("dummy_manager_loop -> R: ~p",[R]),
+ P ! R,
+ dummy_manager_loop(P,S,MA);
+ stop ->
+ ?DBG("dummy_manager_loop -> received stop request",[]),
+ P ! {dummy_manager_stopping, self()},
+ gen_udp:close(S),
+ exit(normal);
+ O ->
+ ?LOG("dummy_manager_loop -> received unknown message:"
+ "~n ~p",[O]),
+ dummy_manager_loop(P,S,MA)
+ end.
+
+dummy_manager_message_sz(B) when binary(B) ->
+ size(B);
+dummy_manager_message_sz(L) when list(L) ->
+ length(L);
+dummy_manager_message_sz(_) ->
+ undefined.
+
+dummy_manager_handle_message(Bytes) ->
+ case (catch snmp_pdus:dec_message(Bytes)) of
+ {'EXIT',Reason} ->
+ ?ERR("dummy_manager_handle_message -> "
+ "failed decoding message only:~n ~p",[Reason]),
+ {error,Reason};
+ M ->
+ ?DBG("dummy_manager_handle_message -> decoded message:"
+ "~n ~p",[M]),
+ {received_trap,M}
+ end.
+
+
+%% -- reported_bugs --
+
+%%%-----------------------------------------------------------------
+%%% Testing of reported bugs and other tickets.
+%%%-----------------------------------------------------------------
+
+reported_bugs(suite) ->
+ [otp_1128, otp_1129, otp_1131, otp_1162,
+ otp_1222, otp_1298, otp_1331, otp_1338,
+ otp_1342, otp_2776, otp_2979, otp_3187, otp_3725].
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-1128
+%% Slogan: Bug in handling of createAndWait set-requests.
+%%-----------------------------------------------------------------
+otp_1128(suite) -> [];
+otp_1128(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?line load_master("OLD-SNMPEA-MIB"),
+ ?line init_old(),
+ ?TRY_TEST1(otp_1128),
+ ?line unload_master("OLD-SNMPEA-MIB").
+
+otp_1128() ->
+ io:format("Testing bug reported in ticket OTP-1128...~n"),
+
+ NewKeyc3 = [intCommunityViewIndex,get(mip),is("test")],
+ NewKeyc4 = [intCommunityAccess,get(mip),is("test")],
+ NewKeyc5 = [intCommunityStatus,get(mip),is("test")],
+
+ s([{NewKeyc5, ?createAndWait}, {NewKeyc4, 2}]),
+ ?line expect(28, [{NewKeyc5, ?createAndWait}, {NewKeyc4, 2}]),
+ g([NewKeyc5]),
+ ?line expect(29, [{NewKeyc5, ?notReady}]),
+ s([{NewKeyc5, ?active}, {NewKeyc3, 2}]),
+ ?line expect(30, [{NewKeyc5, ?active}, {NewKeyc3, 2}]),
+ g([NewKeyc5]),
+ ?line expect(31, [{NewKeyc5, ?active}]),
+ s([{NewKeyc5, ?destroy}]),
+ ?line expect(32, [{NewKeyc5, ?destroy}]).
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-1129, OTP-1169
+%% Slogan: snmpa:int_to_enum crashes on bad oids
+%%-----------------------------------------------------------------
+otp_1129(suite) -> [];
+otp_1129(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?line load_master("Klas3"),
+ ?TRY_TEST2(otp_1129_i, [node()]),
+ ?line unload_master("Klas3").
+
+otp_1129_i(MaNode) ->
+ io:format("Testing bug reported in ticket OTP-1129...~n"),
+ false = rpc:call(MaNode, snmp, int_to_enum, [iso, 1]),
+ false = rpc:call(MaNode, snmp, int_to_enum, [isox, 1]).
+
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-1131
+%% Slogan: Agent crashes / erlang node halts if RowIndex in a
+%% setrequest is of bad type, e.g. an INDEX {INTEGER},
+%% and RowIdenx [3,2].
+%%-----------------------------------------------------------------
+otp_1131(suite) -> [];
+otp_1131(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?line load_master("Klas1"),
+ ?TRY_TEST1(otp_1131),
+ ?line unload_master("Klas1").
+
+otp_1131() ->
+ io:format("Testing bug reported in ticket OTP-1131...~n"),
+ s([{[friendsEntry, [2, 3, 1]], s, "kompis3"},
+ {[friendsEntry, [3, 3, 1]], i, ?createAndGo}]),
+ ?line expect(1, ?v1_2(noSuchName, noCreation), 2, any).
+
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-1162
+%% Slogan: snmp_agent can't handle wrongValue from instrum.func
+%%-----------------------------------------------------------------
+otp_1162(suite) -> [];
+otp_1162(Config) when list(Config) ->
+ ?P1(otp_1162),
+ {SaNode, _MgrNode, _MibDir} = ?INIT_CASE(Config),
+ ?line {ok, SA} = ?START_SA(SaNode, ?sa, "SA-MIB"),
+ ?TRY_TEST1(otp_1162),
+ ?STOP_SA(SA).
+
+otp_1162() ->
+ s([{[sa, [2,0]], 6}]), % wrongValue (i is_set_ok)
+ ?line expect(1, ?v1_2(badValue, wrongValue), 1, any).
+
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-1222
+%% Slogan: snmp agent crash if faulty index is returned from instrum
+%%-----------------------------------------------------------------
+otp_1222(suite) -> [];
+otp_1222(Config) when list(Config) ->
+ ?P1(otp_1222),
+ ?INIT_CASE(Config),
+ ?line load_master("Klas3"),
+ ?line load_master("Klas4"),
+ ?TRY_TEST1(otp_1222),
+ ?line unload_master("Klas3"),
+ ?line unload_master("Klas4").
+
+otp_1222() ->
+ io:format("Testing bug reported in ticket OTP-1222...~n"),
+ s([{[fStatus4,1], 4}, {[fName4,1], 1}]),
+ ?line expect(1, genErr, 0, any),
+ s([{[fStatus4,2], 4}, {[fName4,2], 1}]),
+ ?line expect(2, genErr, 0, any).
+
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-1298
+%% Slogan: Negative INTEGER values are treated as positive.
+%%-----------------------------------------------------------------
+otp_1298(suite) -> [];
+otp_1298(Config) when list(Config) ->
+ ?P1(otp_1298),
+ ?INIT_CASE(Config),
+ ?line load_master("Klas2"),
+ ?TRY_TEST1(otp_1298),
+ ?line unload_master("Klas2").
+
+otp_1298() ->
+ io:format("Testing bug reported in ticket OTP-1298...~n"),
+ s([{[fint,0], -1}]),
+ ?line expect(1298, [{[fint,0], -1}]).
+
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-1331
+%% Slogan: snmp_generic should return noError when deleting non-ex row
+%%-----------------------------------------------------------------
+otp_1331(suite) -> [];
+otp_1331(Config) when list(Config) ->
+ ?P1(otp_1331),
+ ?INIT_CASE(Config),
+ ?line load_master("OLD-SNMPEA-MIB"),
+ ?line init_old(),
+ ?TRY_TEST1(otp_1331),
+ ?line unload_master("OLD-SNMPEA-MIB").
+
+otp_1331() ->
+ NewKeyc5 = [intCommunityStatus,[127,32,0,0],is("test")],
+ s([{NewKeyc5, ?destroy}]),
+ ?line expect(1, [{NewKeyc5, ?destroy}]).
+
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-1338
+%% Slogan: snmp bug in initialisation of default values for mnesia tabs
+%%-----------------------------------------------------------------
+otp_1338(suite) -> [];
+otp_1338(Config) when list(Config) ->
+ ?P1(otp_1338),
+ ?INIT_CASE(Config),
+ ?line load_master("Klas2"),
+ ?TRY_TEST1(otp_1338),
+ ?line unload_master("Klas2").
+
+otp_1338() ->
+ s([{[kStatus2, 7], i, ?createAndGo}]),
+ ?line expect(1, [{[kStatus2, 7], ?createAndGo}]),
+ g([[kName2, 7]]),
+ ?line expect(2, [{[kName2, 7], "JJJ"}]).
+
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-1342
+%% Slogan: default impl of snmp table can't handle bad index access,
+%% Set when INDEX is read-write gets into an infinite loop!
+%%-----------------------------------------------------------------
+otp_1342(suite) -> [];
+otp_1342(Config) when list(Config) ->
+ ?P1(otp_1342),
+ ?INIT_CASE(Config),
+ ?line load_master("Klas4"),
+ ?TRY_TEST1(otp_1342),
+ ?line unload_master("Klas4").
+
+otp_1342() ->
+ s([{[fIndex5, 1], i, 1},
+ {[fName5, 1], i, 3},
+ {[fStatus5, 1], i, ?createAndGo}]),
+ ?line expect(1, ?v1_2(noSuchName, noCreation), 3, any).
+
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-1366
+%% Slogan: snmp traps not sent to all managers
+%% Note: NYI! We need a way to tell the test server that we need
+%% mgrs on two different machines.
+%%-----------------------------------------------------------------
+otp_1366(suite) -> [];
+otp_1366(Config) when list(Config) ->
+ ?P1(otp_1366),
+ ?INIT_CASE(Config),
+ ?line load_master("OLD-SNMPEA-MIB"),
+ ?line init_old(),
+ ?TRY_TEST1(otp_1366),
+ ?line unload_master("OLD-SNMPEA-MIB").
+
+otp_1366() ->
+ ?INF("NOT YET IMPLEMENTED", []),
+ 'NYI'.
+
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-2776
+%% Slogan: snmp:validate_date_and_time() fails when time is 00:00
+%%-----------------------------------------------------------------
+otp_2776(suite) -> [];
+otp_2776(Config) when list(Config) ->
+ ?P1(otp_2776),
+ ?INIT_CASE(Config),
+ ?TRY_TEST1(otp_2776).
+
+otp_2776() ->
+ io:format("Testing bug reported in ticket OTP-2776...~n"),
+
+ Dt01_valid = [19,98,9,1,1,0,23,0,43,0,0],
+ Dt02_valid = [19,98,9,1,0,0,0,0,43,0,0], % This is what is fixed: 00:00
+ Dt03_valid = [19,98,2,28,1,0,23,0,43,0,0],
+ Dt04_invalid = [19,98,2,29,1,0,23,0,43,0,0],
+ Dt05_valid = [19,96,2,29,1,0,23,0,43,0,0],
+ Dt06_valid = [20,0,2,29,1,0,23,0,43,0,0],
+ Dt07_invalid = [19,96,2,30,1,0,23,0,43,0,0], % This is also fixed: 30/2
+ Dt08_valid = [19,98,4,30,1,0,23,0,43,0,0],
+ Dt09_invalid = [19,98,4,31,1,0,23,0,43,0,0], % This is also fixed: 31/4
+ Dt10_invalid = [],
+ Dt11_invalid = [kalle,hobbe],
+ L = [{ 1, true, Dt01_valid},
+ { 2, true, Dt02_valid},
+ { 3, true, Dt03_valid},
+ { 4, false, Dt04_invalid},
+ { 5, true, Dt05_valid},
+ { 6, true, Dt06_valid},
+ { 7, false, Dt07_invalid},
+ { 8, true, Dt08_valid},
+ { 9, false, Dt09_invalid},
+ {10, false, Dt10_invalid},
+ {11, false, Dt11_invalid}],
+
+ ?line ok = validate_dat(L).
+
+
+validate_dat(L) -> validate_dat(L,[]).
+
+validate_dat([],V) ->
+ Fun = fun({_,X}) -> case X of
+ ok -> false;
+ _ -> true
+ end
+ end,
+ validate_dat1( lists:reverse( lists:filter(Fun,V) ) );
+validate_dat([{Id,E,Dat}|T],V) ->
+ validate_dat(T,[validate_dat2(Id,E,Dat) | V]).
+
+validate_dat1([]) -> ok;
+validate_dat1(L) -> {error,L}.
+
+validate_dat2(Id, E, Dat) ->
+ Res = case {E,snmp:validate_date_and_time(Dat)} of
+ {E,E} -> ok;
+ {E,A} -> {E,A}
+ end,
+ {Id, Res}.
+
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-2979
+%% Slogan: get-next on more than 1 column in an empty table
+%% returns bad response.
+%%-----------------------------------------------------------------
+otp_2979(suite) -> [];
+otp_2979(Config) when list(Config) ->
+ ?P1(otp_2979),
+ ?INIT_CASE(Config),
+ ?line load_master("Test1"),
+ ?line init_old(),
+ ?TRY_TEST1(otp_2979),
+ ?line unload_master("Test1").
+
+otp_2979() ->
+ gn([[sparseDescr], [sparseStatus]]),
+ ?line expect(1, [{[sparseStr,0], "slut"},
+ {[sparseStr,0], "slut"}]).
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-3187
+%% Slogan: get-next on vacmAccessTable for colums > 5 returns
+%% endOfTable - should return value.
+%%-----------------------------------------------------------------
+otp_3187(suite) -> [];
+otp_3187(Config) when list(Config) ->
+ ?P1(otp_3187),
+ ?INIT_CASE(Config),
+ ?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"),
+ otp_3187(),
+ ?line unload_master("SNMP-VIEW-BASED-ACM-MIB").
+
+otp_3187() ->
+ ?line Elements =
+ snmp_view_based_acm_mib:vacmAccessTable(get_next,[],[4,5,6]),
+ lists:foreach(fun(E) ->
+ ?line if E == endOfTable ->
+ ?FAIL(endOfTable);
+ true -> ok
+ end
+ end, Elements).
+
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-3542
+%% Slogan:
+%%-----------------------------------------------------------------
+otp_3542(suite) -> [];
+otp_3542(Config) when list(Config) ->
+ ?P1(otp_3542),
+ ?INIT_CASE(Config),
+ ?TRY_TEST1(otp_3542).
+
+otp_3542() ->
+ io:format("SNMP v3 discovery...~n"),
+ ?line Res = snmp_test_mgr:d(),
+ io:format("SNMP v3 discovery result: ~p~n",[Res]).
+
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-3725
+%% Slogan: Slow response time on snmpa:int_to_enum
+%%-----------------------------------------------------------------
+otp_3725(suite) -> [];
+otp_3725(Config) when list(Config) ->
+ ?P1(otp_3725),
+ ?INIT_CASE(Config),
+
+ ?line load_master("OLD-SNMPEA-MIB"),
+ ?line init_old(),
+ ?TRY_TEST2(otp_3725_test, [node()]),
+ ?line unload_master("OLD-SNMPEA-MIB").
+
+%% Req. OLD-SNMPEA-MIB
+otp_3725_test(MaNode) ->
+ io:format("Testing feature requested in ticket OTP-3725...~n"),
+ ?line rpc:call(MaNode,snmpa,verbosity,[symbolic_store,trace]),
+ ?line Db = rpc:call(MaNode,snmp,get_symbolic_store_db,[]),
+ ?DBG("otp_3725_test -> Db = ~p",[Db]),
+
+ ?line {value, OID} = rpc:call(MaNode, snmp, name_to_oid,
+ [Db, intAgentIpAddress]),
+ ?DBG("otp_3725_test -> name_to_oid for ~p: ~p",[intAgentIpAddress,OID]),
+ ?line {value, intAgentIpAddress} = rpc:call(MaNode, snmp, oid_to_name,
+ [Db,OID]),
+ ?DBG("otp_3725_test -> oid_to_name for ~p: ~p",[OID,intAgentIpAddress]),
+ ?line false = rpc:call(MaNode, snmp, name_to_oid, [Db, intAgentIpAddres]),
+ ?line false = rpc:call(MaNode, snmp, oid_to_name,
+ [Db, [1,5,32,3,54,3,3,34,4]]),
+ ?line {value, 2} = rpc:call(MaNode, snmp, enum_to_int,
+ [Db, intViewType, excluded]),
+ ?line {value, excluded} = rpc:call(MaNode, snmp, int_to_enum,
+ [Db, intViewType, 2]),
+ ?line false = rpc:call(MaNode, snmp, enum_to_int,
+ [Db, intViewType, exclude]),
+ ?line false = rpc:call(MaNode, snmp, enum_to_int,
+ [Db, intAgentIpAddress, exclude]),
+ ?line false = rpc:call(MaNode, snmp, enum_to_int,
+ [Db, intAgentIpAddre, exclude]),
+ ?line false = rpc:call(MaNode, snmp, int_to_enum, [Db, intViewType, 3]),
+ ?line false = rpc:call(MaNode, snmp, int_to_enum,
+ [Db, intAgentIpAddress, 2]),
+ ?line false = rpc:call(MaNode, snmp, int_to_enum,
+ [Db, intAgentIpAddre, 2]),
+ ?line {value, active} = rpc:call(MaNode, snmp, int_to_enum,
+ [Db, 'RowStatus', ?active]),
+ ?line {value, ?destroy} = rpc:call(MaNode, snmp, enum_to_int,
+ [Db, 'RowStatus', destroy]),
+ ?line false = rpc:call(MaNode, snmp, enum_to_int,
+ [Db, 'RowStatus', xxxdestroy]),
+ ?line false = rpc:call(MaNode, snmp, enum_to_int,
+ [Db, 'xxRowStatus', destroy]),
+ ?line false = rpc:call(MaNode, snmp, int_to_enum, [Db, 'RowStatus', 25]),
+ ?line false = rpc:call(MaNode, snmp, int_to_enum, [Db, 'xxRowStatus', 1]),
+ ok.
+
+
+%% -- tickets --
+
+%% These are (ticket) test cases where the initiation has to be done
+%% individually.
+tickets(suite) ->
+ [otp_4394].
+
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-4394
+%% Slogan: Target mib tag list check invalid
+%%-----------------------------------------------------------------
+
+otp_4394(suite) -> {req, [], {conf,
+ init_otp_4394,
+ [otp_4394_test],
+ finish_otp_4394}}.
+
+init_otp_4394(Config) when list(Config) ->
+ ?DBG("init_otp_4394 -> entry with"
+ "~n Config: ~p", [Config]),
+ ?line AgentDir = ?config(agent_dir, Config),
+ ?line MgrDir = ?config(mgr_dir, Config),
+ ?line Ip = ?config(ip, Config),
+ ?line otp_4394_config(AgentDir, MgrDir, Ip),
+ MasterAgentVerbosity = {master_agent_verbosity, trace},
+ NetIfVerbosity = {net_if_verbosity, trace},
+ Opts = [MasterAgentVerbosity,NetIfVerbosity],
+ [{vsn, v1} | start_v1_agent(Config,Opts)].
+
+otp_4394_config(AgentDir, MgrDir, Ip0) ->
+ ?DBG("otp_4394_config -> entry with"
+ "~n AgentDir: ~p"
+ "~n MgrDir: ~p"
+ "~n Ip0: ~p", [AgentDir, MgrDir, Ip0]),
+ Vsn = [v1],
+ Ip = tuple_to_list(Ip0),
+ ?line snmp_config:write_agent_snmp_files(AgentDir, Vsn, Ip,
+ ?TRAP_UDP, Ip, 4000,
+ "OTP-4394 test"),
+ ?line case update_usm(Vsn, AgentDir) of
+ true ->
+ ?line copy_file(filename:join(AgentDir, "usm.conf"),
+ filename:join(MgrDir, "usm.conf")),
+ ?line update_usm_mgr(Vsn, MgrDir);
+ false ->
+ ?line ok
+ end,
+ C1 = {"a", "all-rights", "initial", "", "pc"},
+ C2 = {"c", "secret", "secret_name", "", "secret_tag"},
+ ?line write_community_conf(AgentDir, [C1, C2]),
+ ?line update_vacm(Vsn, AgentDir),
+ Ta1 = {"shelob v1",
+ [134,138,177,177], 5000, 1500, 3, %% Anv�nd Ip och modda
+ "pc1",
+ "target_v1", "",
+ %% [255,255,255,255,0,0],
+ [],
+ 2048},
+ Ta2 = {"bifur v1",
+ [134,138,177,75], 5000, 1500, 3, %% Anv�nd Ip
+ "pc2",
+ "target_v1", "",
+ %% [255,255,255,255,0,0],
+ [], 2048},
+ ?line write_target_addr_conf(AgentDir, [Ta1, Ta2]),
+ ?line write_target_params_conf(AgentDir, Vsn),
+ ?line write_notify_conf(AgentDir),
+ ok.
+
+finish_otp_4394(Config) when list(Config) ->
+ ?DBG("finish_otp_4394 -> entry", []),
+ C1 = stop_agent(Config),
+ delete_files(C1),
+ erase(mgr_node),
+ lists:keydelete(vsn, 1, C1).
+
+otp_4394_test(suite) -> [];
+otp_4394_test(Config) ->
+ ?P1(otp_4394_test),
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?TRY_TEST1(otp_4394_test1),
+ ?DBG("otp_4394_test -> done", []),
+ ok.
+
+otp_4394_test1() ->
+ ?DBG("otp_4394_test1 -> entry", []),
+ gn([[1,1]]),
+ Res =
+ case snmp_test_mgr:expect(1, [{[sysDescr,0], "Erlang SNMP agent"}]) of
+ %% {error, 1, {"?",[]}, {"~w",[timeout]}}
+ {error, 1, _, {_, [timeout]}} ->
+ ?DBG("otp_4394_test1 -> expected result: timeout", []),
+ ok;
+ Else ->
+ Else
+ end,
+ ?DBG("otp_4394_test1 -> done with: ~p", [Res]),
+ Res.
+
+
+mk_ln(X) ->
+ [length(X) | X].
+
+
+
+%% string used in index
+is(S) -> [length(S) | S].
+
+expect(A,B) -> ok = ?MGR:expect(A,B).
+expect(A,B,C) -> ok = ?MGR:expect(A,B,C).
+expect(A,B,C,D) -> ok = ?MGR:expect(A,B,C,D).
+expect(A,B,C,D,E,F) -> ok = ?MGR:expect(A,B,C,D,E,F).
+
diff --git a/lib/snmp/test/snmp_agent_v2_test.erl b/lib/snmp/test/snmp_agent_v2_test.erl
new file mode 100644
index 0000000000..eca66dc30d
--- /dev/null
+++ b/lib/snmp/test/snmp_agent_v2_test.erl
@@ -0,0 +1,5657 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2005-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%
+%%
+
+-module(snmp_agent_v2_test).
+
+%% TODO
+%% * Test fault-tolerance (kill master etc)
+%%
+
+-compile(export_all).
+
+-define(application, snmp).
+
+-include_lib("kernel/include/file.hrl").
+-include("test_server.hrl").
+-include("snmp_test_lib.hrl").
+-define(SNMP_USE_V3, true).
+-include_lib("snmp/include/snmp_types.hrl").
+%% -include_lib("snmp/include/SNMP-COMMUNITY-MIB.hrl").
+%% -include_lib("snmp/include/SNMP-VIEW-BASED-ACM-MIB.hrl").
+%% -include_lib("snmp/include/SNMP-USER-BASED-SM-MIB.hrl").
+
+
+-define(klas1, [1,3,6,1,2,1,7]).
+-define(klas2, [1,3,6,1,2,1,9]).
+-define(klas3, [1,3,6,1,2,1,8,1]).
+-define(klas4, [1,3,6,1,2,1,8,4]).
+-define(sa, [1,3,6,1,4,1,193,2]).
+-define(system, [1,3,6,1,2,1,1]).
+-define(snmp, [1,3,6,1,2,1,11]).
+-define(snmpTraps, [1,3,6,1,6,3,1,1,5]).
+-define(ericsson, [1,3,6,1,4,1,193]).
+-define(testTrap, [1,3,6,1,2,1,15,0]).
+-define(xDescr, [1,3,6,1,2,1,17,1]).
+-define(xDescr2, [1,3,6,1,2,1,17,2]).
+
+-define(active, 1).
+-define(notInService, 2).
+-define(notReady, 3).
+-define(createAndGo, 4).
+-define(createAndWait, 5).
+-define(destroy, 6).
+
+-define(TRAP_UDP, 5000).
+
+-define(tooBigStr, "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").
+
+-define(str(X), snmp_pdus:bits_to_str(X)).
+
+-define(break(), begin io:format(user, "break at line ~w: pid: ~p\n",
+ [?LINE, self()]),
+ receive cont -> ok end
+ end).
+
+
+-import(snmp_test_mgr, [gn/1, g/1, s/1, gb/3]).
+-define(v1_2(V1,V2),
+ case get(vsn) of
+ v1 -> V1;
+ _ -> V2
+ end).
+
+-define(v1_2_3(V1,V2,V3),
+ case get(vsn) of
+ v1 -> V1;
+ v2 -> V2;
+ _ -> V3
+ end).
+
+all(suite) -> {req,
+ [mnesia, distribution,
+ {local_slave_nodes, 2}, {time, 360}],
+ [{conf, init_all, cases(), finish_all}]}.
+
+init_per_testcase(_Case, Config) when list(Config) ->
+ Dog = ?t:timetrap(?t:minutes(6)),
+ [{watchdog, Dog}|Config].
+
+fin_per_testcase(_Case, Config) when list(Config) ->
+ Dog = ?config(watchdog, Config),
+ ?t:timetrap_cancel(Dog),
+ Config.
+
+cases() ->
+ case ?OSTYPE() of
+ vxworks ->
+ %% No crypto app, so skip v3 testcases
+ [
+ app_info,
+ test_v1, test_v2, test_v1_v2,
+ test_multi_threaded,
+ mib_storage,
+ tickets];
+ _Else ->
+ [
+ app_info,
+ test_v1, test_v2, test_v1_v2, test_v3,
+ test_multi_threaded,
+ mib_storage,
+ tickets
+ ]
+ end.
+
+
+%%%-----------------------------------------------------------------
+%%% The test case structure is as follows:
+%%%
+%%% init_all - starts mnesia,
+%%%
+%%% init_v1 - starts agent
+%%% simple
+%%% big - e.g. starts/stops subagent, load/unloads mibs
+%%% init_mul
+%%% mul_get
+%%% mul_set
+%%% <etc>
+%%% finish_mul
+%%% <etc>
+%%% finish_v1
+%%%
+%%% init_v2 - starts agent
+%%% finish_v2
+%%%
+%%% init_bilingual - starts agent
+%%% finish_bilingual
+%%%
+%%% finish_all
+%%%
+%%% There is still one problem with these testsuites. If one test
+%%% fails, it may not be possible to run some other cases, as it
+%%% may have e.g. created some row or loaded some table, that it
+%%% didn't undo (since it failed).
+%%%-----------------------------------------------------------------
+
+init_all(Config0) when list(Config0) ->
+ ?LOG("init_all -> entry with"
+ "~n Config0: ~p",[Config0]),
+
+ %% --
+ %% Fix config:
+ %%
+
+ DataDir0 = ?config(data_dir, Config0),
+ DataDir1 = filename:split(filename:absname(DataDir0)),
+ [_|DataDir2] = lists:reverse(DataDir1),
+ DataDir3 = filename:join(lists:reverse(DataDir2) ++ [?snmp_test_data]),
+ Config1 = lists:keydelete(data_dir, 1, Config0),
+ Config = [{data_dir, DataDir3 ++ "/"}|Config1],
+
+ %% --
+ %% Start nodes
+ %%
+
+ ?line {ok, SaNode} = start_node(snmp_sa),
+ ?line {ok, MgrNode} = start_node(snmp_mgr),
+
+
+ %% --
+ %% Create necessary files
+ %%
+
+ Dir = ?config(priv_dir, Config),
+ ?DBG("init_all -> Dir ~p", [Dir]),
+
+ DataDir = ?config(data_dir, Config),
+ ?DBG("init_all -> DataDir ~p", [DataDir]),
+
+ file:make_dir(MgrDir = filename:join(Dir, "mgr_dir/")),
+ ?DBG("init_all -> MgrDir ~p", [MgrDir]),
+
+ file:make_dir(AgentDir = filename:join(Dir, "agent_dir/")),
+ ?DBG("init_all -> AgentDir ~p", [AgentDir]),
+
+ file:make_dir(SaDir = filename:join(Dir, "sa_dir/")),
+ ?DBG("init_all -> SaDir ~p", [SaDir]),
+
+
+ %% --
+ %% Start and initiate mnesia
+ %%
+
+ ?DBG("init_all -> load application mnesia", []),
+ ?line ok = application:load(mnesia),
+
+ ?DBG("init_all -> load application mnesia on node ~p", [SaNode]),
+ ?line ok = rpc:call(SaNode, application, load, [mnesia]),
+
+ ?DBG("init_all -> application mnesia: set_env dir",[]),
+ ?line application_controller:set_env(mnesia, dir,
+ filename:join(Dir, "Mnesia1")),
+
+ ?DBG("init_all -> application mnesia: set_env dir on node ~p",[SaNode]),
+ ?line rpc:call(SaNode, application_controller, set_env,
+ [mnesia, dir, filename:join(Dir, "Mnesia2")]),
+
+ ?DBG("init_all -> create mnesia schema",[]),
+ ?line ok = mnesia:create_schema([SaNode, node()]),
+
+ ?DBG("init_all -> start application mnesia",[]),
+ ?line ok = application:start(mnesia),
+
+ ?DBG("init_all -> start application mnesia on ~p",[SaNode]),
+ ?line ok = rpc:call(SaNode, application, start, [mnesia]),
+ Ip = ?LOCALHOST(),
+ [{snmp_sa, SaNode},
+ {snmp_mgr, MgrNode},
+ {agent_dir, AgentDir ++ "/"},
+ {mgr_dir, MgrDir ++ "/"},
+ {sa_dir, SaDir ++ "/"},
+ {mib_dir, DataDir},
+ {ip, Ip} |
+ Config].
+
+finish_all(Config) when list(Config) ->
+ SaNode = ?config(snmp_sa, Config),
+ MgrNode = ?config(snmp_mgr, Config),
+ stop_node(SaNode),
+ stop_node(MgrNode),
+ application:stop(mnesia).
+
+start_v1_agent(Config) when list(Config) ->
+ start_agent(Config, [v1]).
+
+start_v1_agent(Config,Opts) when list(Config), list(Opts) ->
+ start_agent(Config, [v1], Opts).
+
+start_v2_agent(Config) when list(Config) ->
+ start_agent(Config, [v2]).
+
+start_v3_agent(Config) when list(Config) ->
+ start_agent(Config, [v3]).
+
+start_bilingual_agent(Config) when list(Config) ->
+ start_agent(Config, [v1,v2]).
+
+start_multi_threaded_agent(Config) when list(Config) ->
+ start_agent(Config, [v2], [{snmp_multi_threaded, true}]).
+
+stop_agent(Config) when list(Config) ->
+ ?LOG("stop_agent -> entry with"
+ "~n Config: ~p",[Config]),
+
+ {Sup, Par} = ?config(snmp_sup, Config),
+ ?DBG("stop_agent -> attempt to stop (sup) ~p"
+ "~n Sup: ~p"
+ "~n Par: ~p",
+ [Sup,
+ (catch process_info(Sup)),
+ (catch process_info(Par))]),
+ stop_sup(Sup, Par),
+
+ {Sup2, Par2} = ?config(snmp_sub, Config),
+ ?DBG("stop_agent -> attempt to stop (sub) ~p"
+ "~n Sup2: ~p"
+ "~n Par2: ~p",
+ [Sup2,
+ (catch process_info(Sup2)),
+ (catch process_info(Par2))]),
+ stop_sup(Sup2, Par2),
+
+ ?DBG("stop_agent -> done - now cleanup config", []),
+ C1 = lists:keydelete(snmp_sup, 1, Config),
+ lists:keydelete(snmp_sub, 1, C1).
+
+
+stop_sup(Pid, _) when node(Pid) == node() ->
+ case (catch process_info(Pid)) of
+ PI when list(PI) ->
+ ?LOG("stop_sup -> attempt to stop ~p", [Pid]),
+ Ref = erlang:monitor(process, Pid),
+ exit(Pid, kill),
+ await_stopped(Pid, Ref);
+ {'EXIT', _Reason} ->
+ ?LOG("stop_sup -> ~p not running", [Pid]),
+ ok
+ end;
+stop_sup(Pid, _) ->
+ ?LOG("stop_sup -> attempt to stop ~p", [Pid]),
+ Ref = erlang:monitor(process, Pid),
+ ?LOG("stop_sup -> Ref: ~p", [Ref]),
+ %% Pid ! {'EXIT', Parent, shutdown}, % usch
+ exit(Pid, kill),
+ await_stopped(Pid, Ref).
+
+await_stopped(Pid, Ref) ->
+ receive
+ {'DOWN', Ref, process, Pid, _Reason} ->
+ ?DBG("received down message for ~p", [Pid]),
+ ok
+ after 10000 ->
+ ?INF("await_stopped -> timeout for ~p",[Pid]),
+ erlang:demonitor(Ref),
+ ?FAIL({failed_stop,Pid})
+ end.
+
+
+start_agent(Config, Vsn) ->
+ start_agent(Config, Vsn, []).
+start_agent(Config, Vsn, Opts) ->
+ ?LOG("start_agent -> entry (~p) with"
+ "~n Config: ~p"
+ "~n Vsn: ~p"
+ "~n Opts: ~p",[node(), Config, Vsn, Opts]),
+
+ ?line AgentDir = ?config(agent_dir, Config),
+ ?line SaNode = ?config(snmp_sa, Config),
+
+ snmp_app_env_init(vsn_init(Vsn) ++
+ [{audit_trail_log, read_write_log},
+ {audit_trail_log_dir, AgentDir},
+ {audit_trail_log_size, {10240, 10}},
+ {force_config_reload, false},
+ {snmp_agent_type, master},
+ {snmp_config_dir, AgentDir},
+ {snmp_db_dir, AgentDir},
+ {snmp_local_db_auto_repair, true},
+ {snmp_master_agent_verbosity, trace},
+ {snmp_supervisor_verbosity, trace},
+ {snmp_mibserver_verbosity, trace},
+ {snmp_symbolic_store_verbosity, trace},
+ {snmp_note_store_verbosity, trace},
+ {snmp_net_if_verbosity, trace}],
+ Opts),
+
+
+ process_flag(trap_exit,true),
+
+ {ok, AppSup} = snmp_app_sup:start_link(),
+ unlink(AppSup),
+ ?DBG("start_agent -> snmp app supervisor: ~p",[AppSup]),
+
+ ?DBG("start_agent -> start master agent (old style)",[]),
+ Sup = case (catch snmpa_app:start(normal)) of
+ {ok, S} ->
+ ?DBG("start_agent -> started, Sup: ~p",[S]),
+ S;
+
+ Else ->
+ ?DBG("start_agent -> unknown result: ~n~p",[Else]),
+ %% Get info about the apps we depend on
+ MnesiaInfo = mnesia_running(),
+ ?FAIL({start_failed,Else,MnesiaInfo})
+ end,
+
+ ?DBG("start_agent -> unlink from supervisor",[]),
+ ?line unlink(Sup),
+ ?line SaDir = ?config(sa_dir, Config),
+ ?DBG("start_agent -> (rpc) start sub on ~p",[SaNode]),
+ ?line {ok, Sub} = rpc:call(SaNode, ?MODULE, start_sub, [SaDir]),
+ ?DBG("start_agent -> done",[]),
+ ?line [{snmp_sup, {Sup, self()}}, {snmp_sub, Sub} | Config].
+
+
+vsn_init(Vsn) ->
+ vsn_init([v1,v2,v3], Vsn, []).
+
+vsn_init([], _Vsn, Acc) ->
+ Acc;
+vsn_init([V|Vsns], Vsn, Acc) ->
+ case lists:member(V, Vsn) of
+ true ->
+ vsn_init(Vsns, Vsn, [{V, true}|Acc]);
+ false ->
+ vsn_init(Vsns, Vsn, [{V, false}|Acc])
+ end.
+
+snmp_app_env_init(Env0, Opts) ->
+ ?DBG("snmp_app_env_init -> unload snmp",[]),
+ ?line application:unload(snmp),
+ ?DBG("snmp_app_env_init -> load snmp",[]),
+ ?line application:load(snmp),
+ ?DBG("snmp_app_env_init -> initiate (snmp) application env",[]),
+ F1 = fun({Key,Val} = New, Acc0) ->
+ ?DBG("snmp_app_env_init -> "
+ "updating setting ~p to ~p", [Key, Val]),
+ case lists:keyreplace(Key, 1, Acc0, New) of
+ Acc0 ->
+ [New|Acc0];
+ Acc ->
+ Acc
+ end
+ end,
+ Env = lists:foldr(F1, Env0, Opts),
+ ?DBG("snmp_app_env_init -> Env: ~p",[Env]),
+ F2 = fun({Key,Val}) ->
+ ?DBG("snmp_app_env_init -> setting ~p to ~p",[Key, Val]),
+ application_controller:set_env(snmp, Key, Val)
+ end,
+ lists:foreach(F2, Env).
+
+
+
+
+%% Test if application is running
+mnesia_running() -> ?IS_MNESIA_RUNNING().
+crypto_running() -> ?IS_CRYPTO_RUNNING().
+
+
+start_sub(Dir) ->
+ ?DBG("start_sub -> entry",[]),
+ Opts = [{db_dir, Dir},
+ {supervisor, [{verbosity, trace}]}],
+ %% BMK BMK
+% {ok, P} = snmp_supervisor:start_sub(Dir),
+ {ok, P} = snmpa_supervisor:start_sub_sup(Opts),
+ unlink(P),
+ {ok, {P, self()}}.
+
+create_tables(SaNode) ->
+ ?line {atomic, ok} = mnesia:create_table([{name, friendsTable2},
+ {ram_copies, [SaNode]},
+ {snmp, [{key, integer}]},
+ {attributes, [a1,a2,a3]}]),
+ ?line {atomic, ok} = mnesia:create_table([{name, kompissTable2},
+ {ram_copies, [SaNode]},
+ {snmp, [{key, integer}]},
+ {attributes, [a1,a2,a3]}]),
+ ?line {atomic, ok} = mnesia:create_table([{name, snmp_variables},
+ {attributes, [a1,a2]}]).
+
+delete_tables() ->
+ mnesia:delete_table(friendsTable2),
+ mnesia:delete_table(kompissTable2),
+ mnesia:delete_table(snmp_variables).
+
+%% Creation is done in runtime!
+delete_mib_storage_mnesia_tables() ->
+ mnesia:delete_table(snmpa_mib_data),
+ mnesia:delete_table(snmpa_mib_tree),
+ mnesia:delete_table(snmpa_symbolic_store).
+
+%%-----------------------------------------------------------------
+%% A test case is always one of:
+%% - v1 specific case
+%% - v2 specific case
+%% - v1 and v2 case
+%% All v1 specific cases are prefixed with v1_, and all v2 with
+%% v2_. E.g. v1_trap/v2_trap.
+%%
+%% All other cases are shared. However, the testserver uses the name
+%% of the case to generate a file for that case. The same case cannot
+%% be used in different configurations in the same suite. Therefore
+%% all these functions exists in two variants, the base function
+%% <base>, and a second version <base>_2. There may be several
+%% versions as well, <base>_N.
+%%-----------------------------------------------------------------
+mib_storage(suite) -> [
+ mib_storage_ets,
+ mib_storage_dets,
+ mib_storage_mnesia,
+ mib_storage_size_check_ets,
+ mib_storage_size_check_dets,
+ mib_storage_size_check_mnesia,
+ mib_storage_varm_dets,
+ mib_storage_varm_mnesia
+ ].
+
+mib_storage_ets(suite) -> {req, [], {conf, init_mib_storage_ets,
+ mib_storage_ets_cases(),
+ finish_mib_storage_ets}}.
+
+mib_storage_dets(suite) -> {req, [], {conf, init_mib_storage_dets,
+ mib_storage_dets_cases(),
+ finish_mib_storage_dets}}.
+
+mib_storage_mnesia(suite) -> {req, [], {conf, init_mib_storage_mnesia,
+ mib_storage_mnesia_cases(),
+ finish_mib_storage_mnesia}}.
+
+mib_storage_size_check_ets(suite) ->
+ {req, [], {conf,
+ init_size_check_mse,
+ mse_size_check_cases(),
+ finish_size_check_mse}}.
+
+mib_storage_size_check_dets(suite) ->
+ {req, [], {conf,
+ init_size_check_msd,
+ msd_size_check_cases(),
+ finish_size_check_msd}}.
+
+mib_storage_size_check_mnesia(suite) ->
+ {req, [], {conf,
+ init_size_check_msm,
+ msm_size_check_cases(),
+ finish_size_check_msm}}.
+
+mib_storage_varm_dets(suite) ->
+ {req, [], {conf,
+ init_varm_mib_storage_dets,
+ varm_mib_storage_dets_cases(),
+ finish_varm_mib_storage_dets}}.
+
+mib_storage_varm_mnesia(suite) ->
+ {req, [], {conf,
+ init_varm_mib_storage_mnesia,
+ varm_mib_storage_mnesia_cases(),
+ finish_varm_mib_storage_mnesia}}.
+
+mib_storage_ets_cases() ->
+ [
+ mse_simple,
+ mse_v1_processing,
+ mse_big,
+ mse_big2,
+ mse_loop_mib,
+ mse_api,
+ mse_sa_register,
+ mse_v1_trap,
+ mse_sa_error,
+ mse_next_across_sa,
+ mse_undo,
+ mse_standard_mib,
+ mse_community_mib,
+ mse_framework_mib,
+ mse_target_mib,
+ mse_notification_mib,
+ mse_view_based_acm_mib,
+ mse_sparse_table,
+ mse_me_of,
+ mse_mib_of].
+
+mib_storage_dets_cases() ->
+ [
+ msd_simple,
+ msd_v1_processing,
+ msd_big,
+ msd_big2,
+ msd_loop_mib,
+ msd_api,
+ msd_sa_register,
+ msd_v1_trap,
+ msd_sa_error,
+ msd_next_across_sa,
+ msd_undo,
+ msd_standard_mib,
+ msd_community_mib,
+ msd_framework_mib,
+ msd_target_mib,
+ msd_notification_mib,
+ msd_view_based_acm_mib,
+ msd_sparse_table,
+ msd_me_of,
+ msd_mib_of
+ ].
+
+mib_storage_mnesia_cases() ->
+ [
+ msm_simple,
+ msm_v1_processing,
+ msm_big,
+ msm_big2,
+ msm_loop_mib,
+ msm_api,
+ msm_sa_register,
+ msm_v1_trap,
+ msm_sa_error,
+ msm_next_across_sa,
+ msm_undo,
+ msm_standard_mib,
+ msm_community_mib,
+ msm_framework_mib,
+ msm_target_mib,
+ msm_notification_mib,
+ msm_view_based_acm_mib,
+ msm_sparse_table,
+ msm_me_of,
+ msm_mib_of
+ ].
+
+mse_size_check_cases() ->
+ [mse_size_check].
+
+msd_size_check_cases() ->
+ [msd_size_check].
+
+msm_size_check_cases() ->
+ [msm_size_check].
+
+varm_mib_storage_dets_cases() ->
+ [msd_varm_mib_start].
+
+varm_mib_storage_mnesia_cases() ->
+ [msm_varm_mib_start].
+
+init_mib_storage_ets(Config) when list(Config) ->
+ ?LOG("init_mib_storage_ets -> entry", []),
+ MibStorage = {snmp_mib_storage,ets},
+ init_ms(Config, [MibStorage]).
+
+init_mib_storage_dets(Config) when list(Config) ->
+ ?LOG("init_mib_storage_ets -> entry", []),
+ ?line AgentDir = ?GCONF(agent_dir, Config),
+ MibStorage = {snmp_mib_storage,{dets,AgentDir}},
+ init_ms(Config, [MibStorage]).
+
+init_mib_storage_mnesia(Config) when list(Config) ->
+ ?LOG("init_mib_storage_ets -> entry", []),
+ MibStorage = {snmp_mib_storage,{mnesia,[]}},
+ init_ms(Config, [MibStorage]).
+
+init_ms(Config, Opts) when list(Config) ->
+ ?LOG("init_mib_storage_ets -> entry", []),
+ ?line SaNode = ?GCONF(snmp_sa, Config),
+ ?line create_tables(SaNode),
+ ?line AgentDir = ?GCONF(agent_dir, Config),
+ ?line MgrDir = ?GCONF(mgr_dir, Config),
+ ?line Ip = ?GCONF(ip, Config),
+ ?line config([v1], MgrDir, AgentDir, tuple_to_list(Ip), tuple_to_list(Ip)),
+ MasterAgentVerbosity = {snmp_master_agent_verbosity, trace},
+ MibsVerbosity = {snmp_mibserver_verbosity, trace},
+ SymStoreVerbosity = {snmp_symbolic_store_verbosity, trace},
+ Opts1 = [MasterAgentVerbosity,MibsVerbosity,SymStoreVerbosity|Opts],
+ [{vsn, v1} | start_v1_agent(Config,Opts1)].
+
+init_size_check_mse(Config) when list(Config) ->
+ MibStorage = {snmp_mib_storage, ets},
+ init_size_check_ms(Config, [MibStorage]).
+
+init_size_check_msd(Config) when list(Config) ->
+ AgentDir = ?GCONF(agent_dir, Config),
+ MibStorage = {snmp_mib_storage, {dets, AgentDir}},
+ init_size_check_ms(Config, [MibStorage]).
+
+init_size_check_msm(Config) when list(Config) ->
+ MibStorage = {snmp_mib_storage, {mnesia,[]}},
+ init_size_check_ms(Config, [MibStorage]).
+
+init_size_check_ms(Config, Opts) when list(Config) ->
+ SaNode = ?GCONF(snmp_sa, Config),
+ %% We are using v3 here, so crypto must be supported or else...
+ case ?CRYPTO_START() of
+ ok ->
+ case ?CRYPTO_SUPPORT() of
+ {no, Reason} ->
+ ?SKIP({unsupported_encryption, Reason});
+ yes ->
+ ok
+ end;
+ {error, Reason} ->
+ ?SKIP({failed_starting_crypto, Reason})
+ end,
+ create_tables(SaNode),
+ AgentDir = ?GCONF(agent_dir, Config),
+ MgrDir = ?GCONF(mgr_dir, Config),
+ Ip = ?GCONF(ip, Config),
+ ?line ok =
+ config([v3], MgrDir, AgentDir, tuple_to_list(Ip), tuple_to_list(Ip)),
+ [{vsn, v3} | start_agent(Config, [v3], Opts)].
+
+init_varm_mib_storage_dets(Config) when list(Config) ->
+ ?LOG("init_varm_mib_storage_dets -> entry", []),
+ ?line SaNode = ?GCONF(snmp_sa, Config),
+ ?line create_tables(SaNode),
+ ?line AgentDir = ?GCONF(agent_dir, Config),
+ ?line MgrDir = ?GCONF(mgr_dir, Config),
+ ?line Ip = ?GCONF(ip, Config),
+ ?line config([v1], MgrDir, AgentDir, tuple_to_list(Ip), tuple_to_list(Ip)),
+ MibStorage = {snmp_mib_storage,{dets,AgentDir}},
+ MasterAgentVerbosity = {snmp_master_agent_verbosity, trace},
+ MibsVerbosity = {snmp_mibserver_verbosity, trace},
+ SymStoreVerbosity = {snmp_symbolic_store_verbosity, trace},
+ Opts = [MibStorage,MasterAgentVerbosity,MibsVerbosity,SymStoreVerbosity],
+ [{vsn, v1}, {agent_opts,Opts} | Config].
+
+init_varm_mib_storage_mnesia(Config) when list(Config) ->
+ ?LOG("init_varm_mib_storage_mnesia -> entry", []),
+ ?line SaNode = ?GCONF(snmp_sa, Config),
+ ?line create_tables(SaNode),
+ ?line AgentDir = ?GCONF(agent_dir, Config),
+ ?line MgrDir = ?GCONF(mgr_dir, Config),
+ ?line Ip = ?GCONF(ip, Config),
+ ?line config([v1], MgrDir, AgentDir, tuple_to_list(Ip), tuple_to_list(Ip)),
+ MibStorage = {snmp_mib_storage,{mnesia,[]}},
+ MasterAgentVerbosity = {snmp_master_agent_verbosity, trace},
+ MibsVerbosity = {snmp_mibserver_verbosity, trace},
+ SymStoreVerbosity = {snmp_symbolic_store_verbosity, trace},
+ Opts = [MibStorage,MasterAgentVerbosity,MibsVerbosity,SymStoreVerbosity],
+ [{vsn, v1}, {agent_opts,Opts} | Config].
+
+finish_mib_storage_ets(Config) when list(Config) ->
+ ?LOG("finish_mib_storage_ets -> entry", []),
+ delete_tables(),
+ C1 = stop_agent(Config),
+ delete_files(C1),
+ C2 = lists:keydelete(vsn, 1, C1),
+ lists:keydelete(agent_opts, 1, C2).
+
+finish_mib_storage_dets(Config) when list(Config) ->
+ ?LOG("finish_mib_storage_dets -> entry", []),
+ delete_tables(),
+ C1 = stop_agent(Config),
+ delete_files(C1),
+ C2 = lists:keydelete(vsn, 1, C1),
+ lists:keydelete(agent_opts, 1, C2).
+
+finish_mib_storage_mnesia(Config) when list(Config) ->
+ ?LOG("finish_mib_storage_mnesia -> entry", []),
+ delete_tables(),
+ delete_mib_storage_mnesia_tables(),
+ C1 = stop_agent(Config),
+ delete_files(C1),
+ C2 = lists:keydelete(vsn, 1, C1),
+ lists:keydelete(agent_opts, 1, C2).
+
+finish_varm_mib_storage_dets(Config) when list(Config) ->
+ ?LOG("finish_varm_mib_storage_dets -> entry", []),
+ delete_tables(),
+ %% C1 = stop_agent(Config), % In case something went wrong...
+ delete_files(Config),
+ C2 = lists:keydelete(vsn, 1, Config),
+ lists:keydelete(agent_opts, 1, C2).
+
+finish_varm_mib_storage_mnesia(Config) when list(Config) ->
+ ?LOG("finish_varm_mib_storage_mnesia -> entry", []),
+ delete_tables(),
+ delete_mib_storage_mnesia_tables(),
+ %% C1 = stop_agent(Config), % In case something went wrong...
+ delete_files(Config),
+ C2 = lists:keydelete(vsn, 1, Config),
+ lists:keydelete(agent_opts, 1, C2).
+
+finish_size_check_mse(Config) when list(Config) ->
+ finish_size_check_ms(Config).
+
+finish_size_check_msd(Config) when list(Config) ->
+ finish_size_check_ms(Config).
+
+finish_size_check_msm(Config) when list(Config) ->
+ finish_size_check_ms(Config).
+
+finish_size_check_ms(Config) when list(Config) ->
+ delete_tables(),
+ C1 = stop_agent(Config),
+ delete_files(C1),
+ lists:keydelete(vsn, 1, C1).
+
+
+%% These are just interface functions to fool the test server
+mse_simple(X) -> simple(X).
+mse_v1_processing(X) -> v1_processing(X).
+mse_big(X) -> big(X).
+mse_big2(X) -> big2(X).
+mse_loop_mib(X) -> loop_mib(X).
+mse_api(X) -> api(X).
+mse_sa_register(X) -> sa_register(X).
+mse_v1_trap(X) -> v1_trap(X).
+mse_sa_error(X) -> sa_error(X).
+mse_next_across_sa(X) -> next_across_sa(X).
+mse_undo(X) -> undo(X).
+mse_standard_mib(X) -> snmp_standard_mib(X).
+mse_community_mib(X) -> snmp_community_mib(X).
+mse_framework_mib(X) -> snmp_framework_mib(X).
+mse_target_mib(X) -> snmp_target_mib(X).
+mse_notification_mib(X) -> snmp_notification_mib(X).
+mse_view_based_acm_mib(X) -> snmp_view_based_acm_mib(X).
+mse_sparse_table(X) -> sparse_table(X).
+mse_me_of(X) -> ms_me_of(X).
+mse_mib_of(X) -> ms_mib_of(X).
+
+msd_simple(X) -> simple(X).
+msd_v1_processing(X) -> v1_processing(X).
+msd_big(X) -> big(X).
+msd_big2(X) -> big2(X).
+msd_loop_mib(X) -> loop_mib(X).
+msd_api(X) -> api(X).
+msd_sa_register(X) -> sa_register(X).
+msd_v1_trap(X) -> v1_trap(X).
+msd_sa_error(X) -> sa_error(X).
+msd_next_across_sa(X) -> next_across_sa(X).
+msd_undo(X) -> undo(X).
+msd_standard_mib(X) -> snmp_standard_mib(X).
+msd_community_mib(X) -> snmp_community_mib(X).
+msd_framework_mib(X) -> snmp_framework_mib(X).
+msd_target_mib(X) -> snmp_target_mib(X).
+msd_notification_mib(X) -> snmp_notification_mib(X).
+msd_view_based_acm_mib(X) -> snmp_view_based_acm_mib(X).
+msd_sparse_table(X) -> sparse_table(X).
+msd_me_of(X) -> ms_me_of(X).
+msd_mib_of(X) -> ms_mib_of(X).
+
+msm_simple(X) -> simple(X).
+msm_v1_processing(X) -> v1_processing(X).
+msm_big(X) -> big(X).
+msm_big2(X) -> big2(X).
+msm_loop_mib(X) -> loop_mib(X).
+msm_api(X) -> api(X).
+msm_sa_register(X) -> sa_register(X).
+msm_v1_trap(X) -> v1_trap(X).
+msm_sa_error(X) -> sa_error(X).
+msm_next_across_sa(X) -> next_across_sa(X).
+msm_undo(X) -> undo(X).
+msm_standard_mib(X) -> snmp_standard_mib(X).
+msm_community_mib(X) -> snmp_community_mib(X).
+msm_framework_mib(X) -> snmp_framework_mib(X).
+msm_target_mib(X) -> snmp_target_mib(X).
+msm_notification_mib(X) -> snmp_notification_mib(X).
+msm_view_based_acm_mib(X) -> snmp_view_based_acm_mib(X).
+msm_sparse_table(X) -> sparse_table(X).
+msm_me_of(X) -> ms_me_of(X).
+msm_mib_of(X) -> ms_mib_of(X).
+
+
+mse_size_check(X) -> p("mse_size_check..."), ms_size_check(X).
+msd_size_check(X) -> p("msd_size_check..."), ms_size_check(X).
+msm_size_check(X) -> p("msm_size_check..."), ms_size_check(X).
+
+msd_varm_mib_start(X) -> p("msd_varm_mib_start..."), varm_mib_start(X).
+msm_varm_mib_start(X) -> p("msm_varm_mib_start..."), varm_mib_start(X).
+
+ms_size_check(suite) -> [];
+ms_size_check(Config) when list(Config) ->
+ p("ms_size_check..."),
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?LOG("mib server size check...", []),
+
+ ?line load_master("Test2"),
+ ?line load_master("TestTrap"),
+ ?line load_master("TestTrapv2"),
+ ?line load_master_std("OTP-SNMPEA-MIB"),
+ ?line load_master_std("SNMP-COMMUNITY-MIB"),
+ ?line load_master_std("SNMP-FRAMEWORK-MIB"),
+ ?line load_master_std("SNMP-MPD-MIB"),
+ ?line load_master_std("SNMP-NOTIFICATION-MIB"),
+ ?line load_master_std("SNMP-TARGET-MIB"),
+ ?line load_master_std("SNMP-USER-BASED-SM-MIB"),
+ ?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"),
+ ?line load_master_std("SNMPv2-MIB"),
+ ?line load_master_std("SNMPv2-TM"),
+
+ ?SLEEP(2000),
+
+ ?line display_memory_usage(),
+
+ ?line unload_master("OTP-SNMPEA-MIB"),
+ ?line unload_master("SNMP-COMMUNITY-MIB"),
+ ?line unload_master("SNMP-FRAMEWORK-MIB"),
+ ?line unload_master("SNMP-MPD-MIB"),
+ ?line unload_master("SNMP-NOTIFICATION-MIB"),
+ ?line unload_master("SNMP-TARGET-MIB"),
+ ?line unload_master("SNMP-USER-BASED-SM-MIB"),
+ ?line unload_master("SNMP-VIEW-BASED-ACM-MIB"),
+ ?line unload_master("SNMPv2-MIB"),
+ ?line unload_master("SNMPv2-TM"),
+
+ ?line unload_master("TestTrapv2"),
+ ?line unload_master("TestTrap"),
+ ?line unload_master("Test2"),
+
+ ok.
+
+
+varm_mib_start(suite) -> [];
+varm_mib_start(Config) when list(Config) ->
+ p("varm_mib_start..."),
+ ?LOG("varm_mib_start -> entry", []),
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ %% Start the agent
+ Opts = ?GCONF(agent_opts, Config),
+ Config1 = start_v1_agent(Config, Opts),
+
+ %% Sleep some in order for the agent to start properly
+ ?DBG("varm_mib_start -> sleep some (before loading mobs)", []),
+ ?SLEEP(5000),
+
+ %% Load all the mibs
+ HardwiredMibs = loaded_mibs(),
+ ?DBG("varm_mib_start -> load all mibs", []),
+ ?line load_master_std("SNMP-COMMUNITY-MIB"),
+ ?line load_master_std("SNMP-FRAMEWORK-MIB"),
+ ?line load_master_std("SNMP-TARGET-MIB"),
+ ?line load_master_std("SNMP-NOTIFICATION-MIB"),
+
+ %% Unload the hardwired mibs
+ ?DBG("varm_mib_start -> sleep some (before unloading hardwired mibs)", []),
+ ?SLEEP(1000),
+ ?DBG("varm_mib_start -> unload (hardwired) mibs", []),
+ ?line unload_mibs(HardwiredMibs), %% unload hardwired
+
+ ?DBG("varm_mib_start -> sleep some (before stopping agent)", []),
+ ?SLEEP(1000),
+
+ %% Stop the agent (without deleting the stored files)
+ ?DBG("varm_mib_start -> stop the agent", []),
+ Config2 = stop_agent(Config1),
+
+ %% Sleep some in order for the agent to stop properly
+ ?DBG("varm_mib_start -> sleep some (before re-starting the agent)", []),
+ ?SLEEP(5000),
+
+ %% Start the agent (again)
+ ?DBG("varm_mib_start -> start the agent", []),
+ Config3 = start_v1_agent(Config2, Opts),
+
+ ?DBG("varm_mib_start -> sleep some (before starting tests)", []),
+ ?SLEEP(5000),
+
+ %% Perform the test(s)
+ ?DBG("varm_mib_start -> perform the tests", []),
+ try_test(snmp_community_mib),
+ try_test(snmp_framework_mib),
+ try_test(snmp_target_mib),
+ try_test(snmp_notification_mib),
+
+ %% Stop the agent (without deleting the stored files)
+ ?DBG("varm_mib_start -> stop the agent", []),
+ stop_agent(Config3),
+ ok.
+
+
+-define(snmpTrapCommunity_instance, [1,3,6,1,6,3,18,1,4,0]).
+-define(vacmViewSpinLock_instance, [1,3,6,1,6,3,16,1,5,1,0]).
+-define(usmStatsNotInTimeWindows_instance, [1,3,6,1,6,3,15,1,1,2,0]).
+
+ms_me_of(suite) -> [];
+ms_me_of(Config) when list(Config) ->
+ p("ms_me_of..."),
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ ?line load_master("Test2"),
+ ?line load_master("TestTrap"),
+ ?line load_master("TestTrapv2"),
+ ?line load_master_std("OTP-SNMPEA-MIB"),
+ ?line load_master_std("SNMP-COMMUNITY-MIB"),
+ ?line load_master_std("SNMP-FRAMEWORK-MIB"),
+ ?line load_master_std("SNMP-MPD-MIB"),
+ ?line load_master_std("SNMP-NOTIFICATION-MIB"),
+ ?line load_master_std("SNMP-TARGET-MIB"),
+ ?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"),
+
+ ?SLEEP(2000),
+
+ ?line display_memory_usage(),
+
+
+ ?DBG("ms_me_of -> find ~w from SNMP-COMMUNITY-MIB",
+ [?snmpTrapCommunity_instance]),
+ ?line ok = me_of(?snmpTrapCommunity_instance),
+
+ ?DBG("ms_me_of -> find ~w from SNMP-VIEW-BASED-ACM-MIB",
+ [?vacmViewSpinLock_instance]),
+ ?line ok = me_of(?vacmViewSpinLock_instance),
+
+ ?DBG("ms_me_of -> find ~w from SNMP-USER-BASED-SM-MIB",
+ [?usmStatsNotInTimeWindows_instance]),
+ ?line {error, _} = me_of(?usmStatsNotInTimeWindows_instance),
+
+
+ ?line unload_master("OTP-SNMPEA-MIB"),
+ ?line unload_master("SNMP-COMMUNITY-MIB"),
+ ?line unload_master("SNMP-FRAMEWORK-MIB"),
+ ?line unload_master("SNMP-MPD-MIB"),
+ ?line unload_master("SNMP-NOTIFICATION-MIB"),
+ ?line unload_master("SNMP-TARGET-MIB"),
+ ?line unload_master("SNMP-VIEW-BASED-ACM-MIB"),
+
+ ?line unload_master("TestTrapv2"),
+ ?line unload_master("TestTrap"),
+ ?line unload_master("Test2"),
+
+ ok.
+
+me_of(Oid) ->
+ case snmpa:me_of(Oid) of
+ {ok, #me{oid = Oid}} ->
+ ok;
+ {ok, #me{oid = OtherOid}} ->
+ case lists:reverse(Oid) of
+ [0|Rest] ->
+ case lists:reverse(Rest) of
+ OtherOid ->
+ ok;
+ AnotherOid ->
+ {error, {invalid_oid, Oid, AnotherOid}}
+ end;
+ _ ->
+ {error, {invalid_oid, Oid, OtherOid}}
+ end;
+ {error, Reason} ->
+ {error, Reason};
+ Else ->
+ {error, Else}
+ end.
+
+
+ms_mib_of(suite) -> [];
+ms_mib_of(Config) when list(Config) ->
+ p("ms_mib_of..."),
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ ?line load_master("Test2"),
+ ?line load_master("TestTrap"),
+ ?line load_master("TestTrapv2"),
+ ?line load_master_std("OTP-SNMPEA-MIB"),
+ ?line load_master_std("SNMP-COMMUNITY-MIB"),
+ ?line load_master_std("SNMP-FRAMEWORK-MIB"),
+ ?line load_master_std("SNMP-MPD-MIB"),
+ ?line load_master_std("SNMP-NOTIFICATION-MIB"),
+ ?line load_master_std("SNMP-TARGET-MIB"),
+ ?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"),
+
+ ?SLEEP(2000),
+
+ ?line display_memory_usage(),
+
+
+ ?DBG("ms_mib_of -> find ~w from SNMP-COMMUNITY-MIB",
+ [?snmpTrapCommunity_instance]),
+ ?line ok = mib_of(?snmpTrapCommunity_instance, 'SNMP-COMMUNITY-MIB'),
+
+ ?DBG("ms_mib_of -> find ~w from SNMP-VIEW-BASED-ACM-MIB",
+ [?vacmViewSpinLock_instance]),
+ ?line ok = mib_of(?vacmViewSpinLock_instance, 'SNMP-VIEW-BASED-ACM-MIB'),
+
+ ?DBG("ms_mib_of -> find ~w from SNMP-USER-BASED-SM-MIB",
+ [?usmStatsNotInTimeWindows_instance]),
+ ?line {error, _} = mib_of(?usmStatsNotInTimeWindows_instance,
+ 'SNMP-USER-BASED-SM-MIB'),
+
+
+ ?line unload_master("OTP-SNMPEA-MIB"),
+ ?line unload_master("SNMP-COMMUNITY-MIB"),
+ ?line unload_master("SNMP-FRAMEWORK-MIB"),
+ ?line unload_master("SNMP-MPD-MIB"),
+ ?line unload_master("SNMP-NOTIFICATION-MIB"),
+ ?line unload_master("SNMP-TARGET-MIB"),
+ ?line unload_master("SNMP-VIEW-BASED-ACM-MIB"),
+
+ ?line unload_master("TestTrapv2"),
+ ?line unload_master("TestTrap"),
+ ?line unload_master("Test2"),
+
+ ok.
+
+mib_of(Oid, ExpectedMibName) ->
+ ?DBG("mib_of -> entry with"
+ "~n Oid: ~p"
+ "~n ExpectedMibName: ~p", [Oid, ExpectedMibName]),
+ %% case snmpa:mib_of(Oid) of
+ MibOf = snmpa:mib_of(Oid),
+ ?DBG("mib_of -> MibOf: ~n~p", [MibOf]),
+ case MibOf of
+ {ok, ExpectedMibName} ->
+ ok;
+ {ok, OtherMibName} ->
+ {error, {invalid_mib, ExpectedMibName, OtherMibName}};
+ {error, Reason} ->
+ {error, Reason};
+ Else ->
+ ?DBG("mib_of -> Else: ~n~p", [Else]),
+ {error, Else}
+ end.
+
+
+app_info(suite) -> [];
+app_info(Config) when list(Config) ->
+ SnmpDir = app_dir(snmp),
+ SslDir = app_dir(ssl),
+ CryptoDir = app_dir(crypto),
+ Attr = snmp:module_info(attributes),
+ AppVsn =
+ case lists:keysearch(app_vsn, 1, Attr) of
+ {value, {app_vsn, V}} ->
+ V;
+ false ->
+ "undefined"
+ end,
+ io:format("Root dir: ~s~n"
+ "SNMP: Application dir: ~s~n"
+ " Application ver: ~s~n"
+ "SSL: Application dir: ~s~n"
+ "CRYPTO: Application dir: ~s~n",
+ [code:root_dir(), SnmpDir, AppVsn, SslDir, CryptoDir]),
+ ok.
+
+app_dir(App) ->
+ case code:lib_dir(App) of
+ D when list(D) ->
+ filename:basename(D);
+ {error, _Reason} ->
+ "undefined"
+ end.
+
+
+test_v1(suite) -> {req, [], {conf, init_v1, v1_cases(), finish_v1}}.
+
+%v1_cases() -> [loop_mib];
+v1_cases() ->
+ [simple,
+ db_notify_client,
+ v1_processing, big, big2, loop_mib,
+ api, subagent, mnesia, multiple_reqs,
+ sa_register, v1_trap, sa_error, next_across_sa, undo, reported_bugs,
+ standard_mibs, sparse_table, cnt_64,
+ opaque,
+ % opaque].
+
+ change_target_addr_config].
+
+init_v1(Config) when list(Config) ->
+ ?line SaNode = ?config(snmp_sa, Config),
+ ?line create_tables(SaNode),
+ ?line AgentDir = ?config(agent_dir, Config),
+ ?line MgrDir = ?config(mgr_dir, Config),
+ ?line Ip = ?config(ip, Config),
+ ?line config([v1], MgrDir, AgentDir, tuple_to_list(Ip), tuple_to_list(Ip)),
+ [{vsn, v1} | start_v1_agent(Config)].
+
+finish_v1(Config) when list(Config) ->
+ delete_tables(),
+ C1 = stop_agent(Config),
+ delete_files(C1),
+ lists:keydelete(vsn, 1, C1).
+
+test_v2(suite) -> {req, [], {conf, init_v2, v2_cases(), finish_v2}}.
+
+%v2_cases() -> [loop_mib_2];
+v2_cases() ->
+ [simple_2, v2_processing, big_2, big2_2, loop_mib_2,
+ api_2, subagent_2, mnesia_2,
+ multiple_reqs_2, sa_register_2, v2_trap, v2_inform, sa_error_2,
+ next_across_sa_2, undo_2, reported_bugs_2, standard_mibs_2,
+ v2_types, implied, sparse_table_2, cnt_64_2, opaque_2, v2_caps].
+
+init_v2(Config) when list(Config) ->
+ SaNode = ?config(snmp_sa, Config),
+ create_tables(SaNode),
+ AgentDir = ?config(agent_dir, Config),
+ MgrDir = ?config(mgr_dir, Config),
+ Ip = ?config(ip, Config),
+ config([v2], MgrDir, AgentDir, tuple_to_list(Ip), tuple_to_list(Ip)),
+ [{vsn, v2} | start_v2_agent(Config)].
+
+finish_v2(Config) when list(Config) ->
+ delete_tables(),
+ C1 = stop_agent(Config),
+ delete_files(C1),
+ lists:keydelete(vsn, 1, C1).
+
+test_v1_v2(suite) -> {req, [], {conf, init_v1_v2, v1_v2_cases(), finish_v1_v2}}.
+
+v1_v2_cases() ->
+ [simple_bi].
+
+init_v1_v2(Config) when list(Config) ->
+ SaNode = ?config(snmp_sa, Config),
+ create_tables(SaNode),
+ AgentDir = ?config(agent_dir, Config),
+ MgrDir = ?config(mgr_dir, Config),
+ Ip = ?config(ip, Config),
+ config([v1,v2], MgrDir, AgentDir, tuple_to_list(Ip), tuple_to_list(Ip)),
+ [{vsn, bilingual} | start_bilingual_agent(Config)].
+
+finish_v1_v2(Config) when list(Config) ->
+ delete_tables(),
+ C1 = stop_agent(Config),
+ delete_files(C1),
+ lists:keydelete(vsn, 1, C1).
+
+test_v3(suite) -> {req, [], {conf, init_v3, v3_cases(), finish_v3}}.
+
+%v3_cases() -> [loop_mib_3];
+v3_cases() ->
+ [simple_3, v3_processing,
+ big_3, big2_3, api_3, subagent_3, mnesia_3, loop_mib_3,
+ multiple_reqs_3, sa_register_3, v3_trap, v3_inform, sa_error_3,
+ next_across_sa_3, undo_3, reported_bugs_3, standard_mibs_3,
+ v3_security,
+ v2_types_3, implied_3, sparse_table_3, cnt_64_3, opaque_3, v2_caps_3].
+
+init_v3(Config) when list(Config) ->
+ %% Make sure crypto works, otherwise start_agent will fail
+ %% and we will be stuck with a bunch of mnesia tables for
+ %% the rest of this suite...
+ ?DBG("start_agent -> start crypto app",[]),
+ case os:type() of
+ vxworks ->
+ no_crypto;
+ _ ->
+ case ?CRYPTO_START() of
+ ok ->
+ case ?CRYPTO_SUPPORT() of
+ {no, Reason} ->
+ ?SKIP({unsupported_encryption, Reason});
+ yes ->
+ ok
+ end;
+ {error, Reason} ->
+ ?SKIP({failed_starting_crypto, Reason})
+ end
+ end,
+ SaNode = ?config(snmp_sa, Config),
+ create_tables(SaNode),
+ AgentDir = ?config(agent_dir, Config),
+ MgrDir = ?config(mgr_dir, Config),
+ Ip = ?config(ip, Config),
+ ?line ok = config([v3], MgrDir, AgentDir,
+ tuple_to_list(Ip), tuple_to_list(Ip)),
+ [{vsn, v3} | start_v3_agent(Config)].
+
+finish_v3(Config) when list(Config) ->
+ delete_tables(),
+ C1 = stop_agent(Config),
+ delete_files(C1),
+ lists:keydelete(vsn, 1, C1).
+
+test_multi_threaded(suite) -> {req, [], {conf, init_mt, mt_cases(), finish_mt}}.
+
+mt_cases() ->
+ [multi_threaded, mt_trap].
+
+init_mt(Config) when list(Config) ->
+ SaNode = ?config(snmp_sa, Config),
+ create_tables(SaNode),
+ AgentDir = ?config(agent_dir, Config),
+ MgrDir = ?config(mgr_dir, Config),
+ Ip = ?config(ip, Config),
+ ?line ok = config([v2], MgrDir, AgentDir, tuple_to_list(Ip), tuple_to_list(Ip)),
+ [{vsn, v2} | start_multi_threaded_agent(Config)].
+
+finish_mt(Config) when list(Config) ->
+ delete_tables(),
+ C1 = stop_agent(Config),
+ delete_files(C1),
+ lists:keydelete(vsn, 1, C1).
+
+%% This one *must* be run first in each case.
+init_case(Config) when list(Config) ->
+ ?DBG("init_case -> entry with"
+ "~n Config: ~p", [Config]),
+ SaNode = ?config(snmp_sa, Config),
+ MgrNode = ?config(snmp_mgr, Config),
+ MasterNode = node(),
+
+ SaHost = ?HOSTNAME(SaNode),
+ MgrHost = ?HOSTNAME(MgrNode),
+ MasterHost = ?HOSTNAME(MasterNode),
+ {ok, MasterIP} = snmp_misc:ip(MasterHost),
+ {ok, MIP} = snmp_misc:ip(MgrHost),
+ {ok, SIP} = snmp_misc:ip(SaHost),
+
+
+ put(mgr_node, MgrNode),
+ put(sa_node, SaNode),
+ put(master_node, MasterNode),
+ put(sa_host, SaHost),
+ put(mgr_host, MgrHost),
+ put(master_host, MasterHost),
+ put(mip, tuple_to_list(MIP)),
+ put(masterip , tuple_to_list(MasterIP)),
+ put(sip, tuple_to_list(SIP)),
+
+ MibDir = ?config(mib_dir, Config),
+ put(mib_dir, MibDir),
+ StdM = filename:join(code:priv_dir(snmp), "mibs") ++ "/",
+ put(std_mib_dir, StdM),
+
+ MgrDir = ?config(mgr_dir, Config),
+ put(mgr_dir, MgrDir),
+
+ put(vsn, ?config(vsn, Config)),
+ ?DBG("init_case -> exit with"
+ "~n MasterNode: ~p"
+ "~n SaNode: ~p"
+ "~n MgrNode: ~p"
+ "~n MibDir: ~p", [MasterNode, SaNode, MgrNode, MibDir]),
+ {SaNode, MgrNode, MibDir}.
+
+load_master(Mib) ->
+ ?DBG("load_master -> entry with"
+ "~n Mib: ~p", [Mib]),
+ snmpa:unload_mibs(snmp_master_agent, [Mib]), % Unload for safety
+ ok = snmpa:load_mibs(snmp_master_agent, [get(mib_dir) ++ Mib]).
+
+load_master_std(Mib) ->
+ ?DBG("load_master_std -> entry with"
+ "~n Mib: ~p", [Mib]),
+ snmpa:unload_mibs(snmp_master_agent, [Mib]), % Unload for safety
+ ok = snmpa:load_mibs(snmp_master_agent, [get(std_mib_dir) ++ Mib]).
+
+unload_master(Mib) ->
+ ?DBG("unload_master -> entry with"
+ "~n Mib: ~p", [Mib]),
+ ok = snmpa:unload_mibs(snmp_master_agent, [Mib]).
+
+loaded_mibs() ->
+ ?DBG("loaded_mibs -> entry",[]),
+ Info = snmpa:info(snmp_master_agent),
+ {value, {loaded_mibs, Mibs}} = lists:keysearch(loaded_mibs, 1, Info),
+ [atom_to_list(Mib) || {Mib,_,_} <- Mibs].
+
+unload_mibs(Mibs) ->
+ ?DBG("unload_mibs -> entry with"
+ "~n Mibs: ~p", [Mibs]),
+ ok = snmpa:unload_mibs(snmp_master_agent, Mibs).
+
+start_subagent(SaNode, RegTree, Mib) ->
+ ?DBG("start_subagent -> entry with"
+ "~n SaNode: ~p"
+ "~n RegTree: ~p"
+ "~n Mib: ~p", [SaNode, RegTree, Mib]),
+ MA = whereis(snmp_master_agent),
+ ?DBG("start_subagent -> MA: ~p", [MA]),
+ MibDir = get(mib_dir),
+ Mib1 = join(MibDir,Mib),
+ %% BMK BMK
+% case rpc:call(SaNode,snmp_supervisor,start_subagent,[MA,RegTree,[Mib1]]) of
+ case rpc:call(SaNode, snmpa_supervisor,
+ start_sub_agent, [MA, RegTree, [Mib1]]) of
+ {ok, SA} ->
+ ?DBG("start_subagent -> SA: ~p", [SA]),
+ {ok, SA};
+ Error ->
+ ?FAIL({subagent_start_failed, SaNode, Error, [MA, RegTree, Mib1]})
+ end.
+
+stop_subagent(SA) ->
+ ?DBG("stop_subagent -> entry with"
+ "~n SA: ~p", [SA]),
+ %% BNK BMK
+ %% rpc:call(node(SA), snmp_supervisor, stop_subagent, [SA]).
+ rpc:call(node(SA), snmpa_supervisor, stop_sub_agent, [SA]).
+
+%%-----------------------------------------------------------------
+%% This function takes care of the old OTP-SNMPEA-MIB.
+%% Unfortunately, the testcases were written to use the data in the
+%% internal tables, and these table are now obsolete and not used
+%% by the agent. Therefore, we emulate them by using
+%% OLD-SNMPEA-MIB, which uses the default impl. of all tables.
+%%
+%% These two rows must exist in intCommunityTable
+%% {[147,214,36,45], "public", 2, readWrite}.
+%% {[147,214,36,45], "standard trap", 2, read}.
+%% (But with the manager's IP address)
+%%
+%%-----------------------------------------------------------------
+init_old() ->
+ snmpa_local_db:table_create_row(intCommunityTable,
+ get(mip) ++ [6 | "public"],
+ {get(mip), "public", 2, 2}),
+ snmpa_local_db:table_create_row(intCommunityTable,
+ get(mip) ++ [13 | "standard trap"],
+ {get(mip), "standard trap", 2, 1}),
+ snmpa_local_db:variable_set(intAgentIpAddress, [127,0,0,1]).
+
+
+
+simple(suite) -> [];
+simple(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ try_test(simple_standard_test).
+
+simple_2(X) -> simple(X).
+
+simple_bi(suite) -> [];
+simple_bi(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ put(vsn, v1), % First, try v1 manager
+ try_test(simple_standard_test),
+
+ put(vsn, v2), % Then, try v2 manager
+ try_test(simple_standard_test).
+
+simple_3(X) ->
+ simple(X).
+
+big(suite) -> [];
+big(Config) when list(Config) ->
+ ?DBG("big -> entry", []),
+ {SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ p("Starting subagent..."),
+ ?line pong = net_adm:ping(SaNode),
+
+ ?line {ok, SA} = start_subagent(SaNode, ?klas1, "Klas1"),
+ ?DBG("big -> SA: ~p", [SA]),
+ ?line load_master("OLD-SNMPEA-MIB"),
+ ?line init_old(),
+ try_test(big_test),
+ ?line stop_subagent(SA),
+ ?line unload_master("OLD-SNMPEA-MIB").
+
+big_2(X) -> big(X).
+
+big_3(X) -> big(X).
+
+
+big2(suite) -> [];
+big2(Config) when list(Config) ->
+ %% This is exactly the same tests as 'big', but with the
+ %% v2 equivalent of the mibs.
+ {SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ p("Starting subagent..."),
+ ?line pong = net_adm:ping(SaNode),
+
+ ?line {ok, SA} = start_subagent(SaNode, ?klas1, "Klas1-v2"),
+ ?line load_master("OLD-SNMPEA-MIB-v2"),
+ ?line init_old(),
+ try_test(big_test),
+ ?line stop_subagent(SA),
+ ?line unload_master("OLD-SNMPEA-MIB-v2").
+
+big2_2(X) -> big2(X).
+
+big2_3(X) -> big2(X).
+
+
+multi_threaded(suite) -> [];
+multi_threaded(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ ?line load_master("Test1"),
+ try_test(multi_threaded_test),
+ ?line unload_master("Test1").
+
+mt_trap(suite) -> [];
+mt_trap(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ MA = whereis(snmp_master_agent),
+
+ ?line load_master("Test1"),
+ ?line load_master("TestTrapv2"),
+ try_test(mt_trap_test, [MA]),
+ ?line unload_master("TestTrapv2"),
+ ?line unload_master("Test1").
+
+v2_types(suite) -> [];
+v2_types(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ ?line load_master("Test1"),
+ try_test(types_v2_test),
+ ?line unload_master("Test1").
+
+v2_types_3(X) -> v2_types(X).
+
+
+implied(suite) -> [];
+implied(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ MA = whereis(snmp_master_agent),
+
+ ?line load_master("Test1"),
+ try_test(implied_test,[MA]),
+ ?line unload_master("Test1").
+
+implied_3(X) -> implied(X).
+
+
+sparse_table(suite) -> [];
+sparse_table(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ ?line load_master("Test1"),
+ try_test(sparse_table_test),
+ ?line unload_master("Test1").
+
+sparse_table_2(X) -> sparse_table(X).
+
+sparse_table_3(X) -> sparse_table(X).
+
+cnt_64(suite) -> [];
+cnt_64(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ MA = whereis(snmp_master_agent),
+
+ ?line load_master("Test1"),
+ try_test(cnt_64_test, [MA]),
+ ?line unload_master("Test1").
+
+cnt_64_2(X) -> cnt_64(X).
+
+cnt_64_3(X) -> cnt_64(X).
+
+opaque(suite) -> [];
+opaque(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ ?line load_master("Test1"),
+ try_test(opaque_test),
+ ?line unload_master("Test1").
+
+opaque_2(X) -> opaque(X).
+
+opaque_3(X) -> opaque(X).
+
+
+change_target_addr_config(suite) -> [];
+change_target_addr_config(Config) when list(Config) ->
+ p("Testing changing target address config..."),
+ ?LOG("change_target_addr_config -> entry",[]),
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ put(sname,snmp_suite),
+ put(verbosity,trace),
+
+ MA = whereis(snmp_master_agent),
+
+ ?LOG("change_target_addr_config -> load TestTrap",[]),
+ ?line load_master("TestTrap"),
+
+ ?LOG("change_target_addr_config -> set trace verbosity for local_db",[]),
+ ?line snmpa:verbosity(local_db,trace),
+
+ %% First send some traps that will arive att the original manager
+ ?LOG("change_target_addr_config -> send trap",[]),
+ try_test(ma_trap1, [MA]),
+
+ ?LOG("change_target_addr_config -> set silence verbosity for local_db",[]),
+ ?line snmpa:verbosity(local_db,silence),
+
+ %% Start new dummy listener
+ ?LOG("change_target_addr_config -> start dummy manager",[]),
+ ?line {ok,Pid,NewPort} = dummy_manager_start(MA),
+
+ %% Reconfigure
+ ?LOG("change_target_addr_config -> reconfigure",[]),
+ AgentDir = ?config(agent_dir, Config),
+ ?line rewrite_target_addr_conf(AgentDir, NewPort),
+ ?line snmp_target_mib:reconfigure(AgentDir),
+
+ %% Send the trap again
+ ?LOG("change_target_addr_config -> send trap again",[]),
+ catch dummy_manager_send_trap2(Pid),
+
+ ?LOG("change_target_addr_config -> await trap ack",[]),
+ catch dummy_manager_await_trap2_ack(),
+
+ ?LOG("change_target_addr_config -> stop dummy manager",[]),
+ ?line ok = dummy_manager_stop(Pid),
+
+ ?LOG("change_target_addr_config -> reset target address config",[]),
+ ?line reset_target_addr_conf(AgentDir),
+
+ ?LOG("change_target_addr_config -> unload TestTrap",[]),
+ ?line unload_master("TestTrap").
+
+
+dummy_manager_start(MA) ->
+ ?DBG("dummy_manager_start -> entry",[]),
+ Pid = spawn(get(mgr_node), ?MODULE,dummy_manager_init,[self(),MA]),
+ ?DBG("dummy_manager_start -> Pid: ~p",[Pid]),
+ await_dummy_manager_started(Pid).
+
+await_dummy_manager_started(Pid) ->
+ receive
+ {dummy_manager_started,Pid,Port} ->
+ ?DBG("dummy_manager_start -> acknowledge received with"
+ "~n Port: ~p",[Port]),
+ {ok,Pid,Port};
+ {'EXIT', Pid, Reason} ->
+ {error, Pid, Reason};
+ O ->
+ ?LOG("dummy_manager_start -> received unknown message:"
+ "~n ~p",[O]),
+ await_dummy_manager_started(Pid)
+ end.
+
+dummy_manager_stop(Pid) ->
+ ?DBG("dummy_manager_stop -> entry with Pid: ~p",[Pid]),
+ Pid ! stop,
+ receive
+ {dummy_manager_stopping, Pid} ->
+ ?DBG("dummy_manager_stop -> acknowledge received",[]),
+ ok
+ after 10000 ->
+ ?ERR("dummy_manager_stop -> timeout",[]),
+ timeout
+ end.
+
+dummy_manager_send_trap2(Pid) ->
+ ?DBG("dummy_manager_send_trap2 -> entry",[]),
+ Pid ! {send_trap,testTrap2}.
+
+dummy_manager_await_trap2_ack() ->
+ ?DBG("dummy_manager_await_trap2 -> entry",[]),
+ receive
+ {received_trap,Trap} ->
+ ?LOG("dummy_manager_await_trap2 -> received trap: ~p",[Trap]),
+ %% Note:
+ %% Without this sleep the v2_inform_i testcase failes! There
+ %% is no relation between these two test cases as far as I
+ %% able to figure out...
+ sleep(60000),
+ ok;
+ O ->
+ ?ERR("dummy_manager_await_trap2 -> unexpected message: ~p",[O]),
+ ok
+ after 10000 ->
+ ?ERR("dummy_manager_await_trap2 -> timeout",[]),
+ timeout
+ end.
+
+dummy_manager_init(Parent,MA) ->
+ ?DBG("dummy_manager_init -> entry with"
+ "~n Parent: ~p"
+ "~n MA: ~p",[Parent,MA]),
+ {ok,S} = gen_udp:open(0,[{recbuf,65535}]),
+ ?DBG("dummy_manager_init -> S: ~p",[S]),
+ {ok,Port} = inet:port(S),
+ ?DBG("dummy_manager_init -> Port: ~p",[Port]),
+ Parent ! {dummy_manager_started,self(),Port},
+ dummy_manager_loop(Parent,S,MA).
+
+dummy_manager_loop(P,S,MA) ->
+ ?LOG("dummy_manager_loop -> ready for receive",[]),
+ receive
+ {send_trap,Trap} ->
+ ?LOG("dummy_manager_loop -> received trap send request"
+ "~n Trap: ~p",[Trap]),
+ snmpa:send_trap(MA, Trap, "standard trap"),
+ dummy_manager_loop(P,S,MA);
+ {udp, _UdpId, Ip, UdpPort, Bytes} ->
+ ?LOG("dummy_manager_loop -> received upd message"
+ "~n from: ~p:~p"
+ "~n size: ~p",
+ [Ip, UdpPort, dummy_manager_message_sz(Bytes)]),
+ R = dummy_manager_handle_message(Bytes),
+ ?DBG("dummy_manager_loop -> R: ~p",[R]),
+ P ! R,
+ dummy_manager_loop(P,S,MA);
+ stop ->
+ ?DBG("dummy_manager_loop -> received stop request",[]),
+ P ! {dummy_manager_stopping, self()},
+ gen_udp:close(S),
+ exit(normal);
+ O ->
+ ?LOG("dummy_manager_loop -> received unknown message:"
+ "~n ~p",[O]),
+ dummy_manager_loop(P,S,MA)
+ end.
+
+dummy_manager_message_sz(B) when binary(B) ->
+ size(B);
+dummy_manager_message_sz(L) when list(L) ->
+ length(L);
+dummy_manager_message_sz(_) ->
+ undefined.
+
+dummy_manager_handle_message(Bytes) ->
+ case (catch snmp_pdus:dec_message(Bytes)) of
+ {'EXIT',Reason} ->
+ ?ERR("dummy_manager_handle_message -> "
+ "failed decoding message only:~n ~p",[Reason]),
+ {error,Reason};
+ M ->
+ ?DBG("dummy_manager_handle_message -> decoded message:"
+ "~n ~p",[M]),
+ {received_trap,M}
+ end.
+
+
+api(suite) -> [];
+api(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ ?line load_master("OLD-SNMPEA-MIB"),
+ ?line init_old(),
+ try_test(api_test, [node()]),
+ ?line unload_master("OLD-SNMPEA-MIB").
+
+api_2(X) -> api(X).
+
+api_3(X) -> api(X).
+
+
+subagent(suite) -> [];
+subagent(Config) when list(Config) ->
+ {SaNode, _MgrNode, MibDir} = init_case(Config),
+
+ ?line {ok, SA} = start_subagent(SaNode, ?klas1, "Klas1"),
+ try_test(load_test_sa),
+
+ p("Testing unregister subagent..."),
+ MA = whereis(snmp_master_agent),
+ rpc:call(SaNode, snmp, unregister_subagent, [MA, SA]),
+ try_test(unreg_test),
+
+ p("Loading previous subagent mib in master and testing..."),
+ ?line ok = snmpa:load_mibs(MA, [MibDir ++ "Klas1"]),
+ try_test(load_test),
+
+ p("Unloading previous subagent mib in master and testing..."),
+ ?line ok = snmpa:unload_mibs(MA, [MibDir ++ "Klas1"]),
+ try_test(unreg_test),
+ p("Testing register subagent..."),
+ rpc:call(SaNode, snmp, register_subagent,
+ [MA, ?klas1, SA]),
+ try_test(load_test_sa),
+
+ ?line stop_subagent(SA),
+ try_test(unreg_test).
+
+subagent_2(X) -> subagent(X).
+
+subagent_3(X) -> subagent(X).
+
+
+mnesia(suite) -> [];
+mnesia(Config) when list(Config) ->
+ {SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ p("Starting subagent with mnesia impl..."),
+ {ok, SA} = start_subagent(SaNode, ?klas2, "Klas2"),
+ ?line load_master("OLD-SNMPEA-MIB"),
+ ?line init_old(),
+
+ try_test(big_test_2),
+
+ p("Testing unregister subagent..."),
+ MA = whereis(snmp_master_agent),
+ rpc:call(SaNode, snmp, unregister_subagent, [MA, SA]),
+ try_test(unreg_test),
+ ?line unload_master("OLD-SNMPEA-MIB"),
+ ?line stop_subagent(SA).
+
+mnesia_2(X) -> mnesia(X).
+
+mnesia_3(X) -> mnesia(X).
+
+
+multiple_reqs(suite) ->
+ {req, [], {conf, init_mul, mul_cases(), finish_mul}}.
+
+mul_cases() ->
+ [mul_get, mul_get_err, mul_next, mul_next_err, mul_set_err].
+
+multiple_reqs_2(suite) ->
+ {req, [], {conf, init_mul, mul_cases_2(), finish_mul}}.
+
+multiple_reqs_3(_X) ->
+ {req, [], {conf, init_mul, mul_cases_3(), finish_mul}}.
+
+
+mul_cases_2() ->
+ [mul_get_2, mul_get_err_2, mul_next_2, mul_next_err_2, mul_set_err_2].
+
+
+mul_cases_3() ->
+ [mul_get_3, mul_get_err_3, mul_next_3, mul_next_err_3, mul_set_err_3].
+
+
+init_mul(Config) when list(Config) ->
+ {SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ ?line {ok, SA} = start_subagent(SaNode, ?klas1, "Klas1"),
+ ?line load_master("OLD-SNMPEA-MIB"),
+ ?line init_old(),
+ [{mul_sub, SA} | Config].
+
+finish_mul(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ SA = ?config(mul_sub, Config),
+
+ ?line unload_master("OLD-SNMPEA-MIB"),
+ ?line stop_subagent(SA),
+ lists:keydelete(mul_sub, 1, Config).
+
+mul_get(suite) -> [];
+mul_get(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ p("Testing multiple get..."),
+ try_test(do_mul_get).
+
+mul_get_2(X) -> mul_get(X).
+
+mul_get_3(X) -> mul_get(X).
+
+
+mul_get_err(suite) -> [];
+mul_get_err(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ p("Testing multiple get with error..."),
+ try_test(do_mul_get_err).
+
+mul_get_err_2(X) -> mul_get_err(X).
+
+mul_get_err_3(X) -> mul_get_err(X).
+
+
+mul_next(suite) -> [];
+mul_next(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ p("Testing multiple next..."),
+ try_test(do_mul_next).
+
+mul_next_2(X) -> mul_next(X).
+
+mul_next_3(X) -> mul_next(X).
+
+
+mul_next_err(suite) -> [];
+mul_next_err(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ p("Testing multiple next..."),
+ try_test(do_mul_next_err).
+
+mul_next_err_2(X) -> mul_next_err(X).
+
+mul_next_err_3(X) -> mul_next_err(X).
+
+
+mul_set(suite) -> [];
+mul_set(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ p("Testing multiple set..."),
+ try_test(do_mul_set).
+
+mul_set_2(X) -> mul_set(X).
+
+mul_set_3(X) -> mul_set(X).
+
+
+mul_set_err(suite) -> [];
+mul_set_err(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ p("Testing multiple set with error..."),
+ try_test(do_mul_set_err).
+
+mul_set_err_2(X) -> mul_set_err(X).
+
+mul_set_err_3(X) -> mul_set_err(X).
+
+
+sa_register(suite) -> [];
+sa_register(Config) when list(Config) ->
+ ?DBG("sa_register -> entry", []),
+ {SaNode, _MgrNode, MibDir} = init_case(Config),
+
+ ?DBG("sa_register -> start subagent", []),
+ ?line {ok, SA} = start_subagent(SaNode, ?klas1, "Klas1"),
+
+ ?DBG("sa_register -> unregister subagent", []),
+ p("Testing unregister subagent (2)..."),
+ MA = whereis(snmp_master_agent),
+ rpc:call(SaNode, snmp, unregister_subagent, [MA, ?klas1]),
+ try_test(unreg_test),
+
+ p("Loading SA-MIB..."),
+ ?DBG("sa_register -> unload mibs", []),
+ snmpa:unload_mibs(SA, [MibDir ++ "Klas1"]),
+ ?DBG("sa_register -> unload mibs", []),
+ snmpa:load_mibs(SA, [MibDir ++ "SA-MIB"]),
+ ?DBG("sa_register -> register subagent", []),
+ rpc:call(SaNode, snmp, register_subagent, [MA,?sa,SA]),
+ try_test(sa_mib),
+
+ ?DBG("sa_register -> stop subagent", []),
+ ?line stop_subagent(SA).
+
+sa_register_2(X) -> sa_register(X).
+
+sa_register_3(X) -> sa_register(X).
+
+
+v1_trap(suite) -> [];
+v1_trap(Config) when list(Config) ->
+ {SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ ?line {ok, SA} = start_subagent(SaNode, ?sa, "SA-MIB"),
+
+ p("Testing trap sending from master agent..."),
+ MA = whereis(snmp_master_agent),
+
+ ?line load_master("TestTrap"),
+ ?line load_master("TestTrapv2"),
+
+ try_test(ma_trap1, [MA]),
+ try_test(ma_trap2, [MA]),
+ try_test(ma_v2_2_v1_trap, [MA]),
+ try_test(ma_v2_2_v1_trap2, [MA]),
+
+ p("Testing trap sending from subagent..."),
+ try_test(sa_trap1, [SA]),
+ try_test(sa_trap2, [SA]),
+ try_test(sa_trap3, [SA]),
+
+ ?line unload_master("TestTrap"),
+ ?line unload_master("TestTrapv2"),
+
+ ?line stop_subagent(SA).
+
+v2_trap(suite) -> [];
+v2_trap(Config) when list(Config) ->
+ {SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ ?line {ok, SA} = start_subagent(SaNode, ?sa, "SA-MIB"),
+
+ p("Testing trap sending from master agent..."),
+ MA = whereis(snmp_master_agent),
+
+ ?line load_master("TestTrap"),
+ ?line load_master("TestTrapv2"),
+
+
+ try_test(ma_v2_trap1, [MA]),
+ try_test(ma_v2_trap2, [MA]),
+ try_test(ma_v1_2_v2_trap, [MA]),
+ try_test(ma_v1_2_v2_trap2, [MA]),
+
+ try_test(sa_mib),
+ p("Testing trap sending from subagent..."),
+ try_test(sa_v1_2_v2_trap1, [SA]),
+ try_test(sa_v1_2_v2_trap2, [SA]),
+ try_test(sa_v1_2_v2_trap3, [SA]),
+
+ ?line unload_master("TestTrap"),
+ ?line unload_master("TestTrapv2"),
+
+ ?line stop_subagent(SA).
+
+v3_trap(X) ->
+ v2_trap(X).
+
+v2_inform(suite) ->
+ {req, [], {conf, init_v2_inform, [v2_inform_i], finish_v2_inform}}.
+
+v3_inform(_X) ->
+ %% v2_inform(X).
+ {req, [], {conf, init_v3_inform, [v3_inform_i], finish_v3_inform}}.
+
+init_v2_inform(Config) when list(Config) ->
+ _Dir = ?config(agent_dir, Config),
+% snmp_internal_mib:configure(Dir),
+ Config.
+
+init_v3_inform(X) ->
+ init_v2_inform(X).
+
+finish_v2_inform(Config) when list(Config) ->
+ _Dir = ?config(agent_dir, Config),
+% snmp_internal_mib:configure(Dir),
+ Config.
+
+finish_v3_inform(X) ->
+ finish_v2_inform(X).
+
+
+
+v2_inform_i(suite) -> [];
+v2_inform_i(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ p("Testing inform sending from master agent... NOTE! This test\ntakes a "
+ "few minutes (5) to complete."),
+ MA = whereis(snmp_master_agent),
+
+ ?line load_master("TestTrap"),
+ ?line load_master("TestTrapv2"),
+
+ try_test(ma_v2_inform1, [MA]),
+
+ ?line unload_master("TestTrap"),
+ ?line unload_master("TestTrapv2").
+
+v3_inform_i(X) -> v2_inform_i(X).
+
+
+sa_error(suite) -> [];
+sa_error(Config) when list(Config) ->
+ {SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ ?line load_master("OLD-SNMPEA-MIB"),
+ ?line init_old(),
+ ?line {ok, SA} = start_subagent(SaNode, ?sa, "SA-MIB"),
+
+ p("Testing sa bad value (is_set_ok)..."),
+ try_test(sa_errs_bad_value),
+
+ p("Testing sa gen err (set)..."),
+ try_test(sa_errs_gen_err),
+
+ p("Testing too big..."),
+ try_test(sa_too_big),
+
+ ?line unload_master("OLD-SNMPEA-MIB"),
+ stop_subagent(SA).
+
+sa_error_2(X) -> sa_error(X).
+
+sa_error_3(X) -> sa_error(X).
+
+
+next_across_sa(suite) -> [];
+next_across_sa(Config) when list(Config) ->
+ {SaNode, _MgrNode, MibDir} = init_case(Config),
+ MA = whereis(snmp_master_agent),
+
+ ?line {ok, SA} = start_subagent(SaNode, ?sa, "SA-MIB"),
+
+ p("Loading another subagent mib..."),
+ ?line ok = snmpa:load_mibs(SA, [MibDir ++ "Klas1"]),
+
+ rpc:call(SaNode, snmp, register_subagent, [MA, ?klas1, SA]),
+ try_test(load_test_sa),
+
+ p("Testing next across subagent (endOfMibView from SA)..."),
+ try_test(next_across_sa),
+
+ p("Unloading mib"),
+ snmpa:unload_mibs(SA, [MibDir ++ "Klas1"]),
+ rpc:call(SaNode, snmp, unregister_subagent, [MA, ?klas1]),
+ try_test(unreg_test),
+
+ p("Starting another subagent"),
+ ?line {ok, SA2} = start_subagent(SaNode, ?klas1, "Klas1"),
+ p("Testing next across subagent (wrong prefix from SA)..."),
+ try_test(next_across_sa),
+
+ stop_subagent(SA),
+ stop_subagent(SA2).
+
+next_across_sa_2(X) -> next_across_sa(X).
+
+next_across_sa_3(X) -> next_across_sa(X).
+
+
+undo(suite) -> [];
+undo(Config) when list(Config) ->
+ {SaNode, _MgrNode, MibDir} = init_case(Config),
+ MA = whereis(snmp_master_agent),
+
+ ?line {ok, SA} = start_subagent(SaNode, ?sa, "SA-MIB"),
+
+ p("Testing undo phase at master agent..."),
+ ?line ok = snmpa:load_mibs(MA, [MibDir ++ "Klas3"]),
+ ?line ok = snmpa:load_mibs(MA, [MibDir ++ "Klas4"]),
+ try_test(undo_test),
+ try_test(api_test2),
+ ?line ok = snmpa:unload_mibs(MA, [MibDir ++ "Klas3"]),
+
+ p("Testing bad return values from instrum. funcs..."),
+ try_test(bad_return),
+
+ ?line ok = snmpa:unload_mibs(MA, [MibDir ++ "Klas4"]),
+
+ p("Testing undo phase at subagent..."),
+ ?line ok = snmpa:load_mibs(SA, [MibDir ++ "Klas3"]),
+ ?line ok = snmpa:load_mibs(SA, [MibDir ++ "Klas4"]),
+ ?line ok = snmpa:register_subagent(MA, ?klas3, SA),
+ ?line ok = snmpa:register_subagent(MA, ?klas4, SA),
+ try_test(undo_test),
+ try_test(api_test3),
+
+ p("Testing undo phase across master/subagents..."),
+ try_test(undo_test),
+ try_test(api_test3),
+ stop_subagent(SA).
+
+undo_2(X) -> undo(X).
+
+undo_3(X) -> undo(X).
+
+%% Req. Test2
+v1_processing(suite) -> [];
+v1_processing(Config) when list(Config) ->
+ ?DBG("v1_processing -> entry", []),
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ ?line load_master("Test2"),
+ try_test(v1_proc),
+ ?line unload_master("Test2").
+
+%% Req. Test2
+v2_processing(suite) -> [];
+v2_processing(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ ?line load_master("Test2"),
+ try_test(v2_proc),
+ ?line unload_master("Test2").
+
+%% Req. Test2
+v3_processing(suite) -> [];
+v3_processing(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ ?line load_master("Test2"),
+ try_test(v2_proc), % same as v2!
+ ?line unload_master("Test2").
+
+
+%% We'll try get/set/trap and inform for all the auth & priv protocols.
+%% For informs, the mgr is auth-engine. The agent has to sync. This is
+%% accomplished by the first inform sent. That one will generate a
+%% report, which makes it in sync. The notification-generating
+%% application times out, and send again. This time it'll work.
+v3_security(suite) -> [v3_crypto_basic, v3_md5_auth, v3_sha_auth, v3_des_priv].
+
+v3_crypto_basic(suite) -> [];
+v3_crypto_basic(_Config) ->
+ EID = [0,0,0,0,0,0,0,0,0,0,0,2],
+ %% From rfc2274 appendix A.3.1
+ ?line KMd5_1 = snmp:passwd2localized_key(md5, "maplesyrup", EID),
+ ?line [16#52,16#6f,16#5e,16#ed,16#9f,16#cc,16#e2,16#6f,
+ 16#89,16#64,16#c2,16#93,16#07,16#87,16#d8,16#2b] =
+ KMd5_1,
+ %% From rfc2274 appendix A.3.2
+ ?line KSHA_1 = snmp:passwd2localized_key(sha, "maplesyrup", EID),
+ ?line [16#66,16#95,16#fe,16#bc,16#92,16#88,16#e3,16#62,16#82,16#23,
+ 16#5f,16#c7,16#15,16#1f,16#12,16#84,16#97,16#b3,16#8f,16#3f] =
+ KSHA_1,
+ %% From rfc2274, appendix A.5.1
+ ?line KMd5_2 = snmp:passwd2localized_key(md5, "newsyrup", EID),
+ ?line [16#00,16#00,16#00,16#00,16#00,16#00,16#00,16#00,
+ 16#00,16#00,16#00,16#00,16#00,16#00,16#00,16#00,
+ 16#88,16#05,16#61,16#51,16#41,16#67,16#6c,16#c9,
+ 16#19,16#61,16#74,16#e7,16#42,16#a3,16#25,16#51] =
+ snmp_user_based_sm_mib:mk_key_change(md5, KMd5_1, KMd5_2, 16,
+ [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]),
+ %% From rfc2274, appendix A.5.2
+ ?line KSHA_2 = snmp:passwd2localized_key(sha, "newsyrup", EID),
+ ?line [16#00,16#00,16#00,16#00,16#00,16#00,16#00,16#00,
+ 16#00,16#00,16#00,16#00,16#00,16#00,16#00,16#00,
+ 16#00,16#00,16#00,16#00,16#9c,16#10,16#17,16#f4,
+ 16#fd,16#48,16#3d,16#2d,16#e8,16#d5,16#fa,16#db,
+ 16#f8,16#43,16#92,16#cb,16#06,16#45,16#70,16#51] =
+ snmp_user_based_sm_mib:mk_key_change(sha, KSHA_1, KSHA_2, 20,
+ [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]),
+ KSHA_1t = lists:sublist(KSHA_1, 16),
+ KSHA_2t = lists:sublist(KSHA_2, 16),
+ ?line [16#00,16#00,16#00,16#00,16#00,16#00,16#00,16#00,
+ 16#00,16#00,16#00,16#00,16#00,16#00,16#00,16#00,
+ 16#7e,16#f8,16#d8,16#a4,16#c9,16#cd,16#b2,16#6b,
+ 16#47,16#59,16#1c,16#d8,16#52,16#ff,16#88,16#b5] =
+ snmp_user_based_sm_mib:mk_key_change(sha, KSHA_1t, KSHA_2t, 16,
+ [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]),
+
+ %% Try with correct random
+ ?line Kc1 = snmp_user_based_sm_mib:mk_key_change(md5, KMd5_1, KMd5_2),
+ ?line KMd5_2 = snmp_user_based_sm_mib:extract_new_key(md5, KMd5_1, Kc1),
+ ?line Kc2 = snmp_user_based_sm_mib:mk_key_change(sha, KSHA_1, KSHA_2),
+ ?line KSHA_2 = snmp_user_based_sm_mib:extract_new_key(sha, KSHA_1, Kc2),
+ ok.
+
+
+
+v3_md5_auth(suite) -> [];
+v3_md5_auth(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ p("Testing MD5 authentication...takes a few seconds..."),
+
+ AgentDir = ?config(agent_dir, Config),
+ ?line rewrite_target_params_conf(AgentDir, "authMD5", authNoPriv),
+ ?line snmp_target_mib:reconfigure(AgentDir),
+
+ MA = whereis(snmp_master_agent),
+
+ ?line load_master("Test2"),
+ ?line load_master("TestTrap"),
+ ?line load_master("TestTrapv2"),
+
+ try_test(v3_sync, [[{v2_proc, []},
+ {ma_v2_trap1, [MA]},
+ {v3_inform_sync, [MA]}]],
+ [{sec_level, authNoPriv}, {user, "authMD5"}]),
+
+ ?line unload_master("TestTrapv2"),
+ ?line unload_master("TestTrap"),
+ ?line unload_master("Test2"),
+ ?line reset_target_params_conf(AgentDir).
+
+v3_sha_auth(suite) -> [];
+v3_sha_auth(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ p("Testing SHA authentication...takes a few seconds..."),
+
+ AgentDir = ?config(agent_dir, Config),
+ ?line rewrite_target_params_conf(AgentDir, "authSHA", authNoPriv),
+ ?line snmp_target_mib:reconfigure(AgentDir),
+
+ MA = whereis(snmp_master_agent),
+
+ ?line load_master("Test2"),
+ ?line load_master("TestTrap"),
+ ?line load_master("TestTrapv2"),
+
+ try_test(v3_sync, [[{v2_proc, []},
+ {ma_v2_trap1, [MA]},
+ {v3_inform_sync, [MA]}]],
+ [{sec_level, authNoPriv}, {user, "authSHA"}]),
+
+ ?line unload_master("TestTrapv2"),
+ ?line unload_master("TestTrap"),
+ ?line unload_master("Test2"),
+ ?line reset_target_params_conf(AgentDir).
+
+v3_des_priv(suite) -> [];
+v3_des_priv(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ p("Testing DES encryption...takes a few seconds..."),
+
+ AgentDir = ?config(agent_dir, Config),
+ ?line rewrite_target_params_conf(AgentDir, "privDES", authPriv),
+ ?line snmp_target_mib:reconfigure(AgentDir),
+
+ MA = whereis(snmp_master_agent),
+
+ ?line load_master("Test2"),
+ ?line load_master("TestTrap"),
+ ?line load_master("TestTrapv2"),
+
+ try_test(v3_sync, [[{v2_proc, []},
+ {ma_v2_trap1, [MA]},
+ {v3_inform_sync, [MA]}]],
+ [{sec_level, authPriv}, {user, "privDES"}]),
+
+ ?line unload_master("TestTrapv2"),
+ ?line unload_master("TestTrap"),
+ ?line unload_master("Test2"),
+ ?line reset_target_params_conf(AgentDir).
+
+%% -define(usmStatsNotInTimeWindows_instance, [1,3,6,1,6,3,15,1,1,2,0]).
+
+%% Make sure mgr is in sync with agent
+v3_sync(Funcs) ->
+ ?DBG("v3_sync -> entry with Funcs: ~p",[Funcs]),
+ g([[sysDescr, 0]]),
+ expect(432, report, [{?usmStatsNotInTimeWindows_instance, any}]),
+ g([[sysDescr, 0]]),
+ expect(433, [{[sysDescr,0], any}]),
+ lists:foreach(fun({Func, Args}) -> apply(?MODULE, Func, Args) end, Funcs).
+
+v3_inform_sync(MA) ->
+ ?DBG("v3_sync -> entry with MA: ~p => Send notification",[MA]),
+ ?line snmpa:send_notification(MA, testTrapv22, no_receiver,
+ "standard inform", []),
+ %% Make sure agent is in sync with mgr...
+ ?DBG("v3_sync -> wait some time: ",[]),
+ sleep(20000), % more than 1500*10 in target_addr.conf
+ ?DBG("v3_sync -> await response",[]),
+ ?line expect(1, {inform, true},
+ [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?system ++ [0,1]}]).
+
+
+v2_caps(suite) -> [];
+v2_caps(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ try_test(v2_caps_i, [node()]).
+
+v2_caps_3(X) -> v2_caps(X).
+
+
+v2_caps_i(Node) ->
+ ?line Idx = rpc:call(Node, snmp, add_agent_caps, [[1,2,3,4,5], "test cap"]),
+ g([[sysORID, Idx], [sysORDescr, Idx]]),
+ ?line expect(1, [{[sysORID, Idx], [1,2,3,4,5]},
+ {[sysORDescr, Idx], "test cap"}]),
+ ?line rpc:call(Node, snmp, del_agent_caps, [Idx]),
+ g([[sysORID, Idx]]),
+ ?line expect(2, [{[sysORID, Idx], noSuchInstance}]).
+
+
+%% Req. Test2
+v1_proc() ->
+ ?DBG("v1_proc -> entry", []),
+ %% According to RFC1157.
+ %% Template: <Section>:<list no>
+ v1_get_p(),
+ v1_get_next_p(),
+ v1_set_p().
+
+
+v1_get_p() ->
+ %% 4.1.2:1
+ g([[test2]]),
+ ?line expect(10, noSuchName, 1, [{[test2], 'NULL'}]),
+ g([[tDescr]]),
+ ?line expect(11, noSuchName, 1, [{[tDescr], 'NULL'}]),
+ g([[tDescr2,0]]),
+ ?line expect(12, noSuchName, 1, [{[tDescr2,0], 'NULL'}]),
+ g([[tDescr3,0]]),
+ ?line expect(131, noSuchName, 1, [{[tDescr3,0], 'NULL'}]),
+ g([[tDescr4,0]]),
+ ?line expect(132, noSuchName, 1, [{[tDescr4,0], 'NULL'}]),
+ g([[sysDescr, 0], [tDescr,0]]), % Outside mibview
+ ?line expect(14, noSuchName, 2, [{[sysDescr, 0], 'NULL'},
+ {[tDescr,0], 'NULL'}]),
+ g([[sysDescr,3]]),
+ ?line expect(15, noSuchName, 1, [{[sysDescr, 3], 'NULL'}]),
+
+ %% 4.1.2:2
+ g([[tTable]]),
+ ?line expect(20, noSuchName, 1, [{[tTable], 'NULL'}]),
+ g([[tEntry]]),
+ ?line expect(21, noSuchName, 1, [{[tEntry], 'NULL'}]),
+
+ %% 4.1.2:3
+ g([[tTooBig, 0]]),
+ ?line expect(30, tooBig, 0, [{[tTooBig, 0], 'NULL'}]),
+
+ %% 4.1.2:4
+ g([[tGenErr1, 0]]),
+ ?line expect(40, genErr, 1, [{[tGenErr1, 0], 'NULL'}]),
+ g([[tGenErr2, 0]]),
+ ?line expect(41, genErr, 1, [{[tGenErr2, 0], 'NULL'}]),
+ g([[sysDescr, 0], [tGenErr3, 0]]),
+ ?line expect(42, genErr, 2, [{[sysDescr, 0], 'NULL'},
+ {[tGenErr3, 0], 'NULL'}]).
+
+
+v1_get_next_p() ->
+ %% 4.1.3:1
+ gn([[1,3,7,1]]),
+ ?line expect(10, noSuchName, 1, [{[1,3,7,1], 'NULL'}]),
+ gn([[tDescr2]]),
+ ?line expect(11, tooBig, 0, any),
+
+ %% 4.1.3:2
+ gn([[tTooBig]]),
+ io:format("We currently don't handle tooBig correct!!!\n"),
+% ?line expect(20, tooBig, 0, [{[tTooBig], 'NULL'}]),
+ ?line expect(20, tooBig, 0, any),
+
+ %% 4.1.3:3
+ gn([[tGenErr1]]),
+% ?line expect(40, genErr, 1, [{[tGenErr1], 'NULL'}]),
+ ?line expect(40, genErr, 1, any),
+ gn([[tGenErr2]]),
+% ?line expect(41, genErr, 1, [{[tGenErr2], 'NULL'}]),
+ ?line expect(41, genErr, 1, any),
+ gn([[sysDescr], [tGenErr3]]),
+% ?line expect(42, genErr, 2, [{[sysDescr], 'NULL'},
+% {[tGenErr3], 'NULL'}]).
+ ?line expect(42, genErr, 2, any).
+
+v1_set_p() ->
+ %% 4.1.5:1
+ s([{[1,3,7,0], i, 4}]),
+ ?line expect(10, noSuchName, 1, [{[1,3,7,0], 4}]),
+ s([{[tDescr,0], s, "outside mibview"}]),
+ ?line expect(11, noSuchName, 1, [{[tDescr,0], "outside mibview"}]),
+ s([{[tDescr3,0], s, "read-only"}]),
+ ?line expect(12, noSuchName, 1, [{[tDescr3,0], "read-only"}]),
+ s([{[tDescr3], s, "noSuchObject"}]),
+ ?line expect(13, noSuchName, 1, [{[tDescr3], "noSuchObject"}]),
+ s([{[tDescr3,1], s, "noSuchInstance"}]),
+ ?line expect(14, noSuchName, 1, [{[tDescr3,1], "noSuchInstance"}]),
+ s([{[tDescr2,0], s, "inconsistentName"}]),
+ ?line expect(15, noSuchName, 1, [{[tDescr2,0], "inconsistentName"}]),
+
+ %% 4.1.5:2
+ s([{[tDescr2, 0], i, 4}]),
+ ?line expect(20, badValue, 1, [{[tDescr2, 0], 4}]),
+ s([{[tDescr2, 0], s, "badValue"}]),
+ ?line expect(21, badValue, 1, [{[tDescr2, 0], "badValue"}]),
+
+ %% 4.1.5:3
+ %% The standard is quite incorrect here. The resp pdu was too big. In
+ %% the resp pdu, we have the original vbs. In the tooBig pdu we still
+ %% have to original vbs => the tooBig pdu is too big as well!!! It
+ %% may not get it to the manager, unless the agent uses 'NULL' instead
+ %% of the std-like original value.
+ s([{[tTooBig, 0], s, ?tooBigStr}]),
+ %% according to std:
+% ?line expect(30, tooBig, 0, [{[tTooBig, 0], ?tooBigStr}]),
+ ?line expect(30, tooBig, 0, [{[tTooBig, 0], 'NULL'}]),
+
+ %% 4.1.5:4
+ s([{[tDescr2, 0], s, "is_set_ok_fail"}]),
+ ?line expect(40, genErr, 1, [{[tDescr2, 0], "is_set_ok_fail"}]),
+ s([{[tDescr2, 0], s, "commit_fail"}]),
+ ?line expect(41, genErr, 1, [{[tDescr2, 0], "commit_fail"}]).
+
+%% Req. Test2
+v2_proc() ->
+ %% According to RFC1905.
+ %% Template: <Section>:<list no>
+ ?DBG("v2_proc -> entry",[]),
+ v2_get_p(),
+ v2_get_next_p(),
+ v2_get_bulk_p(),
+ v2_set_p().
+
+v2_get_p() ->
+ %% 4.2.1:2
+ ?DBG("v2_get_p -> entry",[]),
+ g([[test2]]),
+ ?line expect(10, [{[test2], noSuchObject}]),
+ g([[tDescr]]),
+ ?line expect(11, [{[tDescr], noSuchObject}]),
+ g([[tDescr4,0]]),
+ ?line expect(12, [{[tDescr4,0], noSuchObject}]),
+ g([[sysDescr, 0], [tDescr,0]]), % Outside mibview
+ ?line expect(13, [{[sysDescr,0], "Erlang SNMP agent"},
+ {[tDescr,0], noSuchObject}]),
+ g([[tTable]]),
+ ?line expect(14, [{[tTable], noSuchObject}]),
+ g([[tEntry]]),
+ ?line expect(15, [{[tEntry], noSuchObject}]),
+
+ %% 4.2.1:3
+ g([[tDescr2,0]]), %% instrum ret noSuchName!!!
+ ?line expect(20, [{[tDescr2,0], noSuchInstance}]),
+ g([[tDescr3,0]]),
+ ?line expect(21, [{[tDescr3,0], noSuchInstance}]),
+ g([[sysDescr,3]]),
+ ?line expect(22, [{[sysDescr, 3], noSuchInstance}]),
+ g([[tIndex,1]]),
+ ?line expect(23, [{[tIndex, 1], noSuchInstance}]),
+
+ %% 4.2.1 - any other error: genErr
+ g([[tGenErr1, 0]]),
+ ?line expect(30, genErr, 1, [{[tGenErr1, 0], 'NULL'}]),
+ g([[tGenErr2, 0]]),
+ ?line expect(31, genErr, 1, [{[tGenErr2, 0], 'NULL'}]),
+ g([[sysDescr, 0], [tGenErr3, 0]]),
+ ?line expect(32, genErr, 2, [{[sysDescr, 0], 'NULL'},
+ {[tGenErr3, 0], 'NULL'}]),
+
+ %% 4.2.1 - tooBig
+ g([[tTooBig, 0]]),
+ ?line expect(40, tooBig, 0, []).
+
+
+v2_get_next_p() ->
+ %% 4.2.2:2
+ ?DBG("v2_get_next_p -> entry",[]),
+ gn([[1,3,7,1]]),
+ ?line expect(10, [{[1,3,7,1], endOfMibView}]),
+ gn([[sysDescr], [1,3,7,1]]),
+ ?line expect(11, [{[sysDescr, 0], "Erlang SNMP agent"},
+ {[1,3,7,1], endOfMibView}]),
+ gn([[tCnt2, 1]]),
+ ?line expect(12, [{[tCnt2,2], 100}]),
+ gn([[tCnt2, 2]]),
+ ?line expect(12, [{[tCnt2,2], endOfMibView}]),
+
+ %% 4.2.2 - any other error: genErr
+ gn([[tGenErr1]]),
+ ?line expect(20, genErr, 1, [{[tGenErr1], 'NULL'}]),
+ gn([[tGenErr2]]),
+ ?line expect(21, genErr, 1, [{[tGenErr2], 'NULL'}]),
+ gn([[sysDescr], [tGenErr3]]),
+ ?line expect(22, genErr, 2, [{[sysDescr], 'NULL'},
+ {[tGenErr3], 'NULL'}]),
+
+ %% 4.2.2 - tooBig
+ gn([[tTooBig]]),
+ ?line expect(20, tooBig, 0, []).
+
+v2_get_bulk_p() ->
+ %% 4.2.3
+ ?DBG("v2_get_bulk_p -> entry",[]),
+ gb(1, 1, []),
+ ?line expect(10, []),
+ gb(-1, 1, []),
+ ?line expect(11, []),
+ gb(-1, -1, []),
+ ?line expect(12, []),
+ gb(-1, -1, []),
+ ?line expect(13, []),
+ gb(2, 0, [[sysDescr], [1,3,7,1]]),
+ ?line expect(14, [{[sysDescr, 0], "Erlang SNMP agent"},
+ {[1,3,7,1], endOfMibView}]),
+ gb(1, 2, [[sysDescr], [1,3,7,1]]),
+ ?line expect(15, [{[sysDescr, 0], "Erlang SNMP agent"},
+ {[1,3,7,1], endOfMibView}]),
+ gb(0, 2, [[sysDescr], [1,3,7,1]]),
+ ?line expect(16, [{[sysDescr, 0], "Erlang SNMP agent"},
+ {[1,3,7,1], endOfMibView},
+ {[sysObjectID, 0], [1,2,3]},
+ {[1,3,7,1], endOfMibView}]),
+
+ gb(2, 2, [[sysDescr], [1,3,7,1], [sysDescr], [1,3,7,1]]),
+ ?line expect(17, [{[sysDescr, 0], "Erlang SNMP agent"},
+ {[1,3,7,1], endOfMibView},
+ {[sysDescr, 0], "Erlang SNMP agent"},
+ {[1,3,7,1], endOfMibView},
+ {[sysObjectID, 0], [1,2,3]},
+ {[1,3,7,1], endOfMibView}]),
+
+ gb(1, 2, [[sysDescr], [sysDescr], [tTooBig]]),
+ ?line expect(18, [{[sysDescr, 0], "Erlang SNMP agent"},
+ {[sysDescr, 0], "Erlang SNMP agent"}]),
+
+ gb(1,12, [[tDescr2], [sysDescr]]), % next one after tDescr2 is tTooBig.
+ ?line expect(19, []),
+
+ gb(2,2, [[sysDescr], [sysObjectID], [tGenErr1], [sysDescr]]),
+ ?line expect(20, genErr, 3, [{[sysDescr], 'NULL'},
+ {[sysObjectID], 'NULL'},
+ {[tGenErr1], 'NULL'},
+ {[sysDescr], 'NULL'}]),
+ gb(0, 2, [[tCnt2, 1]]),
+ ?line expect(21, [{[tCnt2,2], 100},
+ {[tCnt2,2], endOfMibView}]).
+
+
+v2_set_p() ->
+ %% 4.2.5:1
+ ?DBG("v2_set_p -> entry",[]),
+ s([{[1,3,7,0], i, 4}]),
+ ?line expect(10, noAccess, 1, [{[1,3,7,0], 4}]),
+ s([{[tDescr,0], s, "outside mibview"}]),
+ ?line expect(11, noAccess, 1, [{[tDescr,0], "outside mibview"}]),
+
+ %% 4.2.5:2
+ s([{[1,3,6,1,0], s, "noSuchObject"}]),
+ ?line expect(20, notWritable, 1, [{[1,3,6,1,0], "noSuchObject"}]),
+
+ %% 4.2.5:3
+ s([{[tDescr2, 0], i, 4}]),
+ ?line expect(30, wrongType, 1, [{[tDescr2, 0], 4}]),
+ s([{[tDescr2, 0], s, "badValue"}]),
+ ?line expect(31, badValue, 1, [{[tDescr2, 0], "badValue"}]),
+
+ %% 4.2.5:4
+ s([{[tStr, 0], s, ""}]),
+ ?line expect(40, wrongLength, 1, [{[tStr, 0], ""}]),
+ s([{[tStr, 0], s, "12345"}]),
+ ?line expect(40, wrongLength, 1, [{[tStr, 0], "12345"}]),
+
+ %% 4.2.5:5 - N/A
+
+ %% 4.2.5:6
+ s([{[tInt1, 0], i, 0}]),
+ ?line expect(60, wrongValue, 1, [{[tInt1, 0], 0}]),
+ s([{[tInt1, 0], i, 5}]),
+ ?line expect(61, wrongValue, 1, [{[tInt1, 0], 5}]),
+ s([{[tInt2, 0], i, 0}]),
+ ?line expect(62, wrongValue, 1, [{[tInt2, 0], 0}]),
+ s([{[tInt2, 0], i, 5}]),
+ ?line expect(63, wrongValue, 1, [{[tInt2, 0], 5}]),
+ s([{[tInt3, 0], i, 5}]),
+ ?line expect(64, wrongValue, 1, [{[tInt3, 0], 5}]),
+
+ %% 4.2.5:7
+ s([{[tDescrX, 1, 1], s, "noCreation"}]),
+ ?line expect(70, noCreation, 1, [{[tDescrX, 1, 1], "noCreation"}]),
+
+ %% 4.2.5:8
+ s([{[tDescrX, 1, 2], s, "inconsistentName"}]),
+ ?line expect(80, inconsistentName, 1,
+ [{[tDescrX, 1, 2], "inconsistentName"}]),
+
+ %% 4.2.5:9
+ s([{[tCnt, 1, 2], i, 5}]),
+ ?line expect(90, notWritable, 1, [{[tCnt, 1, 2], 5}]),
+ s([{[tDescr3,0], s, "read-only"}]),
+ ?line expect(90, notWritable, 1, [{[tDescr3,0], "read-only"}]),
+
+ %% 4.2.5:10
+ s([{[tDescr2,0], s, "inconsistentValue"}]),
+ ?line expect(100, inconsistentValue, 1,
+ [{[tDescr2,0], "inconsistentValue"}]),
+
+ %% 4.2.5:11
+ s([{[tDescr2,0], s, "resourceUnavailable"}]),
+ ?line expect(110, resourceUnavailable, 1,
+ [{[tDescr2,0],"resourceUnavailable"}]),
+
+ %% 4.2.5:12
+ s([{[tDescr2, 0], s, "is_set_ok_fail"}]),
+ ?line expect(120, genErr, 1, [{[tDescr2, 0], "is_set_ok_fail"}]).
+
+ %% commitFailed and undoFailed is tested by the 'undo' case.
+
+
+%% Req. OLD-SNMPEA-MIB
+table_test() ->
+ io:format("Testing simple get, next and set on communityTable...~n"),
+%% {[147,214,36,45], "public", 2, readWrite}.
+%% {[147,214,36,45], "standard trap", 2, read}.
+ Key1c3 = [intCommunityViewIndex,get(mip),is("public")],
+ Key2c3 = [intCommunityViewIndex,get(mip),is("standard trap")],
+ Key1c4 = [intCommunityAccess,get(mip),is("public")],
+ EndKey = [intCommunityEntry,[9],get(mip),is("public")],
+ gn([[intCommunityEntry]]),
+ ?line expect(7, [{Key1c3, 2}]),
+ gn([[intCommunityTable]]),
+ ?line expect(71, [{Key1c3, 2}]),
+ gn([[community]]),
+ ?line expect(72, [{Key1c3, 2}]),
+ gn([[otpSnmpeaMIB]]),
+ ?line expect(73, [{Key1c3, 2}]),
+ gn([[ericsson]]),
+ ?line expect(74, [{Key1c3, 2}]),
+ gn([Key1c3]),
+ ?line expect(8, [{Key2c3, 2}]),
+ gn([Key2c3]),
+ ?line expect(9, [{Key1c4, 2}]),
+ gn([EndKey]),
+ AgentIp = [intAgentIpAddress,0],
+ ?line expect(10, [{AgentIp, any}]),
+ g([Key1c3]),
+ ?line expect(11, [{Key1c3, 2}]),
+ g([EndKey]),
+ ?line ?v1_2(expect(12, noSuchName, 1, any),
+ expect(12, [{EndKey, noSuchObject}])),
+
+ io:format("Testing row creation/deletion on communityTable...~n"),
+ NewKeyc3 = [intCommunityViewIndex,get(mip),is("test")],
+ NewKeyc4 = [intCommunityAccess,get(mip),is("test")],
+ NewKeyc5 = [intCommunityStatus,get(mip),is("test")],
+ s([{NewKeyc5, ?createAndGo}]),
+ ?line expect(14, ?v1_2(badValue, inconsistentValue), 1,any),
+ s([{NewKeyc5, ?createAndGo}, {NewKeyc3, 2}, {NewKeyc4, 2}]),
+ ?line expect(15, [{NewKeyc5, ?createAndGo},{NewKeyc3, 2}, {NewKeyc4, 2}]),
+ g([NewKeyc4]),
+ ?line expect(16, [{NewKeyc4, 2}]),
+ s([{NewKeyc5, ?destroy}]),
+ ?line expect(17, [{NewKeyc5, ?destroy}]),
+ s([{NewKeyc4, 2}]),
+ ?line expect(18, ?v1_2(noSuchName, inconsistentName), 1,[{NewKeyc4, 2}]),
+ s([{NewKeyc5, ?createAndWait}]),
+ ?line expect(19, [{NewKeyc5, ?createAndWait}]),
+ g([NewKeyc5]),
+ ?line expect(20, [{NewKeyc5, ?notReady}]),
+ s([{NewKeyc4, 2}]),
+ ?line expect(21, [{NewKeyc4, 2}]),
+ g([NewKeyc5]),
+ ?line expect(22, [{NewKeyc5, ?notReady}]),
+ s([{NewKeyc3, 2}]),
+ ?line expect(23, [{NewKeyc3, 2}]),
+ g([NewKeyc5]),
+ ?line expect(24, [{NewKeyc5, ?notInService}]),
+ s([{NewKeyc5, ?active}]),
+ ?line expect(25, [{NewKeyc5, ?active}]),
+ s([{NewKeyc5, ?destroy}]),
+ ?line expect(26, [{NewKeyc5, ?destroy}]),
+ s([{NewKeyc3, 3}]),
+ ?line expect(27, ?v1_2(noSuchName, inconsistentName), 1,[{NewKeyc3, 3}]),
+ otp_1128().
+
+%% Req. system group
+simple_standard_test() ->
+ ?DBG("simple_standard_test -> entry",[]),
+ gn([[1,1]]),
+ ?line expect(1, [{[sysDescr,0], "Erlang SNMP agent"}]),
+ gn([[1,3]]),
+ ?line expect(11, [{[sysDescr,0], "Erlang SNMP agent"}]),
+ gn([[1,3,6]]),
+ ?line expect(12, [{[sysDescr,0], "Erlang SNMP agent"}]),
+ gn([[1,3,6,1]]),
+ ?line expect(13, [{[sysDescr,0], "Erlang SNMP agent"}]),
+ gn([[1,3,6,1,2]]),
+ ?line expect(14, [{[sysDescr,0], "Erlang SNMP agent"}]),
+ gn([[1,3,6,1,2,1]]),
+ ?line expect(15, [{[sysDescr,0], "Erlang SNMP agent"}]),
+ gn([[1,3,6,1,2,1,1]]),
+ ?line expect(16, [{[sysDescr,0], "Erlang SNMP agent"}]),
+ gn([[sysDescr]]),
+ ?line expect(17, [{[sysDescr,0], "Erlang SNMP agent"}]),
+ g([[sysDescr,0]]),
+ ?line expect(2, [{[sysDescr,0], "Erlang SNMP agent"}]),
+ g([[sysDescr]]),
+ ?line ?v1_2(expect(3, noSuchName, 1, any),
+ expect(3, [{[sysDescr], noSuchObject}])),
+ g([[1,6,7,0]]),
+ ?line ?v1_2(expect(41, noSuchName, 1, any),
+ expect(3, [{[1,6,7,0], noSuchObject}])),
+ gn([[1,13]]),
+ ?line ?v1_2(expect(4, noSuchName,1, any),
+ expect(4, [{[1,13], endOfMibView}])),
+ s([{[sysLocation, 0], "new_value"}]),
+ ?line expect(5, [{[sysLocation, 0], "new_value"}]),
+ g([[sysLocation, 0]]),
+ ?line expect(6, [{[sysLocation, 0], "new_value"}]),
+ io:format("Testing noSuchName and badValue...~n"),
+ s([{[sysServices,0], 3}]),
+ ?line expect(61, ?v1_2(noSuchName, notWritable), 1, any),
+ s([{[sysLocation, 0], i, 3}]),
+ ?line expect(62, ?v1_2(badValue, wrongType), 1, any),
+ ?DBG("simple_standard_test -> done",[]),
+ ok.
+
+%% This is run in the agent node
+db_notify_client(suite) -> [];
+db_notify_client(Config) when list(Config) ->
+ {SaNode, MgrNode, MibDir} = init_case(Config),
+ ?DBG("~n\tSaNode: ~p~n\tMgrNode: ~p~n\tMibDir: ~p",
+ [SaNode,MgrNode,MibDir]),
+ snmpa_local_db:register_notify_client(self(),?MODULE),
+
+ %% This call (the manager) will issue to set operations, so
+ %% we expect to receive to notify(insert) calls.
+ try_test(db_notify_client_test),
+
+ ?DBG("await first notify",[]),
+ receive
+ {db_notify_test_reply,insert} -> ?DBG("first notify received",[]),ok
+ end,
+
+ ?DBG("await second notify",[]),
+ receive
+ {db_notify_test_reply,insert} -> ?DBG("second notify received",[]),ok
+ end,
+
+ snmpa_local_db:unregister_notify_client(self()).
+
+
+%% This is run in the manager node
+db_notify_client_test() ->
+ ?DBG("set first new sysLocation",[]),
+ s([{[sysLocation, 0], "new_value"}]),
+ ?line expect(5, [{[sysLocation, 0], "new_value"}]),
+
+ ?DBG("set second new sysLocation",[]),
+ s([{[sysLocation, 0], "new_value"}]),
+ ?line expect(5, [{[sysLocation, 0], "new_value"}]).
+
+notify(Pid,What) ->
+ ?DBG("notify(~p,~p) -> called",[Pid,What]),
+ Pid ! {db_notify_test_reply,What}.
+
+
+%% Req: system group, OLD-SNMPEA-MIB, Klas1
+big_test() ->
+ ?DBG("big_test -> testing simple next/get/set @ master agent...",[]),
+ simple_standard_test(),
+
+ ?DBG("big_test -> testing simple next/get/set @ subagent...",[]),
+ gn([[klas1]]),
+ ?line expect(1, [{[fname,0], ""}]),
+ g([[fname,0]]),
+ ?line expect(2, [{[fname,0], ""}]),
+ s([{[fname,0], s, "test set"}]),
+ ?line expect(3, [{[fname,0], "test set"}]),
+ g([[fname,0]]),
+ ?line expect(4, [{[fname,0], "test set"}]),
+
+ ?DBG("big_test -> "
+ "testing next from last instance in master to subagent...",[]),
+ gn([[?v1_2(sysServices, sysORLastChange),0]]),
+ ?line expect(5, [{[fname,0], "test set"}]),
+ gn([[1,1],
+ [?v1_2(sysServices, sysORLastChange),0]]),
+ ?line expect(51, [{[sysDescr,0], "Erlang SNMP agent"},
+ {[fname,0], "test set"}]),
+ s([{[fname,0], s, ""}]),
+ ?line expect(52, [{[fname,0], ""}]),
+
+ table_test(),
+
+ ?DBG("big_test -> adding one row in subagent table",[]),
+ _FTab = [friendsEntry],
+ s([{[friendsEntry, [2, 3]], s, "kompis3"},
+ {[friendsEntry, [3, 3]], i, ?createAndGo}]),
+ ?line expect(6, [{[friendsEntry, [2, 3]], "kompis3"},
+ {[friendsEntry, [3, 3]], ?createAndGo}]),
+ g([[friendsEntry, [2, 3]],
+ [friendsEntry, [3, 3]]]),
+ ?line expect(7, [{[friendsEntry, [2, 3]], "kompis3"},
+ {[friendsEntry, [3, 3]], ?active}]),
+ s([{[friendsEntry, [3, 3]], i, ?destroy}]),
+ ?line expect(8, [{[friendsEntry, [3, 3]], ?destroy}]),
+
+ otp_1131(),
+
+ ?DBG("big_test -> adding two rows in subagent table with special INDEX",
+ []),
+ s([{[kompissEntry, [1, 3]], s, "kompis3"},
+ {[kompissEntry, [2, 3]], i, ?createAndGo}]),
+ ?line expect(9, [{[kompissEntry, [1, 3]], "kompis3"},
+ {[kompissEntry, [2, 3]], ?createAndGo}]),
+ g([[kompissEntry, [1, 3]],
+ [kompissEntry, [2, 3]]]),
+ ?line expect(10, [{[kompissEntry, [1, 3]], "kompis3"},
+ {[kompissEntry, [2, 3]], ?active}]),
+ gn([[kompissEntry, [1]],
+ [kompissEntry, [2]]]),
+ ?line expect(11, [{[kompissEntry, [1, 3]], "kompis3"},
+ {[kompissEntry, [2, 3]], ?active}]),
+ s([{[kompissEntry, [1, 2]], s, "kompis3"},
+ {[kompissEntry, [2, 2]], i, ?createAndGo}]),
+ ?line expect(12, [{[kompissEntry, [1, 2]], "kompis3"},
+ {[kompissEntry, [2, 2]], ?createAndGo}]),
+ gn([[kompissEntry, [1, 1]],
+ [kompissEntry, [2, 1]]]),
+ ?line expect(13, [{[kompissEntry, [1, 2]], "kompis3"},
+ {[kompissEntry, [2, 2]], ?active}]),
+ s([{[kompissEntry, [2, 3]], i, ?destroy}]),
+ ?line expect(14, [{[kompissEntry, [2, 3]], ?destroy}]),
+ s([{[kompissEntry, [2, 2]], i, ?destroy}]),
+ ?line expect(15, [{[kompissEntry, [2, 2]], ?destroy}]),
+ ?DBG("big_test -> done",[]),
+ ok.
+
+%% Req. system group, Klas2, OLD-SNMPEA-MIB
+big_test_2() ->
+ p("Testing simple next/get/set @ master agent (2)..."),
+ simple_standard_test(),
+
+ p("Testing simple next/get/set @ subagent (2)..."),
+ gn([[klas2]]),
+ ?line expect(1, [{[fname2,0], ""}]),
+ g([[fname2,0]]),
+ ?line expect(2, [{[fname2,0], ""}]),
+ s([{[fname2,0], s, "test set"}]),
+ ?line expect(3, [{[fname2,0], "test set"}]),
+ g([[fname2,0]]),
+ ?line expect(4, [{[fname2,0], "test set"}]),
+
+ otp_1298(),
+
+ p("Testing next from last object in master to subagent (2)..."),
+ gn([[?v1_2(sysServices, sysORLastChange),0]]),
+ ?line expect(5, [{[fname2,0], "test set"}]),
+ gn([[1,1],
+ [?v1_2(sysServices, sysORLastChange),0]]),
+ ?line expect(51, [{[sysDescr,0], "Erlang SNMP agent"},
+ {[fname2,0], "test set"}]),
+
+ table_test(),
+
+ p("Adding one row in subagent table (2)"),
+ _FTab = [friendsEntry2],
+ s([{[friendsEntry2, [2, 3]], s, "kompis3"},
+ {[friendsEntry2, [3, 3]], i, ?createAndGo}]),
+ ?line expect(6, [{[friendsEntry2, [2, 3]], "kompis3"},
+ {[friendsEntry2, [3, 3]], ?createAndGo}]),
+ g([[friendsEntry2, [2, 3]],
+ [friendsEntry2, [3, 3]]]),
+ ?line expect(7, [{[friendsEntry2, [2, 3]], "kompis3"},
+ {[friendsEntry2, [3, 3]], ?active}]),
+ s([{[friendsEntry2, [3, 3]], i, ?destroy}]),
+ ?line expect(8, [{[friendsEntry2, [3, 3]], ?destroy}]),
+
+ p("Adding two rows in subagent table with special INDEX (2)"),
+ s([{[kompissEntry2, [1, 3]], s, "kompis3"},
+ {[kompissEntry2, [2, 3]], i, ?createAndGo}]),
+ ?line expect(9, [{[kompissEntry2, [1, 3]], "kompis3"},
+ {[kompissEntry2, [2, 3]], ?createAndGo}]),
+ g([[kompissEntry2, [1, 3]],
+ [kompissEntry2, [2, 3]]]),
+ ?line expect(10, [{[kompissEntry2, [1, 3]], "kompis3"},
+ {[kompissEntry2, [2, 3]], ?active}]),
+ gn([[kompissEntry2, [1]],
+ [kompissEntry2, [2]]]),
+ ?line expect(11, [{[kompissEntry2, [1, 3]], "kompis3"},
+ {[kompissEntry2, [2, 3]], ?active}]),
+ s([{[kompissEntry2, [1, 2]], s, "kompis3"},
+ {[kompissEntry2, [2, 2]], i, ?createAndGo}]),
+ ?line expect(12, [{[kompissEntry2, [1, 2]], "kompis3"},
+ {[kompissEntry2, [2, 2]], ?createAndGo}]),
+ gn([[kompissEntry2, [1, 1]],
+ [kompissEntry2, [2, 1]]]),
+ ?line expect(13, [{[kompissEntry2, [1, 2]], "kompis3"},
+ {[kompissEntry2, [2, 2]], ?active}]),
+ s([{[kompissEntry2, [2, 3]], i, ?destroy}]),
+ ?line expect(14, [{[kompissEntry2, [2, 3]], ?destroy}]),
+ s([{[kompissEntry2, [2, 2]], i, ?destroy}]),
+ ?line expect(15, [{[kompissEntry2, [2, 2]], ?destroy}]),
+ ok.
+
+%% Req. Test1
+multi_threaded_test() ->
+ p("Testing multi threaded agent..."),
+ g([[multiStr,0]]),
+ Pid = get_multi_pid(),
+ g([[sysUpTime,0]]),
+ ?line expect(1, [{[sysUpTime,0], any}]),
+ s([{[sysLocation, 0], s, "pelle"}]),
+ ?line expect(2, [{[sysLocation, 0], "pelle"}]),
+ Pid ! continue,
+ ?line expect(3, [{[multiStr,0], "ok"}]),
+
+ s([{[multiStr, 0], s, "block"}]),
+ Pid2 = get_multi_pid(),
+ g([[sysUpTime,0]]),
+ ?line expect(4, [{[sysUpTime,0], any}]),
+ g([[multiStr,0]]),
+ Pid3 = get_multi_pid(),
+ g([[sysUpTime,0]]),
+ ?line expect(5, [{[sysUpTime,0], any}]),
+ s([{[sysLocation, 0], s, "kalle"}]),
+ Pid3 ! continue,
+ ?line expect(6, [{[multiStr,0], "ok"}]),
+ Pid2 ! continue,
+ ?line expect(7, [{[multiStr,0], "block"}]),
+ ?line expect(8, [{[sysLocation,0], "kalle"}]).
+
+%% Req. Test1, TestTrapv2
+mt_trap_test(MA) ->
+ snmpa:send_trap(MA, testTrapv22, "standard trap"),
+ ?line expect(1, v2trap, [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?system ++ [0,1]}]),
+
+ snmpa:send_trap(MA, mtTrap, "standard trap"),
+ Pid = get_multi_pid(),
+ g([[sysUpTime,0]]),
+ ?line expect(2, [{[sysUpTime,0], any}]),
+ snmpa:send_trap(MA, testTrapv22, "standard trap"),
+ ?line expect(3, v2trap, [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?system ++ [0,1]}]),
+ Pid ! continue,
+ ?line expect(4, v2trap, [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?testTrap ++ [2]},
+ {[multiStr,0], "ok"}]).
+
+
+get_multi_pid() ->
+ get_multi_pid(10).
+get_multi_pid(0) ->
+ ?line ?FAIL(no_global_name);
+get_multi_pid(N) ->
+ sleep(1000),
+ case global:whereis_name(snmp_multi_tester) of
+ Pid when pid(Pid) -> Pid;
+ _ -> get_multi_pid(N-1)
+ end.
+
+%% Req. Test1
+types_v2_test() ->
+ p("Testing v2 types..."),
+
+ s([{[bits1,0], 2#10}]),
+ ?line expect(1, [{[bits1,0], ?str(2#10)}]),
+ g([[bits1,0]]),
+ ?line expect(2, [{[bits1,0], ?str(2#101)}]),
+
+ s([{[bits2,0], 2#11000000110}]),
+ ?line expect(3, [{[bits2,0], ?str(2#11000000110)}]),
+ g([[bits2,0]]),
+ ?line expect(4, [{[bits2,0], ?str(2#11000000110)}]),
+
+ g([[bits3,0]]),
+ ?line expect(50, genErr, 1, any),
+
+ g([[bits4,0]]),
+ ?line expect(51, genErr, 1, any),
+
+ s([{[bits1,0], s, [2#10]}]),
+ ?line expect(6, ?v1_2(badValue, wrongValue), 1, any),
+
+ s([{[bits2,0], 2#11001001101010011}]),
+ ?line expect(7, ?v1_2(badValue, wrongValue), 1, any).
+
+
+%% Req. Test1
+implied_test(MA) ->
+ ?LOG("implied_test -> start",[]),
+ p("Testing IMPLIED..."),
+
+ snmpa:verbosity(MA,trace),
+ snmpa:verbosity(MA,trace),
+
+ %% Create two rows, check that they are get-nexted in correct order.
+ Idx1 = "apa",
+ Idx2 = "qq",
+ ?DBG("implied_test -> (send) create row 1 '~s' in table 1",[Idx1]),
+ s([{[testStatus, Idx1], i, ?createAndGo}, {[testDescr, Idx1],s,"row 1"}]),
+ ?line expect(1, [{[testStatus, Idx1], ?createAndGo},
+ {[testDescr, Idx1], "row 1"}]),
+ ?DBG("implied_test -> (send) create row 2 '~s' in table 1",[Idx2]),
+ s([{[testStatus, Idx2], i, ?createAndGo}, {[testDescr, Idx2],s,"row 2"}]),
+ ?line expect(2, [{[testStatus, Idx2], ?createAndGo},
+ {[testDescr, Idx2], "row 2"}]),
+ ?DBG("implied_test -> get-next(testDescr)",[]),
+ gn([[testDescr]]),
+ ?line expect(3, [{[testDescr,Idx1], "row 1"}]),
+ ?DBG("implied_test -> get-next(testDescr) of row 1",[]),
+ gn([[testDescr,Idx1]]),
+ ?line expect(4, [{[testDescr,Idx2], "row 2"}]),
+
+ % Delete the rows
+ ?DBG("implied_test -> (send) delete row 1 '~s' from table 1",[Idx1]),
+ s([{[testStatus, Idx1], i, ?destroy}]),
+ ?line expect(5, [{[testStatus, Idx1], ?destroy}]),
+ ?DBG("implied_test -> (send) delete row 2 '~s' from table 1",[Idx2]),
+ s([{[testStatus, Idx2], i, ?destroy}]),
+ ?line expect(6, [{[testStatus, Idx2], ?destroy}]),
+
+ %% Try the same in other table
+ Idx3 = [1, "apa"],
+ Idx4 = [1, "qq"],
+ ?DBG("implied_test -> (send) create row 1 '~s' in table 2",[Idx3]),
+ s([{[testStatus2, Idx3], i, ?createAndGo}, {[testDescr2,Idx3],s,"row 1"}]),
+ ?line expect(1, [{[testStatus2, Idx3], ?createAndGo},
+ {[testDescr2, Idx3], "row 1"}]),
+ ?DBG("implied_test -> (send) create row 2 '~s' in table 2",[Idx4]),
+ s([{[testStatus2, Idx4], i, ?createAndGo}, {[testDescr2,Idx4],s,"row 2"}]),
+ ?line expect(2, [{[testStatus2, Idx4], ?createAndGo},
+ {[testDescr2, Idx4], "row 2"}]),
+ ?DBG("implied_test -> get-next(testDescr2)",[]),
+ gn([[testDescr2]]),
+ ?line expect(3, [{[testDescr2,Idx3], "row 1"}]),
+ ?DBG("implied_test -> get-next(testDescr2) of row 1",[]),
+ gn([[testDescr2,Idx3]]),
+ ?line expect(4, [{[testDescr2,Idx4], "row 2"}]),
+
+ % Delete the rows
+ ?DBG("implied_test -> (send) delete row 1 '~s' from table 2",[Idx3]),
+ s([{[testStatus2, Idx3], i, ?destroy}]),
+ ?line expect(5, [{[testStatus2, Idx3], ?destroy}]),
+ ?DBG("implied_test -> (send) delete row 2 '~s' from table 2",[Idx4]),
+ s([{[testStatus2, Idx4], i, ?destroy}]),
+ ?line expect(6, [{[testStatus2, Idx4], ?destroy}]),
+
+ snmpa:verbosity(MA,log),
+
+ ?LOG("implied_test -> done",[]).
+
+
+
+%% Req. Test1
+sparse_table_test() ->
+ p("Testing sparse table..."),
+
+ %% Create two rows, check that they are get-nexted in correct order.
+ Idx1 = 1,
+ Idx2 = 2,
+ s([{[sparseStatus, Idx1], i, ?createAndGo},
+ {[sparseDescr, Idx1], s, "row 1"}]),
+ ?line expect(1, [{[sparseStatus, Idx1], ?createAndGo},
+ {[sparseDescr, Idx1], "row 1"}]),
+ s([{[sparseStatus, Idx2], i, ?createAndGo},
+ {[sparseDescr, Idx2], s, "row 2"}]),
+ ?line expect(2, [{[sparseStatus, Idx2], ?createAndGo},
+ {[sparseDescr, Idx2], "row 2"}]),
+ ?v1_2(gn([[sparseIndex], [sparseDescr,Idx1], [sparseDescr,Idx2],
+ [sparseStatus,Idx1], [sparseStatus,Idx2]]),
+ gb(0,5,[[sparseIndex]])),
+ ?line expect(3, [{[sparseDescr,Idx1], "row 1"},
+ {[sparseDescr,Idx2], "row 2"},
+ {[sparseStatus,Idx1], ?active},
+ {[sparseStatus,Idx2], ?active},
+ {[sparseStr,0], "slut"}]),
+ % Delete the rows
+ s([{[sparseStatus, Idx1], i, ?destroy}]),
+ ?line expect(4, [{[sparseStatus, Idx1], ?destroy}]),
+ s([{[sparseStatus, Idx2], i, ?destroy}]),
+ ?line expect(5, [{[sparseStatus, Idx2], ?destroy}]).
+
+
+%% Req. Test1
+cnt_64_test(MA) ->
+ ?LOG("start cnt64 test (~p)",[MA]),
+ snmpa:verbosity(MA,trace),
+ ?LOG("start cnt64 test",[]),
+ p("Testing Counter64, and at the same time, RowStatus is not last column"),
+
+ ?DBG("get cnt64",[]),
+ g([[cnt64,0]]),
+ ?DBG("await response",[]),
+ ?line ?v1_2(expect(1, noSuchName, 1, any),
+ expect(1, [{[cnt64,0],18446744073709551615}])),
+ ?DBG("get-next cnt64",[]),
+ gn([[cnt64]]),
+ ?DBG("await response",[]),
+ ?line ?v1_2(expect(2, [{[cnt64Str,0], "after cnt64"}]),
+ expect(2, [{[cnt64,0],18446744073709551615}])),
+ ?DBG("send cntTrap",[]),
+ snmpa:send_trap(MA,cntTrap,"standard trap",[{sysContact,"pelle"},
+ {cnt64, 10},
+ {sysLocation, "here"}]),
+ ?DBG("await response",[]),
+ ?line ?v1_2(expect(3, trap, [test], 6, 1, [{[sysContact,0], "pelle"},
+ {[sysLocation,0], "here"}]),
+ expect(3, v2trap, [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?testTrap ++ [1]},
+ {[sysContact,0], "pelle"},
+ {[cnt64,0], 10},
+ {[sysLocation,0], "here"}])),
+
+ %% Create two rows, check that they are get-nexted in correct order.
+ Idx1 = 1,
+ Idx2 = 2,
+ ?DBG("create row (cntStatus): ~p",[Idx1]),
+ s([{[cntStatus, Idx1], i, ?createAndGo}]),
+ ?DBG("await response",[]),
+ ?line expect(1, [{[cntStatus, Idx1], ?createAndGo}]),
+ ?DBG("create row (cntStatus): ~p",[Idx2]),
+ s([{[cntStatus, Idx2], i, ?createAndGo}]),
+ ?DBG("await response",[]),
+ ?line expect(2, [{[cntStatus, Idx2], ?createAndGo}]),
+
+ ?DBG("get-next (cntIndex)",[]),
+ gn([[cntIndex]]),
+ ?DBG("await response",[]),
+ ?line ?v1_2(expect(3, [{[cntStatus,Idx1], ?active}]),
+ expect(3, [{[cntCnt,Idx1], 0}])),
+ % Delete the rows
+ ?DBG("delete row (cntStatus): ~p",[Idx1]),
+ s([{[cntStatus, Idx1], i, ?destroy}]),
+ ?DBG("await response",[]),
+ ?line expect(4, [{[cntStatus, Idx1], ?destroy}]),
+ ?DBG("delete row (cntStatus): ~p",[Idx2]),
+ s([{[cntStatus, Idx2], i, ?destroy}]),
+ ?DBG("await response",[]),
+ ?line expect(5, [{[cntStatus, Idx2], ?destroy}]),
+ catch snmpa:verbosity(MA,log),
+ ?DBG("done",[]),
+ ok.
+
+%% Req. Test1
+opaque_test() ->
+ p("Testing Opaque datatype..."),
+ g([[opaqueObj,0]]),
+ ?line expect(1, [{[opaqueObj,0], "opaque-data"}]).
+
+%% Req. OLD-SNMPEA-MIB
+api_test(MaNode) ->
+ ?line {value, OID} = rpc:call(MaNode, snmp, name_to_oid,
+ [intAgentIpAddress]),
+ ?line {value, intAgentIpAddress} = rpc:call(MaNode, snmp,
+ oid_to_name, [OID]),
+ ?line false = rpc:call(MaNode, snmp, name_to_oid, [intAgentIpAddres]),
+ ?line false = rpc:call(MaNode, snmp, oid_to_name,
+ [[1,5,32,3,54,3,3,34,4]]),
+ ?line {value, 2} = rpc:call(MaNode, snmp, enum_to_int,
+ [intViewType, excluded]),
+ ?line {value, excluded} = rpc:call(MaNode, snmp, int_to_enum,
+ [intViewType, 2]),
+ ?line false = rpc:call(MaNode, snmp, enum_to_int, [intViewType, exclude]),
+ ?line false = rpc:call(MaNode, snmp, enum_to_int,
+ [intAgentIpAddress, exclude]),
+ ?line false = rpc:call(MaNode, snmp, enum_to_int,
+ [intAgentIpAddre, exclude]),
+ ?line false = rpc:call(MaNode, snmp, int_to_enum, [intViewType, 3]),
+ ?line false = rpc:call(MaNode, snmp, int_to_enum, [intAgentIpAddress, 2]),
+ ?line false = rpc:call(MaNode, snmp, int_to_enum, [intAgentIpAddre, 2]),
+ ?line {value, active} = rpc:call(MaNode, snmp,
+ int_to_enum, ['RowStatus', ?active]),
+ ?line {value, ?destroy} = rpc:call(MaNode, snmp,
+ enum_to_int, ['RowStatus', destroy]),
+ ?line false = rpc:call(MaNode, snmp,
+ enum_to_int, ['RowStatus', xxxdestroy]),
+ ?line false = rpc:call(MaNode, snmp,
+ enum_to_int, ['xxRowStatus', destroy]),
+ ?line false = rpc:call(MaNode, snmp, int_to_enum, ['RowStatus', 25]),
+ ?line false = rpc:call(MaNode, snmp, int_to_enum, ['xxRowStatus', 1]),
+ ?line case snmp:date_and_time() of
+ List when list(List), length(List) == 8 -> ok;
+ List when list(List), length(List) == 11 -> ok
+ end.
+
+%% Req. Klas3
+api_test2() ->
+ g([[fname3,0]]),
+ ?line expect(1, [{[fname3,0], "ok"}]),
+ g([[fname4,0]]),
+ ?line expect(2, [{[fname4,0], 1}]).
+
+api_test3() ->
+ g([[fname3,0]]),
+ ?line expect(1, [{[fname3,0], "ok"}]).
+
+
+unreg_test() ->
+ gn([[?v1_2(sysServices, sysORLastChange),0]]),
+ ?line expect(1, [{[snmpInPkts, 0], any}]).
+
+load_test() ->
+ gn([[?v1_2(sysServices, sysORLastChange),0]]),
+ ?line expect(1, [{[fname,0], ""}]).
+
+%% Req. Klas1
+load_test_sa() ->
+ gn([[?v1_2(sysServices,sysORLastChange), 0]]),
+ ?line expect(1, [{[fname,0], any}]).
+
+%% Req. system group, Klas1, OLD-SNMPEA-MIB
+do_mul_get() ->
+ Key1c3 = [intCommunityEntry,[3],get(mip),is("public")],
+ Key1c4 = [intCommunityEntry,[4],get(mip),is("public")],
+ s([{[fname,0], s, "test set"}]),
+ ?line expect(3, [{[fname,0], "test set"}]),
+ g([[sysDescr,0], Key1c4, [fname,0],Key1c3,
+ [sysName,0]]),
+ ?line expect(1, [{[sysDescr,0], "Erlang SNMP agent"},
+ {Key1c4, 2},
+ {[fname,0], "test set"},
+ {Key1c3, 2},
+ {[sysName,0], "test"}]),
+ g([[1,3,7,1], Key1c4, [sysDescr,0], [1,3,7,2], Key1c3, [sysDescr,0]]),
+ ?line ?v1_2(expect(2, noSuchName, [1,4], any),
+ expect(2, [{[1,3,7,1], noSuchObject},
+ {Key1c4, 2},
+ {[sysDescr,0], "Erlang SNMP agent"},
+ {[1,3,7,2], noSuchObject},
+ {Key1c3, 2},
+ {[sysDescr,0], "Erlang SNMP agent"}])).
+
+%% Req. v1, system group, Klas1, OLD-SNMPEA-MIB, *ej* Klas3.
+do_mul_get_err() ->
+ Key1c3 = [intCommunityEntry,[3],get(mip),is("public")],
+ Key1c4 = [intCommunityEntry,[4],get(mip),is("public")],
+ s([{[fname,0], s, "test set"}]),
+ ?line expect(3, [{[fname,0], "test set"}]),
+ g([[sysDescr,0],Key1c4,[fname,0], Key1c3, [sysName,2]]),
+ ?line ?v1_2(expect(1, noSuchName, 5, any),
+ expect(1, [{[sysDescr,0], "Erlang SNMP agent"},
+ {Key1c4, 2},
+ {[fname,0], "test set"},
+ {Key1c3, 2},
+ {[sysName,2], noSuchInstance}])),
+ g([[sysDescr,0],Key1c4,[fname3,0], Key1c3, [sysName,1]]),
+ ?line ?v1_2(expect(1, noSuchName, [3,5], any),
+ expect(1, [{[sysDescr,0], "Erlang SNMP agent"},
+ {Key1c4, 2},
+ {[fname3,0], noSuchObject},
+ {Key1c3, 2},
+ {[sysName,1], noSuchInstance}])).
+
+
+%% Req. system group, Klas1, OLD-SNMPEA-MIB
+do_mul_next() ->
+ Key1c3s = [intCommunityEntry,[3],get(mip),is("publi")],
+ Key1c4s = [intCommunityEntry,[4],get(mip),is("publi")],
+ Key1c3 = [intCommunityEntry,[3],get(mip),is("public")],
+ Key1c4 = [intCommunityEntry,[4],get(mip),is("public")],
+ s([{[fname,0], s, "test set"}]),
+ ?line expect(3, [{[fname,0], "test set"}]),
+ gn([[sysDescr], Key1c4s, [fname],Key1c3s,[sysName]]),
+ ?line expect(1, [{[sysDescr,0], "Erlang SNMP agent"},
+ {Key1c4, 2}, {[fname,0], "test set"},
+ {Key1c3, 2}, {[sysName,0], "test"}]).
+
+%% Req. system group, Klas1, OLD-SNMPEA-MIB
+do_mul_next_err() ->
+ Key1c3s = [intCommunityEntry,[3],get(mip),is("publi")],
+ Key1c4s = [intCommunityEntry,[4],get(mip),is("publi")],
+ Key1c3 = [intCommunityEntry,[3],get(mip),is("public")],
+ Key1c4 = [intCommunityEntry,[4],get(mip),is("public")],
+ s([{[fname,0], s, "test set"}]),
+ ?line expect(3, [{[fname,0], "test set"}]),
+ gn([[sysDescr], Key1c4s, [1,3,6,999], [fname],[1,3,90], Key1c3s,[sysName]]),
+ ?line ?v1_2(expect(1, noSuchName, [3,5], any),
+ expect(1, [{[sysDescr,0], "Erlang SNMP agent"},
+ {Key1c4, 2},
+ {[1,3,6,999], endOfMibView},
+ {[fname,0], "test set"},
+ {[1,3,90], endOfMibView},
+ {Key1c3, 2},
+ {[sysName,0], "test"}])).
+
+
+%% Req. system group, Klas1, OLD-SNMPEA-MIB
+do_mul_set() ->
+ p("Adding one row in subagent table, and one in master table"),
+ NewKeyc3 = [intCommunityEntry,[3],get(mip),is("test")],
+ NewKeyc4 = [intCommunityEntry,[4],get(mip),is("test")],
+ NewKeyc5 = [intCommunityEntry,[5],get(mip),is("test")],
+ s([{[friendsEntry, [2, 3]], "kompis3"},
+ {NewKeyc3, 2},
+ {[sysLocation,0], "new_value"},
+ {NewKeyc5, ?createAndGo},
+ {NewKeyc4, 2},
+ {[friendsEntry, [3, 3]], ?createAndGo}]),
+ ?line expect(1, [{[friendsEntry, [2, 3]], "kompis3"},
+ {NewKeyc3, 2},
+ {[sysLocation,0], "new_value"},
+ {NewKeyc5, ?createAndGo},
+ {NewKeyc4, 2},
+ {[friendsEntry, [3, 3]], ?createAndGo}]),
+ g([[friendsEntry, [2, 3]],
+ [sysLocation,0],
+ [friendsEntry, [3, 3]]]),
+ ?line expect(2, [{[friendsEntry, [2, 3]], "kompis3"},
+ {[sysLocation,0], "new_value"},
+ {[friendsEntry, [3, 3]], ?active}]),
+ g([NewKeyc4]),
+ ?line expect(3, [{NewKeyc4, 2}]),
+ s([{[friendsEntry, [3, 3]], ?destroy},
+ {NewKeyc5, ?destroy}]),
+ ?line expect(4, [{[friendsEntry, [3, 3]], ?destroy},
+ {NewKeyc5, ?destroy}]).
+
+%% Req. system group, Klas1, OLD-SNMPEA-MIB
+do_mul_set_err() ->
+ NewKeyc3 = [intCommunityEntry,[3],get(mip),is("test")],
+ NewKeyc4 = [intCommunityEntry,[4],get(mip),is("test")],
+ NewKeyc5 = [intCommunityEntry,[5],get(mip),is("test")],
+ p("Adding one row in subagent table, and one in master table"),
+ s([{[friendsEntry, [2, 3]], s, "kompis3"},
+ {NewKeyc3, 2},
+ {[sysUpTime,0], 45}, % sysUpTime (readOnly)
+ {NewKeyc5, ?createAndGo},
+ {NewKeyc4, 2},
+ {[friendsEntry, [3, 3]], ?createAndGo}]),
+ ?line expect(1, ?v1_2(noSuchName, notWritable), 3, any),
+ g([[friendsEntry, [2, 3]]]),
+ ?line ?v1_2(expect(2, noSuchName, 1, any),
+ expect(2, [{[friendsEntry, [2,3]], noSuchInstance}])),
+ g([NewKeyc4]),
+ ?line ?v1_2(expect(3, noSuchName, 1, any),
+ expect(3, [{NewKeyc4, noSuchInstance}])).
+
+%% Req. SA-MIB
+sa_mib() ->
+ g([[sa, [2,0]]]),
+ ?line expect(1, [{[sa, [2,0]], 3}]),
+ s([{[sa, [1,0]], s, "sa_test"}]),
+ ?line expect(2, [{[sa, [1,0]], "sa_test"}]).
+
+ma_trap1(MA) ->
+ snmpa:send_trap(MA, testTrap2, "standard trap"),
+ ?line expect(1, trap, [system], 6, 1, [{[system, [4,0]],
+ "{mbj,eklas}@erlang.ericsson.se"}]),
+ snmpa:send_trap(MA, testTrap1, "standard trap"),
+ ?line expect(2, trap, [1,2,3] , 1, 0, [{[system, [4,0]],
+ "{mbj,eklas}@erlang.ericsson.se"}]).
+
+ma_trap2(MA) ->
+ snmpa:send_trap(MA,testTrap2,"standard trap",[{sysContact,"pelle"}]),
+ ?line expect(3, trap, [system], 6, 1, [{[system, [4,0]], "pelle"}]).
+
+ma_v2_2_v1_trap(MA) ->
+ snmpa:send_trap(MA,testTrapv22,"standard trap",[{sysContact,"pelle"}]),
+ ?line expect(3, trap, [system], 6, 1, [{[system, [4,0]], "pelle"}]).
+
+ma_v2_2_v1_trap2(MA) ->
+ snmpa:send_trap(MA,linkUp,"standard trap",[{ifIndex, [1], 1},
+ {ifAdminStatus, [1], 1},
+ {ifOperStatus, [1], 2}]),
+ ?line expect(3, trap, [1,2,3], 3, 0, [{[ifIndex, 1], 1},
+ {[ifAdminStatus, 1], 1},
+ {[ifOperStatus, 1], 2}]).
+
+sa_trap1(SA) ->
+ snmpa:send_trap(SA, saTrap, "standard trap"),
+ ?line expect(4, trap, [ericsson], 6, 1, [{[system, [4,0]],
+ "{mbj,eklas}@erlang.ericsson.se"},
+ {[sa, [1,0]], "sa_test"}]).
+
+sa_trap2(SA) ->
+ snmpa:send_trap(SA, saTrap, "standard trap",[{sysContact,"pelle"}]),
+ ?line expect(5, trap, [ericsson], 6, 1, [{[system, [4,0]],
+ "pelle"},
+ {[sa, [1,0]], "sa_test"}]).
+
+sa_trap3(SA) ->
+ snmpa:send_trap(SA, saTrap2, "standard trap",
+ [{intViewSubtree, [4], [1,2,3,4]}]),
+ ?line expect(6, trap, [ericsson], 6, 2, [{[system, [4,0]],
+ "{mbj,eklas}@erlang.ericsson.se"},
+ {[sa, [1,0]], "sa_test"},
+ {[intViewSubtree,4],[1,2,3,4]}]).
+
+ma_v2_trap1(MA) ->
+ ?DBG("ma_v2_traps -> entry with MA = ~p => "
+ "send standard trap: testTrapv22",[MA]),
+ snmpa:send_trap(MA, testTrapv22, "standard trap"),
+ ?line expect(1, v2trap, [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?system ++ [0,1]}]),
+ ?DBG("ma_v2_traps -> send standard trap: testTrapv21",[]),
+ snmpa:send_trap(MA, testTrapv21, "standard trap"),
+ ?line expect(2, v2trap, [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?snmp ++ [1]}]).
+
+ma_v2_trap2(MA) ->
+ snmpa:send_trap(MA,testTrapv22,"standard trap",[{sysContact,"pelle"}]),
+ ?line expect(3, v2trap, [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?system ++ [0,1]},
+ {[system, [4,0]], "pelle"}]).
+
+%% Note: This test case takes a while... actually a couple of minutes.
+ma_v2_inform1(MA) ->
+ ?DBG("ma_v2_inform -> entry with MA = ~p => "
+ "send notification: testTrapv22",[MA]),
+ ?line snmpa:send_notification(MA, testTrapv22, no_receiver, "standard inform", []),
+ ?line expect(1, {inform, true},
+ [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?system ++ [0,1]}]),
+
+ ?DBG("ma_v2_inform -> send notification: testTrapv22",[]),
+ snmpa:send_notification(MA, testTrapv22, {tag1, self()},
+ "standard inform", []),
+ ?line expect(1, {inform, true},
+ [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?system ++ [0,1]}]),
+ ?DBG("ma_v2_inform -> await targets",[]),
+ receive
+ {snmp_targets, tag1, [_]} ->
+ ok;
+ {snmp_targets, tag1, Addrs1} ->
+ ?line ?FAIL({bad_addrs, Addrs1})
+ after
+ 5000 ->
+ ?ERR("ma_v2_inform1 -> awaiting snmp_targets(tag1) timeout",[]),
+ ?line ?FAIL(nothing_at_all)
+ end,
+ ?DBG("ma_v2_inform -> await notification",[]),
+ receive
+ {snmp_notification, tag1, {got_response, _}} ->
+ ok;
+ {snmp_notification, tag1, {no_response, _}} ->
+ ?line ?FAIL(no_response)
+ after
+ 20000 ->
+ ?ERR("ma_v2_inform1 -> "
+ "awaiting snmp_notification(tag1) timeout",[]),
+ ?line ?FAIL(nothing_at_all)
+ end,
+
+ %%
+ %% -- The rest is possibly erroneous...
+ %%
+
+ ?DBG("ma_v2_inform -> send notification: testTrapv22",[]),
+ snmpa:send_notification(MA, testTrapv22, {tag2, self()},
+ "standard inform", []),
+ ?line expect(2, {inform, false},
+ [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?system ++ [0,1]}]),
+ ?DBG("ma_v2_inform -> await targets",[]),
+ receive
+ {snmp_targets, tag2, [_]} ->
+ ok;
+ {snmp_targets, tag2, Addrs2} ->
+ ?ERR("ma_v2_inform1 -> awaiting snmp_targets(tag2) timeout",[]),
+ ?line ?FAIL({bad_addrs, Addrs2})
+ after
+ 5000 ->
+ ?line ?FAIL(nothing_at_all)
+ end,
+ ?DBG("ma_v2_inform -> await notification",[]),
+ receive
+ {snmp_notification, tag2, {got_response, _}} ->
+ ?line ?FAIL(got_response);
+ {snmp_notification, tag2, {no_response, _}} ->
+ ok
+ after
+ 240000 ->
+ ?ERR("ma_v2_inform1 -> "
+ "awaiting snmp_notification(tag2) timeout",[]),
+ ?line ?FAIL(nothing_at_all)
+ end.
+
+
+ma_v1_2_v2_trap(MA) ->
+ snmpa:send_trap(MA,linkDown,"standard trap",[{ifIndex, [1], 1}]),
+ ?line expect(2, v2trap, [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?snmpTraps ++ [3]},
+ {[ifIndex, 1], 1},
+ {[snmpTrapEnterprise, 0], [1,2,3]}]).
+
+
+ma_v1_2_v2_trap2(MA) ->
+ snmpa:send_trap(MA,testTrap2,"standard trap",[{sysContact,"pelle"}]),
+ ?line expect(3, v2trap, [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?system ++ [0,1]},
+ {[system, [4,0]], "pelle"},
+ {[snmpTrapEnterprise, 0], ?system}]).
+
+
+sa_v1_2_v2_trap1(SA) ->
+ snmpa:send_trap(SA, saTrap, "standard trap"),
+ ?line expect(4, v2trap, [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?ericsson ++ [0, 1]},
+ {[system, [4,0]],
+ "{mbj,eklas}@erlang.ericsson.se"},
+ {[sa, [1,0]], "sa_test"},
+ {[snmpTrapEnterprise, 0], ?ericsson}]).
+
+sa_v1_2_v2_trap2(SA) ->
+ snmpa:send_trap(SA, saTrap, "standard trap",[{sysContact,"pelle"}]),
+ ?line expect(4, v2trap, [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?ericsson ++ [0, 1]},
+ {[system, [4,0]], "pelle"},
+ {[sa, [1,0]], "sa_test"},
+ {[snmpTrapEnterprise, 0], ?ericsson}]).
+
+
+sa_v1_2_v2_trap3(SA) ->
+ snmpa:send_trap(SA, saTrap2, "standard trap",
+ [{intViewSubtree, [4], [1,2,3,4]}]),
+ ?line expect(4, v2trap, [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?ericsson ++ [0, 2]},
+ {[system, [4,0]],
+ "{mbj,eklas}@erlang.ericsson.se"},
+ {[sa, [1,0]], "sa_test"},
+ {[intViewSubtree,4],[1,2,3,4]},
+ {[snmpTrapEnterprise, 0], ?ericsson}]).
+
+
+%% Req. SA-MIB, OLD-SNMPEA-MIB
+sa_errs_bad_value() ->
+ NewKeyc3 = [intCommunityEntry,[3],get(mip),is("test")],
+ NewKeyc4 = [intCommunityEntry,[4],get(mip),is("test")],
+ NewKeyc5 = [intCommunityEntry,[5],get(mip),is("test")],
+ s([{NewKeyc3, 2},
+ {[sa, [2,0]], 5}, % badValue (i is_set_ok)
+ {NewKeyc5, ?createAndGo},
+ {NewKeyc4, 2}]),
+ ?line expect(1, badValue, 2, any),
+ s([{NewKeyc3, 2},
+ {[sa, [2,0]], 6}, % wrongValue (i is_set_ok)
+ {NewKeyc5, ?createAndGo},
+ {NewKeyc4, 2}]),
+ ?line expect(1, ?v1_2(badValue, wrongValue), 2, any),
+ g([NewKeyc4]),
+ ?line ?v1_2(expect(2, noSuchName, 1, any),
+ expect(2, [{NewKeyc4, noSuchInstance}])).
+
+%% Req. SA-MIB, OLD-SNMPEA-MIB
+sa_errs_gen_err() ->
+ NewKeyc3 = [intCommunityEntry,[3],get(mip),is("test")],
+ NewKeyc4 = [intCommunityEntry,[4],get(mip),is("test")],
+ NewKeyc5 = [intCommunityEntry,[5],get(mip),is("test")],
+ s([{NewKeyc3, 2},{NewKeyc4, 2},
+ {NewKeyc5, ?createAndGo}, {[sa, [3,0]], 5}]),
+ ?line expect(1, genErr, 4, any),
+% The row might have been added; we don't know.
+% (as a matter of fact we do - it is added, because the agent
+% first sets its own vars, and then th SAs. Lets destroy it.
+ s([{NewKeyc5, ?destroy}]),
+ ?line expect(2, [{NewKeyc5, ?destroy}]).
+
+%% Req. SA-MIB, OLD-SNMPEA-MIB
+sa_too_big() ->
+ g([[sa, [4,0]]]),
+ ?line expect(1, tooBig).
+
+%% Req. Klas1, system group, snmp group (v1/v2)
+next_across_sa() ->
+ gn([[sysDescr],[klas1,5]]),
+ ?line expect(1, [{[sysDescr,0], "Erlang SNMP agent"},
+ {[snmpInPkts, 0], any}]).
+
+%% snmp_test_mgr:s([{[fStatus3, 1], 4}, {[fname3,0], "ok"}]). -> noError
+%% snmp_test_mgr:s([{[fStatus3, 1], 4}, {[fname3,0], "hoj"}]). -> {badValue, 2}
+%% snmp_test_mgr:s([{[fStatus3, 3], 4}, {[fname3,0], "hoj"}]). -> {genErr, 1}
+%% snmp_test_mgr:s([{[fStatus3, 4], 4}, {[fname3,0], "ok"}]). -> {genErr, 1}
+%% snmp_test_mgr:s([{[fStatus3, 4], 4}, {[fname3,0], "ufail"}]). -> {genErr, 1}
+%% snmp_test_mgr:s([{[fStatus3, 1], 4}, {[fname3,0], "xfail"}]). -> {genErr, 2}
+%% Req. Klas3, Klas4
+undo_test() ->
+ s([{[fStatus3, 1], 4}, {[fname3,0], "ok"}]),
+ ?line expect(1, [{[fStatus3, 1], 4}, {[fname3,0], "ok"}]),
+ s([{[fStatus3, 1], 4}, {[fname3,0], "hoj"}]),
+ ?line expect(2, ?v1_2(badValue, inconsistentValue), 2, any),
+ s([{[fStatus3, 3], 4}, {[fname3,0], "hoj"}]),
+ ?line expect(3, ?v1_2(genErr, undoFailed), 1, any),
+ s([{[fStatus3, 4], 4}, {[fname3,0], "ok"}]),
+ ?line expect(4, ?v1_2(genErr, commitFailed), 1, any),
+% unfortunatly we don't know if we'll get undoFailed or commitFailed.
+% it depends on which order the agent traverses the varbind list.
+% s([{[fStatus3, 4], 4}, {[fname3,0], "ufail"}]),
+% ?line expect(5, ?v1_2(genErr, undoFailed), 1, any),
+ s([{[fStatus3, 1], 4}, {[fname3,0], "xfail"}]),
+ ?line expect(6, genErr, 2, any).
+
+%% Req. Klas3, Klas4
+bad_return() ->
+ g([[fStatus4,4],
+ [fName4,4]]),
+ ?line expect(4, genErr, 2, any),
+ g([[fStatus4,5],
+ [fName4,5]]),
+ ?line expect(5, genErr, 1, any),
+ g([[fStatus4,6],
+ [fName4,6]]),
+ ?line expect(6, genErr, 2, any),
+ gn([[fStatus4,7],
+ [fName4,7]]),
+ ?line expect(7, genErr, 2, any),
+ gn([[fStatus4,8],
+ [fName4,8]]),
+ ?line expect(8, genErr, 1, any),
+ gn([[fStatus4,9],
+ [fName4,9]]),
+ ?line expect(9, genErr, 2, any).
+
+
+%%%-----------------------------------------------------------------
+%%% Test the implementation of standard mibs.
+%%% We should *at least* try to GET all variables, just to make
+%%% sure the instrumentation functions work.
+%%% Note that many of the functions in the standard mib is
+%%% already tested by the normal tests.
+%%%-----------------------------------------------------------------
+standard_mibs(suite) ->
+ [snmp_standard_mib, snmp_community_mib,
+ snmp_framework_mib,
+ snmp_target_mib, snmp_notification_mib,
+ snmp_view_based_acm_mib].
+
+standard_mibs_2(suite) ->
+ [snmpv2_mib_2, snmp_community_mib_2,
+ snmp_framework_mib_2,
+ snmp_target_mib_2, snmp_notification_mib_2,
+ snmp_view_based_acm_mib_2].
+
+standard_mibs_3(suite) ->
+ [snmpv2_mib_3,snmp_framework_mib_3, snmp_mpd_mib_3,
+ snmp_target_mib_3, snmp_notification_mib_3,
+ snmp_view_based_acm_mib_3, snmp_user_based_sm_mib_3].
+
+%%-----------------------------------------------------------------
+%% For this test, the agent is configured for v1.
+%% o Test the counters and control objects in SNMP-STANDARD-MIB
+%%-----------------------------------------------------------------
+snmp_standard_mib(suite) -> [];
+snmp_standard_mib(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?DBG("snmp_standard_mib -> std_mib_init", []),
+ try_test(std_mib_init),
+
+ ?DBG("snmp_standard_mib -> std_mib_a", []),
+ InBadVsns = try_test(std_mib_a),
+ put(vsn, v2),
+ ?DBG("snmp_standard_mib -> std_mib_read", []),
+ try_test(std_mib_read),
+ put(vsn, v1),
+
+ ?DBG("snmp_standard_mib -> std_mib_b (~w)", [InBadVsns]),
+ Bad = try_test(std_mib_b, [InBadVsns]),
+ ?DBG("snmp_standard_mib -> std_mib_read (community: 'bad community')", []),
+ try_test(std_mib_read, [], [{community, "bad community"}]),
+ ?DBG("snmp_standard_mib -> std_mib_write (community: 'public')", []),
+ try_test(std_mib_write, [], [{community, "public"}]),
+ ?DBG("snmp_standard_mib -> std_mib_asn_err", []),
+ try_test(std_mib_asn_err),
+ ?DBG("snmp_standard_mib -> std_mib_c (~w)", [Bad]),
+ try_test(std_mib_c, [Bad]),
+ ?DBG("snmp_standard_mib -> std_mib_a", []),
+ try_test(standard_mib_a),
+
+ ?DBG("snmp_standard_mib -> std_mib_finish", []),
+ try_test(std_mib_finish),
+ ?DBG("snmp_standard_mib -> std_mib_test_finish", []),
+ try_test(standard_mib_test_finish, [], [{community, "bad community"}]).
+
+%% Req. SNMP-STANDARD-MIB
+standard_mib_a() ->
+ ?line [OutPkts] = get_req(2, [[snmpOutPkts,0]]),
+ ?line [OutPkts2] = get_req(3, [[snmpOutPkts,0]]),
+ ?line OutPkts2 = OutPkts + 1,
+ %% There are some more counters we could test here, but it's not that
+ %% important, since they are removed from SNMPv2-MIB.
+ ok.
+
+%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB
+std_mib_init() ->
+ %% disable authentication failure traps. (otherwise w'd get many of
+ %% them - this is also a test to see that it works).
+ s([{[snmpEnableAuthenTraps,0], 2}]),
+ ?line expect(1, [{[snmpEnableAuthenTraps, 0], 2}]).
+
+%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB
+std_mib_finish() ->
+ %% enable again
+ s([{[snmpEnableAuthenTraps,0], 1}]),
+ ?line expect(1, [{[snmpEnableAuthenTraps, 0], 1}]).
+
+%% Req. SNMP-STANDARD-MIB
+standard_mib_test_finish() ->
+ %% force a authenticationFailure
+ std_mib_write(),
+ %% check that we got a trap
+ ?line expect(2, trap, [1,2,3], 4, 0, []).
+
+%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB
+std_mib_read() ->
+ ?DBG("std_mib_read -> entry", []),
+ g([[sysUpTime,0]]), % try a bad <something>; msg dropped, no reply
+ ?DBG("std_mib_read -> await timeout (i.e. no reply)", []),
+ ?line expect(1, timeout). % make sure we don't get a trap!
+
+
+%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB
+std_mib_write() ->
+ ?DBG("std_mib_write -> entry", []),
+ s([{[sysLocation, 0], "new_value"}]).
+
+%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB
+std_mib_asn_err() ->
+ snmp_test_mgr:send_bytes([48,99,67,12,0,0,0,0,0,0,5]).
+
+%%-----------------------------------------------------------------
+%% For this test, the agent is configured for v2 and v3.
+%% o Test the counters and control objects in SNMPv2-MIB
+%%-----------------------------------------------------------------
+snmpv2_mib_2(suite) -> [];
+snmpv2_mib_2(Config) when list(Config) ->
+ ?LOG("snmpv2_mib_2 -> start",[]),
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ ?DBG("snmpv2_mib_2 -> standard mib init",[]),
+ try_test(std_mib_init),
+
+ ?DBG("snmpv2_mib_2 -> get number of (so far) bad versions",[]),
+ InBadVsns = try_test(std_mib_a),
+
+ ?DBG("snmpv2_mib_2 -> make a bad version read",[]),
+ put(vsn, v1),
+ try_test(std_mib_read),
+
+ ?DBG("snmpv2_mib_2 -> bad version read",[]),
+ put(vsn, v2),
+ Bad = try_test(std_mib_b, [InBadVsns]),
+
+ ?DBG("snmpv2_mib_2 -> read with bad community",[]),
+ try_test(std_mib_read, [], [{community, "bad community"}]),
+
+ ?DBG("snmpv2_mib_2 -> write with public community",[]),
+ try_test(std_mib_write, [], [{community, "public"}]),
+
+ ?DBG("snmpv2_mib_2 -> asn err",[]),
+ try_test(std_mib_asn_err),
+
+ ?DBG("snmpv2_mib_2 -> check counters",[]),
+ try_test(std_mib_c, [Bad]),
+
+ ?DBG("snmpv2_mib_2 -> get som counters",[]),
+ try_test(snmpv2_mib_a),
+
+ ?DBG("snmpv2_mib_2 -> enable auth traps, and await some",[]),
+ try_test(std_mib_finish),
+
+ ?DBG("snmpv2_mib_2 -> force auth failure, and await trap, "
+ "then disable auth traps",[]),
+ try_test(snmpv2_mib_test_finish, [], [{community, "bad community"}]),
+
+ ?LOG("snmpv2_mib_2 -> done",[]).
+
+%% Req. SNMPv2-MIB
+snmpv2_mib_3(suite) -> [];
+snmpv2_mib_3(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ InBadVsns = try_test(std_mib_a),
+ put(vsn, v1),
+ try_test(std_mib_read),
+ put(vsn, v3),
+ _Bad = try_test(std_mib_b, [InBadVsns]),
+ try_test(snmpv2_mib_a),
+
+ try_test(std_mib_finish).
+
+-define(authenticationFailure, [1,3,6,1,6,3,1,1,5,5]).
+
+%% Req. SNMPv2-MIB
+snmpv2_mib_test_finish() ->
+ %% force a authenticationFailure
+ ?DBG("ma_v2_inform -> write to std mib",[]),
+ std_mib_write(),
+
+ %% check that we got a trap
+ ?DBG("ma_v2_inform -> await trap",[]),
+ ?line expect(2, v2trap, [{[sysUpTime,0], any},
+ {[snmpTrapOID,0], ?authenticationFailure}]),
+
+ %% and the the inform
+ ?DBG("ma_v2_inform -> await inform",[]),
+ ?line expect(2, {inform,true}, [{[sysUpTime,0], any},
+ {[snmpTrapOID,0],?authenticationFailure}]).
+
+%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB
+std_mib_a() ->
+ ?line [InPkts] = get_req(2, [[snmpInPkts,0]]),
+ ?line [InPkts2] = get_req(3, [[snmpInPkts,0]]),
+ ?line InPkts2 = InPkts + 1,
+
+ ?line [InBadVsns] = get_req(4, [[snmpInBadVersions,0]]),
+ InBadVsns.
+
+%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB
+std_mib_b(InBadVsns) ->
+ ?line [InBadVsns2] = get_req(1, [[snmpInBadVersions,0]]),
+ ?line InBadVsns2 = InBadVsns + 1,
+ ?line [InPkts] = get_req(2, [[snmpInPkts,0]]),
+ ?line [InPkts2] = get_req(3, [[snmpInPkts,0]]),
+ ?line InPkts2 = InPkts + 1,
+ ?line [InBadCommunityNames, InBadCommunityUses, InASNErrs] =
+ get_req(4, [[snmpInBadCommunityNames,0],
+ [snmpInBadCommunityUses,0],
+ [snmpInASNParseErrs, 0]]),
+ {InBadCommunityNames, InBadCommunityUses, InASNErrs}.
+
+%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB
+std_mib_c({InBadCommunityNames, InBadCommunityUses, InASNErrs}) ->
+ ?line [InBadCommunityNames2, InBadCommunityUses2, InASNErrs2] =
+ get_req(1, [[snmpInBadCommunityNames,0],
+ [snmpInBadCommunityUses,0],
+ [snmpInASNParseErrs, 0]]),
+ ?line InBadCommunityNames2 = InBadCommunityNames + 1,
+ ?line InBadCommunityUses2 = InBadCommunityUses + 1,
+ ?line InASNErrs2 = InASNErrs + 1.
+
+%% Req. SNMPv2-MIB
+snmpv2_mib_a() ->
+ ?line [SetSerial] = get_req(2, [[snmpSetSerialNo,0]]),
+ s([{[snmpSetSerialNo,0], SetSerial}, {[sysLocation, 0], "val2"}]),
+ ?line expect(3, [{[snmpSetSerialNo,0], SetSerial},
+ {[sysLocation, 0], "val2"}]),
+ s([{[sysLocation, 0], "val3"}, {[snmpSetSerialNo,0], SetSerial}]),
+ ?line expect(4, inconsistentValue, 2,
+ [{[sysLocation, 0], "val3"},
+ {[snmpSetSerialNo,0], SetSerial}]),
+ ?line ["val2"] = get_req(5, [[sysLocation,0]]).
+
+
+%%-----------------------------------------------------------------
+%% o Bad community uses/name is tested already
+%% in SNMPv2-MIB and STANDARD-MIB.
+%% o Test add/deletion of rows.
+%%-----------------------------------------------------------------
+snmp_community_mib(suite) -> [];
+snmp_community_mib(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?line load_master_std("SNMP-COMMUNITY-MIB"),
+ try_test(snmp_community_mib),
+ ?line unload_master("SNMP-COMMUNITY-MIB").
+
+snmp_community_mib_2(X) -> snmp_community_mib(X).
+
+%% Req. SNMP-COMMUNITY-MIB
+snmp_community_mib() ->
+ ?INF("NOT YET IMPLEMENTED", []),
+ nyi.
+
+%%-----------------------------------------------------------------
+%% o Test engine boots / time
+%%-----------------------------------------------------------------
+snmp_framework_mib(suite) -> [];
+snmp_framework_mib(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?line load_master_std("SNMP-FRAMEWORK-MIB"),
+ try_test(snmp_framework_mib),
+ ?line unload_master("SNMP-FRAMEWORK-MIB").
+
+snmp_framework_mib_2(X) -> snmp_framework_mib(X).
+
+snmp_framework_mib_3(suite) -> [];
+snmp_framework_mib_3(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ try_test(snmp_framework_mib).
+
+
+%% Req. SNMP-FRAMEWORK-MIB
+snmp_framework_mib() ->
+ ?line ["agentEngine"] = get_req(1, [[snmpEngineID,0]]),
+ ?line [EngineTime] = get_req(2, [[snmpEngineTime,0]]),
+ sleep(5000),
+ ?line [EngineTime2] = get_req(3, [[snmpEngineTime,0]]),
+ if
+ EngineTime+7 < EngineTime2 ->
+ ?line ?FAIL({too_large_diff, EngineTime, EngineTime2});
+ EngineTime+4 > EngineTime2 ->
+ ?line ?FAIL({too_large_diff, EngineTime, EngineTime2});
+ true -> ok
+ end,
+ ?line case get_req(4, [[snmpEngineBoots,0]]) of
+ [Boots] when integer(Boots) -> ok;
+ Else -> ?FAIL(Else)
+ end,
+ ok.
+
+%%-----------------------------------------------------------------
+%% o Test the counters
+%%-----------------------------------------------------------------
+snmp_mpd_mib_3(suite) -> [];
+snmp_mpd_mib_3(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ UnknownPDUHs = try_test(snmp_mpd_mib_a),
+ try_test(snmp_mpd_mib_b, [], [{context_engine_id, "bad engine"}]),
+ try_test(snmp_mpd_mib_c, [UnknownPDUHs]).
+
+
+%% Req. SNMP-MPD-MIB
+snmp_mpd_mib_a() ->
+ ?line [UnknownSecs, InvalidMsgs] =
+ get_req(1, [[snmpUnknownSecurityModels,0],
+ [snmpInvalidMsgs,0]]),
+ Pdu = #pdu{type = 'get-request',
+ request_id = 23,
+ error_status = noError,
+ error_index = 0,
+ varbinds = []},
+ SPdu = #scopedPdu{contextEngineID = "agentEngine",
+ contextName = "",
+ data = Pdu},
+ ?line SPDUBytes = snmp_pdus:enc_scoped_pdu(SPdu),
+ V3Hdr1 = #v3_hdr{msgID = 21,
+ msgMaxSize = 484,
+ msgFlags = [7],
+ msgSecurityModel = 23, % bad sec model
+ msgSecurityParameters = []},
+ V3Hdr2 = #v3_hdr{msgID = 21,
+ msgMaxSize = 484,
+ msgFlags = [6], % bad flag combination
+ msgSecurityModel = 3,
+ msgSecurityParameters = []},
+ Message1 = #message{version = 'version-3', vsn_hdr = V3Hdr1,
+ data = SPDUBytes},
+ Message2 = #message{version = 'version-3', vsn_hdr = V3Hdr2,
+ data = SPDUBytes},
+ ?line MsgBytes1 = snmp_pdus:enc_message_only(Message1),
+ ?line MsgBytes2 = snmp_pdus:enc_message_only(Message2),
+ snmp_test_mgr:send_bytes(MsgBytes1),
+ snmp_test_mgr:send_bytes(MsgBytes2),
+
+ ?line [UnknownSecs2, InvalidMsgs2, UnknownPDUHs] =
+ get_req(1, [[snmpUnknownSecurityModels,0],
+ [snmpInvalidMsgs,0],
+ [snmpUnknownPDUHandlers, 0]]),
+ ?line UnknownSecs2 = UnknownSecs + 1,
+ ?line InvalidMsgs2 = InvalidMsgs + 1,
+ UnknownPDUHs.
+
+-define(snmpUnknownPDUHandlers_instance, [1,3,6,1,6,3,11,2,1,3,0]).
+snmp_mpd_mib_b() ->
+ g([[sysUpTime,0]]),
+ ?line expect(1, report, [{?snmpUnknownPDUHandlers_instance, any}]).
+
+
+snmp_mpd_mib_c(UnknownPDUHs) ->
+ ?line [UnknownPDUHs2] = get_req(1, [[snmpUnknownPDUHandlers, 0]]),
+ ?line UnknownPDUHs2 = UnknownPDUHs + 1.
+
+
+snmp_target_mib(suite) -> [];
+snmp_target_mib(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?line load_master_std("SNMP-TARGET-MIB"),
+ try_test(snmp_target_mib),
+ ?line unload_master("SNMP-TARGET-MIB").
+
+snmp_target_mib_2(X) -> snmp_target_mib(X).
+
+snmp_target_mib_3(X) -> snmp_target_mib(X).
+
+snmp_target_mib() ->
+ ?INF("NOT YET IMPLEMENTED", []),
+ nyi.
+
+snmp_notification_mib(suite) -> [];
+snmp_notification_mib(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?line load_master_std("SNMP-NOTIFICATION-MIB"),
+ try_test(snmp_notification_mib),
+ ?line unload_master("SNMP-NOTIFICATION-MIB").
+
+snmp_notification_mib_2(X) -> snmp_notification_mib(X).
+
+snmp_notification_mib_3(X) -> snmp_notification_mib(X).
+
+snmp_notification_mib() ->
+ ?INF("NOT YET IMPLEMENTED", []),
+ nyi.
+
+%%-----------------------------------------------------------------
+%% o add/delete views and try them
+%% o try boundaries
+%%-----------------------------------------------------------------
+snmp_view_based_acm_mib(suite) -> [];
+snmp_view_based_acm_mib(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"),
+ ?line load_master("Test2"),
+ snmp_view_based_acm_mib(),
+ ?line unload_master("Test2"),
+ ?line unload_master("SNMP-VIEW-BASED-ACM-MIB").
+
+snmp_view_based_acm_mib_2(X) -> snmp_view_based_acm_mib(X).
+
+snmp_view_based_acm_mib_3(X) -> snmp_view_based_acm_mib(X).
+
+snmp_view_based_acm_mib() ->
+ snmpa:verbosity(net_if,trace),
+ snmpa:verbosity(master_agent,trace),
+ ?LOG("start snmp_view_based_acm_mib test",[]),
+ %% The user "no-rights" is present in USM, and is mapped to security
+ %% name 'no-rights", which is not present in VACM.
+ %% So, we'll add rights for it, try them and delete them.
+ %% We'll give "no-rights" write access to tDescr.0 and read access
+ %% to tDescr2.0
+ %% These are the options we'll use to the mgr
+ Opts = [{user, "no-rights"}, {community, "no-rights"}],
+ %% Find the valid secmodel, and one invalid secmodel.
+ {SecMod, InvSecMod} =
+ case get(vsn) of
+ v1 -> {?SEC_V1, ?SEC_V2C};
+ v2 -> {?SEC_V2C, ?SEC_USM};
+ v3 -> {?SEC_USM, ?SEC_V1}
+ end,
+ ?DBG("assign rights for 'no-rights'",[]),
+ ?line try_test(use_no_rights, [], Opts),
+
+ %% Now, add a mapping from "no-rights" -> "no-rights-group"
+ GRow1Status = [vacmSecurityToGroupStatus,[SecMod, 9,"no-rights"]],
+ GRow1 =
+ [{[vacmGroupName, [SecMod, 9,"no-rights"]], "no-rights-group"},
+ {GRow1Status, ?createAndGo}],
+ ?DBG("set '~p'",[GRow1]),
+ ?line try_test(do_set, [GRow1]),
+
+ ?DBG("assign rights for 'no-rights'",[]),
+ ?line try_test(use_no_rights, [], Opts),
+
+ %% Create a mapping for another sec model, and make sure it dosn't
+ %% give us access
+ GRow2Status = [vacmSecurityToGroupStatus,[InvSecMod, 9,"no-rights"]],
+ GRow2 = [{[vacmGroupName, [InvSecMod, 9, "no-rights"]], "initial"},
+ {GRow2Status, ?createAndGo}],
+
+ ?DBG("set '~p'",[GRow2]),
+ ?line try_test(do_set, [GRow2]),
+
+ ?DBG("assign rights for 'no-rights'",[]),
+ ?line try_test(use_no_rights, [], Opts),
+
+ %% Delete that row
+ ?line try_test(del_row, [GRow2Status]),
+
+ RVName = "rv_name",
+ WVName = "wv_name",
+
+ %% Access row
+ ARow1Idx = [15 | "no-rights-group"] ++ [0, ?SEC_ANY, 1],
+ ARow1Status = [vacmAccessStatus, ARow1Idx],
+ ARow1 = [{[vacmAccessContextMatch, ARow1Idx], 1},
+ {[vacmAccessReadViewName, ARow1Idx], RVName},
+ {[vacmAccessWriteViewName, ARow1Idx], WVName},
+ {ARow1Status, ?createAndGo}],
+
+ %% This access row would give acces, if InvSecMod was valid.
+ ARow2Idx = [15 | "no-rights-group"] ++ [0, InvSecMod, 1],
+ ARow2Status = [vacmAccessStatus, ARow2Idx],
+ ARow2 = [{[vacmAccessContextMatch, ARow2Idx], 1},
+ {[vacmAccessReadViewName, ARow2Idx], "internet"},
+ {[vacmAccessWriteViewName, ARow2Idx], "internet"},
+ {ARow2Status, ?createAndGo}],
+
+ ?line try_test(do_set, [ARow2]),
+
+ ?line try_test(use_no_rights, [], Opts),
+
+ %% Delete that row
+ ?line try_test(del_row, [ARow2Status]),
+
+
+ %% Add valid row
+ ?line try_test(do_set, [ARow1]),
+
+ ?line try_test(use_no_rights, [], Opts),
+
+ %% Create the view family
+ VRow1Idx = mk_ln(RVName) ++ mk_ln(?xDescr), % object access
+ VRow2Idx = mk_ln(RVName) ++ mk_ln(?xDescr2 ++ [0]), % instance access
+ VRow3Idx = mk_ln(WVName) ++ mk_ln(?xDescr), % object access
+ VRow4Idx = mk_ln(WVName) ++ mk_ln(?xDescr ++ [0]), % instance access
+ VRow1Status = [vacmViewTreeFamilyStatus, VRow1Idx],
+ VRow2Status = [vacmViewTreeFamilyStatus, VRow2Idx],
+ VRow3Status = [vacmViewTreeFamilyStatus, VRow3Idx],
+ VRow4Status = [vacmViewTreeFamilyStatus, VRow4Idx],
+
+ ?line try_test(add_row, [VRow1Status]),
+ ?line try_test(add_row, [VRow2Status]),
+ ?line try_test(add_row, [VRow3Status]),
+
+ %% We're supposed to have access now...
+ ?line try_test(use_rights, [], Opts),
+
+ %% Change Row3 to Row4
+ ?line try_test(del_row, [VRow3Status]),
+ ?line try_test(add_row, [VRow4Status]),
+
+ %% We should still have access...
+ ?line try_test(use_rights, [], Opts),
+
+ %% Delete rows
+ ?line try_test(del_row, [GRow1Status]),
+
+ ?line try_test(use_no_rights, [], Opts),
+
+ %% Delete rest of rows
+ ?line try_test(del_row, [ARow1Status]),
+ ?line try_test(del_row, [VRow1Status]),
+ ?line try_test(del_row, [VRow2Status]),
+ ?line try_test(del_row, [VRow4Status]),
+
+ ?line try_test(use_no_rights, [], Opts),
+ snmpa:verbosity(master_agent,log).
+
+do_set(Row) ->
+ s(Row),
+ expect(1, Row).
+
+add_row(RowStatus) ->
+ s([{RowStatus, ?createAndGo}]),
+ expect(1, [{RowStatus, ?createAndGo}]).
+
+del_row(RowStatus) ->
+ s([{RowStatus, ?destroy}]),
+ expect(1, [{RowStatus, ?destroy}]).
+
+
+
+use_no_rights() ->
+ g([[xDescr,0]]),
+ ?v1_2_3(expect(11, noSuchName, 1, any),
+ expect(12, [{[xDescr,0], noSuchObject}]),
+ expect(13, authorizationError, 1, any)),
+ g([[xDescr2,0]]),
+ ?v1_2_3(expect(21, noSuchName, 1, any),
+ expect(22, [{[xDescr2,0], noSuchObject}]),
+ expect(23, authorizationError, 1, any)),
+ gn([[xDescr]]),
+ ?v1_2_3(expect(31, noSuchName, 1, any),
+ expect(32, [{[xDescr], endOfMibView}]),
+ expect(33, authorizationError, 1, any)),
+ s([{[xDescr,0], "tryit"}]),
+ ?v1_2_3(expect(41, noSuchName, 1, any),
+ expect(42, noAccess, 1, any),
+ expect(43, authorizationError, 1, any)).
+
+
+use_rights() ->
+ g([[xDescr,0]]),
+ expect(1, [{[xDescr,0], any}]),
+ g([[xDescr2,0]]),
+ expect(2, [{[xDescr2,0], any}]),
+ s([{[xDescr,0], "tryit"}]),
+ expect(3, noError, 0, any),
+ g([[xDescr,0]]),
+ expect(4, [{[xDescr,0], "tryit"}]).
+
+mk_ln(X) ->
+ [length(X) | X].
+
+%%-----------------------------------------------------------------
+%% o add/delete users and try them
+%% o test all secLevels
+%% o test all combinations of protocols
+%% o try bad ops; check counters
+%%-----------------------------------------------------------------
+snmp_user_based_sm_mib_3(suite) -> [];
+snmp_user_based_sm_mib_3(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ _AgentDir = ?config(agent_dir, Config),
+ ?line load_master_std("SNMP-USER-BASED-SM-MIB"),
+
+ %% The newUser used here already has VACM access.
+
+ %% Add a new user in the simplest way; just createAndGo
+ try_test(v3_sync, [[{usm_add_user1, []}]],
+ [{sec_level, authPriv}, {user, "privDES"}]),
+
+ %% Try to use the new user
+ ?line load_master("Test2"),
+ try_test(v3_sync, [[{usm_use_user, []}]],
+ [{sec_level, authPriv}, {user, "newUser"}]),
+ ?line unload_master("Test2"),
+
+ ShaKey1 = snmp:passwd2localized_key(sha, "new sha password", "agentEngine"),
+ DesKey1 = lists:sublist(ShaKey1, 16),
+
+ %% Change the new user's keys - 1
+ try_test(v3_sync, [[{usm_key_change1, [ShaKey1, DesKey1]}]],
+ [{sec_level, authPriv}, {user, "newUser"}]),
+
+ %% Try to use the new keys
+ MgrDir = ?config(mgr_dir, Config),
+ ?line rewrite_usm_mgr(MgrDir, ShaKey1, DesKey1),
+ ?line load_master("Test2"),
+ try_test(v3_sync, [[{usm_use_user, []}]],
+ [{sec_level, authPriv}, {user, "newUser"}]),
+ ?line unload_master("Test2"),
+
+ ShaKey2 = snmp:passwd2localized_key(sha, "newer password", "agentEngine"),
+ DesKey2 = lists:sublist(ShaKey2, 16),
+
+ %% Change the new user's keys - 2
+ ?line try_test(v3_sync,
+ [[{usm_key_change2, [ShaKey1, DesKey1, ShaKey2, DesKey2]}]],
+ [{sec_level, authPriv}, {user, "newUser"}]),
+
+ %% Try to use the new keys
+ reset_usm_mgr(MgrDir),
+ ?line rewrite_usm_mgr(MgrDir, ShaKey2, DesKey2),
+ ?line load_master("Test2"),
+ ?line try_test(v3_sync, [[{usm_use_user, []}]],
+ [{sec_level, authPriv}, {user, "newUser"}]),
+ ?line unload_master("Test2"),
+ reset_usm_mgr(MgrDir),
+
+ %% Change the new user's keys - 3
+ ?line try_test(v3_sync,
+ [[{usm_key_change3, [ShaKey2, DesKey2, ShaKey1, DesKey1]}]],
+ [{sec_level, authPriv}, {user, "privDES"}]),
+
+ %% Try to use the new keys
+ ?line rewrite_usm_mgr(MgrDir, ShaKey1, DesKey1),
+ ?line load_master("Test2"),
+ try_test(v3_sync, [[{usm_use_user, []}]],
+ [{sec_level, authPriv}, {user, "newUser"}]),
+ ?line unload_master("Test2"),
+ reset_usm_mgr(MgrDir),
+
+ %% Try some read requests
+ ?line try_test(v3_sync, [[{usm_read, []}]],
+ [{sec_level, authPriv}, {user, "privDES"}]),
+
+ %% Delete the new user
+ ?line try_test(v3_sync, [[{usm_del_user, []}]],
+ [{sec_level, authPriv}, {user, "privDES"}]),
+
+ %% Try some bad requests
+ ?line try_test(v3_sync, [[{usm_bad, []}]],
+ [{sec_level, authPriv}, {user, "privDES"}]),
+
+ ?line unload_master("SNMP-USER-BASED-SM-MIB").
+
+-define(usmUserSecurityName, [1,3,6,1,6,3,15,1,2,2,1,3]).
+
+usm_add_user1() ->
+ NewRowIndex = [11,"agentEngine", 7, "newUser"],
+ RowPointer = ?usmUserSecurityName ++ [11|"agentEngine"] ++ [7|"privDES"],
+ Vbs1 = [{[usmUserCloneFrom, NewRowIndex], RowPointer},
+ {[usmUserStatus, NewRowIndex], ?createAndGo}],
+ ?line s(Vbs1),
+ ?line expect(1, Vbs1),
+ ok.
+
+usm_use_user() ->
+ v2_proc().
+
+
+%% Change own public keys
+usm_key_change1(ShaKey, DesKey) ->
+ NewRowIndex = [11,"agentEngine", 7, "newUser"],
+ ShaKeyChange = snmp_user_based_sm_mib:mk_key_change(sha,
+ "passwd_shaxxxxxxxxxx",
+ ShaKey),
+ DesKeyChange = snmp_user_based_sm_mib:mk_key_change(sha,
+ "passwd_desxxxxxx",
+ DesKey),
+ Vbs1 = [{[usmUserAuthKeyChange, NewRowIndex], ShaKeyChange},
+ {[usmUserPrivKeyChange, NewRowIndex], DesKeyChange}],
+ s(Vbs1),
+ ?line expect(1, Vbs1).
+
+%% Change own private keys
+usm_key_change2(OldShaKey, OldDesKey, ShaKey, DesKey) ->
+ NewRowIndex = [11,"agentEngine", 7, "newUser"],
+ ShaKeyChange = snmp_user_based_sm_mib:mk_key_change(sha,
+ OldShaKey,
+ ShaKey),
+ DesKeyChange = snmp_user_based_sm_mib:mk_key_change(sha,
+ OldDesKey,
+ DesKey),
+ Vbs1 = [{[usmUserOwnAuthKeyChange, NewRowIndex], ShaKeyChange},
+ {[usmUserOwnPrivKeyChange, NewRowIndex], DesKeyChange}],
+ s(Vbs1),
+ ?line expect(1, Vbs1).
+
+%% Change other's public keys
+usm_key_change3(OldShaKey, OldDesKey, ShaKey, DesKey) ->
+ NewRowIndex = [11,"agentEngine", 7, "newUser"],
+ ShaKeyChange = snmp_user_based_sm_mib:mk_key_change(sha,
+ OldShaKey,
+ ShaKey),
+ DesKeyChange = snmp_user_based_sm_mib:mk_key_change(sha,
+ OldDesKey,
+ DesKey),
+ Vbs1 = [{[usmUserOwnAuthKeyChange, NewRowIndex], ShaKeyChange}],
+ s(Vbs1),
+ ?line expect(1, noAccess, 1, any),
+ Vbs2 = [{[usmUserOwnPrivKeyChange, NewRowIndex], DesKeyChange}],
+ s(Vbs2),
+ ?line expect(2, noAccess, 1, any),
+
+
+ Vbs3 = [{[usmUserAuthKeyChange, NewRowIndex], ShaKeyChange},
+ {[usmUserPrivKeyChange, NewRowIndex], DesKeyChange}],
+ s(Vbs3),
+ ?line expect(1, Vbs3).
+
+usm_read() ->
+ NewRowIndex = [11,"agentEngine", 7, "newUser"],
+ ?line g([[usmUserSecurityName, NewRowIndex],
+ [usmUserCloneFrom, NewRowIndex],
+ [usmUserAuthKeyChange, NewRowIndex],
+ [usmUserOwnAuthKeyChange, NewRowIndex],
+ [usmUserPrivKeyChange, NewRowIndex],
+ [usmUserOwnPrivKeyChange, NewRowIndex]]),
+ ?line expect(1,
+ [{[usmUserSecurityName, NewRowIndex], "newUser"},
+ {[usmUserCloneFrom, NewRowIndex], [0,0]},
+ {[usmUserAuthKeyChange, NewRowIndex], ""},
+ {[usmUserOwnAuthKeyChange, NewRowIndex], ""},
+ {[usmUserPrivKeyChange, NewRowIndex], ""},
+ {[usmUserOwnPrivKeyChange, NewRowIndex], ""}]),
+ ok.
+
+
+
+usm_del_user() ->
+ NewRowIndex = [11,"agentEngine", 7, "newUser"],
+ Vbs1 = [{[usmUserStatus, NewRowIndex], ?destroy}],
+ ?line s(Vbs1),
+ ?line expect(1, Vbs1),
+ ok.
+
+-define(usmUserCloneFrom, [1,3,6,1,6,3,15,1,2,2,1,4]).
+
+-define(usmNoAuthProtocol, [1,3,6,1,6,3,10,1,1,1]).
+
+-define(usmHMACMD5AuthProtocol, [1,3,6,1,6,3,10,1,1,2]).
+
+-define(usmHMACSHAAuthProtocol, [1,3,6,1,6,3,10,1,1,3]).
+
+-define(usmNoPrivProtocol, [1,3,6,1,6,3,10,1,2,1]).
+
+-define(usmDESPrivProtocol, [1,3,6,1,6,3,10,1,2,2]).
+
+usm_bad() ->
+ NewRowIndex = [11,"agentEngine", 7, "newUser"],
+ RowPointer1 = ?usmUserSecurityName ++ [11|"agentEngine"] ++ [7|"privDOS"],
+ Vbs1 = [{[usmUserCloneFrom, NewRowIndex], RowPointer1},
+ {[usmUserStatus, NewRowIndex], ?createAndGo}],
+ ?line s(Vbs1),
+ ?line expect(1, inconsistentName, 1, any),
+
+ RowPointer2 = ?usmUserCloneFrom ++ [11|"agentEngine"] ++ [7|"privDES"],
+ Vbs2 = [{[usmUserCloneFrom, NewRowIndex], RowPointer2},
+ {[usmUserStatus, NewRowIndex], ?createAndGo}],
+ ?line s(Vbs2),
+ ?line expect(2, wrongValue, 1, any),
+
+ RowPointer3 = ?usmUserSecurityName ++ [11|"agentEngine"] ++ [7|"privDES"],
+ Vbs3 = [{[usmUserCloneFrom, NewRowIndex], RowPointer3},
+ {[usmUserStatus, NewRowIndex], ?createAndGo}],
+ ?line s(Vbs3),
+ ?line expect(3, Vbs3),
+ ?line s([{[usmUserAuthProtocol, NewRowIndex], ?usmNoAuthProtocol}]),
+ ?line expect(4, inconsistentValue, 1, any),
+ ?line s([{[usmUserAuthProtocol, NewRowIndex], ?usmHMACMD5AuthProtocol}]),
+ ?line expect(5, inconsistentValue, 1, any),
+ ?line s([{[usmUserAuthProtocol, NewRowIndex], ?usmDESPrivProtocol}]),
+ ?line expect(6, wrongValue, 1, any),
+ ?line s([{[usmUserPrivProtocol, NewRowIndex], ?usmHMACSHAAuthProtocol}]),
+ ?line expect(7, wrongValue, 1, any),
+
+ Vbs4 = [{[usmUserStatus, NewRowIndex], ?destroy}],
+ ?line s(Vbs4),
+ ?line expect(1, Vbs4),
+
+ ok.
+
+
+%%-----------------------------------------------------------------
+%% Loop through entire MIB, to make sure that all instrum. funcs
+%% works.
+%% Load all std mibs that are not loaded by default.
+%%-----------------------------------------------------------------
+loop_mib(suite) -> [];
+loop_mib(Config) when list(Config) ->
+ ?LOG("loop_mib -> initiate case",[]),
+ %% snmpa:verbosity(master_agent,debug),
+ %% snmpa:verbosity(mib_server,info),
+ {SaNode, MgrNode, MibDir} = init_case(Config),
+ ?DBG("loop_mib -> ~n"
+ "\tSaNode: ~p~n"
+ "\tMgrNode: ~p~n"
+ "\tMibDir: ~p",[SaNode, MgrNode, MibDir]),
+ ?DBG("loop_mib -> load mib SNMP-COMMUNITY-MIB",[]),
+ ?line load_master_std("SNMP-COMMUNITY-MIB"),
+ ?DBG("loop_mib -> load mib SNMP-MPD-MIB",[]),
+ ?line load_master_std("SNMP-MPD-MIB"),
+ ?DBG("loop_mib -> load mib SNMP-TARGET-MIB",[]),
+ ?line load_master_std("SNMP-TARGET-MIB"),
+ ?DBG("loop_mib -> load mib SNMP-NOTIFICATION-MIB",[]),
+ ?line load_master_std("SNMP-NOTIFICATION-MIB"),
+ ?DBG("loop_mib -> load mib SNMP-FRAMEWORK-MIB",[]),
+ ?line load_master_std("SNMP-FRAMEWORK-MIB"),
+ ?DBG("loop_mib -> load mib SNMP-VIEW-BASED-ACM-MIB",[]),
+ ?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"),
+ ?DBG("loop_mib -> try",[]),
+ try_test(loop_mib_1),
+ ?DBG("loop_mib -> unload mib SNMP-COMMUNITY-MIB",[]),
+ ?line unload_master("SNMP-COMMUNITY-MIB"),
+ ?DBG("loop_mib -> unload mib SNMP-MPD-MIB",[]),
+ ?line unload_master("SNMP-MPD-MIB"),
+ ?DBG("loop_mib -> unload mib SNMP-TARGET-MIB",[]),
+ ?line unload_master("SNMP-TARGET-MIB"),
+ ?DBG("loop_mib -> unload mib SNMP-NOTIFICATION-MIB",[]),
+ ?line unload_master("SNMP-NOTIFICATION-MIB"),
+ ?DBG("loop_mib -> unload mib SNMP-FRAMEWORK-MIB",[]),
+ ?line unload_master("SNMP-FRAMEWORK-MIB"),
+ ?DBG("loop_mib -> unload mib SNMP-VIEW-BASED-ACM-MIB",[]),
+ ?line unload_master("SNMP-VIEW-BASED-ACM-MIB"),
+ %% snmpa:verbosity(master_agent,log),
+ %% snmpa:verbosity(mib_server,silence),
+ ?LOG("loop_mib -> done",[]).
+
+
+loop_mib_2(suite) -> [];
+loop_mib_2(Config) when list(Config) ->
+ ?LOG("loop_mib_2 -> initiate case",[]),
+ {SaNode, MgrNode, MibDir} = init_case(Config),
+ ?DBG("loop_mib_2 -> ~n"
+ "\tSaNode: ~p~n"
+ "\tMgrNode: ~p~n"
+ "\tMibDir: ~p",[SaNode, MgrNode, MibDir]),
+ ?DBG("loop_mib_2 -> load mibs",[]),
+ ?line load_master_std("SNMP-COMMUNITY-MIB"),
+ ?line load_master_std("SNMP-MPD-MIB"),
+ ?line load_master_std("SNMP-TARGET-MIB"),
+ ?line load_master_std("SNMP-NOTIFICATION-MIB"),
+ ?line load_master_std("SNMP-FRAMEWORK-MIB"),
+ ?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"),
+ try_test(loop_mib_2),
+ ?DBG("loop_mib_2 -> unload mibs",[]),
+ ?line unload_master("SNMP-COMMUNITY-MIB"),
+ ?line unload_master("SNMP-MPD-MIB"),
+ ?line unload_master("SNMP-TARGET-MIB"),
+ ?line unload_master("SNMP-NOTIFICATION-MIB"),
+ ?line unload_master("SNMP-FRAMEWORK-MIB"),
+ ?line unload_master("SNMP-VIEW-BASED-ACM-MIB"),
+ ?LOG("loop_mib_2 -> done",[]).
+
+
+loop_mib_3(suite) -> [];
+loop_mib_3(Config) when list(Config) ->
+ ?LOG("loop_mib_3 -> initiate case",[]),
+ {SaNode, MgrNode, MibDir} = init_case(Config),
+ ?DBG("loop_mib_3 -> ~n"
+ "\tSaNode: ~p~n"
+ "\tMgrNode: ~p~n"
+ "\tMibDir: ~p",[SaNode, MgrNode, MibDir]),
+ ?DBG("loop_mib_3 -> load mibs",[]),
+ ?line load_master_std("SNMP-TARGET-MIB"),
+ ?line load_master_std("SNMP-NOTIFICATION-MIB"),
+ ?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"),
+ ?line load_master_std("SNMP-USER-BASED-SM-MIB"),
+ try_test(loop_mib_2),
+ ?DBG("loop_mib_3 -> unload mibs",[]),
+ ?line unload_master("SNMP-TARGET-MIB"),
+ ?line unload_master("SNMP-NOTIFICATION-MIB"),
+ ?line unload_master("SNMP-VIEW-BASED-ACM-MIB"),
+ ?line unload_master("SNMP-USER-BASED-SM-MIB"),
+ ?LOG("loop_mib_3 -> done",[]).
+
+
+%% Req. As many mibs all possible
+loop_mib_1() ->
+ ?DBG("loop_mib_1 -> entry",[]),
+ N = loop_it_1([1,1], 0),
+ io:format(user, "found ~w varibles\n", [N]),
+ ?line N = if N < 100 -> 100;
+ true -> N
+ end.
+
+
+loop_it_1(Oid, N) ->
+ ?DBG("loop_it_1 -> entry with~n"
+ "\tOid: ~p~n"
+ "\tN: ~p",[Oid,N]),
+ case get_next_req([Oid]) of
+ #pdu{type='get-response', error_status=noError, error_index=0,
+ varbinds=[#varbind{oid = NOid,value = Value}]} when NOid > Oid ->
+ ?DBG("loop_it_1 -> ~n"
+ "\tNOid: ~p~n"
+ "\tValue: ~p",[NOid,Value]),
+ ?line [Value2] = get_req(1, [NOid]), % must not be same
+ ?DBG("loop_it_1 -> ~n"
+ "\tValue2: ~p",[Value2]),
+ loop_it_1(NOid, N+1);
+ #pdu{type='get-response', error_status=noSuchName, error_index=1,
+ varbinds=[_]} ->
+ ?DBG("loop_it_1 -> done",[]),
+ N;
+
+ #pdu{type = Type, error_status = Err, error_index = Idx,
+ varbinds = Vbs} ->
+ exit({unexpected_pdu, ?LINE, Type, Err, Idx, Vbs})
+ end.
+
+%% Req. As many mibs all possible
+loop_mib_2() ->
+ ?DBG("loop_mib_1 -> entry",[]),
+ N = loop_it_2([1,1], 0),
+ io:format(user, "found ~w varibles\n", [N]),
+ ?line N = if N < 100 -> 100;
+ true -> N
+ end.
+
+
+loop_it_2(Oid, N) ->
+ ?DBG("loop_it_2 -> entry with~n"
+ "\tOid: ~p~n"
+ "\tN: ~p",[Oid,N]),
+ case get_next_req([Oid]) of
+ #pdu{type='get-response', error_status=noError, error_index=0,
+ varbinds=[#varbind{oid = NOid, value = endOfMibView}]} ->
+ ?DBG("loop_it_2 -> ~n"
+ "\tNOid: ~p",[NOid]),
+ N;
+ #pdu{type='get-response', error_status=noError, error_index=0,
+ varbinds=[#varbind{oid = NOid,value = Value}]} when NOid > Oid ->
+ ?DBG("loop_it_2 -> ~n"
+ "\tNOid: ~p~n"
+ "\tValue: ~p",[NOid,Value]),
+ ?line [Value2] = get_req(1, [NOid]), % must not be same
+ ?DBG("loop_it_2 -> ~n"
+ "\tValue2: ~p",[Value2]),
+ loop_it_2(NOid, N+1)
+ end.
+
+
+%%%-----------------------------------------------------------------
+%%% Testing of reported bugs and other tickets.
+%%%-----------------------------------------------------------------
+
+reported_bugs(suite) ->
+ [otp_1128, otp_1129, otp_1131, otp_1162,
+ otp_1222, otp_1298, otp_1331, otp_1338,
+ otp_1342, otp_2776, otp_2979, otp_3187, otp_3725].
+
+reported_bugs_2(suite) ->
+ [otp_1128_2, otp_1129_2, otp_1131_2, otp_1162_2,
+ otp_1222_2, otp_1298_2, otp_1331_2, otp_1338_2,
+ otp_1342_2, otp_2776_2, otp_2979_2, otp_3187_2].
+
+reported_bugs_3(suite) ->
+ [otp_1128_3, otp_1129_3, otp_1131_3, otp_1162_3,
+ otp_1222_3, otp_1298_3, otp_1331_3, otp_1338_3,
+ otp_1342_3, otp_2776_3, otp_2979_3, otp_3187_3,
+ otp_3542].
+
+
+%% These are (ticket) test cases where the initiation has to be done
+%% individually.
+tickets(suite) ->
+ [otp_4394].
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-1128
+%% Slogan: Bug in handling of createAndWait set-requests.
+%%-----------------------------------------------------------------
+otp_1128(suite) -> [];
+otp_1128(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?line load_master("OLD-SNMPEA-MIB"),
+ ?line init_old(),
+ try_test(otp_1128),
+ ?line unload_master("OLD-SNMPEA-MIB").
+
+otp_1128_2(X) -> otp_1128(X).
+
+otp_1128_3(X) -> otp_1128(X).
+
+otp_1128() ->
+ io:format("Testing bug reported in ticket OTP-1128...~n"),
+
+ NewKeyc3 = [intCommunityViewIndex,get(mip),is("test")],
+ NewKeyc4 = [intCommunityAccess,get(mip),is("test")],
+ NewKeyc5 = [intCommunityStatus,get(mip),is("test")],
+
+ s([{NewKeyc5, ?createAndWait}, {NewKeyc4, 2}]),
+ ?line expect(28, [{NewKeyc5, ?createAndWait}, {NewKeyc4, 2}]),
+ g([NewKeyc5]),
+ ?line expect(29, [{NewKeyc5, ?notReady}]),
+ s([{NewKeyc5, ?active}, {NewKeyc3, 2}]),
+ ?line expect(30, [{NewKeyc5, ?active}, {NewKeyc3, 2}]),
+ g([NewKeyc5]),
+ ?line expect(31, [{NewKeyc5, ?active}]),
+ s([{NewKeyc5, ?destroy}]),
+ ?line expect(32, [{NewKeyc5, ?destroy}]).
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-1129, OTP-1169
+%% Slogan: snmpa:int_to_enum crashes on bad oids
+%%-----------------------------------------------------------------
+otp_1129(suite) -> [];
+otp_1129(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?line load_master("Klas3"),
+ try_test(otp_1129_i, [node()]),
+ ?line unload_master("Klas3").
+
+otp_1129_2(X) -> otp_1129(X).
+
+otp_1129_3(X) -> otp_1129(X).
+
+otp_1129_i(MaNode) ->
+ io:format("Testing bug reported in ticket OTP-1129...~n"),
+ false = rpc:call(MaNode, snmp, int_to_enum, [iso, 1]),
+ false = rpc:call(MaNode, snmp, int_to_enum, [isox, 1]).
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-1131
+%% Slogan: Agent crashes / erlang node halts if RowIndex in a
+%% setrequest is of bad type, e.g. an INDEX {INTEGER},
+%% and RowIdenx [3,2].
+%%-----------------------------------------------------------------
+otp_1131(suite) -> [];
+otp_1131(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?line load_master("Klas1"),
+ try_test(otp_1131),
+ ?line unload_master("Klas1").
+
+otp_1131_2(X) -> otp_1131(X).
+
+otp_1131_3(X) -> otp_1131(X).
+
+otp_1131() ->
+ io:format("Testing bug reported in ticket OTP-1131...~n"),
+ s([{[friendsEntry, [2, 3, 1]], s, "kompis3"},
+ {[friendsEntry, [3, 3, 1]], i, ?createAndGo}]),
+ ?line expect(1, ?v1_2(noSuchName, noCreation), 2, any).
+
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-1162
+%% Slogan: snmp_agent can't handle wrongValue from instrum.func
+%%-----------------------------------------------------------------
+otp_1162(suite) -> [];
+otp_1162(Config) when list(Config) ->
+ {SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?line {ok, SA} = start_subagent(SaNode, ?sa, "SA-MIB"),
+ try_test(otp_1162),
+ stop_subagent(SA).
+
+otp_1162_2(X) -> otp_1162(X).
+
+otp_1162_3(X) -> otp_1162(X).
+
+otp_1162() ->
+ s([{[sa, [2,0]], 6}]), % wrongValue (i is_set_ok)
+ ?line expect(1, ?v1_2(badValue, wrongValue), 1, any).
+
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-1222
+%% Slogan: snmp agent crash if faulty index is returned from instrum
+%%-----------------------------------------------------------------
+otp_1222(suite) -> [];
+otp_1222(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?line load_master("Klas3"),
+ ?line load_master("Klas4"),
+ try_test(otp_1222),
+ ?line unload_master("Klas3"),
+ ?line unload_master("Klas4").
+
+otp_1222_2(X) -> otp_1222(X).
+
+otp_1222_3(X) -> otp_1222(X).
+
+otp_1222() ->
+ io:format("Testing bug reported in ticket OTP-1222...~n"),
+ s([{[fStatus4,1], 4}, {[fName4,1], 1}]),
+ ?line expect(1, genErr, 0, any),
+ s([{[fStatus4,2], 4}, {[fName4,2], 1}]),
+ ?line expect(2, genErr, 0, any).
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-1298
+%% Slogan: Negative INTEGER values are treated as positive.
+%%-----------------------------------------------------------------
+otp_1298(suite) -> [];
+otp_1298(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?line load_master("Klas2"),
+ try_test(otp_1298),
+ ?line unload_master("Klas2").
+
+otp_1298_2(X) -> otp_1298(X).
+
+otp_1298_3(X) -> otp_1298(X).
+
+otp_1298() ->
+ io:format("Testing bug reported in ticket OTP-1298...~n"),
+ s([{[fint,0], -1}]),
+ ?line expect(1298, [{[fint,0], -1}]).
+
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-1331
+%% Slogan: snmp_generic should return noError when deleting non-ex row
+%%-----------------------------------------------------------------
+otp_1331(suite) -> [];
+otp_1331(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?line load_master("OLD-SNMPEA-MIB"),
+ ?line init_old(),
+ try_test(otp_1331),
+ ?line unload_master("OLD-SNMPEA-MIB").
+
+otp_1331_2(X) -> otp_1331(X).
+
+otp_1331_3(X) -> otp_1331(X).
+
+otp_1331() ->
+ NewKeyc5 = [intCommunityStatus,[127,32,0,0],is("test")],
+ s([{NewKeyc5, ?destroy}]),
+ ?line expect(1, [{NewKeyc5, ?destroy}]).
+
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-1338
+%% Slogan: snmp bug in initialisation of default values for mnesia tabs
+%%-----------------------------------------------------------------
+otp_1338(suite) -> [];
+otp_1338(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?line load_master("Klas2"),
+ try_test(otp_1338),
+ ?line unload_master("Klas2").
+
+otp_1338_2(X) -> otp_1338(X).
+
+otp_1338_3(X) -> otp_1338(X).
+
+otp_1338() ->
+ s([{[kStatus2, 7], i, ?createAndGo}]),
+ ?line expect(1, [{[kStatus2, 7], ?createAndGo}]),
+ g([[kName2, 7]]),
+ ?line expect(2, [{[kName2, 7], "JJJ"}]).
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-1342
+%% Slogan: default impl of snmp table can't handle bad index access,
+%% Set when INDEX is read-write gets into an infinite loop!
+%%-----------------------------------------------------------------
+otp_1342(suite) -> [];
+otp_1342(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?line load_master("Klas4"),
+ try_test(otp_1342),
+ ?line unload_master("Klas4").
+
+otp_1342_2(X) -> otp_1342(X).
+
+otp_1342_3(X) -> otp_1342(X).
+
+otp_1342() ->
+ s([{[fIndex5, 1], i, 1},
+ {[fName5, 1], i, 3},
+ {[fStatus5, 1], i, ?createAndGo}]),
+ ?line expect(1, ?v1_2(noSuchName, noCreation), 3, any).
+
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-1366
+%% Slogan: snmp traps not sent to all managers
+%% Note: NYI! We need a way to tell the test server that we need
+%% mgrs on two different machines.
+%%-----------------------------------------------------------------
+otp_1366(suite) -> [];
+otp_1366(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?line load_master("OLD-SNMPEA-MIB"),
+ ?line init_old(),
+ try_test(otp_1366),
+ ?line unload_master("OLD-SNMPEA-MIB").
+
+otp_1366_2(X) -> otp_1366(X).
+
+otp_1366_3(X) -> otp_1366(X).
+
+otp_1366() ->
+ ?INF("NOT YET IMPLEMENTED", []),
+ 'NYI'.
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-2776
+%% Slogan: snmp:validate_date_and_time() fails when time is 00:00
+%%-----------------------------------------------------------------
+otp_2776(suite) -> [];
+otp_2776(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ try_test(otp_2776).
+
+otp_2776_2(X) -> otp_2776(X).
+
+otp_2776_3(X) -> otp_2776(X).
+
+otp_2776() ->
+ io:format("Testing bug reported in ticket OTP-2776...~n"),
+
+ Dt01_valid = [19,98,9,1,1,0,23,0,43,0,0],
+ Dt02_valid = [19,98,9,1,0,0,0,0,43,0,0], % This is what is fixed: 00:00
+ Dt03_valid = [19,98,2,28,1,0,23,0,43,0,0],
+ Dt04_invalid = [19,98,2,29,1,0,23,0,43,0,0],
+ Dt05_valid = [19,96,2,29,1,0,23,0,43,0,0],
+ Dt06_valid = [20,0,2,29,1,0,23,0,43,0,0],
+ Dt07_invalid = [19,96,2,30,1,0,23,0,43,0,0], % This is also fixed: 30/2
+ Dt08_valid = [19,98,4,30,1,0,23,0,43,0,0],
+ Dt09_invalid = [19,98,4,31,1,0,23,0,43,0,0], % This is also fixed: 31/4
+ Dt10_invalid = [],
+ Dt11_invalid = [kalle,hobbe],
+ L = [{ 1, true, Dt01_valid},
+ { 2, true, Dt02_valid},
+ { 3, true, Dt03_valid},
+ { 4, false, Dt04_invalid},
+ { 5, true, Dt05_valid},
+ { 6, true, Dt06_valid},
+ { 7, false, Dt07_invalid},
+ { 8, true, Dt08_valid},
+ { 9, false, Dt09_invalid},
+ {10, false, Dt10_invalid},
+ {11, false, Dt11_invalid}],
+
+ ?line ok = validate_dat(L).
+
+
+validate_dat(L) -> validate_dat(L,[]).
+
+validate_dat([],V) ->
+ Fun = fun({_,X}) -> case X of
+ ok -> false;
+ _ -> true
+ end
+ end,
+ validate_dat1( lists:reverse( lists:filter(Fun,V) ) );
+validate_dat([{Id,E,Dat}|T],V) ->
+ validate_dat(T,[validate_dat2(Id,E,Dat) | V]).
+
+validate_dat1([]) -> ok;
+validate_dat1(L) -> {error,L}.
+
+validate_dat2(Id, E, Dat) ->
+ Res = case {E,snmp:validate_date_and_time(Dat)} of
+ {E,E} -> ok;
+ {E,A} -> {E,A}
+ end,
+ {Id, Res}.
+
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-2979
+%% Slogan: get-next on more than 1 column in an empty table
+%% returns bad response.
+%%-----------------------------------------------------------------
+otp_2979(suite) -> [];
+otp_2979(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?line load_master("Test1"),
+ ?line init_old(),
+ try_test(otp_2979),
+ ?line unload_master("Test1").
+
+otp_2979_2(X) -> otp_2979(X).
+
+otp_2979_3(X) -> otp_2979(X).
+
+otp_2979() ->
+ gn([[sparseDescr], [sparseStatus]]),
+ ?line expect(1, [{[sparseStr,0], "slut"},
+ {[sparseStr,0], "slut"}]).
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-3187
+%% Slogan: get-next on vacmAccessTable for colums > 5 returns
+%% endOfTable - should return value.
+%%-----------------------------------------------------------------
+otp_3187(suite) -> [];
+otp_3187(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"),
+ otp_3187(),
+ ?line unload_master("SNMP-VIEW-BASED-ACM-MIB").
+
+otp_3187_2(X) -> otp_3187(X).
+
+otp_3187_3(X) -> otp_3187(X).
+
+otp_3187() ->
+ ?line Elements =
+ snmp_view_based_acm_mib:vacmAccessTable(get_next,[],[4,5,6]),
+ lists:foreach(fun(E) ->
+ ?line if E == endOfTable ->
+ ?FAIL(endOfTable);
+ true -> ok
+ end
+ end, Elements).
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-3542
+%% Slogan:
+%%-----------------------------------------------------------------
+otp_3542(suite) -> [];
+otp_3542(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ try_test(otp_3542).
+
+otp_3542() ->
+ io:format("SNMP v3 discovery...~n"),
+ ?line Res = snmp_test_mgr:d(),
+ io:format("SNMP v3 discovery result: ~p~n",[Res]).
+
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-3725
+%% Slogan: Slow response time on snmpa:int_to_enum
+%%-----------------------------------------------------------------
+otp_3725(suite) -> [];
+otp_3725(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ ?line load_master("OLD-SNMPEA-MIB"),
+ ?line init_old(),
+ try_test(otp_3725_test, [node()]),
+ ?line unload_master("OLD-SNMPEA-MIB").
+
+%% Req. OLD-SNMPEA-MIB
+otp_3725_test(MaNode) ->
+ io:format("Testing feature requested in ticket OTP-3725...~n"),
+ ?line rpc:call(MaNode,snmpa,verbosity,[symbolic_store,trace]),
+ ?line Db = rpc:call(MaNode,snmp,get_symbolic_store_db,[]),
+ ?DBG("otp_3725_test -> Db = ~p",[Db]),
+
+ ?line {value, OID} = rpc:call(MaNode, snmp, name_to_oid,
+ [Db, intAgentIpAddress]),
+ ?DBG("otp_3725_test -> name_to_oid for ~p: ~p",[intAgentIpAddress,OID]),
+ ?line {value, intAgentIpAddress} = rpc:call(MaNode, snmp, oid_to_name,
+ [Db,OID]),
+ ?DBG("otp_3725_test -> oid_to_name for ~p: ~p",[OID,intAgentIpAddress]),
+ ?line false = rpc:call(MaNode, snmp, name_to_oid, [Db, intAgentIpAddres]),
+ ?line false = rpc:call(MaNode, snmp, oid_to_name,
+ [Db, [1,5,32,3,54,3,3,34,4]]),
+ ?line {value, 2} = rpc:call(MaNode, snmp, enum_to_int,
+ [Db, intViewType, excluded]),
+ ?line {value, excluded} = rpc:call(MaNode, snmp, int_to_enum,
+ [Db, intViewType, 2]),
+ ?line false = rpc:call(MaNode, snmp, enum_to_int,
+ [Db, intViewType, exclude]),
+ ?line false = rpc:call(MaNode, snmp, enum_to_int,
+ [Db, intAgentIpAddress, exclude]),
+ ?line false = rpc:call(MaNode, snmp, enum_to_int,
+ [Db, intAgentIpAddre, exclude]),
+ ?line false = rpc:call(MaNode, snmp, int_to_enum, [Db, intViewType, 3]),
+ ?line false = rpc:call(MaNode, snmp, int_to_enum,
+ [Db, intAgentIpAddress, 2]),
+ ?line false = rpc:call(MaNode, snmp, int_to_enum,
+ [Db, intAgentIpAddre, 2]),
+ ?line {value, active} = rpc:call(MaNode, snmp, int_to_enum,
+ [Db, 'RowStatus', ?active]),
+ ?line {value, ?destroy} = rpc:call(MaNode, snmp, enum_to_int,
+ [Db, 'RowStatus', destroy]),
+ ?line false = rpc:call(MaNode, snmp, enum_to_int,
+ [Db, 'RowStatus', xxxdestroy]),
+ ?line false = rpc:call(MaNode, snmp, enum_to_int,
+ [Db, 'xxRowStatus', destroy]),
+ ?line false = rpc:call(MaNode, snmp, int_to_enum, [Db, 'RowStatus', 25]),
+ ?line false = rpc:call(MaNode, snmp, int_to_enum, [Db, 'xxRowStatus', 1]),
+ ok.
+
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-4394
+%% Slogan: Target mib tag list check invalid
+%%-----------------------------------------------------------------
+
+
+otp_4394(suite) -> {req, [], {conf,
+ init_otp_4394,
+ [otp_4394_test],
+ finish_otp_4394}}.
+
+init_otp_4394(Config) when list(Config) ->
+ ?DBG("init_otp_4394 -> entry with"
+ "~n Config: ~p", [Config]),
+ ?line AgentDir = ?config(agent_dir, Config),
+ ?line MgrDir = ?config(mgr_dir, Config),
+ ?line Ip = ?config(ip, Config),
+ ?line otp_4394_config(AgentDir, MgrDir, Ip),
+ MasterAgentVerbosity = {master_agent_verbosity, trace},
+ NetIfVerbosity = {net_if_verbosity, trace},
+ Opts = [MasterAgentVerbosity,NetIfVerbosity],
+ [{vsn, v1} | start_v1_agent(Config,Opts)].
+
+otp_4394_config(AgentDir, MgrDir, Ip0) ->
+ ?DBG("otp_4394_config -> entry with"
+ "~n AgentDir: ~p"
+ "~n MgrDir: ~p"
+ "~n Ip0: ~p", [AgentDir, MgrDir, Ip0]),
+ Vsn = [v1],
+ Ip = tuple_to_list(Ip0),
+ ?line snmp_config:write_agent_snmp_files(AgentDir, Vsn, Ip,
+ ?TRAP_UDP, Ip, 4000,
+ "OTP-4394 test"),
+ ?line case update_usm(Vsn, AgentDir) of
+ true ->
+ ?line copy_file(filename:join(AgentDir, "usm.conf"),
+ filename:join(MgrDir, "usm.conf")),
+ ?line update_usm_mgr(Vsn, MgrDir);
+ false ->
+ ?line ok
+ end,
+ C1 = {"a", "all-rights", "initial", "", "pc"},
+ C2 = {"c", "secret", "secret_name", "", "secret_tag"},
+ ?line write_community_conf(AgentDir, [C1, C2]),
+ ?line update_vacm(Vsn, AgentDir),
+ Ta1 = {"shelob v1",
+ [134,138,177,177], 5000, 1500, 3, %% Anv�nd Ip och modda
+ "pc1",
+ "target_v1", "",
+ %% [255,255,255,255,0,0],
+ [],
+ 2048},
+ Ta2 = {"bifur v1",
+ [134,138,177,75], 5000, 1500, 3, %% Anv�nd Ip
+ "pc2",
+ "target_v1", "",
+ %% [255,255,255,255,0,0],
+ [], 2048},
+ ?line write_target_addr_conf(AgentDir, [Ta1, Ta2]),
+ ?line write_target_params_conf(AgentDir, Vsn),
+ ?line write_notify_conf(AgentDir),
+ ok.
+
+
+
+finish_otp_4394(Config) when list(Config) ->
+ ?DBG("finish_otp_4394 -> entry", []),
+ C1 = stop_agent(Config),
+ delete_files(C1),
+ erase(mgr_node),
+ lists:keydelete(vsn, 1, C1).
+
+otp_4394_test(suite) -> [];
+otp_4394_test(Config) ->
+ ?DBG("otp_4394_test -> entry", []),
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ try_test(otp_4394_test1),
+ ?DBG("otp_4394_test -> done", []),
+ ok.
+
+otp_4394_test1() ->
+ ?DBG("otp_4394_test1 -> entry", []),
+ gn([[1,1]]),
+ Res =
+ case snmp_test_mgr:expect(1, [{[sysDescr,0], "Erlang SNMP agent"}]) of
+ %% {error, 1, {"?",[]}, {"~w",[timeout]}}
+ {error, 1, _, {_, [timeout]}} ->
+ ?DBG("otp_4394_test1 -> expected result: timeout", []),
+ ok;
+ Else ->
+ Else
+ end,
+ ?DBG("otp_4394_test1 -> done with: ~p", [Res]),
+ Res.
+
+
+%%%--------------------------------------------------
+%%% Used to test the standard mib with our
+%%% configuration.
+%%%--------------------------------------------------
+run(F, A, Opts) ->
+ M = get(mib_dir),
+ Dir = get(mgr_dir),
+ User = snmp_misc:get_option(user, Opts, "all-rights"),
+ SecLevel = snmp_misc:get_option(sec_level, Opts, noAuthNoPriv),
+ EngineID = snmp_misc:get_option(engine_id, Opts, "agentEngine"),
+ CtxEngineID = snmp_misc:get_option(context_engine_id, Opts, EngineID),
+ Community = snmp_misc:get_option(community, Opts, "all-rights"),
+ ?DBG("run -> start crypto app",[]),
+ Crypto = case os:type() of
+ vxworks ->
+ no_crypto;
+ _ ->
+ ?CRYPTO_START()
+ end,
+ ?DBG("run -> Crypto: ~p",[Crypto]),
+ catch snmp_test_mgr:stop(), % If we had a running mgr from a failed case
+ StdM = filename:join(code:priv_dir(snmp), "mibs") ++ "/",
+ ?DBG("run -> config:~n"
+ "\tM: ~p~n"
+ "\tDir: ~p~n"
+ "\tUser: ~p~n"
+ "\tSecLevel: ~p~n"
+ "\tEngineID: ~p~n"
+ "\tCtxEngineID: ~p~n"
+ "\tCommunity: ~p~n"
+ "\tStdM: ~p",
+ [M,Dir,User,SecLevel,EngineID,CtxEngineID,Community,StdM]),
+ case snmp_test_mgr:start([%% {agent, snmp_test_lib:hostname()},
+ {packet_server_debug,true},
+ {debug,true},
+ {agent, get(master_host)},
+ {agent_udp, 4000},
+ {trap_udp, 5000},
+ {recbuf,65535},
+ quiet,
+ get(vsn),
+ {community, Community},
+ {user, User},
+ {sec_level, SecLevel},
+ {engine_id, EngineID},
+ {context_engine_id, CtxEngineID},
+ {dir, Dir},
+ {mibs, mibs(StdM, M)}]) of
+ {ok, _Pid} ->
+ Res = apply(?MODULE, F, A),
+ catch snmp_test_mgr:stop(),
+ Res;
+ Err ->
+ io:format("Error starting manager: ~p\n", [Err]),
+ catch snmp_test_mgr:stop(),
+ ?line exit({mgr_start, Err})
+ end.
+
+
+mibs(StdMibDir,MibDir) ->
+ [join(StdMibDir, ?v1_2("STANDARD-MIB.bin", "SNMPv2-MIB.bin")),
+ join(MibDir, "OLD-SNMPEA-MIB.bin"),
+ join(StdMibDir, "SNMP-FRAMEWORK-MIB"),
+ join(StdMibDir, "SNMP-MPD-MIB"),
+ join(StdMibDir, "SNMP-VIEW-BASED-ACM-MIB"),
+ join(StdMibDir, "SNMP-USER-BASED-SM-MIB"),
+ join(StdMibDir, "SNMP-TARGET-MIB"),
+ join(StdMibDir, "SNMP-NOTIFICATION-MIB"),
+ join(MibDir, "Klas1.bin"),
+ join(MibDir, "Klas2.bin"),
+ join(MibDir, "Klas3.bin"),
+ join(MibDir, "Klas4.bin"),
+ join(MibDir, "SA-MIB.bin"),
+ join(MibDir, "TestTrap.bin"),
+ join(MibDir, "Test1.bin"),
+ join(MibDir, "Test2.bin"),
+ join(MibDir, "TestTrapv2.bin")].
+
+join(D,F) ->
+ filename:join(D,F).
+
+%% string used in index
+is(S) -> [length(S) | S].
+
+try_test(Func) ->
+ call(get(mgr_node), ?MODULE, run, [Func, [], []]).
+
+try_test(Func, A) ->
+ call(get(mgr_node), ?MODULE, run, [Func, A, []]).
+
+try_test(Func, A, Opts) ->
+ call(get(mgr_node), ?MODULE, run, [Func, A, Opts]).
+
+call(N,M,F,A) ->
+ ?DBG("call -> entry with~n"
+ " N: ~p~n"
+ " M: ~p~n"
+ " F: ~p~n"
+ " A: ~p~n"
+ " when~n"
+ " get(): ~p",
+ [N,M,F,A,get()]),
+ spawn(N, ?MODULE, wait, [self(),get(),M,F,A]),
+ receive
+ {done, {'EXIT', Rn}, Loc} ->
+ ?DBG("call -> returned ~p",[{done, {'EXIT', Rn}, Loc}]),
+ put(test_server_loc, Loc),
+ exit(Rn);
+ {done, Ret, Zed} ->
+ ?DBG("call -> returned ~p~n",[{done, Ret, Zed}]),
+ Ret
+ end.
+
+wait(From, Env, M, F, A) ->
+ ?DBG("wait -> entry with ~n"
+ "\tFrom: ~p~n"
+ "\tEnv: ~p",[From,Env]),
+ lists:foreach(fun({K,V}) -> put(K,V) end, Env),
+ Rn = (catch apply(M, F, A)),
+ ?DBG("wait -> Rn: ~n~p", [Rn]),
+ From ! {done, Rn, get(test_server_loc)},
+ exit(Rn).
+
+expect(A,B) -> ok = snmp_test_mgr:expect(A,B).
+expect(A,B,C) -> ok = snmp_test_mgr:expect(A,B,C).
+expect(A,B,C,D) -> ok = snmp_test_mgr:expect(A,B,C,D).
+expect(A,B,C,D,E,F) -> ok = snmp_test_mgr:expect(A,B,C,D,E,F).
+
+get_req(Id, Vars) ->
+ ?DBG("get_req -> entry with~n"
+ "\tId: ~p~n"
+ "\tVars: ~p",[Id,Vars]),
+ g(Vars),
+ ?DBG("get_req -> await response",[]),
+ {ok, Val} = snmp_test_mgr:get_response(Id, Vars),
+ ?DBG("get_req -> response: ~p",[Val]),
+ Val.
+
+get_next_req(Vars) ->
+ ?DBG("get_next_req -> entry with Vars '~p', send request",[Vars]),
+ gn(Vars),
+ ?DBG("get_next_req -> await response",[]),
+ Response = snmp_test_mgr:receive_response(),
+ ?DBG("get_next_req -> response: ~p",[Response]),
+ Response.
+
+
+
+start_node(Name) ->
+ ?LOG("start_node -> entry with Name: ~p",[Name]),
+ M = list_to_atom(?HOSTNAME(node())),
+ ?DBG("start_node -> M: ~p",[M]),
+ Pa = filename:dirname(code:which(?MODULE)),
+ ?DBG("start_node -> Pa: ~p",[Pa]),
+
+ Args = case init:get_argument('CC_TEST') of
+ {ok, [[]]} ->
+ " -pa /clearcase/otp/libraries/snmp/ebin ";
+ {ok, [[Path]]} ->
+ " -pa " ++ Path;
+ error ->
+ ""
+ end,
+ %% Do not use start_link!!! (the proc that calls this one is tmp)
+ ?DBG("start_node -> Args: ~p~n",[Args]),
+ A = Args ++ " -pa " ++ Pa,
+ case (catch ?START_NODE(Name, A)) of
+ {ok, Node} ->
+ %% Tell the test_server to not clean up things it never started.
+ ?DBG("start_node -> Node: ~p",[Node]),
+ {ok, Node};
+ Else ->
+ ?ERR("start_node -> failed with(other): Else: ~p",[Else]),
+ ?line ?FAIL(Else)
+ end.
+
+
+stop_node(Node) ->
+ ?LOG("stop_node -> Node: ~p",[Node]),
+ rpc:cast(Node, erlang, halt, []).
+
+p(X) ->
+ io:format(user, X++"\n", []).
+
+sleep(X) ->
+ receive
+ after
+ X -> ok
+ end.
+
+%%%-----------------------------------------------------------------
+%%% Configuration
+%%%-----------------------------------------------------------------
+config(Vsns, MgrDir, AgentDir, MIp, AIp) ->
+ ?line snmp_config:write_agent_snmp_files(AgentDir, Vsns, MIp,
+ ?TRAP_UDP, AIp, 4000,
+ "test"),
+ ?line case update_usm(Vsns, AgentDir) of
+ true ->
+ ?line copy_file(filename:join(AgentDir, "usm.conf"),
+ filename:join(MgrDir, "usm.conf")),
+ ?line update_usm_mgr(Vsns, MgrDir);
+ false ->
+ ?line ok
+ end,
+ ?line update_community(Vsns, AgentDir),
+ ?line update_vacm(Vsns, AgentDir),
+ ?line write_target_addr_conf(AgentDir, MIp, ?TRAP_UDP, Vsns),
+ ?line write_target_params_conf(AgentDir, Vsns),
+ ?line write_notify_conf(AgentDir),
+ ok.
+
+delete_files(Config) ->
+ Dir = ?config(agent_dir, Config),
+ {ok, List} = file:list_dir(Dir),
+ lists:foreach(fun(FName) -> file:delete(filename:join(Dir, FName)) end,
+ List).
+
+update_usm(Vsns, Dir) ->
+ case lists:member(v3, Vsns) of
+ true ->
+ {ok, Fid} = file:open(filename:join(Dir,"usm.conf"),[read,write]),
+ file:position(Fid, eof),
+ ok = io:format(Fid, "{\"agentEngine\", \"all-rights\", "
+ "\"all-rights\", zeroDotZero, "
+ "usmNoAuthProtocol, \"\", \"\", "
+ "usmNoPrivProtocol, \"\", \"\", \"\", "
+ "\"\", \"\"}.\n", []),
+ ok = io:format(Fid, "{\"agentEngine\", \"no-rights\", "
+ "\"no-rights\", zeroDotZero, "
+ "usmNoAuthProtocol, \"\", \"\", "
+ "usmNoPrivProtocol, \"\", \"\", \"\", "
+ "\"\", \"\"}.\n", []),
+ ok = io:format(Fid, "{\"agentEngine\", \"authMD5\", "
+ "\"authMD5\", zeroDotZero, "
+ "usmHMACMD5AuthProtocol, \"\", \"\", "
+ "usmNoPrivProtocol, \"\", \"\", \"\", "
+ "\"passwd_md5xxxxxx\", \"\"}.\n", []),
+ ok = io:format(Fid, "{\"agentEngine\", \"authSHA\", "
+ "\"authSHA\", zeroDotZero, "
+ "usmHMACSHAAuthProtocol, \"\", \"\", "
+ "usmNoPrivProtocol, \"\", \"\", \"\", "
+ "\"passwd_shaxxxxxxxxxx\", \"\"}.\n", []),
+ ok = io:format(Fid, "{\"agentEngine\", \"privDES\", "
+ "\"privDES\", zeroDotZero, "
+ "usmHMACSHAAuthProtocol, \"\", \"\", "
+ "usmDESPrivProtocol, \"\", \"\", \"\", "
+ "\"passwd_shaxxxxxxxxxx\", \"passwd_desxxxxxx\"}.\n",
+ []),
+ ok = io:format(Fid, "{\"mgrEngine\", \"all-rights\", "
+ "\"all-rights\", zeroDotZero, "
+ "usmNoAuthProtocol, \"\", \"\", "
+ "usmNoPrivProtocol, \"\", \"\", \"\", "
+ "\"\", \"\"}.\n", []),
+ ok = io:format(Fid, "{\"mgrEngine\", \"no-rights\", "
+ "\"no-rights\", zeroDotZero, "
+ "usmNoAuthProtocol, \"\", \"\", "
+ "usmNoPrivProtocol, \"\", \"\", \"\", "
+ "\"\", \"\"}.\n", []),
+ ok = io:format(Fid, "{\"mgrEngine\", \"authMD5\", "
+ "\"authMD5\", zeroDotZero, "
+ "usmHMACMD5AuthProtocol, \"\", \"\", "
+ "usmNoPrivProtocol, \"\", \"\", \"\", "
+ "\"passwd_md5xxxxxx\", \"\"}.\n", []),
+ ok = io:format(Fid, "{\"mgrEngine\", \"authSHA\", "
+ "\"authSHA\", zeroDotZero, "
+ "usmHMACSHAAuthProtocol, \"\", \"\", "
+ "usmNoPrivProtocol, \"\", \"\", \"\", "
+ "\"passwd_shaxxxxxxxxxx\", \"\"}.\n", []),
+ ok = io:format(Fid, "{\"mgrEngine\", \"privDES\", "
+ "\"privDES\", zeroDotZero, "
+ "usmHMACSHAAuthProtocol, \"\", \"\", "
+ "usmDESPrivProtocol, \"\", \"\", \"\", "
+ "\"passwd_shaxxxxxxxxxx\", \"passwd_desxxxxxx\"}.\n",
+ []),
+ file:close(Fid),
+ true;
+ false ->
+ false
+ end.
+
+update_usm_mgr(Vsns, Dir) ->
+ case lists:member(v3, Vsns) of
+ true ->
+ {ok, Fid} = file:open(filename:join(Dir,"usm.conf"),[read,write]),
+ file:position(Fid, eof),
+ ok = io:format(Fid, "{\"agentEngine\", \"newUser\", "
+ "\"newUser\", zeroDotZero, "
+ "usmHMACSHAAuthProtocol, \"\", \"\", "
+ "usmDESPrivProtocol, \"\", \"\", \"\", "
+ "\"passwd_shaxxxxxxxxxx\", \"passwd_desxxxxxx\"}.\n",
+ []),
+ ok = io:format(Fid, "{\"mgrEngine\", \"newUser\", "
+ "\"newUser\", zeroDotZero, "
+ "usmHMACSHAAuthProtocol, \"\", \"\", "
+ "usmDESPrivProtocol, \"\", \"\", \"\", "
+ "\"passwd_shaxxxxxxxxxx\", \"passwd_desxxxxxx\"}.\n",
+ []),
+ file:close(Fid),
+ true;
+ false ->
+ false
+ end.
+
+rewrite_usm_mgr(Dir, ShaKey, DesKey) ->
+ ?line ok = file:rename(filename:join(Dir,"usm.conf"),
+ filename:join(Dir,"usm.old")),
+ ?line {ok, Fid} = file:open(filename:join(Dir,"usm.conf"),write),
+ ok = io:format(Fid, "{\"agentEngine\", \"newUser\", "
+ "\"newUser\", zeroDotZero, "
+ "usmHMACSHAAuthProtocol, \"\", \"\", "
+ "usmDESPrivProtocol, \"\", \"\", \"\", "
+ "\"~s\", \"~s\"}.\n",
+ [ShaKey, DesKey]),
+ ok = io:format(Fid, "{\"mgrEngine\", \"newUser\", "
+ "\"newUser\", zeroDotZero, "
+ "usmHMACSHAAuthProtocol, \"\", \"\", "
+ "usmDESPrivProtocol, \"\", \"\", \"\", "
+ "\"~s\", \"~s\"}.\n",
+ [ShaKey, DesKey]),
+ file:close(Fid).
+
+reset_usm_mgr(Dir) ->
+ ?line ok = file:rename(filename:join(Dir,"usm.old"),
+ filename:join(Dir,"usm.conf")).
+
+
+update_community([v3], _Dir) -> ok;
+update_community(_, Dir) ->
+ {ok, Fid} = file:open(filename:join(Dir,"community.conf"),[read,write]),
+ file:position(Fid, eof),
+ ok=io:format(Fid,"{\"no-rights\",\"no-rights\",\"no-rights\",\"\",\"\"}.\n",
+ []),
+ file:close(Fid).
+
+
+-define(tDescr_instance, [1,3,6,1,2,1,16,1,0]).
+update_vacm(_Vsn, Dir) ->
+ {ok, Fid} = file:open(filename:join(Dir,"vacm.conf"),[read,write]),
+ file:position(Fid, eof),
+ ok=io:format(Fid,"{vacmSecurityToGroup,usm,\"authMD5\",\"initial\"}.\n",[]),
+ ok=io:format(Fid,"{vacmSecurityToGroup,usm,\"authSHA\",\"initial\"}.\n",[]),
+ ok=io:format(Fid,"{vacmSecurityToGroup,usm,\"privDES\",\"initial\"}.\n",[]),
+ ok=io:format(Fid,"{vacmSecurityToGroup,usm,\"newUser\",\"initial\"}.\n",[]),
+ ok = io:format(Fid, "{vacmViewTreeFamily, \"internet\", "
+ "~w, excluded, null}.\n", [?tDescr_instance]),
+ file:close(Fid).
+
+
+vacm_ver(v1) -> v1;
+vacm_ver(v2) -> v2c;
+vacm_ver(v3) -> usm.
+
+
+write_community_conf(Dir, Confs) ->
+ {ok, Fid} = file:open(filename:join(Dir,"community.conf"),write),
+ ok = write_community_conf1(Fid, Confs),
+ file:close(Fid).
+
+write_community_conf1(_, []) ->
+ ok;
+write_community_conf1(Fid, [{ComIdx, ComName, SecName, CtxName, TransTag}|Confs]) ->
+ ok = io:format(Fid, "{\"~s\", \"~s\", \"~s\", \"~s\", \"~s\"}.~n",
+ [ComIdx, ComName, SecName, CtxName, TransTag]),
+ write_community_conf1(Fid, Confs).
+
+
+write_target_addr_conf(Dir, Confs) ->
+ {ok, Fid} = file:open(filename:join(Dir,"target_addr.conf"),write),
+ ok = write_target_addr_conf1(Fid, Confs),
+ file:close(Fid).
+
+
+write_target_addr_conf1(_, []) ->
+ ok;
+write_target_addr_conf1(Fid,
+ [{Name, Ip, Port, Timeout, Retry, TagList, ParamName,
+ EngineId, TMask, MaxMsgSz}|Confs]) ->
+ ok = io:format(Fid, "{\"~s\", ~w, ~w, ~w, ~w, \"~s\", \"~s\", \"~s\", ~w, ~w}.~n",
+ [Name, Ip, Port, Timeout, Retry, TagList, ParamName,
+ EngineId, TMask, MaxMsgSz]),
+ write_target_addr_conf1(Fid, Confs).
+
+write_target_addr_conf(Dir, ManagerIp, UDP, Vsns) ->
+ {ok, Fid} = file:open(filename:join(Dir,"target_addr.conf"),write),
+ lists:foreach(fun(Vsn) ->
+ ok = io:format(Fid,
+ "{\"~s\", ~w, ~w, 1500, 3, "
+ "\"std_trap\", \"~s\"}.~n",
+ [mk_ip(ManagerIp, Vsn),
+ ManagerIp, UDP, mk_param(Vsn)]),
+ case Vsn of
+ v1 -> ok;
+ v2 ->
+ ok = io:format(Fid,
+ "{\"~s.2\",~w,~w,1500,3, "
+ "\"std_inform\", \"~s\"}.~n",
+ [mk_ip(ManagerIp, Vsn),
+ ManagerIp, UDP,
+ mk_param(Vsn)]);
+ v3 ->
+ ok = io:format(Fid,
+ "{\"~s.3\",~w,~w,1500,3, "
+ "\"std_inform\", \"~s\", "
+ "\"mgrEngine\", [], 1024}.~n",
+ [mk_ip(ManagerIp, Vsn),
+ ManagerIp, UDP,
+ mk_param(Vsn)])
+ end
+ end,
+ Vsns),
+ file:close(Fid).
+
+mk_param(v1) -> "target_v1";
+mk_param(v2) -> "target_v2";
+mk_param(v3) -> "target_v3".
+
+mk_ip([A,B,C,D], Vsn) ->
+ io_lib:format("~w.~w.~w.~w ~w", [A,B,C,D,Vsn]).
+
+
+rewrite_target_addr_conf(Dir,NewPort) ->
+ TAFile = filename:join(Dir, "target_addr.conf"),
+ ?DBG("rewrite_target_addr_conf -> read target file info of address config file",[]),
+ case file:read_file_info(TAFile) of
+ {ok, _} -> ok;
+ {error, R} -> ?ERR("failure reading file info of "
+ "target address config file: ~p",[R]),
+ ok
+ end,
+
+ ?line [TrapAddr|Addrs] =
+ snmp_conf:read(TAFile,fun(R) -> rewrite_target_addr_conf1(R) end),
+
+ ?DBG("rewrite_target_addr_conf -> TrapAddr: ~p",[TrapAddr]),
+
+ NewAddrs = [rewrite_target_addr_conf2(NewPort,TrapAddr)|Addrs],
+
+ ?DBG("rewrite_target_addr_conf -> NewAddrs: ~p",[NewAddrs]),
+
+ ?line ok = file:rename(filename:join(Dir,"target_addr.conf"),
+ filename:join(Dir,"target_addr.old")),
+ ?line {ok, Fid} = file:open(filename:join(Dir,"target_addr.conf"),write),
+
+ ?line ok = rewrite_target_addr_conf3(Fid,NewAddrs),
+
+ file:close(Fid).
+
+rewrite_target_addr_conf1(O) ->
+ {ok,O}.
+
+rewrite_target_addr_conf2(NewPort,{Name,Ip,_Port,Timeout,Retry,
+ "std_trap",EngineId}) ->
+ ?LOG("rewrite_target_addr_conf2 -> entry with std_trap",[]),
+ {Name,Ip,NewPort,Timeout,Retry,"std_trap",EngineId};
+rewrite_target_addr_conf2(_NewPort,O) ->
+ ?LOG("rewrite_target_addr_conf2 -> entry with "
+ "~n O: ~p",[O]),
+ O.
+
+
+rewrite_target_addr_conf3(_,[]) -> ok;
+rewrite_target_addr_conf3(Fid,[{Name,Ip,Port,Timeout,Retry,
+ ParamName,EngineId}|T]) ->
+ ?LOG("rewrite_target_addr_conf3 -> write(1) ~s",[ParamName]),
+ io:format(Fid,
+ "{\"~s\", " % Name
+ "~p, " % Ip
+ "~p, " % Port
+ "~p, " % Timeout
+ "~p, " % Retry
+ "\"~s\", " % ParamsName
+ "\"~s\"}.", % EngineId
+ [Name,Ip,Port,Timeout,Retry,ParamName,EngineId]),
+ rewrite_target_addr_conf3(Fid,T);
+rewrite_target_addr_conf3(Fid,[{Name,Ip,Port,Timeout,Retry,TagList,
+ ParamName,EngineId,TMask,MMS}|T]) ->
+ ?LOG("rewrite_target_addr_conf3 -> write(2) ~s",[ParamName]),
+ io:format(Fid,
+ "{\"~s\", " % Name
+ "~p, " % Ip
+ "~p, " % Port
+ "~p, " % Timeout
+ "~p, " % Retry
+ "\"~s\", " % TagList
+ "\"~s\", " % ParamsName
+ "\"~s\"," % EngineId
+ "~p, " % TMask
+ "~p}.", % MMS
+ [Name,Ip,Port,Timeout,Retry,TagList,ParamName,
+ EngineId,TMask,MMS]),
+ rewrite_target_addr_conf3(Fid,T).
+
+reset_target_addr_conf(Dir) ->
+ ?line ok = file:rename(filename:join(Dir,"target_addr.old"),
+ filename:join(Dir,"target_addr.conf")).
+
+write_target_params_conf(Dir, Vsns) ->
+ {ok, Fid} = file:open(filename:join(Dir,"target_params.conf"),write),
+ lists:foreach(fun(Vsn) ->
+ MP = if Vsn == v1 -> v1;
+ Vsn == v2 -> v2c;
+ Vsn == v3 -> v3
+ end,
+ SM = if Vsn == v1 -> v1;
+ Vsn == v2 -> v2c;
+ Vsn == v3 -> usm
+ end,
+ ok = io:format(Fid, "{\"target_~w\", ~w, ~w, "
+ "\"all-rights\", noAuthNoPriv}.~n",
+ [Vsn, MP, SM])
+ end,
+ Vsns),
+ file:close(Fid).
+
+rewrite_target_params_conf(Dir, SecName, SecLevel) ->
+ ?line ok = file:rename(filename:join(Dir,"target_params.conf"),
+ filename:join(Dir,"target_params.old")),
+ ?line {ok, Fid} = file:open(filename:join(Dir,"target_params.conf"),write),
+ ?line ok = io:format(Fid, "{\"target_v3\", v3, usm, \"~s\", ~w}.~n",
+ [SecName, SecLevel]),
+ file:close(Fid).
+
+reset_target_params_conf(Dir) ->
+ ?line ok = file:rename(filename:join(Dir,"target_params.old"),
+ filename:join(Dir,"target_params.conf")).
+
+write_notify_conf(Dir) ->
+ {ok, Fid} = file:open(filename:join(Dir,"notify.conf"),write),
+ ok = io:format(Fid, "{\"standard trap\", \"std_trap\", trap}.~n", []),
+ ok = io:format(Fid, "{\"standard inform\", \"std_inform\",inform}.~n", []),
+ file:close(Fid).
+
+ver_to_trap_str([v1]) -> "v1";
+ver_to_trap_str([v2]) -> "v2";
+% default is to use the latest snmp version
+ver_to_trap_str([v1,v2]) -> "v2".
+
+
+
+write_view_conf(Dir) ->
+ {ok, Fid} = file:open(a(Dir,"view.conf"),write),
+ ok = io:format(Fid, "{2, [1,3,6], included, null}.~n", []),
+ ok = io:format(Fid, "{2, ~w, excluded, null}.~n", [?tDescr_instance]),
+ file:close(Fid).
+
+a(A,B) -> lists:append(A,B).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+copy_file(From, To) ->
+ {ok, Bin} = file:read_file(From),
+ ok = file:write_file(To, Bin).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+display_memory_usage() ->
+ Info = snmpa:info(snmp_master_agent),
+ TreeSize = lists_key1search(tree_size_bytes, Info),
+ ProcMem = lists_key1search(process_memory, Info),
+ MibDbSize = lists_key1search([db_memory,mib], Info),
+ NodeDbSize = lists_key1search([db_memory,node], Info),
+ TreeDbSize = lists_key1search([db_memory,tree], Info),
+ ?INF("Memory usage: "
+ "~n Tree size: ~p"
+ "~n Process memory size: ~p"
+ "~n Mib db size: ~p"
+ "~n Node db size: ~p"
+ "~n Tree db size: ~p",
+ [TreeSize, ProcMem, MibDbSize, NodeDbSize, TreeDbSize]).
+
+lists_key1search([], Res) ->
+ Res;
+lists_key1search([Key|Keys], List) when atom(Key), list(List) ->
+ case lists:keysearch(Key, 1, List) of
+ {value, {Key, Val}} ->
+ lists_key1search(Keys, Val);
+ false ->
+ undefined
+ end;
+lists_key1search(Key, List) when atom(Key) ->
+ case lists:keysearch(Key, 1, List) of
+ {value, {Key, Val}} ->
+ Val;
+ false ->
+ undefined
+ end.
+
+
+regs() ->
+ lists:sort(registered()).
diff --git a/lib/snmp/test/snmp_agent_v3_test.erl b/lib/snmp/test/snmp_agent_v3_test.erl
new file mode 100644
index 0000000000..823c914136
--- /dev/null
+++ b/lib/snmp/test/snmp_agent_v3_test.erl
@@ -0,0 +1,5657 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2005-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%
+%%
+
+-module(snmp_agent_v3_test).
+
+%% TODO
+%% * Test fault-tolerance (kill master etc)
+%%
+
+-compile(export_all).
+
+-define(application, snmp).
+
+-include_lib("kernel/include/file.hrl").
+-include("test_server.hrl").
+-include("snmp_test_lib.hrl").
+-define(SNMP_USE_V3, true).
+-include_lib("snmp/include/snmp_types.hrl").
+%% -include_lib("snmp/include/SNMP-COMMUNITY-MIB.hrl").
+%% -include_lib("snmp/include/SNMP-VIEW-BASED-ACM-MIB.hrl").
+%% -include_lib("snmp/include/SNMP-USER-BASED-SM-MIB.hrl").
+
+
+-define(klas1, [1,3,6,1,2,1,7]).
+-define(klas2, [1,3,6,1,2,1,9]).
+-define(klas3, [1,3,6,1,2,1,8,1]).
+-define(klas4, [1,3,6,1,2,1,8,4]).
+-define(sa, [1,3,6,1,4,1,193,2]).
+-define(system, [1,3,6,1,2,1,1]).
+-define(snmp, [1,3,6,1,2,1,11]).
+-define(snmpTraps, [1,3,6,1,6,3,1,1,5]).
+-define(ericsson, [1,3,6,1,4,1,193]).
+-define(testTrap, [1,3,6,1,2,1,15,0]).
+-define(xDescr, [1,3,6,1,2,1,17,1]).
+-define(xDescr2, [1,3,6,1,2,1,17,2]).
+
+-define(active, 1).
+-define(notInService, 2).
+-define(notReady, 3).
+-define(createAndGo, 4).
+-define(createAndWait, 5).
+-define(destroy, 6).
+
+-define(TRAP_UDP, 5000).
+
+-define(tooBigStr, "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").
+
+-define(str(X), snmp_pdus:bits_to_str(X)).
+
+-define(break(), begin io:format(user, "break at line ~w: pid: ~p\n",
+ [?LINE, self()]),
+ receive cont -> ok end
+ end).
+
+
+-import(snmp_test_mgr, [gn/1, g/1, s/1, gb/3]).
+-define(v1_2(V1,V2),
+ case get(vsn) of
+ v1 -> V1;
+ _ -> V2
+ end).
+
+-define(v1_2_3(V1,V2,V3),
+ case get(vsn) of
+ v1 -> V1;
+ v2 -> V2;
+ _ -> V3
+ end).
+
+all(suite) -> {req,
+ [mnesia, distribution,
+ {local_slave_nodes, 2}, {time, 360}],
+ [{conf, init_all, cases(), finish_all}]}.
+
+init_per_testcase(_Case, Config) when list(Config) ->
+ Dog = ?t:timetrap(?t:minutes(6)),
+ [{watchdog, Dog}|Config].
+
+fin_per_testcase(_Case, Config) when list(Config) ->
+ Dog = ?config(watchdog, Config),
+ ?t:timetrap_cancel(Dog),
+ Config.
+
+cases() ->
+ case ?OSTYPE() of
+ vxworks ->
+ %% No crypto app, so skip v3 testcases
+ [
+ app_info,
+ test_v1, test_v2, test_v1_v2,
+ test_multi_threaded,
+ mib_storage,
+ tickets];
+ _Else ->
+ [
+ app_info,
+ test_v1, test_v2, test_v1_v2, test_v3,
+ test_multi_threaded,
+ mib_storage,
+ tickets
+ ]
+ end.
+
+
+%%%-----------------------------------------------------------------
+%%% The test case structure is as follows:
+%%%
+%%% init_all - starts mnesia,
+%%%
+%%% init_v1 - starts agent
+%%% simple
+%%% big - e.g. starts/stops subagent, load/unloads mibs
+%%% init_mul
+%%% mul_get
+%%% mul_set
+%%% <etc>
+%%% finish_mul
+%%% <etc>
+%%% finish_v1
+%%%
+%%% init_v2 - starts agent
+%%% finish_v2
+%%%
+%%% init_bilingual - starts agent
+%%% finish_bilingual
+%%%
+%%% finish_all
+%%%
+%%% There is still one problem with these testsuites. If one test
+%%% fails, it may not be possible to run some other cases, as it
+%%% may have e.g. created some row or loaded some table, that it
+%%% didn't undo (since it failed).
+%%%-----------------------------------------------------------------
+
+init_all(Config0) when list(Config0) ->
+ ?LOG("init_all -> entry with"
+ "~n Config0: ~p",[Config0]),
+
+ %% --
+ %% Fix config:
+ %%
+
+ DataDir0 = ?config(data_dir, Config0),
+ DataDir1 = filename:split(filename:absname(DataDir0)),
+ [_|DataDir2] = lists:reverse(DataDir1),
+ DataDir3 = filename:join(lists:reverse(DataDir2) ++ [?snmp_test_data]),
+ Config1 = lists:keydelete(data_dir, 1, Config0),
+ Config = [{data_dir, DataDir3 ++ "/"}|Config1],
+
+ %% --
+ %% Start nodes
+ %%
+
+ ?line {ok, SaNode} = start_node(snmp_sa),
+ ?line {ok, MgrNode} = start_node(snmp_mgr),
+
+
+ %% --
+ %% Create necessary files
+ %%
+
+ Dir = ?config(priv_dir, Config),
+ ?DBG("init_all -> Dir ~p", [Dir]),
+
+ DataDir = ?config(data_dir, Config),
+ ?DBG("init_all -> DataDir ~p", [DataDir]),
+
+ file:make_dir(MgrDir = filename:join(Dir, "mgr_dir/")),
+ ?DBG("init_all -> MgrDir ~p", [MgrDir]),
+
+ file:make_dir(AgentDir = filename:join(Dir, "agent_dir/")),
+ ?DBG("init_all -> AgentDir ~p", [AgentDir]),
+
+ file:make_dir(SaDir = filename:join(Dir, "sa_dir/")),
+ ?DBG("init_all -> SaDir ~p", [SaDir]),
+
+
+ %% --
+ %% Start and initiate mnesia
+ %%
+
+ ?DBG("init_all -> load application mnesia", []),
+ ?line ok = application:load(mnesia),
+
+ ?DBG("init_all -> load application mnesia on node ~p", [SaNode]),
+ ?line ok = rpc:call(SaNode, application, load, [mnesia]),
+
+ ?DBG("init_all -> application mnesia: set_env dir",[]),
+ ?line application_controller:set_env(mnesia, dir,
+ filename:join(Dir, "Mnesia1")),
+
+ ?DBG("init_all -> application mnesia: set_env dir on node ~p",[SaNode]),
+ ?line rpc:call(SaNode, application_controller, set_env,
+ [mnesia, dir, filename:join(Dir, "Mnesia2")]),
+
+ ?DBG("init_all -> create mnesia schema",[]),
+ ?line ok = mnesia:create_schema([SaNode, node()]),
+
+ ?DBG("init_all -> start application mnesia",[]),
+ ?line ok = application:start(mnesia),
+
+ ?DBG("init_all -> start application mnesia on ~p",[SaNode]),
+ ?line ok = rpc:call(SaNode, application, start, [mnesia]),
+ Ip = ?LOCALHOST(),
+ [{snmp_sa, SaNode},
+ {snmp_mgr, MgrNode},
+ {agent_dir, AgentDir ++ "/"},
+ {mgr_dir, MgrDir ++ "/"},
+ {sa_dir, SaDir ++ "/"},
+ {mib_dir, DataDir},
+ {ip, Ip} |
+ Config].
+
+finish_all(Config) when list(Config) ->
+ SaNode = ?config(snmp_sa, Config),
+ MgrNode = ?config(snmp_mgr, Config),
+ stop_node(SaNode),
+ stop_node(MgrNode),
+ application:stop(mnesia).
+
+start_v1_agent(Config) when list(Config) ->
+ start_agent(Config, [v1]).
+
+start_v1_agent(Config,Opts) when list(Config), list(Opts) ->
+ start_agent(Config, [v1], Opts).
+
+start_v2_agent(Config) when list(Config) ->
+ start_agent(Config, [v2]).
+
+start_v3_agent(Config) when list(Config) ->
+ start_agent(Config, [v3]).
+
+start_bilingual_agent(Config) when list(Config) ->
+ start_agent(Config, [v1,v2]).
+
+start_multi_threaded_agent(Config) when list(Config) ->
+ start_agent(Config, [v2], [{snmp_multi_threaded, true}]).
+
+stop_agent(Config) when list(Config) ->
+ ?LOG("stop_agent -> entry with"
+ "~n Config: ~p",[Config]),
+
+ {Sup, Par} = ?config(snmp_sup, Config),
+ ?DBG("stop_agent -> attempt to stop (sup) ~p"
+ "~n Sup: ~p"
+ "~n Par: ~p",
+ [Sup,
+ (catch process_info(Sup)),
+ (catch process_info(Par))]),
+ stop_sup(Sup, Par),
+
+ {Sup2, Par2} = ?config(snmp_sub, Config),
+ ?DBG("stop_agent -> attempt to stop (sub) ~p"
+ "~n Sup2: ~p"
+ "~n Par2: ~p",
+ [Sup2,
+ (catch process_info(Sup2)),
+ (catch process_info(Par2))]),
+ stop_sup(Sup2, Par2),
+
+ ?DBG("stop_agent -> done - now cleanup config", []),
+ C1 = lists:keydelete(snmp_sup, 1, Config),
+ lists:keydelete(snmp_sub, 1, C1).
+
+
+stop_sup(Pid, _) when node(Pid) == node() ->
+ case (catch process_info(Pid)) of
+ PI when list(PI) ->
+ ?LOG("stop_sup -> attempt to stop ~p", [Pid]),
+ Ref = erlang:monitor(process, Pid),
+ exit(Pid, kill),
+ await_stopped(Pid, Ref);
+ {'EXIT', _Reason} ->
+ ?LOG("stop_sup -> ~p not running", [Pid]),
+ ok
+ end;
+stop_sup(Pid, _) ->
+ ?LOG("stop_sup -> attempt to stop ~p", [Pid]),
+ Ref = erlang:monitor(process, Pid),
+ ?LOG("stop_sup -> Ref: ~p", [Ref]),
+ %% Pid ! {'EXIT', Parent, shutdown}, % usch
+ exit(Pid, kill),
+ await_stopped(Pid, Ref).
+
+await_stopped(Pid, Ref) ->
+ receive
+ {'DOWN', Ref, process, Pid, _Reason} ->
+ ?DBG("received down message for ~p", [Pid]),
+ ok
+ after 10000 ->
+ ?INF("await_stopped -> timeout for ~p",[Pid]),
+ erlang:demonitor(Ref),
+ ?FAIL({failed_stop,Pid})
+ end.
+
+
+start_agent(Config, Vsn) ->
+ start_agent(Config, Vsn, []).
+start_agent(Config, Vsn, Opts) ->
+ ?LOG("start_agent -> entry (~p) with"
+ "~n Config: ~p"
+ "~n Vsn: ~p"
+ "~n Opts: ~p",[node(), Config, Vsn, Opts]),
+
+ ?line AgentDir = ?config(agent_dir, Config),
+ ?line SaNode = ?config(snmp_sa, Config),
+
+ snmp_app_env_init(vsn_init(Vsn) ++
+ [{audit_trail_log, read_write_log},
+ {audit_trail_log_dir, AgentDir},
+ {audit_trail_log_size, {10240, 10}},
+ {force_config_reload, false},
+ {snmp_agent_type, master},
+ {snmp_config_dir, AgentDir},
+ {snmp_db_dir, AgentDir},
+ {snmp_local_db_auto_repair, true},
+ {snmp_master_agent_verbosity, trace},
+ {snmp_supervisor_verbosity, trace},
+ {snmp_mibserver_verbosity, trace},
+ {snmp_symbolic_store_verbosity, trace},
+ {snmp_note_store_verbosity, trace},
+ {snmp_net_if_verbosity, trace}],
+ Opts),
+
+
+ process_flag(trap_exit,true),
+
+ {ok, AppSup} = snmp_app_sup:start_link(),
+ unlink(AppSup),
+ ?DBG("start_agent -> snmp app supervisor: ~p",[AppSup]),
+
+ ?DBG("start_agent -> start master agent (old style)",[]),
+ Sup = case (catch snmpa_app:start(normal)) of
+ {ok, S} ->
+ ?DBG("start_agent -> started, Sup: ~p",[S]),
+ S;
+
+ Else ->
+ ?DBG("start_agent -> unknown result: ~n~p",[Else]),
+ %% Get info about the apps we depend on
+ MnesiaInfo = mnesia_running(),
+ ?FAIL({start_failed,Else,MnesiaInfo})
+ end,
+
+ ?DBG("start_agent -> unlink from supervisor",[]),
+ ?line unlink(Sup),
+ ?line SaDir = ?config(sa_dir, Config),
+ ?DBG("start_agent -> (rpc) start sub on ~p",[SaNode]),
+ ?line {ok, Sub} = rpc:call(SaNode, ?MODULE, start_sub, [SaDir]),
+ ?DBG("start_agent -> done",[]),
+ ?line [{snmp_sup, {Sup, self()}}, {snmp_sub, Sub} | Config].
+
+
+vsn_init(Vsn) ->
+ vsn_init([v1,v2,v3], Vsn, []).
+
+vsn_init([], _Vsn, Acc) ->
+ Acc;
+vsn_init([V|Vsns], Vsn, Acc) ->
+ case lists:member(V, Vsn) of
+ true ->
+ vsn_init(Vsns, Vsn, [{V, true}|Acc]);
+ false ->
+ vsn_init(Vsns, Vsn, [{V, false}|Acc])
+ end.
+
+snmp_app_env_init(Env0, Opts) ->
+ ?DBG("snmp_app_env_init -> unload snmp",[]),
+ ?line application:unload(snmp),
+ ?DBG("snmp_app_env_init -> load snmp",[]),
+ ?line application:load(snmp),
+ ?DBG("snmp_app_env_init -> initiate (snmp) application env",[]),
+ F1 = fun({Key,Val} = New, Acc0) ->
+ ?DBG("snmp_app_env_init -> "
+ "updating setting ~p to ~p", [Key, Val]),
+ case lists:keyreplace(Key, 1, Acc0, New) of
+ Acc0 ->
+ [New|Acc0];
+ Acc ->
+ Acc
+ end
+ end,
+ Env = lists:foldr(F1, Env0, Opts),
+ ?DBG("snmp_app_env_init -> Env: ~p",[Env]),
+ F2 = fun({Key,Val}) ->
+ ?DBG("snmp_app_env_init -> setting ~p to ~p",[Key, Val]),
+ application_controller:set_env(snmp, Key, Val)
+ end,
+ lists:foreach(F2, Env).
+
+
+
+
+%% Test if application is running
+mnesia_running() -> ?IS_MNESIA_RUNNING().
+crypto_running() -> ?IS_CRYPTO_RUNNING().
+
+
+start_sub(Dir) ->
+ ?DBG("start_sub -> entry",[]),
+ Opts = [{db_dir, Dir},
+ {supervisor, [{verbosity, trace}]}],
+ %% BMK BMK
+% {ok, P} = snmp_supervisor:start_sub(Dir),
+ {ok, P} = snmpa_supervisor:start_sub_sup(Opts),
+ unlink(P),
+ {ok, {P, self()}}.
+
+create_tables(SaNode) ->
+ ?line {atomic, ok} = mnesia:create_table([{name, friendsTable2},
+ {ram_copies, [SaNode]},
+ {snmp, [{key, integer}]},
+ {attributes, [a1,a2,a3]}]),
+ ?line {atomic, ok} = mnesia:create_table([{name, kompissTable2},
+ {ram_copies, [SaNode]},
+ {snmp, [{key, integer}]},
+ {attributes, [a1,a2,a3]}]),
+ ?line {atomic, ok} = mnesia:create_table([{name, snmp_variables},
+ {attributes, [a1,a2]}]).
+
+delete_tables() ->
+ mnesia:delete_table(friendsTable2),
+ mnesia:delete_table(kompissTable2),
+ mnesia:delete_table(snmp_variables).
+
+%% Creation is done in runtime!
+delete_mib_storage_mnesia_tables() ->
+ mnesia:delete_table(snmpa_mib_data),
+ mnesia:delete_table(snmpa_mib_tree),
+ mnesia:delete_table(snmpa_symbolic_store).
+
+%%-----------------------------------------------------------------
+%% A test case is always one of:
+%% - v1 specific case
+%% - v2 specific case
+%% - v1 and v2 case
+%% All v1 specific cases are prefixed with v1_, and all v2 with
+%% v2_. E.g. v1_trap/v2_trap.
+%%
+%% All other cases are shared. However, the testserver uses the name
+%% of the case to generate a file for that case. The same case cannot
+%% be used in different configurations in the same suite. Therefore
+%% all these functions exists in two variants, the base function
+%% <base>, and a second version <base>_2. There may be several
+%% versions as well, <base>_N.
+%%-----------------------------------------------------------------
+mib_storage(suite) -> [
+ mib_storage_ets,
+ mib_storage_dets,
+ mib_storage_mnesia,
+ mib_storage_size_check_ets,
+ mib_storage_size_check_dets,
+ mib_storage_size_check_mnesia,
+ mib_storage_varm_dets,
+ mib_storage_varm_mnesia
+ ].
+
+mib_storage_ets(suite) -> {req, [], {conf, init_mib_storage_ets,
+ mib_storage_ets_cases(),
+ finish_mib_storage_ets}}.
+
+mib_storage_dets(suite) -> {req, [], {conf, init_mib_storage_dets,
+ mib_storage_dets_cases(),
+ finish_mib_storage_dets}}.
+
+mib_storage_mnesia(suite) -> {req, [], {conf, init_mib_storage_mnesia,
+ mib_storage_mnesia_cases(),
+ finish_mib_storage_mnesia}}.
+
+mib_storage_size_check_ets(suite) ->
+ {req, [], {conf,
+ init_size_check_mse,
+ mse_size_check_cases(),
+ finish_size_check_mse}}.
+
+mib_storage_size_check_dets(suite) ->
+ {req, [], {conf,
+ init_size_check_msd,
+ msd_size_check_cases(),
+ finish_size_check_msd}}.
+
+mib_storage_size_check_mnesia(suite) ->
+ {req, [], {conf,
+ init_size_check_msm,
+ msm_size_check_cases(),
+ finish_size_check_msm}}.
+
+mib_storage_varm_dets(suite) ->
+ {req, [], {conf,
+ init_varm_mib_storage_dets,
+ varm_mib_storage_dets_cases(),
+ finish_varm_mib_storage_dets}}.
+
+mib_storage_varm_mnesia(suite) ->
+ {req, [], {conf,
+ init_varm_mib_storage_mnesia,
+ varm_mib_storage_mnesia_cases(),
+ finish_varm_mib_storage_mnesia}}.
+
+mib_storage_ets_cases() ->
+ [
+ mse_simple,
+ mse_v1_processing,
+ mse_big,
+ mse_big2,
+ mse_loop_mib,
+ mse_api,
+ mse_sa_register,
+ mse_v1_trap,
+ mse_sa_error,
+ mse_next_across_sa,
+ mse_undo,
+ mse_standard_mib,
+ mse_community_mib,
+ mse_framework_mib,
+ mse_target_mib,
+ mse_notification_mib,
+ mse_view_based_acm_mib,
+ mse_sparse_table,
+ mse_me_of,
+ mse_mib_of].
+
+mib_storage_dets_cases() ->
+ [
+ msd_simple,
+ msd_v1_processing,
+ msd_big,
+ msd_big2,
+ msd_loop_mib,
+ msd_api,
+ msd_sa_register,
+ msd_v1_trap,
+ msd_sa_error,
+ msd_next_across_sa,
+ msd_undo,
+ msd_standard_mib,
+ msd_community_mib,
+ msd_framework_mib,
+ msd_target_mib,
+ msd_notification_mib,
+ msd_view_based_acm_mib,
+ msd_sparse_table,
+ msd_me_of,
+ msd_mib_of
+ ].
+
+mib_storage_mnesia_cases() ->
+ [
+ msm_simple,
+ msm_v1_processing,
+ msm_big,
+ msm_big2,
+ msm_loop_mib,
+ msm_api,
+ msm_sa_register,
+ msm_v1_trap,
+ msm_sa_error,
+ msm_next_across_sa,
+ msm_undo,
+ msm_standard_mib,
+ msm_community_mib,
+ msm_framework_mib,
+ msm_target_mib,
+ msm_notification_mib,
+ msm_view_based_acm_mib,
+ msm_sparse_table,
+ msm_me_of,
+ msm_mib_of
+ ].
+
+mse_size_check_cases() ->
+ [mse_size_check].
+
+msd_size_check_cases() ->
+ [msd_size_check].
+
+msm_size_check_cases() ->
+ [msm_size_check].
+
+varm_mib_storage_dets_cases() ->
+ [msd_varm_mib_start].
+
+varm_mib_storage_mnesia_cases() ->
+ [msm_varm_mib_start].
+
+init_mib_storage_ets(Config) when list(Config) ->
+ ?LOG("init_mib_storage_ets -> entry", []),
+ MibStorage = {snmp_mib_storage,ets},
+ init_ms(Config, [MibStorage]).
+
+init_mib_storage_dets(Config) when list(Config) ->
+ ?LOG("init_mib_storage_ets -> entry", []),
+ ?line AgentDir = ?GCONF(agent_dir, Config),
+ MibStorage = {snmp_mib_storage,{dets,AgentDir}},
+ init_ms(Config, [MibStorage]).
+
+init_mib_storage_mnesia(Config) when list(Config) ->
+ ?LOG("init_mib_storage_ets -> entry", []),
+ MibStorage = {snmp_mib_storage,{mnesia,[]}},
+ init_ms(Config, [MibStorage]).
+
+init_ms(Config, Opts) when list(Config) ->
+ ?LOG("init_mib_storage_ets -> entry", []),
+ ?line SaNode = ?GCONF(snmp_sa, Config),
+ ?line create_tables(SaNode),
+ ?line AgentDir = ?GCONF(agent_dir, Config),
+ ?line MgrDir = ?GCONF(mgr_dir, Config),
+ ?line Ip = ?GCONF(ip, Config),
+ ?line config([v1], MgrDir, AgentDir, tuple_to_list(Ip), tuple_to_list(Ip)),
+ MasterAgentVerbosity = {snmp_master_agent_verbosity, trace},
+ MibsVerbosity = {snmp_mibserver_verbosity, trace},
+ SymStoreVerbosity = {snmp_symbolic_store_verbosity, trace},
+ Opts1 = [MasterAgentVerbosity,MibsVerbosity,SymStoreVerbosity|Opts],
+ [{vsn, v1} | start_v1_agent(Config,Opts1)].
+
+init_size_check_mse(Config) when list(Config) ->
+ MibStorage = {snmp_mib_storage, ets},
+ init_size_check_ms(Config, [MibStorage]).
+
+init_size_check_msd(Config) when list(Config) ->
+ AgentDir = ?GCONF(agent_dir, Config),
+ MibStorage = {snmp_mib_storage, {dets, AgentDir}},
+ init_size_check_ms(Config, [MibStorage]).
+
+init_size_check_msm(Config) when list(Config) ->
+ MibStorage = {snmp_mib_storage, {mnesia,[]}},
+ init_size_check_ms(Config, [MibStorage]).
+
+init_size_check_ms(Config, Opts) when list(Config) ->
+ SaNode = ?GCONF(snmp_sa, Config),
+ %% We are using v3 here, so crypto must be supported or else...
+ case ?CRYPTO_START() of
+ ok ->
+ case ?CRYPTO_SUPPORT() of
+ {no, Reason} ->
+ ?SKIP({unsupported_encryption, Reason});
+ yes ->
+ ok
+ end;
+ {error, Reason} ->
+ ?SKIP({failed_starting_crypto, Reason})
+ end,
+ create_tables(SaNode),
+ AgentDir = ?GCONF(agent_dir, Config),
+ MgrDir = ?GCONF(mgr_dir, Config),
+ Ip = ?GCONF(ip, Config),
+ ?line ok =
+ config([v3], MgrDir, AgentDir, tuple_to_list(Ip), tuple_to_list(Ip)),
+ [{vsn, v3} | start_agent(Config, [v3], Opts)].
+
+init_varm_mib_storage_dets(Config) when list(Config) ->
+ ?LOG("init_varm_mib_storage_dets -> entry", []),
+ ?line SaNode = ?GCONF(snmp_sa, Config),
+ ?line create_tables(SaNode),
+ ?line AgentDir = ?GCONF(agent_dir, Config),
+ ?line MgrDir = ?GCONF(mgr_dir, Config),
+ ?line Ip = ?GCONF(ip, Config),
+ ?line config([v1], MgrDir, AgentDir, tuple_to_list(Ip), tuple_to_list(Ip)),
+ MibStorage = {snmp_mib_storage,{dets,AgentDir}},
+ MasterAgentVerbosity = {snmp_master_agent_verbosity, trace},
+ MibsVerbosity = {snmp_mibserver_verbosity, trace},
+ SymStoreVerbosity = {snmp_symbolic_store_verbosity, trace},
+ Opts = [MibStorage,MasterAgentVerbosity,MibsVerbosity,SymStoreVerbosity],
+ [{vsn, v1}, {agent_opts,Opts} | Config].
+
+init_varm_mib_storage_mnesia(Config) when list(Config) ->
+ ?LOG("init_varm_mib_storage_mnesia -> entry", []),
+ ?line SaNode = ?GCONF(snmp_sa, Config),
+ ?line create_tables(SaNode),
+ ?line AgentDir = ?GCONF(agent_dir, Config),
+ ?line MgrDir = ?GCONF(mgr_dir, Config),
+ ?line Ip = ?GCONF(ip, Config),
+ ?line config([v1], MgrDir, AgentDir, tuple_to_list(Ip), tuple_to_list(Ip)),
+ MibStorage = {snmp_mib_storage,{mnesia,[]}},
+ MasterAgentVerbosity = {snmp_master_agent_verbosity, trace},
+ MibsVerbosity = {snmp_mibserver_verbosity, trace},
+ SymStoreVerbosity = {snmp_symbolic_store_verbosity, trace},
+ Opts = [MibStorage,MasterAgentVerbosity,MibsVerbosity,SymStoreVerbosity],
+ [{vsn, v1}, {agent_opts,Opts} | Config].
+
+finish_mib_storage_ets(Config) when list(Config) ->
+ ?LOG("finish_mib_storage_ets -> entry", []),
+ delete_tables(),
+ C1 = stop_agent(Config),
+ delete_files(C1),
+ C2 = lists:keydelete(vsn, 1, C1),
+ lists:keydelete(agent_opts, 1, C2).
+
+finish_mib_storage_dets(Config) when list(Config) ->
+ ?LOG("finish_mib_storage_dets -> entry", []),
+ delete_tables(),
+ C1 = stop_agent(Config),
+ delete_files(C1),
+ C2 = lists:keydelete(vsn, 1, C1),
+ lists:keydelete(agent_opts, 1, C2).
+
+finish_mib_storage_mnesia(Config) when list(Config) ->
+ ?LOG("finish_mib_storage_mnesia -> entry", []),
+ delete_tables(),
+ delete_mib_storage_mnesia_tables(),
+ C1 = stop_agent(Config),
+ delete_files(C1),
+ C2 = lists:keydelete(vsn, 1, C1),
+ lists:keydelete(agent_opts, 1, C2).
+
+finish_varm_mib_storage_dets(Config) when list(Config) ->
+ ?LOG("finish_varm_mib_storage_dets -> entry", []),
+ delete_tables(),
+ %% C1 = stop_agent(Config), % In case something went wrong...
+ delete_files(Config),
+ C2 = lists:keydelete(vsn, 1, Config),
+ lists:keydelete(agent_opts, 1, C2).
+
+finish_varm_mib_storage_mnesia(Config) when list(Config) ->
+ ?LOG("finish_varm_mib_storage_mnesia -> entry", []),
+ delete_tables(),
+ delete_mib_storage_mnesia_tables(),
+ %% C1 = stop_agent(Config), % In case something went wrong...
+ delete_files(Config),
+ C2 = lists:keydelete(vsn, 1, Config),
+ lists:keydelete(agent_opts, 1, C2).
+
+finish_size_check_mse(Config) when list(Config) ->
+ finish_size_check_ms(Config).
+
+finish_size_check_msd(Config) when list(Config) ->
+ finish_size_check_ms(Config).
+
+finish_size_check_msm(Config) when list(Config) ->
+ finish_size_check_ms(Config).
+
+finish_size_check_ms(Config) when list(Config) ->
+ delete_tables(),
+ C1 = stop_agent(Config),
+ delete_files(C1),
+ lists:keydelete(vsn, 1, C1).
+
+
+%% These are just interface functions to fool the test server
+mse_simple(X) -> simple(X).
+mse_v1_processing(X) -> v1_processing(X).
+mse_big(X) -> big(X).
+mse_big2(X) -> big2(X).
+mse_loop_mib(X) -> loop_mib(X).
+mse_api(X) -> api(X).
+mse_sa_register(X) -> sa_register(X).
+mse_v1_trap(X) -> v1_trap(X).
+mse_sa_error(X) -> sa_error(X).
+mse_next_across_sa(X) -> next_across_sa(X).
+mse_undo(X) -> undo(X).
+mse_standard_mib(X) -> snmp_standard_mib(X).
+mse_community_mib(X) -> snmp_community_mib(X).
+mse_framework_mib(X) -> snmp_framework_mib(X).
+mse_target_mib(X) -> snmp_target_mib(X).
+mse_notification_mib(X) -> snmp_notification_mib(X).
+mse_view_based_acm_mib(X) -> snmp_view_based_acm_mib(X).
+mse_sparse_table(X) -> sparse_table(X).
+mse_me_of(X) -> ms_me_of(X).
+mse_mib_of(X) -> ms_mib_of(X).
+
+msd_simple(X) -> simple(X).
+msd_v1_processing(X) -> v1_processing(X).
+msd_big(X) -> big(X).
+msd_big2(X) -> big2(X).
+msd_loop_mib(X) -> loop_mib(X).
+msd_api(X) -> api(X).
+msd_sa_register(X) -> sa_register(X).
+msd_v1_trap(X) -> v1_trap(X).
+msd_sa_error(X) -> sa_error(X).
+msd_next_across_sa(X) -> next_across_sa(X).
+msd_undo(X) -> undo(X).
+msd_standard_mib(X) -> snmp_standard_mib(X).
+msd_community_mib(X) -> snmp_community_mib(X).
+msd_framework_mib(X) -> snmp_framework_mib(X).
+msd_target_mib(X) -> snmp_target_mib(X).
+msd_notification_mib(X) -> snmp_notification_mib(X).
+msd_view_based_acm_mib(X) -> snmp_view_based_acm_mib(X).
+msd_sparse_table(X) -> sparse_table(X).
+msd_me_of(X) -> ms_me_of(X).
+msd_mib_of(X) -> ms_mib_of(X).
+
+msm_simple(X) -> simple(X).
+msm_v1_processing(X) -> v1_processing(X).
+msm_big(X) -> big(X).
+msm_big2(X) -> big2(X).
+msm_loop_mib(X) -> loop_mib(X).
+msm_api(X) -> api(X).
+msm_sa_register(X) -> sa_register(X).
+msm_v1_trap(X) -> v1_trap(X).
+msm_sa_error(X) -> sa_error(X).
+msm_next_across_sa(X) -> next_across_sa(X).
+msm_undo(X) -> undo(X).
+msm_standard_mib(X) -> snmp_standard_mib(X).
+msm_community_mib(X) -> snmp_community_mib(X).
+msm_framework_mib(X) -> snmp_framework_mib(X).
+msm_target_mib(X) -> snmp_target_mib(X).
+msm_notification_mib(X) -> snmp_notification_mib(X).
+msm_view_based_acm_mib(X) -> snmp_view_based_acm_mib(X).
+msm_sparse_table(X) -> sparse_table(X).
+msm_me_of(X) -> ms_me_of(X).
+msm_mib_of(X) -> ms_mib_of(X).
+
+
+mse_size_check(X) -> p("mse_size_check..."), ms_size_check(X).
+msd_size_check(X) -> p("msd_size_check..."), ms_size_check(X).
+msm_size_check(X) -> p("msm_size_check..."), ms_size_check(X).
+
+msd_varm_mib_start(X) -> p("msd_varm_mib_start..."), varm_mib_start(X).
+msm_varm_mib_start(X) -> p("msm_varm_mib_start..."), varm_mib_start(X).
+
+ms_size_check(suite) -> [];
+ms_size_check(Config) when list(Config) ->
+ p("ms_size_check..."),
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?LOG("mib server size check...", []),
+
+ ?line load_master("Test2"),
+ ?line load_master("TestTrap"),
+ ?line load_master("TestTrapv2"),
+ ?line load_master_std("OTP-SNMPEA-MIB"),
+ ?line load_master_std("SNMP-COMMUNITY-MIB"),
+ ?line load_master_std("SNMP-FRAMEWORK-MIB"),
+ ?line load_master_std("SNMP-MPD-MIB"),
+ ?line load_master_std("SNMP-NOTIFICATION-MIB"),
+ ?line load_master_std("SNMP-TARGET-MIB"),
+ ?line load_master_std("SNMP-USER-BASED-SM-MIB"),
+ ?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"),
+ ?line load_master_std("SNMPv2-MIB"),
+ ?line load_master_std("SNMPv2-TM"),
+
+ ?SLEEP(2000),
+
+ ?line display_memory_usage(),
+
+ ?line unload_master("OTP-SNMPEA-MIB"),
+ ?line unload_master("SNMP-COMMUNITY-MIB"),
+ ?line unload_master("SNMP-FRAMEWORK-MIB"),
+ ?line unload_master("SNMP-MPD-MIB"),
+ ?line unload_master("SNMP-NOTIFICATION-MIB"),
+ ?line unload_master("SNMP-TARGET-MIB"),
+ ?line unload_master("SNMP-USER-BASED-SM-MIB"),
+ ?line unload_master("SNMP-VIEW-BASED-ACM-MIB"),
+ ?line unload_master("SNMPv2-MIB"),
+ ?line unload_master("SNMPv2-TM"),
+
+ ?line unload_master("TestTrapv2"),
+ ?line unload_master("TestTrap"),
+ ?line unload_master("Test2"),
+
+ ok.
+
+
+varm_mib_start(suite) -> [];
+varm_mib_start(Config) when list(Config) ->
+ p("varm_mib_start..."),
+ ?LOG("varm_mib_start -> entry", []),
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ %% Start the agent
+ Opts = ?GCONF(agent_opts, Config),
+ Config1 = start_v1_agent(Config, Opts),
+
+ %% Sleep some in order for the agent to start properly
+ ?DBG("varm_mib_start -> sleep some (before loading mobs)", []),
+ ?SLEEP(5000),
+
+ %% Load all the mibs
+ HardwiredMibs = loaded_mibs(),
+ ?DBG("varm_mib_start -> load all mibs", []),
+ ?line load_master_std("SNMP-COMMUNITY-MIB"),
+ ?line load_master_std("SNMP-FRAMEWORK-MIB"),
+ ?line load_master_std("SNMP-TARGET-MIB"),
+ ?line load_master_std("SNMP-NOTIFICATION-MIB"),
+
+ %% Unload the hardwired mibs
+ ?DBG("varm_mib_start -> sleep some (before unloading hardwired mibs)", []),
+ ?SLEEP(1000),
+ ?DBG("varm_mib_start -> unload (hardwired) mibs", []),
+ ?line unload_mibs(HardwiredMibs), %% unload hardwired
+
+ ?DBG("varm_mib_start -> sleep some (before stopping agent)", []),
+ ?SLEEP(1000),
+
+ %% Stop the agent (without deleting the stored files)
+ ?DBG("varm_mib_start -> stop the agent", []),
+ Config2 = stop_agent(Config1),
+
+ %% Sleep some in order for the agent to stop properly
+ ?DBG("varm_mib_start -> sleep some (before re-starting the agent)", []),
+ ?SLEEP(5000),
+
+ %% Start the agent (again)
+ ?DBG("varm_mib_start -> start the agent", []),
+ Config3 = start_v1_agent(Config2, Opts),
+
+ ?DBG("varm_mib_start -> sleep some (before starting tests)", []),
+ ?SLEEP(5000),
+
+ %% Perform the test(s)
+ ?DBG("varm_mib_start -> perform the tests", []),
+ try_test(snmp_community_mib),
+ try_test(snmp_framework_mib),
+ try_test(snmp_target_mib),
+ try_test(snmp_notification_mib),
+
+ %% Stop the agent (without deleting the stored files)
+ ?DBG("varm_mib_start -> stop the agent", []),
+ stop_agent(Config3),
+ ok.
+
+
+-define(snmpTrapCommunity_instance, [1,3,6,1,6,3,18,1,4,0]).
+-define(vacmViewSpinLock_instance, [1,3,6,1,6,3,16,1,5,1,0]).
+-define(usmStatsNotInTimeWindows_instance, [1,3,6,1,6,3,15,1,1,2,0]).
+
+ms_me_of(suite) -> [];
+ms_me_of(Config) when list(Config) ->
+ p("ms_me_of..."),
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ ?line load_master("Test2"),
+ ?line load_master("TestTrap"),
+ ?line load_master("TestTrapv2"),
+ ?line load_master_std("OTP-SNMPEA-MIB"),
+ ?line load_master_std("SNMP-COMMUNITY-MIB"),
+ ?line load_master_std("SNMP-FRAMEWORK-MIB"),
+ ?line load_master_std("SNMP-MPD-MIB"),
+ ?line load_master_std("SNMP-NOTIFICATION-MIB"),
+ ?line load_master_std("SNMP-TARGET-MIB"),
+ ?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"),
+
+ ?SLEEP(2000),
+
+ ?line display_memory_usage(),
+
+
+ ?DBG("ms_me_of -> find ~w from SNMP-COMMUNITY-MIB",
+ [?snmpTrapCommunity_instance]),
+ ?line ok = me_of(?snmpTrapCommunity_instance),
+
+ ?DBG("ms_me_of -> find ~w from SNMP-VIEW-BASED-ACM-MIB",
+ [?vacmViewSpinLock_instance]),
+ ?line ok = me_of(?vacmViewSpinLock_instance),
+
+ ?DBG("ms_me_of -> find ~w from SNMP-USER-BASED-SM-MIB",
+ [?usmStatsNotInTimeWindows_instance]),
+ ?line {error, _} = me_of(?usmStatsNotInTimeWindows_instance),
+
+
+ ?line unload_master("OTP-SNMPEA-MIB"),
+ ?line unload_master("SNMP-COMMUNITY-MIB"),
+ ?line unload_master("SNMP-FRAMEWORK-MIB"),
+ ?line unload_master("SNMP-MPD-MIB"),
+ ?line unload_master("SNMP-NOTIFICATION-MIB"),
+ ?line unload_master("SNMP-TARGET-MIB"),
+ ?line unload_master("SNMP-VIEW-BASED-ACM-MIB"),
+
+ ?line unload_master("TestTrapv2"),
+ ?line unload_master("TestTrap"),
+ ?line unload_master("Test2"),
+
+ ok.
+
+me_of(Oid) ->
+ case snmpa:me_of(Oid) of
+ {ok, #me{oid = Oid}} ->
+ ok;
+ {ok, #me{oid = OtherOid}} ->
+ case lists:reverse(Oid) of
+ [0|Rest] ->
+ case lists:reverse(Rest) of
+ OtherOid ->
+ ok;
+ AnotherOid ->
+ {error, {invalid_oid, Oid, AnotherOid}}
+ end;
+ _ ->
+ {error, {invalid_oid, Oid, OtherOid}}
+ end;
+ {error, Reason} ->
+ {error, Reason};
+ Else ->
+ {error, Else}
+ end.
+
+
+ms_mib_of(suite) -> [];
+ms_mib_of(Config) when list(Config) ->
+ p("ms_mib_of..."),
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ ?line load_master("Test2"),
+ ?line load_master("TestTrap"),
+ ?line load_master("TestTrapv2"),
+ ?line load_master_std("OTP-SNMPEA-MIB"),
+ ?line load_master_std("SNMP-COMMUNITY-MIB"),
+ ?line load_master_std("SNMP-FRAMEWORK-MIB"),
+ ?line load_master_std("SNMP-MPD-MIB"),
+ ?line load_master_std("SNMP-NOTIFICATION-MIB"),
+ ?line load_master_std("SNMP-TARGET-MIB"),
+ ?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"),
+
+ ?SLEEP(2000),
+
+ ?line display_memory_usage(),
+
+
+ ?DBG("ms_mib_of -> find ~w from SNMP-COMMUNITY-MIB",
+ [?snmpTrapCommunity_instance]),
+ ?line ok = mib_of(?snmpTrapCommunity_instance, 'SNMP-COMMUNITY-MIB'),
+
+ ?DBG("ms_mib_of -> find ~w from SNMP-VIEW-BASED-ACM-MIB",
+ [?vacmViewSpinLock_instance]),
+ ?line ok = mib_of(?vacmViewSpinLock_instance, 'SNMP-VIEW-BASED-ACM-MIB'),
+
+ ?DBG("ms_mib_of -> find ~w from SNMP-USER-BASED-SM-MIB",
+ [?usmStatsNotInTimeWindows_instance]),
+ ?line {error, _} = mib_of(?usmStatsNotInTimeWindows_instance,
+ 'SNMP-USER-BASED-SM-MIB'),
+
+
+ ?line unload_master("OTP-SNMPEA-MIB"),
+ ?line unload_master("SNMP-COMMUNITY-MIB"),
+ ?line unload_master("SNMP-FRAMEWORK-MIB"),
+ ?line unload_master("SNMP-MPD-MIB"),
+ ?line unload_master("SNMP-NOTIFICATION-MIB"),
+ ?line unload_master("SNMP-TARGET-MIB"),
+ ?line unload_master("SNMP-VIEW-BASED-ACM-MIB"),
+
+ ?line unload_master("TestTrapv2"),
+ ?line unload_master("TestTrap"),
+ ?line unload_master("Test2"),
+
+ ok.
+
+mib_of(Oid, ExpectedMibName) ->
+ ?DBG("mib_of -> entry with"
+ "~n Oid: ~p"
+ "~n ExpectedMibName: ~p", [Oid, ExpectedMibName]),
+ %% case snmpa:mib_of(Oid) of
+ MibOf = snmpa:mib_of(Oid),
+ ?DBG("mib_of -> MibOf: ~n~p", [MibOf]),
+ case MibOf of
+ {ok, ExpectedMibName} ->
+ ok;
+ {ok, OtherMibName} ->
+ {error, {invalid_mib, ExpectedMibName, OtherMibName}};
+ {error, Reason} ->
+ {error, Reason};
+ Else ->
+ ?DBG("mib_of -> Else: ~n~p", [Else]),
+ {error, Else}
+ end.
+
+
+app_info(suite) -> [];
+app_info(Config) when list(Config) ->
+ SnmpDir = app_dir(snmp),
+ SslDir = app_dir(ssl),
+ CryptoDir = app_dir(crypto),
+ Attr = snmp:module_info(attributes),
+ AppVsn =
+ case lists:keysearch(app_vsn, 1, Attr) of
+ {value, {app_vsn, V}} ->
+ V;
+ false ->
+ "undefined"
+ end,
+ io:format("Root dir: ~s~n"
+ "SNMP: Application dir: ~s~n"
+ " Application ver: ~s~n"
+ "SSL: Application dir: ~s~n"
+ "CRYPTO: Application dir: ~s~n",
+ [code:root_dir(), SnmpDir, AppVsn, SslDir, CryptoDir]),
+ ok.
+
+app_dir(App) ->
+ case code:lib_dir(App) of
+ D when list(D) ->
+ filename:basename(D);
+ {error, _Reason} ->
+ "undefined"
+ end.
+
+
+test_v1(suite) -> {req, [], {conf, init_v1, v1_cases(), finish_v1}}.
+
+%v1_cases() -> [loop_mib];
+v1_cases() ->
+ [simple,
+ db_notify_client,
+ v1_processing, big, big2, loop_mib,
+ api, subagent, mnesia, multiple_reqs,
+ sa_register, v1_trap, sa_error, next_across_sa, undo, reported_bugs,
+ standard_mibs, sparse_table, cnt_64,
+ opaque,
+ % opaque].
+
+ change_target_addr_config].
+
+init_v1(Config) when list(Config) ->
+ ?line SaNode = ?config(snmp_sa, Config),
+ ?line create_tables(SaNode),
+ ?line AgentDir = ?config(agent_dir, Config),
+ ?line MgrDir = ?config(mgr_dir, Config),
+ ?line Ip = ?config(ip, Config),
+ ?line config([v1], MgrDir, AgentDir, tuple_to_list(Ip), tuple_to_list(Ip)),
+ [{vsn, v1} | start_v1_agent(Config)].
+
+finish_v1(Config) when list(Config) ->
+ delete_tables(),
+ C1 = stop_agent(Config),
+ delete_files(C1),
+ lists:keydelete(vsn, 1, C1).
+
+test_v2(suite) -> {req, [], {conf, init_v2, v2_cases(), finish_v2}}.
+
+%v2_cases() -> [loop_mib_2];
+v2_cases() ->
+ [simple_2, v2_processing, big_2, big2_2, loop_mib_2,
+ api_2, subagent_2, mnesia_2,
+ multiple_reqs_2, sa_register_2, v2_trap, v2_inform, sa_error_2,
+ next_across_sa_2, undo_2, reported_bugs_2, standard_mibs_2,
+ v2_types, implied, sparse_table_2, cnt_64_2, opaque_2, v2_caps].
+
+init_v2(Config) when list(Config) ->
+ SaNode = ?config(snmp_sa, Config),
+ create_tables(SaNode),
+ AgentDir = ?config(agent_dir, Config),
+ MgrDir = ?config(mgr_dir, Config),
+ Ip = ?config(ip, Config),
+ config([v2], MgrDir, AgentDir, tuple_to_list(Ip), tuple_to_list(Ip)),
+ [{vsn, v2} | start_v2_agent(Config)].
+
+finish_v2(Config) when list(Config) ->
+ delete_tables(),
+ C1 = stop_agent(Config),
+ delete_files(C1),
+ lists:keydelete(vsn, 1, C1).
+
+test_v1_v2(suite) -> {req, [], {conf, init_v1_v2, v1_v2_cases(), finish_v1_v2}}.
+
+v1_v2_cases() ->
+ [simple_bi].
+
+init_v1_v2(Config) when list(Config) ->
+ SaNode = ?config(snmp_sa, Config),
+ create_tables(SaNode),
+ AgentDir = ?config(agent_dir, Config),
+ MgrDir = ?config(mgr_dir, Config),
+ Ip = ?config(ip, Config),
+ config([v1,v2], MgrDir, AgentDir, tuple_to_list(Ip), tuple_to_list(Ip)),
+ [{vsn, bilingual} | start_bilingual_agent(Config)].
+
+finish_v1_v2(Config) when list(Config) ->
+ delete_tables(),
+ C1 = stop_agent(Config),
+ delete_files(C1),
+ lists:keydelete(vsn, 1, C1).
+
+test_v3(suite) -> {req, [], {conf, init_v3, v3_cases(), finish_v3}}.
+
+%v3_cases() -> [loop_mib_3];
+v3_cases() ->
+ [simple_3, v3_processing,
+ big_3, big2_3, api_3, subagent_3, mnesia_3, loop_mib_3,
+ multiple_reqs_3, sa_register_3, v3_trap, v3_inform, sa_error_3,
+ next_across_sa_3, undo_3, reported_bugs_3, standard_mibs_3,
+ v3_security,
+ v2_types_3, implied_3, sparse_table_3, cnt_64_3, opaque_3, v2_caps_3].
+
+init_v3(Config) when list(Config) ->
+ %% Make sure crypto works, otherwise start_agent will fail
+ %% and we will be stuck with a bunch of mnesia tables for
+ %% the rest of this suite...
+ ?DBG("start_agent -> start crypto app",[]),
+ case os:type() of
+ vxworks ->
+ no_crypto;
+ _ ->
+ case ?CRYPTO_START() of
+ ok ->
+ case ?CRYPTO_SUPPORT() of
+ {no, Reason} ->
+ ?SKIP({unsupported_encryption, Reason});
+ yes ->
+ ok
+ end;
+ {error, Reason} ->
+ ?SKIP({failed_starting_crypto, Reason})
+ end
+ end,
+ SaNode = ?config(snmp_sa, Config),
+ create_tables(SaNode),
+ AgentDir = ?config(agent_dir, Config),
+ MgrDir = ?config(mgr_dir, Config),
+ Ip = ?config(ip, Config),
+ ?line ok = config([v3], MgrDir, AgentDir,
+ tuple_to_list(Ip), tuple_to_list(Ip)),
+ [{vsn, v3} | start_v3_agent(Config)].
+
+finish_v3(Config) when list(Config) ->
+ delete_tables(),
+ C1 = stop_agent(Config),
+ delete_files(C1),
+ lists:keydelete(vsn, 1, C1).
+
+test_multi_threaded(suite) -> {req, [], {conf, init_mt, mt_cases(), finish_mt}}.
+
+mt_cases() ->
+ [multi_threaded, mt_trap].
+
+init_mt(Config) when list(Config) ->
+ SaNode = ?config(snmp_sa, Config),
+ create_tables(SaNode),
+ AgentDir = ?config(agent_dir, Config),
+ MgrDir = ?config(mgr_dir, Config),
+ Ip = ?config(ip, Config),
+ ?line ok = config([v2], MgrDir, AgentDir, tuple_to_list(Ip), tuple_to_list(Ip)),
+ [{vsn, v2} | start_multi_threaded_agent(Config)].
+
+finish_mt(Config) when list(Config) ->
+ delete_tables(),
+ C1 = stop_agent(Config),
+ delete_files(C1),
+ lists:keydelete(vsn, 1, C1).
+
+%% This one *must* be run first in each case.
+init_case(Config) when list(Config) ->
+ ?DBG("init_case -> entry with"
+ "~n Config: ~p", [Config]),
+ SaNode = ?config(snmp_sa, Config),
+ MgrNode = ?config(snmp_mgr, Config),
+ MasterNode = node(),
+
+ SaHost = ?HOSTNAME(SaNode),
+ MgrHost = ?HOSTNAME(MgrNode),
+ MasterHost = ?HOSTNAME(MasterNode),
+ {ok, MasterIP} = snmp_misc:ip(MasterHost),
+ {ok, MIP} = snmp_misc:ip(MgrHost),
+ {ok, SIP} = snmp_misc:ip(SaHost),
+
+
+ put(mgr_node, MgrNode),
+ put(sa_node, SaNode),
+ put(master_node, MasterNode),
+ put(sa_host, SaHost),
+ put(mgr_host, MgrHost),
+ put(master_host, MasterHost),
+ put(mip, tuple_to_list(MIP)),
+ put(masterip , tuple_to_list(MasterIP)),
+ put(sip, tuple_to_list(SIP)),
+
+ MibDir = ?config(mib_dir, Config),
+ put(mib_dir, MibDir),
+ StdM = filename:join(code:priv_dir(snmp), "mibs") ++ "/",
+ put(std_mib_dir, StdM),
+
+ MgrDir = ?config(mgr_dir, Config),
+ put(mgr_dir, MgrDir),
+
+ put(vsn, ?config(vsn, Config)),
+ ?DBG("init_case -> exit with"
+ "~n MasterNode: ~p"
+ "~n SaNode: ~p"
+ "~n MgrNode: ~p"
+ "~n MibDir: ~p", [MasterNode, SaNode, MgrNode, MibDir]),
+ {SaNode, MgrNode, MibDir}.
+
+load_master(Mib) ->
+ ?DBG("load_master -> entry with"
+ "~n Mib: ~p", [Mib]),
+ snmpa:unload_mibs(snmp_master_agent, [Mib]), % Unload for safety
+ ok = snmpa:load_mibs(snmp_master_agent, [get(mib_dir) ++ Mib]).
+
+load_master_std(Mib) ->
+ ?DBG("load_master_std -> entry with"
+ "~n Mib: ~p", [Mib]),
+ snmpa:unload_mibs(snmp_master_agent, [Mib]), % Unload for safety
+ ok = snmpa:load_mibs(snmp_master_agent, [get(std_mib_dir) ++ Mib]).
+
+unload_master(Mib) ->
+ ?DBG("unload_master -> entry with"
+ "~n Mib: ~p", [Mib]),
+ ok = snmpa:unload_mibs(snmp_master_agent, [Mib]).
+
+loaded_mibs() ->
+ ?DBG("loaded_mibs -> entry",[]),
+ Info = snmpa:info(snmp_master_agent),
+ {value, {loaded_mibs, Mibs}} = lists:keysearch(loaded_mibs, 1, Info),
+ [atom_to_list(Mib) || {Mib,_,_} <- Mibs].
+
+unload_mibs(Mibs) ->
+ ?DBG("unload_mibs -> entry with"
+ "~n Mibs: ~p", [Mibs]),
+ ok = snmpa:unload_mibs(snmp_master_agent, Mibs).
+
+start_subagent(SaNode, RegTree, Mib) ->
+ ?DBG("start_subagent -> entry with"
+ "~n SaNode: ~p"
+ "~n RegTree: ~p"
+ "~n Mib: ~p", [SaNode, RegTree, Mib]),
+ MA = whereis(snmp_master_agent),
+ ?DBG("start_subagent -> MA: ~p", [MA]),
+ MibDir = get(mib_dir),
+ Mib1 = join(MibDir,Mib),
+ %% BMK BMK
+% case rpc:call(SaNode,snmp_supervisor,start_subagent,[MA,RegTree,[Mib1]]) of
+ case rpc:call(SaNode, snmpa_supervisor,
+ start_sub_agent, [MA, RegTree, [Mib1]]) of
+ {ok, SA} ->
+ ?DBG("start_subagent -> SA: ~p", [SA]),
+ {ok, SA};
+ Error ->
+ ?FAIL({subagent_start_failed, SaNode, Error, [MA, RegTree, Mib1]})
+ end.
+
+stop_subagent(SA) ->
+ ?DBG("stop_subagent -> entry with"
+ "~n SA: ~p", [SA]),
+ %% BNK BMK
+ %% rpc:call(node(SA), snmp_supervisor, stop_subagent, [SA]).
+ rpc:call(node(SA), snmpa_supervisor, stop_sub_agent, [SA]).
+
+%%-----------------------------------------------------------------
+%% This function takes care of the old OTP-SNMPEA-MIB.
+%% Unfortunately, the testcases were written to use the data in the
+%% internal tables, and these table are now obsolete and not used
+%% by the agent. Therefore, we emulate them by using
+%% OLD-SNMPEA-MIB, which uses the default impl. of all tables.
+%%
+%% These two rows must exist in intCommunityTable
+%% {[147,214,36,45], "public", 2, readWrite}.
+%% {[147,214,36,45], "standard trap", 2, read}.
+%% (But with the manager's IP address)
+%%
+%%-----------------------------------------------------------------
+init_old() ->
+ snmpa_local_db:table_create_row(intCommunityTable,
+ get(mip) ++ [6 | "public"],
+ {get(mip), "public", 2, 2}),
+ snmpa_local_db:table_create_row(intCommunityTable,
+ get(mip) ++ [13 | "standard trap"],
+ {get(mip), "standard trap", 2, 1}),
+ snmpa_local_db:variable_set(intAgentIpAddress, [127,0,0,1]).
+
+
+
+simple(suite) -> [];
+simple(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ try_test(simple_standard_test).
+
+simple_2(X) -> simple(X).
+
+simple_bi(suite) -> [];
+simple_bi(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ put(vsn, v1), % First, try v1 manager
+ try_test(simple_standard_test),
+
+ put(vsn, v2), % Then, try v2 manager
+ try_test(simple_standard_test).
+
+simple_3(X) ->
+ simple(X).
+
+big(suite) -> [];
+big(Config) when list(Config) ->
+ ?DBG("big -> entry", []),
+ {SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ p("Starting subagent..."),
+ ?line pong = net_adm:ping(SaNode),
+
+ ?line {ok, SA} = start_subagent(SaNode, ?klas1, "Klas1"),
+ ?DBG("big -> SA: ~p", [SA]),
+ ?line load_master("OLD-SNMPEA-MIB"),
+ ?line init_old(),
+ try_test(big_test),
+ ?line stop_subagent(SA),
+ ?line unload_master("OLD-SNMPEA-MIB").
+
+big_2(X) -> big(X).
+
+big_3(X) -> big(X).
+
+
+big2(suite) -> [];
+big2(Config) when list(Config) ->
+ %% This is exactly the same tests as 'big', but with the
+ %% v2 equivalent of the mibs.
+ {SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ p("Starting subagent..."),
+ ?line pong = net_adm:ping(SaNode),
+
+ ?line {ok, SA} = start_subagent(SaNode, ?klas1, "Klas1-v2"),
+ ?line load_master("OLD-SNMPEA-MIB-v2"),
+ ?line init_old(),
+ try_test(big_test),
+ ?line stop_subagent(SA),
+ ?line unload_master("OLD-SNMPEA-MIB-v2").
+
+big2_2(X) -> big2(X).
+
+big2_3(X) -> big2(X).
+
+
+multi_threaded(suite) -> [];
+multi_threaded(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ ?line load_master("Test1"),
+ try_test(multi_threaded_test),
+ ?line unload_master("Test1").
+
+mt_trap(suite) -> [];
+mt_trap(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ MA = whereis(snmp_master_agent),
+
+ ?line load_master("Test1"),
+ ?line load_master("TestTrapv2"),
+ try_test(mt_trap_test, [MA]),
+ ?line unload_master("TestTrapv2"),
+ ?line unload_master("Test1").
+
+v2_types(suite) -> [];
+v2_types(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ ?line load_master("Test1"),
+ try_test(types_v2_test),
+ ?line unload_master("Test1").
+
+v2_types_3(X) -> v2_types(X).
+
+
+implied(suite) -> [];
+implied(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ MA = whereis(snmp_master_agent),
+
+ ?line load_master("Test1"),
+ try_test(implied_test,[MA]),
+ ?line unload_master("Test1").
+
+implied_3(X) -> implied(X).
+
+
+sparse_table(suite) -> [];
+sparse_table(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ ?line load_master("Test1"),
+ try_test(sparse_table_test),
+ ?line unload_master("Test1").
+
+sparse_table_2(X) -> sparse_table(X).
+
+sparse_table_3(X) -> sparse_table(X).
+
+cnt_64(suite) -> [];
+cnt_64(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ MA = whereis(snmp_master_agent),
+
+ ?line load_master("Test1"),
+ try_test(cnt_64_test, [MA]),
+ ?line unload_master("Test1").
+
+cnt_64_2(X) -> cnt_64(X).
+
+cnt_64_3(X) -> cnt_64(X).
+
+opaque(suite) -> [];
+opaque(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ ?line load_master("Test1"),
+ try_test(opaque_test),
+ ?line unload_master("Test1").
+
+opaque_2(X) -> opaque(X).
+
+opaque_3(X) -> opaque(X).
+
+
+change_target_addr_config(suite) -> [];
+change_target_addr_config(Config) when list(Config) ->
+ p("Testing changing target address config..."),
+ ?LOG("change_target_addr_config -> entry",[]),
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ put(sname,snmp_suite),
+ put(verbosity,trace),
+
+ MA = whereis(snmp_master_agent),
+
+ ?LOG("change_target_addr_config -> load TestTrap",[]),
+ ?line load_master("TestTrap"),
+
+ ?LOG("change_target_addr_config -> set trace verbosity for local_db",[]),
+ ?line snmpa:verbosity(local_db,trace),
+
+ %% First send some traps that will arive att the original manager
+ ?LOG("change_target_addr_config -> send trap",[]),
+ try_test(ma_trap1, [MA]),
+
+ ?LOG("change_target_addr_config -> set silence verbosity for local_db",[]),
+ ?line snmpa:verbosity(local_db,silence),
+
+ %% Start new dummy listener
+ ?LOG("change_target_addr_config -> start dummy manager",[]),
+ ?line {ok,Pid,NewPort} = dummy_manager_start(MA),
+
+ %% Reconfigure
+ ?LOG("change_target_addr_config -> reconfigure",[]),
+ AgentDir = ?config(agent_dir, Config),
+ ?line rewrite_target_addr_conf(AgentDir, NewPort),
+ ?line snmp_target_mib:reconfigure(AgentDir),
+
+ %% Send the trap again
+ ?LOG("change_target_addr_config -> send trap again",[]),
+ catch dummy_manager_send_trap2(Pid),
+
+ ?LOG("change_target_addr_config -> await trap ack",[]),
+ catch dummy_manager_await_trap2_ack(),
+
+ ?LOG("change_target_addr_config -> stop dummy manager",[]),
+ ?line ok = dummy_manager_stop(Pid),
+
+ ?LOG("change_target_addr_config -> reset target address config",[]),
+ ?line reset_target_addr_conf(AgentDir),
+
+ ?LOG("change_target_addr_config -> unload TestTrap",[]),
+ ?line unload_master("TestTrap").
+
+
+dummy_manager_start(MA) ->
+ ?DBG("dummy_manager_start -> entry",[]),
+ Pid = spawn(get(mgr_node), ?MODULE,dummy_manager_init,[self(),MA]),
+ ?DBG("dummy_manager_start -> Pid: ~p",[Pid]),
+ await_dummy_manager_started(Pid).
+
+await_dummy_manager_started(Pid) ->
+ receive
+ {dummy_manager_started,Pid,Port} ->
+ ?DBG("dummy_manager_start -> acknowledge received with"
+ "~n Port: ~p",[Port]),
+ {ok,Pid,Port};
+ {'EXIT', Pid, Reason} ->
+ {error, Pid, Reason};
+ O ->
+ ?LOG("dummy_manager_start -> received unknown message:"
+ "~n ~p",[O]),
+ await_dummy_manager_started(Pid)
+ end.
+
+dummy_manager_stop(Pid) ->
+ ?DBG("dummy_manager_stop -> entry with Pid: ~p",[Pid]),
+ Pid ! stop,
+ receive
+ {dummy_manager_stopping, Pid} ->
+ ?DBG("dummy_manager_stop -> acknowledge received",[]),
+ ok
+ after 10000 ->
+ ?ERR("dummy_manager_stop -> timeout",[]),
+ timeout
+ end.
+
+dummy_manager_send_trap2(Pid) ->
+ ?DBG("dummy_manager_send_trap2 -> entry",[]),
+ Pid ! {send_trap,testTrap2}.
+
+dummy_manager_await_trap2_ack() ->
+ ?DBG("dummy_manager_await_trap2 -> entry",[]),
+ receive
+ {received_trap,Trap} ->
+ ?LOG("dummy_manager_await_trap2 -> received trap: ~p",[Trap]),
+ %% Note:
+ %% Without this sleep the v2_inform_i testcase failes! There
+ %% is no relation between these two test cases as far as I
+ %% able to figure out...
+ sleep(60000),
+ ok;
+ O ->
+ ?ERR("dummy_manager_await_trap2 -> unexpected message: ~p",[O]),
+ ok
+ after 10000 ->
+ ?ERR("dummy_manager_await_trap2 -> timeout",[]),
+ timeout
+ end.
+
+dummy_manager_init(Parent,MA) ->
+ ?DBG("dummy_manager_init -> entry with"
+ "~n Parent: ~p"
+ "~n MA: ~p",[Parent,MA]),
+ {ok,S} = gen_udp:open(0,[{recbuf,65535}]),
+ ?DBG("dummy_manager_init -> S: ~p",[S]),
+ {ok,Port} = inet:port(S),
+ ?DBG("dummy_manager_init -> Port: ~p",[Port]),
+ Parent ! {dummy_manager_started,self(),Port},
+ dummy_manager_loop(Parent,S,MA).
+
+dummy_manager_loop(P,S,MA) ->
+ ?LOG("dummy_manager_loop -> ready for receive",[]),
+ receive
+ {send_trap,Trap} ->
+ ?LOG("dummy_manager_loop -> received trap send request"
+ "~n Trap: ~p",[Trap]),
+ snmpa:send_trap(MA, Trap, "standard trap"),
+ dummy_manager_loop(P,S,MA);
+ {udp, _UdpId, Ip, UdpPort, Bytes} ->
+ ?LOG("dummy_manager_loop -> received upd message"
+ "~n from: ~p:~p"
+ "~n size: ~p",
+ [Ip, UdpPort, dummy_manager_message_sz(Bytes)]),
+ R = dummy_manager_handle_message(Bytes),
+ ?DBG("dummy_manager_loop -> R: ~p",[R]),
+ P ! R,
+ dummy_manager_loop(P,S,MA);
+ stop ->
+ ?DBG("dummy_manager_loop -> received stop request",[]),
+ P ! {dummy_manager_stopping, self()},
+ gen_udp:close(S),
+ exit(normal);
+ O ->
+ ?LOG("dummy_manager_loop -> received unknown message:"
+ "~n ~p",[O]),
+ dummy_manager_loop(P,S,MA)
+ end.
+
+dummy_manager_message_sz(B) when binary(B) ->
+ size(B);
+dummy_manager_message_sz(L) when list(L) ->
+ length(L);
+dummy_manager_message_sz(_) ->
+ undefined.
+
+dummy_manager_handle_message(Bytes) ->
+ case (catch snmp_pdus:dec_message(Bytes)) of
+ {'EXIT',Reason} ->
+ ?ERR("dummy_manager_handle_message -> "
+ "failed decoding message only:~n ~p",[Reason]),
+ {error,Reason};
+ M ->
+ ?DBG("dummy_manager_handle_message -> decoded message:"
+ "~n ~p",[M]),
+ {received_trap,M}
+ end.
+
+
+api(suite) -> [];
+api(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ ?line load_master("OLD-SNMPEA-MIB"),
+ ?line init_old(),
+ try_test(api_test, [node()]),
+ ?line unload_master("OLD-SNMPEA-MIB").
+
+api_2(X) -> api(X).
+
+api_3(X) -> api(X).
+
+
+subagent(suite) -> [];
+subagent(Config) when list(Config) ->
+ {SaNode, _MgrNode, MibDir} = init_case(Config),
+
+ ?line {ok, SA} = start_subagent(SaNode, ?klas1, "Klas1"),
+ try_test(load_test_sa),
+
+ p("Testing unregister subagent..."),
+ MA = whereis(snmp_master_agent),
+ rpc:call(SaNode, snmp, unregister_subagent, [MA, SA]),
+ try_test(unreg_test),
+
+ p("Loading previous subagent mib in master and testing..."),
+ ?line ok = snmpa:load_mibs(MA, [MibDir ++ "Klas1"]),
+ try_test(load_test),
+
+ p("Unloading previous subagent mib in master and testing..."),
+ ?line ok = snmpa:unload_mibs(MA, [MibDir ++ "Klas1"]),
+ try_test(unreg_test),
+ p("Testing register subagent..."),
+ rpc:call(SaNode, snmp, register_subagent,
+ [MA, ?klas1, SA]),
+ try_test(load_test_sa),
+
+ ?line stop_subagent(SA),
+ try_test(unreg_test).
+
+subagent_2(X) -> subagent(X).
+
+subagent_3(X) -> subagent(X).
+
+
+mnesia(suite) -> [];
+mnesia(Config) when list(Config) ->
+ {SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ p("Starting subagent with mnesia impl..."),
+ {ok, SA} = start_subagent(SaNode, ?klas2, "Klas2"),
+ ?line load_master("OLD-SNMPEA-MIB"),
+ ?line init_old(),
+
+ try_test(big_test_2),
+
+ p("Testing unregister subagent..."),
+ MA = whereis(snmp_master_agent),
+ rpc:call(SaNode, snmp, unregister_subagent, [MA, SA]),
+ try_test(unreg_test),
+ ?line unload_master("OLD-SNMPEA-MIB"),
+ ?line stop_subagent(SA).
+
+mnesia_2(X) -> mnesia(X).
+
+mnesia_3(X) -> mnesia(X).
+
+
+multiple_reqs(suite) ->
+ {req, [], {conf, init_mul, mul_cases(), finish_mul}}.
+
+mul_cases() ->
+ [mul_get, mul_get_err, mul_next, mul_next_err, mul_set_err].
+
+multiple_reqs_2(suite) ->
+ {req, [], {conf, init_mul, mul_cases_2(), finish_mul}}.
+
+multiple_reqs_3(_X) ->
+ {req, [], {conf, init_mul, mul_cases_3(), finish_mul}}.
+
+
+mul_cases_2() ->
+ [mul_get_2, mul_get_err_2, mul_next_2, mul_next_err_2, mul_set_err_2].
+
+
+mul_cases_3() ->
+ [mul_get_3, mul_get_err_3, mul_next_3, mul_next_err_3, mul_set_err_3].
+
+
+init_mul(Config) when list(Config) ->
+ {SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ ?line {ok, SA} = start_subagent(SaNode, ?klas1, "Klas1"),
+ ?line load_master("OLD-SNMPEA-MIB"),
+ ?line init_old(),
+ [{mul_sub, SA} | Config].
+
+finish_mul(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ SA = ?config(mul_sub, Config),
+
+ ?line unload_master("OLD-SNMPEA-MIB"),
+ ?line stop_subagent(SA),
+ lists:keydelete(mul_sub, 1, Config).
+
+mul_get(suite) -> [];
+mul_get(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ p("Testing multiple get..."),
+ try_test(do_mul_get).
+
+mul_get_2(X) -> mul_get(X).
+
+mul_get_3(X) -> mul_get(X).
+
+
+mul_get_err(suite) -> [];
+mul_get_err(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ p("Testing multiple get with error..."),
+ try_test(do_mul_get_err).
+
+mul_get_err_2(X) -> mul_get_err(X).
+
+mul_get_err_3(X) -> mul_get_err(X).
+
+
+mul_next(suite) -> [];
+mul_next(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ p("Testing multiple next..."),
+ try_test(do_mul_next).
+
+mul_next_2(X) -> mul_next(X).
+
+mul_next_3(X) -> mul_next(X).
+
+
+mul_next_err(suite) -> [];
+mul_next_err(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ p("Testing multiple next..."),
+ try_test(do_mul_next_err).
+
+mul_next_err_2(X) -> mul_next_err(X).
+
+mul_next_err_3(X) -> mul_next_err(X).
+
+
+mul_set(suite) -> [];
+mul_set(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ p("Testing multiple set..."),
+ try_test(do_mul_set).
+
+mul_set_2(X) -> mul_set(X).
+
+mul_set_3(X) -> mul_set(X).
+
+
+mul_set_err(suite) -> [];
+mul_set_err(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ p("Testing multiple set with error..."),
+ try_test(do_mul_set_err).
+
+mul_set_err_2(X) -> mul_set_err(X).
+
+mul_set_err_3(X) -> mul_set_err(X).
+
+
+sa_register(suite) -> [];
+sa_register(Config) when list(Config) ->
+ ?DBG("sa_register -> entry", []),
+ {SaNode, _MgrNode, MibDir} = init_case(Config),
+
+ ?DBG("sa_register -> start subagent", []),
+ ?line {ok, SA} = start_subagent(SaNode, ?klas1, "Klas1"),
+
+ ?DBG("sa_register -> unregister subagent", []),
+ p("Testing unregister subagent (2)..."),
+ MA = whereis(snmp_master_agent),
+ rpc:call(SaNode, snmp, unregister_subagent, [MA, ?klas1]),
+ try_test(unreg_test),
+
+ p("Loading SA-MIB..."),
+ ?DBG("sa_register -> unload mibs", []),
+ snmpa:unload_mibs(SA, [MibDir ++ "Klas1"]),
+ ?DBG("sa_register -> unload mibs", []),
+ snmpa:load_mibs(SA, [MibDir ++ "SA-MIB"]),
+ ?DBG("sa_register -> register subagent", []),
+ rpc:call(SaNode, snmp, register_subagent, [MA,?sa,SA]),
+ try_test(sa_mib),
+
+ ?DBG("sa_register -> stop subagent", []),
+ ?line stop_subagent(SA).
+
+sa_register_2(X) -> sa_register(X).
+
+sa_register_3(X) -> sa_register(X).
+
+
+v1_trap(suite) -> [];
+v1_trap(Config) when list(Config) ->
+ {SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ ?line {ok, SA} = start_subagent(SaNode, ?sa, "SA-MIB"),
+
+ p("Testing trap sending from master agent..."),
+ MA = whereis(snmp_master_agent),
+
+ ?line load_master("TestTrap"),
+ ?line load_master("TestTrapv2"),
+
+ try_test(ma_trap1, [MA]),
+ try_test(ma_trap2, [MA]),
+ try_test(ma_v2_2_v1_trap, [MA]),
+ try_test(ma_v2_2_v1_trap2, [MA]),
+
+ p("Testing trap sending from subagent..."),
+ try_test(sa_trap1, [SA]),
+ try_test(sa_trap2, [SA]),
+ try_test(sa_trap3, [SA]),
+
+ ?line unload_master("TestTrap"),
+ ?line unload_master("TestTrapv2"),
+
+ ?line stop_subagent(SA).
+
+v2_trap(suite) -> [];
+v2_trap(Config) when list(Config) ->
+ {SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ ?line {ok, SA} = start_subagent(SaNode, ?sa, "SA-MIB"),
+
+ p("Testing trap sending from master agent..."),
+ MA = whereis(snmp_master_agent),
+
+ ?line load_master("TestTrap"),
+ ?line load_master("TestTrapv2"),
+
+
+ try_test(ma_v2_trap1, [MA]),
+ try_test(ma_v2_trap2, [MA]),
+ try_test(ma_v1_2_v2_trap, [MA]),
+ try_test(ma_v1_2_v2_trap2, [MA]),
+
+ try_test(sa_mib),
+ p("Testing trap sending from subagent..."),
+ try_test(sa_v1_2_v2_trap1, [SA]),
+ try_test(sa_v1_2_v2_trap2, [SA]),
+ try_test(sa_v1_2_v2_trap3, [SA]),
+
+ ?line unload_master("TestTrap"),
+ ?line unload_master("TestTrapv2"),
+
+ ?line stop_subagent(SA).
+
+v3_trap(X) ->
+ v2_trap(X).
+
+v2_inform(suite) ->
+ {req, [], {conf, init_v2_inform, [v2_inform_i], finish_v2_inform}}.
+
+v3_inform(_X) ->
+ %% v2_inform(X).
+ {req, [], {conf, init_v3_inform, [v3_inform_i], finish_v3_inform}}.
+
+init_v2_inform(Config) when list(Config) ->
+ _Dir = ?config(agent_dir, Config),
+% snmp_internal_mib:configure(Dir),
+ Config.
+
+init_v3_inform(X) ->
+ init_v2_inform(X).
+
+finish_v2_inform(Config) when list(Config) ->
+ _Dir = ?config(agent_dir, Config),
+% snmp_internal_mib:configure(Dir),
+ Config.
+
+finish_v3_inform(X) ->
+ finish_v2_inform(X).
+
+
+
+v2_inform_i(suite) -> [];
+v2_inform_i(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ p("Testing inform sending from master agent... NOTE! This test\ntakes a "
+ "few minutes (5) to complete."),
+ MA = whereis(snmp_master_agent),
+
+ ?line load_master("TestTrap"),
+ ?line load_master("TestTrapv2"),
+
+ try_test(ma_v2_inform1, [MA]),
+
+ ?line unload_master("TestTrap"),
+ ?line unload_master("TestTrapv2").
+
+v3_inform_i(X) -> v2_inform_i(X).
+
+
+sa_error(suite) -> [];
+sa_error(Config) when list(Config) ->
+ {SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ ?line load_master("OLD-SNMPEA-MIB"),
+ ?line init_old(),
+ ?line {ok, SA} = start_subagent(SaNode, ?sa, "SA-MIB"),
+
+ p("Testing sa bad value (is_set_ok)..."),
+ try_test(sa_errs_bad_value),
+
+ p("Testing sa gen err (set)..."),
+ try_test(sa_errs_gen_err),
+
+ p("Testing too big..."),
+ try_test(sa_too_big),
+
+ ?line unload_master("OLD-SNMPEA-MIB"),
+ stop_subagent(SA).
+
+sa_error_2(X) -> sa_error(X).
+
+sa_error_3(X) -> sa_error(X).
+
+
+next_across_sa(suite) -> [];
+next_across_sa(Config) when list(Config) ->
+ {SaNode, _MgrNode, MibDir} = init_case(Config),
+ MA = whereis(snmp_master_agent),
+
+ ?line {ok, SA} = start_subagent(SaNode, ?sa, "SA-MIB"),
+
+ p("Loading another subagent mib..."),
+ ?line ok = snmpa:load_mibs(SA, [MibDir ++ "Klas1"]),
+
+ rpc:call(SaNode, snmp, register_subagent, [MA, ?klas1, SA]),
+ try_test(load_test_sa),
+
+ p("Testing next across subagent (endOfMibView from SA)..."),
+ try_test(next_across_sa),
+
+ p("Unloading mib"),
+ snmpa:unload_mibs(SA, [MibDir ++ "Klas1"]),
+ rpc:call(SaNode, snmp, unregister_subagent, [MA, ?klas1]),
+ try_test(unreg_test),
+
+ p("Starting another subagent"),
+ ?line {ok, SA2} = start_subagent(SaNode, ?klas1, "Klas1"),
+ p("Testing next across subagent (wrong prefix from SA)..."),
+ try_test(next_across_sa),
+
+ stop_subagent(SA),
+ stop_subagent(SA2).
+
+next_across_sa_2(X) -> next_across_sa(X).
+
+next_across_sa_3(X) -> next_across_sa(X).
+
+
+undo(suite) -> [];
+undo(Config) when list(Config) ->
+ {SaNode, _MgrNode, MibDir} = init_case(Config),
+ MA = whereis(snmp_master_agent),
+
+ ?line {ok, SA} = start_subagent(SaNode, ?sa, "SA-MIB"),
+
+ p("Testing undo phase at master agent..."),
+ ?line ok = snmpa:load_mibs(MA, [MibDir ++ "Klas3"]),
+ ?line ok = snmpa:load_mibs(MA, [MibDir ++ "Klas4"]),
+ try_test(undo_test),
+ try_test(api_test2),
+ ?line ok = snmpa:unload_mibs(MA, [MibDir ++ "Klas3"]),
+
+ p("Testing bad return values from instrum. funcs..."),
+ try_test(bad_return),
+
+ ?line ok = snmpa:unload_mibs(MA, [MibDir ++ "Klas4"]),
+
+ p("Testing undo phase at subagent..."),
+ ?line ok = snmpa:load_mibs(SA, [MibDir ++ "Klas3"]),
+ ?line ok = snmpa:load_mibs(SA, [MibDir ++ "Klas4"]),
+ ?line ok = snmpa:register_subagent(MA, ?klas3, SA),
+ ?line ok = snmpa:register_subagent(MA, ?klas4, SA),
+ try_test(undo_test),
+ try_test(api_test3),
+
+ p("Testing undo phase across master/subagents..."),
+ try_test(undo_test),
+ try_test(api_test3),
+ stop_subagent(SA).
+
+undo_2(X) -> undo(X).
+
+undo_3(X) -> undo(X).
+
+%% Req. Test2
+v1_processing(suite) -> [];
+v1_processing(Config) when list(Config) ->
+ ?DBG("v1_processing -> entry", []),
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ ?line load_master("Test2"),
+ try_test(v1_proc),
+ ?line unload_master("Test2").
+
+%% Req. Test2
+v2_processing(suite) -> [];
+v2_processing(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ ?line load_master("Test2"),
+ try_test(v2_proc),
+ ?line unload_master("Test2").
+
+%% Req. Test2
+v3_processing(suite) -> [];
+v3_processing(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ ?line load_master("Test2"),
+ try_test(v2_proc), % same as v2!
+ ?line unload_master("Test2").
+
+
+%% We'll try get/set/trap and inform for all the auth & priv protocols.
+%% For informs, the mgr is auth-engine. The agent has to sync. This is
+%% accomplished by the first inform sent. That one will generate a
+%% report, which makes it in sync. The notification-generating
+%% application times out, and send again. This time it'll work.
+v3_security(suite) -> [v3_crypto_basic, v3_md5_auth, v3_sha_auth, v3_des_priv].
+
+v3_crypto_basic(suite) -> [];
+v3_crypto_basic(_Config) ->
+ EID = [0,0,0,0,0,0,0,0,0,0,0,2],
+ %% From rfc2274 appendix A.3.1
+ ?line KMd5_1 = snmp:passwd2localized_key(md5, "maplesyrup", EID),
+ ?line [16#52,16#6f,16#5e,16#ed,16#9f,16#cc,16#e2,16#6f,
+ 16#89,16#64,16#c2,16#93,16#07,16#87,16#d8,16#2b] =
+ KMd5_1,
+ %% From rfc2274 appendix A.3.2
+ ?line KSHA_1 = snmp:passwd2localized_key(sha, "maplesyrup", EID),
+ ?line [16#66,16#95,16#fe,16#bc,16#92,16#88,16#e3,16#62,16#82,16#23,
+ 16#5f,16#c7,16#15,16#1f,16#12,16#84,16#97,16#b3,16#8f,16#3f] =
+ KSHA_1,
+ %% From rfc2274, appendix A.5.1
+ ?line KMd5_2 = snmp:passwd2localized_key(md5, "newsyrup", EID),
+ ?line [16#00,16#00,16#00,16#00,16#00,16#00,16#00,16#00,
+ 16#00,16#00,16#00,16#00,16#00,16#00,16#00,16#00,
+ 16#88,16#05,16#61,16#51,16#41,16#67,16#6c,16#c9,
+ 16#19,16#61,16#74,16#e7,16#42,16#a3,16#25,16#51] =
+ snmp_user_based_sm_mib:mk_key_change(md5, KMd5_1, KMd5_2, 16,
+ [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]),
+ %% From rfc2274, appendix A.5.2
+ ?line KSHA_2 = snmp:passwd2localized_key(sha, "newsyrup", EID),
+ ?line [16#00,16#00,16#00,16#00,16#00,16#00,16#00,16#00,
+ 16#00,16#00,16#00,16#00,16#00,16#00,16#00,16#00,
+ 16#00,16#00,16#00,16#00,16#9c,16#10,16#17,16#f4,
+ 16#fd,16#48,16#3d,16#2d,16#e8,16#d5,16#fa,16#db,
+ 16#f8,16#43,16#92,16#cb,16#06,16#45,16#70,16#51] =
+ snmp_user_based_sm_mib:mk_key_change(sha, KSHA_1, KSHA_2, 20,
+ [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]),
+ KSHA_1t = lists:sublist(KSHA_1, 16),
+ KSHA_2t = lists:sublist(KSHA_2, 16),
+ ?line [16#00,16#00,16#00,16#00,16#00,16#00,16#00,16#00,
+ 16#00,16#00,16#00,16#00,16#00,16#00,16#00,16#00,
+ 16#7e,16#f8,16#d8,16#a4,16#c9,16#cd,16#b2,16#6b,
+ 16#47,16#59,16#1c,16#d8,16#52,16#ff,16#88,16#b5] =
+ snmp_user_based_sm_mib:mk_key_change(sha, KSHA_1t, KSHA_2t, 16,
+ [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]),
+
+ %% Try with correct random
+ ?line Kc1 = snmp_user_based_sm_mib:mk_key_change(md5, KMd5_1, KMd5_2),
+ ?line KMd5_2 = snmp_user_based_sm_mib:extract_new_key(md5, KMd5_1, Kc1),
+ ?line Kc2 = snmp_user_based_sm_mib:mk_key_change(sha, KSHA_1, KSHA_2),
+ ?line KSHA_2 = snmp_user_based_sm_mib:extract_new_key(sha, KSHA_1, Kc2),
+ ok.
+
+
+
+v3_md5_auth(suite) -> [];
+v3_md5_auth(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ p("Testing MD5 authentication...takes a few seconds..."),
+
+ AgentDir = ?config(agent_dir, Config),
+ ?line rewrite_target_params_conf(AgentDir, "authMD5", authNoPriv),
+ ?line snmp_target_mib:reconfigure(AgentDir),
+
+ MA = whereis(snmp_master_agent),
+
+ ?line load_master("Test2"),
+ ?line load_master("TestTrap"),
+ ?line load_master("TestTrapv2"),
+
+ try_test(v3_sync, [[{v2_proc, []},
+ {ma_v2_trap1, [MA]},
+ {v3_inform_sync, [MA]}]],
+ [{sec_level, authNoPriv}, {user, "authMD5"}]),
+
+ ?line unload_master("TestTrapv2"),
+ ?line unload_master("TestTrap"),
+ ?line unload_master("Test2"),
+ ?line reset_target_params_conf(AgentDir).
+
+v3_sha_auth(suite) -> [];
+v3_sha_auth(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ p("Testing SHA authentication...takes a few seconds..."),
+
+ AgentDir = ?config(agent_dir, Config),
+ ?line rewrite_target_params_conf(AgentDir, "authSHA", authNoPriv),
+ ?line snmp_target_mib:reconfigure(AgentDir),
+
+ MA = whereis(snmp_master_agent),
+
+ ?line load_master("Test2"),
+ ?line load_master("TestTrap"),
+ ?line load_master("TestTrapv2"),
+
+ try_test(v3_sync, [[{v2_proc, []},
+ {ma_v2_trap1, [MA]},
+ {v3_inform_sync, [MA]}]],
+ [{sec_level, authNoPriv}, {user, "authSHA"}]),
+
+ ?line unload_master("TestTrapv2"),
+ ?line unload_master("TestTrap"),
+ ?line unload_master("Test2"),
+ ?line reset_target_params_conf(AgentDir).
+
+v3_des_priv(suite) -> [];
+v3_des_priv(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ p("Testing DES encryption...takes a few seconds..."),
+
+ AgentDir = ?config(agent_dir, Config),
+ ?line rewrite_target_params_conf(AgentDir, "privDES", authPriv),
+ ?line snmp_target_mib:reconfigure(AgentDir),
+
+ MA = whereis(snmp_master_agent),
+
+ ?line load_master("Test2"),
+ ?line load_master("TestTrap"),
+ ?line load_master("TestTrapv2"),
+
+ try_test(v3_sync, [[{v2_proc, []},
+ {ma_v2_trap1, [MA]},
+ {v3_inform_sync, [MA]}]],
+ [{sec_level, authPriv}, {user, "privDES"}]),
+
+ ?line unload_master("TestTrapv2"),
+ ?line unload_master("TestTrap"),
+ ?line unload_master("Test2"),
+ ?line reset_target_params_conf(AgentDir).
+
+%% -define(usmStatsNotInTimeWindows_instance, [1,3,6,1,6,3,15,1,1,2,0]).
+
+%% Make sure mgr is in sync with agent
+v3_sync(Funcs) ->
+ ?DBG("v3_sync -> entry with Funcs: ~p",[Funcs]),
+ g([[sysDescr, 0]]),
+ expect(432, report, [{?usmStatsNotInTimeWindows_instance, any}]),
+ g([[sysDescr, 0]]),
+ expect(433, [{[sysDescr,0], any}]),
+ lists:foreach(fun({Func, Args}) -> apply(?MODULE, Func, Args) end, Funcs).
+
+v3_inform_sync(MA) ->
+ ?DBG("v3_sync -> entry with MA: ~p => Send notification",[MA]),
+ ?line snmpa:send_notification(MA, testTrapv22, no_receiver,
+ "standard inform", []),
+ %% Make sure agent is in sync with mgr...
+ ?DBG("v3_sync -> wait some time: ",[]),
+ sleep(20000), % more than 1500*10 in target_addr.conf
+ ?DBG("v3_sync -> await response",[]),
+ ?line expect(1, {inform, true},
+ [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?system ++ [0,1]}]).
+
+
+v2_caps(suite) -> [];
+v2_caps(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ try_test(v2_caps_i, [node()]).
+
+v2_caps_3(X) -> v2_caps(X).
+
+
+v2_caps_i(Node) ->
+ ?line Idx = rpc:call(Node, snmp, add_agent_caps, [[1,2,3,4,5], "test cap"]),
+ g([[sysORID, Idx], [sysORDescr, Idx]]),
+ ?line expect(1, [{[sysORID, Idx], [1,2,3,4,5]},
+ {[sysORDescr, Idx], "test cap"}]),
+ ?line rpc:call(Node, snmp, del_agent_caps, [Idx]),
+ g([[sysORID, Idx]]),
+ ?line expect(2, [{[sysORID, Idx], noSuchInstance}]).
+
+
+%% Req. Test2
+v1_proc() ->
+ ?DBG("v1_proc -> entry", []),
+ %% According to RFC1157.
+ %% Template: <Section>:<list no>
+ v1_get_p(),
+ v1_get_next_p(),
+ v1_set_p().
+
+
+v1_get_p() ->
+ %% 4.1.2:1
+ g([[test2]]),
+ ?line expect(10, noSuchName, 1, [{[test2], 'NULL'}]),
+ g([[tDescr]]),
+ ?line expect(11, noSuchName, 1, [{[tDescr], 'NULL'}]),
+ g([[tDescr2,0]]),
+ ?line expect(12, noSuchName, 1, [{[tDescr2,0], 'NULL'}]),
+ g([[tDescr3,0]]),
+ ?line expect(131, noSuchName, 1, [{[tDescr3,0], 'NULL'}]),
+ g([[tDescr4,0]]),
+ ?line expect(132, noSuchName, 1, [{[tDescr4,0], 'NULL'}]),
+ g([[sysDescr, 0], [tDescr,0]]), % Outside mibview
+ ?line expect(14, noSuchName, 2, [{[sysDescr, 0], 'NULL'},
+ {[tDescr,0], 'NULL'}]),
+ g([[sysDescr,3]]),
+ ?line expect(15, noSuchName, 1, [{[sysDescr, 3], 'NULL'}]),
+
+ %% 4.1.2:2
+ g([[tTable]]),
+ ?line expect(20, noSuchName, 1, [{[tTable], 'NULL'}]),
+ g([[tEntry]]),
+ ?line expect(21, noSuchName, 1, [{[tEntry], 'NULL'}]),
+
+ %% 4.1.2:3
+ g([[tTooBig, 0]]),
+ ?line expect(30, tooBig, 0, [{[tTooBig, 0], 'NULL'}]),
+
+ %% 4.1.2:4
+ g([[tGenErr1, 0]]),
+ ?line expect(40, genErr, 1, [{[tGenErr1, 0], 'NULL'}]),
+ g([[tGenErr2, 0]]),
+ ?line expect(41, genErr, 1, [{[tGenErr2, 0], 'NULL'}]),
+ g([[sysDescr, 0], [tGenErr3, 0]]),
+ ?line expect(42, genErr, 2, [{[sysDescr, 0], 'NULL'},
+ {[tGenErr3, 0], 'NULL'}]).
+
+
+v1_get_next_p() ->
+ %% 4.1.3:1
+ gn([[1,3,7,1]]),
+ ?line expect(10, noSuchName, 1, [{[1,3,7,1], 'NULL'}]),
+ gn([[tDescr2]]),
+ ?line expect(11, tooBig, 0, any),
+
+ %% 4.1.3:2
+ gn([[tTooBig]]),
+ io:format("We currently don't handle tooBig correct!!!\n"),
+% ?line expect(20, tooBig, 0, [{[tTooBig], 'NULL'}]),
+ ?line expect(20, tooBig, 0, any),
+
+ %% 4.1.3:3
+ gn([[tGenErr1]]),
+% ?line expect(40, genErr, 1, [{[tGenErr1], 'NULL'}]),
+ ?line expect(40, genErr, 1, any),
+ gn([[tGenErr2]]),
+% ?line expect(41, genErr, 1, [{[tGenErr2], 'NULL'}]),
+ ?line expect(41, genErr, 1, any),
+ gn([[sysDescr], [tGenErr3]]),
+% ?line expect(42, genErr, 2, [{[sysDescr], 'NULL'},
+% {[tGenErr3], 'NULL'}]).
+ ?line expect(42, genErr, 2, any).
+
+v1_set_p() ->
+ %% 4.1.5:1
+ s([{[1,3,7,0], i, 4}]),
+ ?line expect(10, noSuchName, 1, [{[1,3,7,0], 4}]),
+ s([{[tDescr,0], s, "outside mibview"}]),
+ ?line expect(11, noSuchName, 1, [{[tDescr,0], "outside mibview"}]),
+ s([{[tDescr3,0], s, "read-only"}]),
+ ?line expect(12, noSuchName, 1, [{[tDescr3,0], "read-only"}]),
+ s([{[tDescr3], s, "noSuchObject"}]),
+ ?line expect(13, noSuchName, 1, [{[tDescr3], "noSuchObject"}]),
+ s([{[tDescr3,1], s, "noSuchInstance"}]),
+ ?line expect(14, noSuchName, 1, [{[tDescr3,1], "noSuchInstance"}]),
+ s([{[tDescr2,0], s, "inconsistentName"}]),
+ ?line expect(15, noSuchName, 1, [{[tDescr2,0], "inconsistentName"}]),
+
+ %% 4.1.5:2
+ s([{[tDescr2, 0], i, 4}]),
+ ?line expect(20, badValue, 1, [{[tDescr2, 0], 4}]),
+ s([{[tDescr2, 0], s, "badValue"}]),
+ ?line expect(21, badValue, 1, [{[tDescr2, 0], "badValue"}]),
+
+ %% 4.1.5:3
+ %% The standard is quite incorrect here. The resp pdu was too big. In
+ %% the resp pdu, we have the original vbs. In the tooBig pdu we still
+ %% have to original vbs => the tooBig pdu is too big as well!!! It
+ %% may not get it to the manager, unless the agent uses 'NULL' instead
+ %% of the std-like original value.
+ s([{[tTooBig, 0], s, ?tooBigStr}]),
+ %% according to std:
+% ?line expect(30, tooBig, 0, [{[tTooBig, 0], ?tooBigStr}]),
+ ?line expect(30, tooBig, 0, [{[tTooBig, 0], 'NULL'}]),
+
+ %% 4.1.5:4
+ s([{[tDescr2, 0], s, "is_set_ok_fail"}]),
+ ?line expect(40, genErr, 1, [{[tDescr2, 0], "is_set_ok_fail"}]),
+ s([{[tDescr2, 0], s, "commit_fail"}]),
+ ?line expect(41, genErr, 1, [{[tDescr2, 0], "commit_fail"}]).
+
+%% Req. Test2
+v2_proc() ->
+ %% According to RFC1905.
+ %% Template: <Section>:<list no>
+ ?DBG("v2_proc -> entry",[]),
+ v2_get_p(),
+ v2_get_next_p(),
+ v2_get_bulk_p(),
+ v2_set_p().
+
+v2_get_p() ->
+ %% 4.2.1:2
+ ?DBG("v2_get_p -> entry",[]),
+ g([[test2]]),
+ ?line expect(10, [{[test2], noSuchObject}]),
+ g([[tDescr]]),
+ ?line expect(11, [{[tDescr], noSuchObject}]),
+ g([[tDescr4,0]]),
+ ?line expect(12, [{[tDescr4,0], noSuchObject}]),
+ g([[sysDescr, 0], [tDescr,0]]), % Outside mibview
+ ?line expect(13, [{[sysDescr,0], "Erlang SNMP agent"},
+ {[tDescr,0], noSuchObject}]),
+ g([[tTable]]),
+ ?line expect(14, [{[tTable], noSuchObject}]),
+ g([[tEntry]]),
+ ?line expect(15, [{[tEntry], noSuchObject}]),
+
+ %% 4.2.1:3
+ g([[tDescr2,0]]), %% instrum ret noSuchName!!!
+ ?line expect(20, [{[tDescr2,0], noSuchInstance}]),
+ g([[tDescr3,0]]),
+ ?line expect(21, [{[tDescr3,0], noSuchInstance}]),
+ g([[sysDescr,3]]),
+ ?line expect(22, [{[sysDescr, 3], noSuchInstance}]),
+ g([[tIndex,1]]),
+ ?line expect(23, [{[tIndex, 1], noSuchInstance}]),
+
+ %% 4.2.1 - any other error: genErr
+ g([[tGenErr1, 0]]),
+ ?line expect(30, genErr, 1, [{[tGenErr1, 0], 'NULL'}]),
+ g([[tGenErr2, 0]]),
+ ?line expect(31, genErr, 1, [{[tGenErr2, 0], 'NULL'}]),
+ g([[sysDescr, 0], [tGenErr3, 0]]),
+ ?line expect(32, genErr, 2, [{[sysDescr, 0], 'NULL'},
+ {[tGenErr3, 0], 'NULL'}]),
+
+ %% 4.2.1 - tooBig
+ g([[tTooBig, 0]]),
+ ?line expect(40, tooBig, 0, []).
+
+
+v2_get_next_p() ->
+ %% 4.2.2:2
+ ?DBG("v2_get_next_p -> entry",[]),
+ gn([[1,3,7,1]]),
+ ?line expect(10, [{[1,3,7,1], endOfMibView}]),
+ gn([[sysDescr], [1,3,7,1]]),
+ ?line expect(11, [{[sysDescr, 0], "Erlang SNMP agent"},
+ {[1,3,7,1], endOfMibView}]),
+ gn([[tCnt2, 1]]),
+ ?line expect(12, [{[tCnt2,2], 100}]),
+ gn([[tCnt2, 2]]),
+ ?line expect(12, [{[tCnt2,2], endOfMibView}]),
+
+ %% 4.2.2 - any other error: genErr
+ gn([[tGenErr1]]),
+ ?line expect(20, genErr, 1, [{[tGenErr1], 'NULL'}]),
+ gn([[tGenErr2]]),
+ ?line expect(21, genErr, 1, [{[tGenErr2], 'NULL'}]),
+ gn([[sysDescr], [tGenErr3]]),
+ ?line expect(22, genErr, 2, [{[sysDescr], 'NULL'},
+ {[tGenErr3], 'NULL'}]),
+
+ %% 4.2.2 - tooBig
+ gn([[tTooBig]]),
+ ?line expect(20, tooBig, 0, []).
+
+v2_get_bulk_p() ->
+ %% 4.2.3
+ ?DBG("v2_get_bulk_p -> entry",[]),
+ gb(1, 1, []),
+ ?line expect(10, []),
+ gb(-1, 1, []),
+ ?line expect(11, []),
+ gb(-1, -1, []),
+ ?line expect(12, []),
+ gb(-1, -1, []),
+ ?line expect(13, []),
+ gb(2, 0, [[sysDescr], [1,3,7,1]]),
+ ?line expect(14, [{[sysDescr, 0], "Erlang SNMP agent"},
+ {[1,3,7,1], endOfMibView}]),
+ gb(1, 2, [[sysDescr], [1,3,7,1]]),
+ ?line expect(15, [{[sysDescr, 0], "Erlang SNMP agent"},
+ {[1,3,7,1], endOfMibView}]),
+ gb(0, 2, [[sysDescr], [1,3,7,1]]),
+ ?line expect(16, [{[sysDescr, 0], "Erlang SNMP agent"},
+ {[1,3,7,1], endOfMibView},
+ {[sysObjectID, 0], [1,2,3]},
+ {[1,3,7,1], endOfMibView}]),
+
+ gb(2, 2, [[sysDescr], [1,3,7,1], [sysDescr], [1,3,7,1]]),
+ ?line expect(17, [{[sysDescr, 0], "Erlang SNMP agent"},
+ {[1,3,7,1], endOfMibView},
+ {[sysDescr, 0], "Erlang SNMP agent"},
+ {[1,3,7,1], endOfMibView},
+ {[sysObjectID, 0], [1,2,3]},
+ {[1,3,7,1], endOfMibView}]),
+
+ gb(1, 2, [[sysDescr], [sysDescr], [tTooBig]]),
+ ?line expect(18, [{[sysDescr, 0], "Erlang SNMP agent"},
+ {[sysDescr, 0], "Erlang SNMP agent"}]),
+
+ gb(1,12, [[tDescr2], [sysDescr]]), % next one after tDescr2 is tTooBig.
+ ?line expect(19, []),
+
+ gb(2,2, [[sysDescr], [sysObjectID], [tGenErr1], [sysDescr]]),
+ ?line expect(20, genErr, 3, [{[sysDescr], 'NULL'},
+ {[sysObjectID], 'NULL'},
+ {[tGenErr1], 'NULL'},
+ {[sysDescr], 'NULL'}]),
+ gb(0, 2, [[tCnt2, 1]]),
+ ?line expect(21, [{[tCnt2,2], 100},
+ {[tCnt2,2], endOfMibView}]).
+
+
+v2_set_p() ->
+ %% 4.2.5:1
+ ?DBG("v2_set_p -> entry",[]),
+ s([{[1,3,7,0], i, 4}]),
+ ?line expect(10, noAccess, 1, [{[1,3,7,0], 4}]),
+ s([{[tDescr,0], s, "outside mibview"}]),
+ ?line expect(11, noAccess, 1, [{[tDescr,0], "outside mibview"}]),
+
+ %% 4.2.5:2
+ s([{[1,3,6,1,0], s, "noSuchObject"}]),
+ ?line expect(20, notWritable, 1, [{[1,3,6,1,0], "noSuchObject"}]),
+
+ %% 4.2.5:3
+ s([{[tDescr2, 0], i, 4}]),
+ ?line expect(30, wrongType, 1, [{[tDescr2, 0], 4}]),
+ s([{[tDescr2, 0], s, "badValue"}]),
+ ?line expect(31, badValue, 1, [{[tDescr2, 0], "badValue"}]),
+
+ %% 4.2.5:4
+ s([{[tStr, 0], s, ""}]),
+ ?line expect(40, wrongLength, 1, [{[tStr, 0], ""}]),
+ s([{[tStr, 0], s, "12345"}]),
+ ?line expect(40, wrongLength, 1, [{[tStr, 0], "12345"}]),
+
+ %% 4.2.5:5 - N/A
+
+ %% 4.2.5:6
+ s([{[tInt1, 0], i, 0}]),
+ ?line expect(60, wrongValue, 1, [{[tInt1, 0], 0}]),
+ s([{[tInt1, 0], i, 5}]),
+ ?line expect(61, wrongValue, 1, [{[tInt1, 0], 5}]),
+ s([{[tInt2, 0], i, 0}]),
+ ?line expect(62, wrongValue, 1, [{[tInt2, 0], 0}]),
+ s([{[tInt2, 0], i, 5}]),
+ ?line expect(63, wrongValue, 1, [{[tInt2, 0], 5}]),
+ s([{[tInt3, 0], i, 5}]),
+ ?line expect(64, wrongValue, 1, [{[tInt3, 0], 5}]),
+
+ %% 4.2.5:7
+ s([{[tDescrX, 1, 1], s, "noCreation"}]),
+ ?line expect(70, noCreation, 1, [{[tDescrX, 1, 1], "noCreation"}]),
+
+ %% 4.2.5:8
+ s([{[tDescrX, 1, 2], s, "inconsistentName"}]),
+ ?line expect(80, inconsistentName, 1,
+ [{[tDescrX, 1, 2], "inconsistentName"}]),
+
+ %% 4.2.5:9
+ s([{[tCnt, 1, 2], i, 5}]),
+ ?line expect(90, notWritable, 1, [{[tCnt, 1, 2], 5}]),
+ s([{[tDescr3,0], s, "read-only"}]),
+ ?line expect(90, notWritable, 1, [{[tDescr3,0], "read-only"}]),
+
+ %% 4.2.5:10
+ s([{[tDescr2,0], s, "inconsistentValue"}]),
+ ?line expect(100, inconsistentValue, 1,
+ [{[tDescr2,0], "inconsistentValue"}]),
+
+ %% 4.2.5:11
+ s([{[tDescr2,0], s, "resourceUnavailable"}]),
+ ?line expect(110, resourceUnavailable, 1,
+ [{[tDescr2,0],"resourceUnavailable"}]),
+
+ %% 4.2.5:12
+ s([{[tDescr2, 0], s, "is_set_ok_fail"}]),
+ ?line expect(120, genErr, 1, [{[tDescr2, 0], "is_set_ok_fail"}]).
+
+ %% commitFailed and undoFailed is tested by the 'undo' case.
+
+
+%% Req. OLD-SNMPEA-MIB
+table_test() ->
+ io:format("Testing simple get, next and set on communityTable...~n"),
+%% {[147,214,36,45], "public", 2, readWrite}.
+%% {[147,214,36,45], "standard trap", 2, read}.
+ Key1c3 = [intCommunityViewIndex,get(mip),is("public")],
+ Key2c3 = [intCommunityViewIndex,get(mip),is("standard trap")],
+ Key1c4 = [intCommunityAccess,get(mip),is("public")],
+ EndKey = [intCommunityEntry,[9],get(mip),is("public")],
+ gn([[intCommunityEntry]]),
+ ?line expect(7, [{Key1c3, 2}]),
+ gn([[intCommunityTable]]),
+ ?line expect(71, [{Key1c3, 2}]),
+ gn([[community]]),
+ ?line expect(72, [{Key1c3, 2}]),
+ gn([[otpSnmpeaMIB]]),
+ ?line expect(73, [{Key1c3, 2}]),
+ gn([[ericsson]]),
+ ?line expect(74, [{Key1c3, 2}]),
+ gn([Key1c3]),
+ ?line expect(8, [{Key2c3, 2}]),
+ gn([Key2c3]),
+ ?line expect(9, [{Key1c4, 2}]),
+ gn([EndKey]),
+ AgentIp = [intAgentIpAddress,0],
+ ?line expect(10, [{AgentIp, any}]),
+ g([Key1c3]),
+ ?line expect(11, [{Key1c3, 2}]),
+ g([EndKey]),
+ ?line ?v1_2(expect(12, noSuchName, 1, any),
+ expect(12, [{EndKey, noSuchObject}])),
+
+ io:format("Testing row creation/deletion on communityTable...~n"),
+ NewKeyc3 = [intCommunityViewIndex,get(mip),is("test")],
+ NewKeyc4 = [intCommunityAccess,get(mip),is("test")],
+ NewKeyc5 = [intCommunityStatus,get(mip),is("test")],
+ s([{NewKeyc5, ?createAndGo}]),
+ ?line expect(14, ?v1_2(badValue, inconsistentValue), 1,any),
+ s([{NewKeyc5, ?createAndGo}, {NewKeyc3, 2}, {NewKeyc4, 2}]),
+ ?line expect(15, [{NewKeyc5, ?createAndGo},{NewKeyc3, 2}, {NewKeyc4, 2}]),
+ g([NewKeyc4]),
+ ?line expect(16, [{NewKeyc4, 2}]),
+ s([{NewKeyc5, ?destroy}]),
+ ?line expect(17, [{NewKeyc5, ?destroy}]),
+ s([{NewKeyc4, 2}]),
+ ?line expect(18, ?v1_2(noSuchName, inconsistentName), 1,[{NewKeyc4, 2}]),
+ s([{NewKeyc5, ?createAndWait}]),
+ ?line expect(19, [{NewKeyc5, ?createAndWait}]),
+ g([NewKeyc5]),
+ ?line expect(20, [{NewKeyc5, ?notReady}]),
+ s([{NewKeyc4, 2}]),
+ ?line expect(21, [{NewKeyc4, 2}]),
+ g([NewKeyc5]),
+ ?line expect(22, [{NewKeyc5, ?notReady}]),
+ s([{NewKeyc3, 2}]),
+ ?line expect(23, [{NewKeyc3, 2}]),
+ g([NewKeyc5]),
+ ?line expect(24, [{NewKeyc5, ?notInService}]),
+ s([{NewKeyc5, ?active}]),
+ ?line expect(25, [{NewKeyc5, ?active}]),
+ s([{NewKeyc5, ?destroy}]),
+ ?line expect(26, [{NewKeyc5, ?destroy}]),
+ s([{NewKeyc3, 3}]),
+ ?line expect(27, ?v1_2(noSuchName, inconsistentName), 1,[{NewKeyc3, 3}]),
+ otp_1128().
+
+%% Req. system group
+simple_standard_test() ->
+ ?DBG("simple_standard_test -> entry",[]),
+ gn([[1,1]]),
+ ?line expect(1, [{[sysDescr,0], "Erlang SNMP agent"}]),
+ gn([[1,3]]),
+ ?line expect(11, [{[sysDescr,0], "Erlang SNMP agent"}]),
+ gn([[1,3,6]]),
+ ?line expect(12, [{[sysDescr,0], "Erlang SNMP agent"}]),
+ gn([[1,3,6,1]]),
+ ?line expect(13, [{[sysDescr,0], "Erlang SNMP agent"}]),
+ gn([[1,3,6,1,2]]),
+ ?line expect(14, [{[sysDescr,0], "Erlang SNMP agent"}]),
+ gn([[1,3,6,1,2,1]]),
+ ?line expect(15, [{[sysDescr,0], "Erlang SNMP agent"}]),
+ gn([[1,3,6,1,2,1,1]]),
+ ?line expect(16, [{[sysDescr,0], "Erlang SNMP agent"}]),
+ gn([[sysDescr]]),
+ ?line expect(17, [{[sysDescr,0], "Erlang SNMP agent"}]),
+ g([[sysDescr,0]]),
+ ?line expect(2, [{[sysDescr,0], "Erlang SNMP agent"}]),
+ g([[sysDescr]]),
+ ?line ?v1_2(expect(3, noSuchName, 1, any),
+ expect(3, [{[sysDescr], noSuchObject}])),
+ g([[1,6,7,0]]),
+ ?line ?v1_2(expect(41, noSuchName, 1, any),
+ expect(3, [{[1,6,7,0], noSuchObject}])),
+ gn([[1,13]]),
+ ?line ?v1_2(expect(4, noSuchName,1, any),
+ expect(4, [{[1,13], endOfMibView}])),
+ s([{[sysLocation, 0], "new_value"}]),
+ ?line expect(5, [{[sysLocation, 0], "new_value"}]),
+ g([[sysLocation, 0]]),
+ ?line expect(6, [{[sysLocation, 0], "new_value"}]),
+ io:format("Testing noSuchName and badValue...~n"),
+ s([{[sysServices,0], 3}]),
+ ?line expect(61, ?v1_2(noSuchName, notWritable), 1, any),
+ s([{[sysLocation, 0], i, 3}]),
+ ?line expect(62, ?v1_2(badValue, wrongType), 1, any),
+ ?DBG("simple_standard_test -> done",[]),
+ ok.
+
+%% This is run in the agent node
+db_notify_client(suite) -> [];
+db_notify_client(Config) when list(Config) ->
+ {SaNode, MgrNode, MibDir} = init_case(Config),
+ ?DBG("~n\tSaNode: ~p~n\tMgrNode: ~p~n\tMibDir: ~p",
+ [SaNode,MgrNode,MibDir]),
+ snmpa_local_db:register_notify_client(self(),?MODULE),
+
+ %% This call (the manager) will issue to set operations, so
+ %% we expect to receive to notify(insert) calls.
+ try_test(db_notify_client_test),
+
+ ?DBG("await first notify",[]),
+ receive
+ {db_notify_test_reply,insert} -> ?DBG("first notify received",[]),ok
+ end,
+
+ ?DBG("await second notify",[]),
+ receive
+ {db_notify_test_reply,insert} -> ?DBG("second notify received",[]),ok
+ end,
+
+ snmpa_local_db:unregister_notify_client(self()).
+
+
+%% This is run in the manager node
+db_notify_client_test() ->
+ ?DBG("set first new sysLocation",[]),
+ s([{[sysLocation, 0], "new_value"}]),
+ ?line expect(5, [{[sysLocation, 0], "new_value"}]),
+
+ ?DBG("set second new sysLocation",[]),
+ s([{[sysLocation, 0], "new_value"}]),
+ ?line expect(5, [{[sysLocation, 0], "new_value"}]).
+
+notify(Pid,What) ->
+ ?DBG("notify(~p,~p) -> called",[Pid,What]),
+ Pid ! {db_notify_test_reply,What}.
+
+
+%% Req: system group, OLD-SNMPEA-MIB, Klas1
+big_test() ->
+ ?DBG("big_test -> testing simple next/get/set @ master agent...",[]),
+ simple_standard_test(),
+
+ ?DBG("big_test -> testing simple next/get/set @ subagent...",[]),
+ gn([[klas1]]),
+ ?line expect(1, [{[fname,0], ""}]),
+ g([[fname,0]]),
+ ?line expect(2, [{[fname,0], ""}]),
+ s([{[fname,0], s, "test set"}]),
+ ?line expect(3, [{[fname,0], "test set"}]),
+ g([[fname,0]]),
+ ?line expect(4, [{[fname,0], "test set"}]),
+
+ ?DBG("big_test -> "
+ "testing next from last instance in master to subagent...",[]),
+ gn([[?v1_2(sysServices, sysORLastChange),0]]),
+ ?line expect(5, [{[fname,0], "test set"}]),
+ gn([[1,1],
+ [?v1_2(sysServices, sysORLastChange),0]]),
+ ?line expect(51, [{[sysDescr,0], "Erlang SNMP agent"},
+ {[fname,0], "test set"}]),
+ s([{[fname,0], s, ""}]),
+ ?line expect(52, [{[fname,0], ""}]),
+
+ table_test(),
+
+ ?DBG("big_test -> adding one row in subagent table",[]),
+ _FTab = [friendsEntry],
+ s([{[friendsEntry, [2, 3]], s, "kompis3"},
+ {[friendsEntry, [3, 3]], i, ?createAndGo}]),
+ ?line expect(6, [{[friendsEntry, [2, 3]], "kompis3"},
+ {[friendsEntry, [3, 3]], ?createAndGo}]),
+ g([[friendsEntry, [2, 3]],
+ [friendsEntry, [3, 3]]]),
+ ?line expect(7, [{[friendsEntry, [2, 3]], "kompis3"},
+ {[friendsEntry, [3, 3]], ?active}]),
+ s([{[friendsEntry, [3, 3]], i, ?destroy}]),
+ ?line expect(8, [{[friendsEntry, [3, 3]], ?destroy}]),
+
+ otp_1131(),
+
+ ?DBG("big_test -> adding two rows in subagent table with special INDEX",
+ []),
+ s([{[kompissEntry, [1, 3]], s, "kompis3"},
+ {[kompissEntry, [2, 3]], i, ?createAndGo}]),
+ ?line expect(9, [{[kompissEntry, [1, 3]], "kompis3"},
+ {[kompissEntry, [2, 3]], ?createAndGo}]),
+ g([[kompissEntry, [1, 3]],
+ [kompissEntry, [2, 3]]]),
+ ?line expect(10, [{[kompissEntry, [1, 3]], "kompis3"},
+ {[kompissEntry, [2, 3]], ?active}]),
+ gn([[kompissEntry, [1]],
+ [kompissEntry, [2]]]),
+ ?line expect(11, [{[kompissEntry, [1, 3]], "kompis3"},
+ {[kompissEntry, [2, 3]], ?active}]),
+ s([{[kompissEntry, [1, 2]], s, "kompis3"},
+ {[kompissEntry, [2, 2]], i, ?createAndGo}]),
+ ?line expect(12, [{[kompissEntry, [1, 2]], "kompis3"},
+ {[kompissEntry, [2, 2]], ?createAndGo}]),
+ gn([[kompissEntry, [1, 1]],
+ [kompissEntry, [2, 1]]]),
+ ?line expect(13, [{[kompissEntry, [1, 2]], "kompis3"},
+ {[kompissEntry, [2, 2]], ?active}]),
+ s([{[kompissEntry, [2, 3]], i, ?destroy}]),
+ ?line expect(14, [{[kompissEntry, [2, 3]], ?destroy}]),
+ s([{[kompissEntry, [2, 2]], i, ?destroy}]),
+ ?line expect(15, [{[kompissEntry, [2, 2]], ?destroy}]),
+ ?DBG("big_test -> done",[]),
+ ok.
+
+%% Req. system group, Klas2, OLD-SNMPEA-MIB
+big_test_2() ->
+ p("Testing simple next/get/set @ master agent (2)..."),
+ simple_standard_test(),
+
+ p("Testing simple next/get/set @ subagent (2)..."),
+ gn([[klas2]]),
+ ?line expect(1, [{[fname2,0], ""}]),
+ g([[fname2,0]]),
+ ?line expect(2, [{[fname2,0], ""}]),
+ s([{[fname2,0], s, "test set"}]),
+ ?line expect(3, [{[fname2,0], "test set"}]),
+ g([[fname2,0]]),
+ ?line expect(4, [{[fname2,0], "test set"}]),
+
+ otp_1298(),
+
+ p("Testing next from last object in master to subagent (2)..."),
+ gn([[?v1_2(sysServices, sysORLastChange),0]]),
+ ?line expect(5, [{[fname2,0], "test set"}]),
+ gn([[1,1],
+ [?v1_2(sysServices, sysORLastChange),0]]),
+ ?line expect(51, [{[sysDescr,0], "Erlang SNMP agent"},
+ {[fname2,0], "test set"}]),
+
+ table_test(),
+
+ p("Adding one row in subagent table (2)"),
+ _FTab = [friendsEntry2],
+ s([{[friendsEntry2, [2, 3]], s, "kompis3"},
+ {[friendsEntry2, [3, 3]], i, ?createAndGo}]),
+ ?line expect(6, [{[friendsEntry2, [2, 3]], "kompis3"},
+ {[friendsEntry2, [3, 3]], ?createAndGo}]),
+ g([[friendsEntry2, [2, 3]],
+ [friendsEntry2, [3, 3]]]),
+ ?line expect(7, [{[friendsEntry2, [2, 3]], "kompis3"},
+ {[friendsEntry2, [3, 3]], ?active}]),
+ s([{[friendsEntry2, [3, 3]], i, ?destroy}]),
+ ?line expect(8, [{[friendsEntry2, [3, 3]], ?destroy}]),
+
+ p("Adding two rows in subagent table with special INDEX (2)"),
+ s([{[kompissEntry2, [1, 3]], s, "kompis3"},
+ {[kompissEntry2, [2, 3]], i, ?createAndGo}]),
+ ?line expect(9, [{[kompissEntry2, [1, 3]], "kompis3"},
+ {[kompissEntry2, [2, 3]], ?createAndGo}]),
+ g([[kompissEntry2, [1, 3]],
+ [kompissEntry2, [2, 3]]]),
+ ?line expect(10, [{[kompissEntry2, [1, 3]], "kompis3"},
+ {[kompissEntry2, [2, 3]], ?active}]),
+ gn([[kompissEntry2, [1]],
+ [kompissEntry2, [2]]]),
+ ?line expect(11, [{[kompissEntry2, [1, 3]], "kompis3"},
+ {[kompissEntry2, [2, 3]], ?active}]),
+ s([{[kompissEntry2, [1, 2]], s, "kompis3"},
+ {[kompissEntry2, [2, 2]], i, ?createAndGo}]),
+ ?line expect(12, [{[kompissEntry2, [1, 2]], "kompis3"},
+ {[kompissEntry2, [2, 2]], ?createAndGo}]),
+ gn([[kompissEntry2, [1, 1]],
+ [kompissEntry2, [2, 1]]]),
+ ?line expect(13, [{[kompissEntry2, [1, 2]], "kompis3"},
+ {[kompissEntry2, [2, 2]], ?active}]),
+ s([{[kompissEntry2, [2, 3]], i, ?destroy}]),
+ ?line expect(14, [{[kompissEntry2, [2, 3]], ?destroy}]),
+ s([{[kompissEntry2, [2, 2]], i, ?destroy}]),
+ ?line expect(15, [{[kompissEntry2, [2, 2]], ?destroy}]),
+ ok.
+
+%% Req. Test1
+multi_threaded_test() ->
+ p("Testing multi threaded agent..."),
+ g([[multiStr,0]]),
+ Pid = get_multi_pid(),
+ g([[sysUpTime,0]]),
+ ?line expect(1, [{[sysUpTime,0], any}]),
+ s([{[sysLocation, 0], s, "pelle"}]),
+ ?line expect(2, [{[sysLocation, 0], "pelle"}]),
+ Pid ! continue,
+ ?line expect(3, [{[multiStr,0], "ok"}]),
+
+ s([{[multiStr, 0], s, "block"}]),
+ Pid2 = get_multi_pid(),
+ g([[sysUpTime,0]]),
+ ?line expect(4, [{[sysUpTime,0], any}]),
+ g([[multiStr,0]]),
+ Pid3 = get_multi_pid(),
+ g([[sysUpTime,0]]),
+ ?line expect(5, [{[sysUpTime,0], any}]),
+ s([{[sysLocation, 0], s, "kalle"}]),
+ Pid3 ! continue,
+ ?line expect(6, [{[multiStr,0], "ok"}]),
+ Pid2 ! continue,
+ ?line expect(7, [{[multiStr,0], "block"}]),
+ ?line expect(8, [{[sysLocation,0], "kalle"}]).
+
+%% Req. Test1, TestTrapv2
+mt_trap_test(MA) ->
+ snmpa:send_trap(MA, testTrapv22, "standard trap"),
+ ?line expect(1, v2trap, [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?system ++ [0,1]}]),
+
+ snmpa:send_trap(MA, mtTrap, "standard trap"),
+ Pid = get_multi_pid(),
+ g([[sysUpTime,0]]),
+ ?line expect(2, [{[sysUpTime,0], any}]),
+ snmpa:send_trap(MA, testTrapv22, "standard trap"),
+ ?line expect(3, v2trap, [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?system ++ [0,1]}]),
+ Pid ! continue,
+ ?line expect(4, v2trap, [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?testTrap ++ [2]},
+ {[multiStr,0], "ok"}]).
+
+
+get_multi_pid() ->
+ get_multi_pid(10).
+get_multi_pid(0) ->
+ ?line ?FAIL(no_global_name);
+get_multi_pid(N) ->
+ sleep(1000),
+ case global:whereis_name(snmp_multi_tester) of
+ Pid when pid(Pid) -> Pid;
+ _ -> get_multi_pid(N-1)
+ end.
+
+%% Req. Test1
+types_v2_test() ->
+ p("Testing v2 types..."),
+
+ s([{[bits1,0], 2#10}]),
+ ?line expect(1, [{[bits1,0], ?str(2#10)}]),
+ g([[bits1,0]]),
+ ?line expect(2, [{[bits1,0], ?str(2#101)}]),
+
+ s([{[bits2,0], 2#11000000110}]),
+ ?line expect(3, [{[bits2,0], ?str(2#11000000110)}]),
+ g([[bits2,0]]),
+ ?line expect(4, [{[bits2,0], ?str(2#11000000110)}]),
+
+ g([[bits3,0]]),
+ ?line expect(50, genErr, 1, any),
+
+ g([[bits4,0]]),
+ ?line expect(51, genErr, 1, any),
+
+ s([{[bits1,0], s, [2#10]}]),
+ ?line expect(6, ?v1_2(badValue, wrongValue), 1, any),
+
+ s([{[bits2,0], 2#11001001101010011}]),
+ ?line expect(7, ?v1_2(badValue, wrongValue), 1, any).
+
+
+%% Req. Test1
+implied_test(MA) ->
+ ?LOG("implied_test -> start",[]),
+ p("Testing IMPLIED..."),
+
+ snmpa:verbosity(MA,trace),
+ snmpa:verbosity(MA,trace),
+
+ %% Create two rows, check that they are get-nexted in correct order.
+ Idx1 = "apa",
+ Idx2 = "qq",
+ ?DBG("implied_test -> (send) create row 1 '~s' in table 1",[Idx1]),
+ s([{[testStatus, Idx1], i, ?createAndGo}, {[testDescr, Idx1],s,"row 1"}]),
+ ?line expect(1, [{[testStatus, Idx1], ?createAndGo},
+ {[testDescr, Idx1], "row 1"}]),
+ ?DBG("implied_test -> (send) create row 2 '~s' in table 1",[Idx2]),
+ s([{[testStatus, Idx2], i, ?createAndGo}, {[testDescr, Idx2],s,"row 2"}]),
+ ?line expect(2, [{[testStatus, Idx2], ?createAndGo},
+ {[testDescr, Idx2], "row 2"}]),
+ ?DBG("implied_test -> get-next(testDescr)",[]),
+ gn([[testDescr]]),
+ ?line expect(3, [{[testDescr,Idx1], "row 1"}]),
+ ?DBG("implied_test -> get-next(testDescr) of row 1",[]),
+ gn([[testDescr,Idx1]]),
+ ?line expect(4, [{[testDescr,Idx2], "row 2"}]),
+
+ % Delete the rows
+ ?DBG("implied_test -> (send) delete row 1 '~s' from table 1",[Idx1]),
+ s([{[testStatus, Idx1], i, ?destroy}]),
+ ?line expect(5, [{[testStatus, Idx1], ?destroy}]),
+ ?DBG("implied_test -> (send) delete row 2 '~s' from table 1",[Idx2]),
+ s([{[testStatus, Idx2], i, ?destroy}]),
+ ?line expect(6, [{[testStatus, Idx2], ?destroy}]),
+
+ %% Try the same in other table
+ Idx3 = [1, "apa"],
+ Idx4 = [1, "qq"],
+ ?DBG("implied_test -> (send) create row 1 '~s' in table 2",[Idx3]),
+ s([{[testStatus2, Idx3], i, ?createAndGo}, {[testDescr2,Idx3],s,"row 1"}]),
+ ?line expect(1, [{[testStatus2, Idx3], ?createAndGo},
+ {[testDescr2, Idx3], "row 1"}]),
+ ?DBG("implied_test -> (send) create row 2 '~s' in table 2",[Idx4]),
+ s([{[testStatus2, Idx4], i, ?createAndGo}, {[testDescr2,Idx4],s,"row 2"}]),
+ ?line expect(2, [{[testStatus2, Idx4], ?createAndGo},
+ {[testDescr2, Idx4], "row 2"}]),
+ ?DBG("implied_test -> get-next(testDescr2)",[]),
+ gn([[testDescr2]]),
+ ?line expect(3, [{[testDescr2,Idx3], "row 1"}]),
+ ?DBG("implied_test -> get-next(testDescr2) of row 1",[]),
+ gn([[testDescr2,Idx3]]),
+ ?line expect(4, [{[testDescr2,Idx4], "row 2"}]),
+
+ % Delete the rows
+ ?DBG("implied_test -> (send) delete row 1 '~s' from table 2",[Idx3]),
+ s([{[testStatus2, Idx3], i, ?destroy}]),
+ ?line expect(5, [{[testStatus2, Idx3], ?destroy}]),
+ ?DBG("implied_test -> (send) delete row 2 '~s' from table 2",[Idx4]),
+ s([{[testStatus2, Idx4], i, ?destroy}]),
+ ?line expect(6, [{[testStatus2, Idx4], ?destroy}]),
+
+ snmpa:verbosity(MA,log),
+
+ ?LOG("implied_test -> done",[]).
+
+
+
+%% Req. Test1
+sparse_table_test() ->
+ p("Testing sparse table..."),
+
+ %% Create two rows, check that they are get-nexted in correct order.
+ Idx1 = 1,
+ Idx2 = 2,
+ s([{[sparseStatus, Idx1], i, ?createAndGo},
+ {[sparseDescr, Idx1], s, "row 1"}]),
+ ?line expect(1, [{[sparseStatus, Idx1], ?createAndGo},
+ {[sparseDescr, Idx1], "row 1"}]),
+ s([{[sparseStatus, Idx2], i, ?createAndGo},
+ {[sparseDescr, Idx2], s, "row 2"}]),
+ ?line expect(2, [{[sparseStatus, Idx2], ?createAndGo},
+ {[sparseDescr, Idx2], "row 2"}]),
+ ?v1_2(gn([[sparseIndex], [sparseDescr,Idx1], [sparseDescr,Idx2],
+ [sparseStatus,Idx1], [sparseStatus,Idx2]]),
+ gb(0,5,[[sparseIndex]])),
+ ?line expect(3, [{[sparseDescr,Idx1], "row 1"},
+ {[sparseDescr,Idx2], "row 2"},
+ {[sparseStatus,Idx1], ?active},
+ {[sparseStatus,Idx2], ?active},
+ {[sparseStr,0], "slut"}]),
+ % Delete the rows
+ s([{[sparseStatus, Idx1], i, ?destroy}]),
+ ?line expect(4, [{[sparseStatus, Idx1], ?destroy}]),
+ s([{[sparseStatus, Idx2], i, ?destroy}]),
+ ?line expect(5, [{[sparseStatus, Idx2], ?destroy}]).
+
+
+%% Req. Test1
+cnt_64_test(MA) ->
+ ?LOG("start cnt64 test (~p)",[MA]),
+ snmpa:verbosity(MA,trace),
+ ?LOG("start cnt64 test",[]),
+ p("Testing Counter64, and at the same time, RowStatus is not last column"),
+
+ ?DBG("get cnt64",[]),
+ g([[cnt64,0]]),
+ ?DBG("await response",[]),
+ ?line ?v1_2(expect(1, noSuchName, 1, any),
+ expect(1, [{[cnt64,0],18446744073709551615}])),
+ ?DBG("get-next cnt64",[]),
+ gn([[cnt64]]),
+ ?DBG("await response",[]),
+ ?line ?v1_2(expect(2, [{[cnt64Str,0], "after cnt64"}]),
+ expect(2, [{[cnt64,0],18446744073709551615}])),
+ ?DBG("send cntTrap",[]),
+ snmpa:send_trap(MA,cntTrap,"standard trap",[{sysContact,"pelle"},
+ {cnt64, 10},
+ {sysLocation, "here"}]),
+ ?DBG("await response",[]),
+ ?line ?v1_2(expect(3, trap, [test], 6, 1, [{[sysContact,0], "pelle"},
+ {[sysLocation,0], "here"}]),
+ expect(3, v2trap, [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?testTrap ++ [1]},
+ {[sysContact,0], "pelle"},
+ {[cnt64,0], 10},
+ {[sysLocation,0], "here"}])),
+
+ %% Create two rows, check that they are get-nexted in correct order.
+ Idx1 = 1,
+ Idx2 = 2,
+ ?DBG("create row (cntStatus): ~p",[Idx1]),
+ s([{[cntStatus, Idx1], i, ?createAndGo}]),
+ ?DBG("await response",[]),
+ ?line expect(1, [{[cntStatus, Idx1], ?createAndGo}]),
+ ?DBG("create row (cntStatus): ~p",[Idx2]),
+ s([{[cntStatus, Idx2], i, ?createAndGo}]),
+ ?DBG("await response",[]),
+ ?line expect(2, [{[cntStatus, Idx2], ?createAndGo}]),
+
+ ?DBG("get-next (cntIndex)",[]),
+ gn([[cntIndex]]),
+ ?DBG("await response",[]),
+ ?line ?v1_2(expect(3, [{[cntStatus,Idx1], ?active}]),
+ expect(3, [{[cntCnt,Idx1], 0}])),
+ % Delete the rows
+ ?DBG("delete row (cntStatus): ~p",[Idx1]),
+ s([{[cntStatus, Idx1], i, ?destroy}]),
+ ?DBG("await response",[]),
+ ?line expect(4, [{[cntStatus, Idx1], ?destroy}]),
+ ?DBG("delete row (cntStatus): ~p",[Idx2]),
+ s([{[cntStatus, Idx2], i, ?destroy}]),
+ ?DBG("await response",[]),
+ ?line expect(5, [{[cntStatus, Idx2], ?destroy}]),
+ catch snmpa:verbosity(MA,log),
+ ?DBG("done",[]),
+ ok.
+
+%% Req. Test1
+opaque_test() ->
+ p("Testing Opaque datatype..."),
+ g([[opaqueObj,0]]),
+ ?line expect(1, [{[opaqueObj,0], "opaque-data"}]).
+
+%% Req. OLD-SNMPEA-MIB
+api_test(MaNode) ->
+ ?line {value, OID} = rpc:call(MaNode, snmp, name_to_oid,
+ [intAgentIpAddress]),
+ ?line {value, intAgentIpAddress} = rpc:call(MaNode, snmp,
+ oid_to_name, [OID]),
+ ?line false = rpc:call(MaNode, snmp, name_to_oid, [intAgentIpAddres]),
+ ?line false = rpc:call(MaNode, snmp, oid_to_name,
+ [[1,5,32,3,54,3,3,34,4]]),
+ ?line {value, 2} = rpc:call(MaNode, snmp, enum_to_int,
+ [intViewType, excluded]),
+ ?line {value, excluded} = rpc:call(MaNode, snmp, int_to_enum,
+ [intViewType, 2]),
+ ?line false = rpc:call(MaNode, snmp, enum_to_int, [intViewType, exclude]),
+ ?line false = rpc:call(MaNode, snmp, enum_to_int,
+ [intAgentIpAddress, exclude]),
+ ?line false = rpc:call(MaNode, snmp, enum_to_int,
+ [intAgentIpAddre, exclude]),
+ ?line false = rpc:call(MaNode, snmp, int_to_enum, [intViewType, 3]),
+ ?line false = rpc:call(MaNode, snmp, int_to_enum, [intAgentIpAddress, 2]),
+ ?line false = rpc:call(MaNode, snmp, int_to_enum, [intAgentIpAddre, 2]),
+ ?line {value, active} = rpc:call(MaNode, snmp,
+ int_to_enum, ['RowStatus', ?active]),
+ ?line {value, ?destroy} = rpc:call(MaNode, snmp,
+ enum_to_int, ['RowStatus', destroy]),
+ ?line false = rpc:call(MaNode, snmp,
+ enum_to_int, ['RowStatus', xxxdestroy]),
+ ?line false = rpc:call(MaNode, snmp,
+ enum_to_int, ['xxRowStatus', destroy]),
+ ?line false = rpc:call(MaNode, snmp, int_to_enum, ['RowStatus', 25]),
+ ?line false = rpc:call(MaNode, snmp, int_to_enum, ['xxRowStatus', 1]),
+ ?line case snmp:date_and_time() of
+ List when list(List), length(List) == 8 -> ok;
+ List when list(List), length(List) == 11 -> ok
+ end.
+
+%% Req. Klas3
+api_test2() ->
+ g([[fname3,0]]),
+ ?line expect(1, [{[fname3,0], "ok"}]),
+ g([[fname4,0]]),
+ ?line expect(2, [{[fname4,0], 1}]).
+
+api_test3() ->
+ g([[fname3,0]]),
+ ?line expect(1, [{[fname3,0], "ok"}]).
+
+
+unreg_test() ->
+ gn([[?v1_2(sysServices, sysORLastChange),0]]),
+ ?line expect(1, [{[snmpInPkts, 0], any}]).
+
+load_test() ->
+ gn([[?v1_2(sysServices, sysORLastChange),0]]),
+ ?line expect(1, [{[fname,0], ""}]).
+
+%% Req. Klas1
+load_test_sa() ->
+ gn([[?v1_2(sysServices,sysORLastChange), 0]]),
+ ?line expect(1, [{[fname,0], any}]).
+
+%% Req. system group, Klas1, OLD-SNMPEA-MIB
+do_mul_get() ->
+ Key1c3 = [intCommunityEntry,[3],get(mip),is("public")],
+ Key1c4 = [intCommunityEntry,[4],get(mip),is("public")],
+ s([{[fname,0], s, "test set"}]),
+ ?line expect(3, [{[fname,0], "test set"}]),
+ g([[sysDescr,0], Key1c4, [fname,0],Key1c3,
+ [sysName,0]]),
+ ?line expect(1, [{[sysDescr,0], "Erlang SNMP agent"},
+ {Key1c4, 2},
+ {[fname,0], "test set"},
+ {Key1c3, 2},
+ {[sysName,0], "test"}]),
+ g([[1,3,7,1], Key1c4, [sysDescr,0], [1,3,7,2], Key1c3, [sysDescr,0]]),
+ ?line ?v1_2(expect(2, noSuchName, [1,4], any),
+ expect(2, [{[1,3,7,1], noSuchObject},
+ {Key1c4, 2},
+ {[sysDescr,0], "Erlang SNMP agent"},
+ {[1,3,7,2], noSuchObject},
+ {Key1c3, 2},
+ {[sysDescr,0], "Erlang SNMP agent"}])).
+
+%% Req. v1, system group, Klas1, OLD-SNMPEA-MIB, *ej* Klas3.
+do_mul_get_err() ->
+ Key1c3 = [intCommunityEntry,[3],get(mip),is("public")],
+ Key1c4 = [intCommunityEntry,[4],get(mip),is("public")],
+ s([{[fname,0], s, "test set"}]),
+ ?line expect(3, [{[fname,0], "test set"}]),
+ g([[sysDescr,0],Key1c4,[fname,0], Key1c3, [sysName,2]]),
+ ?line ?v1_2(expect(1, noSuchName, 5, any),
+ expect(1, [{[sysDescr,0], "Erlang SNMP agent"},
+ {Key1c4, 2},
+ {[fname,0], "test set"},
+ {Key1c3, 2},
+ {[sysName,2], noSuchInstance}])),
+ g([[sysDescr,0],Key1c4,[fname3,0], Key1c3, [sysName,1]]),
+ ?line ?v1_2(expect(1, noSuchName, [3,5], any),
+ expect(1, [{[sysDescr,0], "Erlang SNMP agent"},
+ {Key1c4, 2},
+ {[fname3,0], noSuchObject},
+ {Key1c3, 2},
+ {[sysName,1], noSuchInstance}])).
+
+
+%% Req. system group, Klas1, OLD-SNMPEA-MIB
+do_mul_next() ->
+ Key1c3s = [intCommunityEntry,[3],get(mip),is("publi")],
+ Key1c4s = [intCommunityEntry,[4],get(mip),is("publi")],
+ Key1c3 = [intCommunityEntry,[3],get(mip),is("public")],
+ Key1c4 = [intCommunityEntry,[4],get(mip),is("public")],
+ s([{[fname,0], s, "test set"}]),
+ ?line expect(3, [{[fname,0], "test set"}]),
+ gn([[sysDescr], Key1c4s, [fname],Key1c3s,[sysName]]),
+ ?line expect(1, [{[sysDescr,0], "Erlang SNMP agent"},
+ {Key1c4, 2}, {[fname,0], "test set"},
+ {Key1c3, 2}, {[sysName,0], "test"}]).
+
+%% Req. system group, Klas1, OLD-SNMPEA-MIB
+do_mul_next_err() ->
+ Key1c3s = [intCommunityEntry,[3],get(mip),is("publi")],
+ Key1c4s = [intCommunityEntry,[4],get(mip),is("publi")],
+ Key1c3 = [intCommunityEntry,[3],get(mip),is("public")],
+ Key1c4 = [intCommunityEntry,[4],get(mip),is("public")],
+ s([{[fname,0], s, "test set"}]),
+ ?line expect(3, [{[fname,0], "test set"}]),
+ gn([[sysDescr], Key1c4s, [1,3,6,999], [fname],[1,3,90], Key1c3s,[sysName]]),
+ ?line ?v1_2(expect(1, noSuchName, [3,5], any),
+ expect(1, [{[sysDescr,0], "Erlang SNMP agent"},
+ {Key1c4, 2},
+ {[1,3,6,999], endOfMibView},
+ {[fname,0], "test set"},
+ {[1,3,90], endOfMibView},
+ {Key1c3, 2},
+ {[sysName,0], "test"}])).
+
+
+%% Req. system group, Klas1, OLD-SNMPEA-MIB
+do_mul_set() ->
+ p("Adding one row in subagent table, and one in master table"),
+ NewKeyc3 = [intCommunityEntry,[3],get(mip),is("test")],
+ NewKeyc4 = [intCommunityEntry,[4],get(mip),is("test")],
+ NewKeyc5 = [intCommunityEntry,[5],get(mip),is("test")],
+ s([{[friendsEntry, [2, 3]], "kompis3"},
+ {NewKeyc3, 2},
+ {[sysLocation,0], "new_value"},
+ {NewKeyc5, ?createAndGo},
+ {NewKeyc4, 2},
+ {[friendsEntry, [3, 3]], ?createAndGo}]),
+ ?line expect(1, [{[friendsEntry, [2, 3]], "kompis3"},
+ {NewKeyc3, 2},
+ {[sysLocation,0], "new_value"},
+ {NewKeyc5, ?createAndGo},
+ {NewKeyc4, 2},
+ {[friendsEntry, [3, 3]], ?createAndGo}]),
+ g([[friendsEntry, [2, 3]],
+ [sysLocation,0],
+ [friendsEntry, [3, 3]]]),
+ ?line expect(2, [{[friendsEntry, [2, 3]], "kompis3"},
+ {[sysLocation,0], "new_value"},
+ {[friendsEntry, [3, 3]], ?active}]),
+ g([NewKeyc4]),
+ ?line expect(3, [{NewKeyc4, 2}]),
+ s([{[friendsEntry, [3, 3]], ?destroy},
+ {NewKeyc5, ?destroy}]),
+ ?line expect(4, [{[friendsEntry, [3, 3]], ?destroy},
+ {NewKeyc5, ?destroy}]).
+
+%% Req. system group, Klas1, OLD-SNMPEA-MIB
+do_mul_set_err() ->
+ NewKeyc3 = [intCommunityEntry,[3],get(mip),is("test")],
+ NewKeyc4 = [intCommunityEntry,[4],get(mip),is("test")],
+ NewKeyc5 = [intCommunityEntry,[5],get(mip),is("test")],
+ p("Adding one row in subagent table, and one in master table"),
+ s([{[friendsEntry, [2, 3]], s, "kompis3"},
+ {NewKeyc3, 2},
+ {[sysUpTime,0], 45}, % sysUpTime (readOnly)
+ {NewKeyc5, ?createAndGo},
+ {NewKeyc4, 2},
+ {[friendsEntry, [3, 3]], ?createAndGo}]),
+ ?line expect(1, ?v1_2(noSuchName, notWritable), 3, any),
+ g([[friendsEntry, [2, 3]]]),
+ ?line ?v1_2(expect(2, noSuchName, 1, any),
+ expect(2, [{[friendsEntry, [2,3]], noSuchInstance}])),
+ g([NewKeyc4]),
+ ?line ?v1_2(expect(3, noSuchName, 1, any),
+ expect(3, [{NewKeyc4, noSuchInstance}])).
+
+%% Req. SA-MIB
+sa_mib() ->
+ g([[sa, [2,0]]]),
+ ?line expect(1, [{[sa, [2,0]], 3}]),
+ s([{[sa, [1,0]], s, "sa_test"}]),
+ ?line expect(2, [{[sa, [1,0]], "sa_test"}]).
+
+ma_trap1(MA) ->
+ snmpa:send_trap(MA, testTrap2, "standard trap"),
+ ?line expect(1, trap, [system], 6, 1, [{[system, [4,0]],
+ "{mbj,eklas}@erlang.ericsson.se"}]),
+ snmpa:send_trap(MA, testTrap1, "standard trap"),
+ ?line expect(2, trap, [1,2,3] , 1, 0, [{[system, [4,0]],
+ "{mbj,eklas}@erlang.ericsson.se"}]).
+
+ma_trap2(MA) ->
+ snmpa:send_trap(MA,testTrap2,"standard trap",[{sysContact,"pelle"}]),
+ ?line expect(3, trap, [system], 6, 1, [{[system, [4,0]], "pelle"}]).
+
+ma_v2_2_v1_trap(MA) ->
+ snmpa:send_trap(MA,testTrapv22,"standard trap",[{sysContact,"pelle"}]),
+ ?line expect(3, trap, [system], 6, 1, [{[system, [4,0]], "pelle"}]).
+
+ma_v2_2_v1_trap2(MA) ->
+ snmpa:send_trap(MA,linkUp,"standard trap",[{ifIndex, [1], 1},
+ {ifAdminStatus, [1], 1},
+ {ifOperStatus, [1], 2}]),
+ ?line expect(3, trap, [1,2,3], 3, 0, [{[ifIndex, 1], 1},
+ {[ifAdminStatus, 1], 1},
+ {[ifOperStatus, 1], 2}]).
+
+sa_trap1(SA) ->
+ snmpa:send_trap(SA, saTrap, "standard trap"),
+ ?line expect(4, trap, [ericsson], 6, 1, [{[system, [4,0]],
+ "{mbj,eklas}@erlang.ericsson.se"},
+ {[sa, [1,0]], "sa_test"}]).
+
+sa_trap2(SA) ->
+ snmpa:send_trap(SA, saTrap, "standard trap",[{sysContact,"pelle"}]),
+ ?line expect(5, trap, [ericsson], 6, 1, [{[system, [4,0]],
+ "pelle"},
+ {[sa, [1,0]], "sa_test"}]).
+
+sa_trap3(SA) ->
+ snmpa:send_trap(SA, saTrap2, "standard trap",
+ [{intViewSubtree, [4], [1,2,3,4]}]),
+ ?line expect(6, trap, [ericsson], 6, 2, [{[system, [4,0]],
+ "{mbj,eklas}@erlang.ericsson.se"},
+ {[sa, [1,0]], "sa_test"},
+ {[intViewSubtree,4],[1,2,3,4]}]).
+
+ma_v2_trap1(MA) ->
+ ?DBG("ma_v2_traps -> entry with MA = ~p => "
+ "send standard trap: testTrapv22",[MA]),
+ snmpa:send_trap(MA, testTrapv22, "standard trap"),
+ ?line expect(1, v2trap, [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?system ++ [0,1]}]),
+ ?DBG("ma_v2_traps -> send standard trap: testTrapv21",[]),
+ snmpa:send_trap(MA, testTrapv21, "standard trap"),
+ ?line expect(2, v2trap, [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?snmp ++ [1]}]).
+
+ma_v2_trap2(MA) ->
+ snmpa:send_trap(MA,testTrapv22,"standard trap",[{sysContact,"pelle"}]),
+ ?line expect(3, v2trap, [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?system ++ [0,1]},
+ {[system, [4,0]], "pelle"}]).
+
+%% Note: This test case takes a while... actually a couple of minutes.
+ma_v2_inform1(MA) ->
+ ?DBG("ma_v2_inform -> entry with MA = ~p => "
+ "send notification: testTrapv22",[MA]),
+ ?line snmpa:send_notification(MA, testTrapv22, no_receiver, "standard inform", []),
+ ?line expect(1, {inform, true},
+ [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?system ++ [0,1]}]),
+
+ ?DBG("ma_v2_inform -> send notification: testTrapv22",[]),
+ snmpa:send_notification(MA, testTrapv22, {tag1, self()},
+ "standard inform", []),
+ ?line expect(1, {inform, true},
+ [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?system ++ [0,1]}]),
+ ?DBG("ma_v2_inform -> await targets",[]),
+ receive
+ {snmp_targets, tag1, [_]} ->
+ ok;
+ {snmp_targets, tag1, Addrs1} ->
+ ?line ?FAIL({bad_addrs, Addrs1})
+ after
+ 5000 ->
+ ?ERR("ma_v2_inform1 -> awaiting snmp_targets(tag1) timeout",[]),
+ ?line ?FAIL(nothing_at_all)
+ end,
+ ?DBG("ma_v2_inform -> await notification",[]),
+ receive
+ {snmp_notification, tag1, {got_response, _}} ->
+ ok;
+ {snmp_notification, tag1, {no_response, _}} ->
+ ?line ?FAIL(no_response)
+ after
+ 20000 ->
+ ?ERR("ma_v2_inform1 -> "
+ "awaiting snmp_notification(tag1) timeout",[]),
+ ?line ?FAIL(nothing_at_all)
+ end,
+
+ %%
+ %% -- The rest is possibly erroneous...
+ %%
+
+ ?DBG("ma_v2_inform -> send notification: testTrapv22",[]),
+ snmpa:send_notification(MA, testTrapv22, {tag2, self()},
+ "standard inform", []),
+ ?line expect(2, {inform, false},
+ [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?system ++ [0,1]}]),
+ ?DBG("ma_v2_inform -> await targets",[]),
+ receive
+ {snmp_targets, tag2, [_]} ->
+ ok;
+ {snmp_targets, tag2, Addrs2} ->
+ ?ERR("ma_v2_inform1 -> awaiting snmp_targets(tag2) timeout",[]),
+ ?line ?FAIL({bad_addrs, Addrs2})
+ after
+ 5000 ->
+ ?line ?FAIL(nothing_at_all)
+ end,
+ ?DBG("ma_v2_inform -> await notification",[]),
+ receive
+ {snmp_notification, tag2, {got_response, _}} ->
+ ?line ?FAIL(got_response);
+ {snmp_notification, tag2, {no_response, _}} ->
+ ok
+ after
+ 240000 ->
+ ?ERR("ma_v2_inform1 -> "
+ "awaiting snmp_notification(tag2) timeout",[]),
+ ?line ?FAIL(nothing_at_all)
+ end.
+
+
+ma_v1_2_v2_trap(MA) ->
+ snmpa:send_trap(MA,linkDown,"standard trap",[{ifIndex, [1], 1}]),
+ ?line expect(2, v2trap, [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?snmpTraps ++ [3]},
+ {[ifIndex, 1], 1},
+ {[snmpTrapEnterprise, 0], [1,2,3]}]).
+
+
+ma_v1_2_v2_trap2(MA) ->
+ snmpa:send_trap(MA,testTrap2,"standard trap",[{sysContact,"pelle"}]),
+ ?line expect(3, v2trap, [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?system ++ [0,1]},
+ {[system, [4,0]], "pelle"},
+ {[snmpTrapEnterprise, 0], ?system}]).
+
+
+sa_v1_2_v2_trap1(SA) ->
+ snmpa:send_trap(SA, saTrap, "standard trap"),
+ ?line expect(4, v2trap, [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?ericsson ++ [0, 1]},
+ {[system, [4,0]],
+ "{mbj,eklas}@erlang.ericsson.se"},
+ {[sa, [1,0]], "sa_test"},
+ {[snmpTrapEnterprise, 0], ?ericsson}]).
+
+sa_v1_2_v2_trap2(SA) ->
+ snmpa:send_trap(SA, saTrap, "standard trap",[{sysContact,"pelle"}]),
+ ?line expect(4, v2trap, [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?ericsson ++ [0, 1]},
+ {[system, [4,0]], "pelle"},
+ {[sa, [1,0]], "sa_test"},
+ {[snmpTrapEnterprise, 0], ?ericsson}]).
+
+
+sa_v1_2_v2_trap3(SA) ->
+ snmpa:send_trap(SA, saTrap2, "standard trap",
+ [{intViewSubtree, [4], [1,2,3,4]}]),
+ ?line expect(4, v2trap, [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?ericsson ++ [0, 2]},
+ {[system, [4,0]],
+ "{mbj,eklas}@erlang.ericsson.se"},
+ {[sa, [1,0]], "sa_test"},
+ {[intViewSubtree,4],[1,2,3,4]},
+ {[snmpTrapEnterprise, 0], ?ericsson}]).
+
+
+%% Req. SA-MIB, OLD-SNMPEA-MIB
+sa_errs_bad_value() ->
+ NewKeyc3 = [intCommunityEntry,[3],get(mip),is("test")],
+ NewKeyc4 = [intCommunityEntry,[4],get(mip),is("test")],
+ NewKeyc5 = [intCommunityEntry,[5],get(mip),is("test")],
+ s([{NewKeyc3, 2},
+ {[sa, [2,0]], 5}, % badValue (i is_set_ok)
+ {NewKeyc5, ?createAndGo},
+ {NewKeyc4, 2}]),
+ ?line expect(1, badValue, 2, any),
+ s([{NewKeyc3, 2},
+ {[sa, [2,0]], 6}, % wrongValue (i is_set_ok)
+ {NewKeyc5, ?createAndGo},
+ {NewKeyc4, 2}]),
+ ?line expect(1, ?v1_2(badValue, wrongValue), 2, any),
+ g([NewKeyc4]),
+ ?line ?v1_2(expect(2, noSuchName, 1, any),
+ expect(2, [{NewKeyc4, noSuchInstance}])).
+
+%% Req. SA-MIB, OLD-SNMPEA-MIB
+sa_errs_gen_err() ->
+ NewKeyc3 = [intCommunityEntry,[3],get(mip),is("test")],
+ NewKeyc4 = [intCommunityEntry,[4],get(mip),is("test")],
+ NewKeyc5 = [intCommunityEntry,[5],get(mip),is("test")],
+ s([{NewKeyc3, 2},{NewKeyc4, 2},
+ {NewKeyc5, ?createAndGo}, {[sa, [3,0]], 5}]),
+ ?line expect(1, genErr, 4, any),
+% The row might have been added; we don't know.
+% (as a matter of fact we do - it is added, because the agent
+% first sets its own vars, and then th SAs. Lets destroy it.
+ s([{NewKeyc5, ?destroy}]),
+ ?line expect(2, [{NewKeyc5, ?destroy}]).
+
+%% Req. SA-MIB, OLD-SNMPEA-MIB
+sa_too_big() ->
+ g([[sa, [4,0]]]),
+ ?line expect(1, tooBig).
+
+%% Req. Klas1, system group, snmp group (v1/v2)
+next_across_sa() ->
+ gn([[sysDescr],[klas1,5]]),
+ ?line expect(1, [{[sysDescr,0], "Erlang SNMP agent"},
+ {[snmpInPkts, 0], any}]).
+
+%% snmp_test_mgr:s([{[fStatus3, 1], 4}, {[fname3,0], "ok"}]). -> noError
+%% snmp_test_mgr:s([{[fStatus3, 1], 4}, {[fname3,0], "hoj"}]). -> {badValue, 2}
+%% snmp_test_mgr:s([{[fStatus3, 3], 4}, {[fname3,0], "hoj"}]). -> {genErr, 1}
+%% snmp_test_mgr:s([{[fStatus3, 4], 4}, {[fname3,0], "ok"}]). -> {genErr, 1}
+%% snmp_test_mgr:s([{[fStatus3, 4], 4}, {[fname3,0], "ufail"}]). -> {genErr, 1}
+%% snmp_test_mgr:s([{[fStatus3, 1], 4}, {[fname3,0], "xfail"}]). -> {genErr, 2}
+%% Req. Klas3, Klas4
+undo_test() ->
+ s([{[fStatus3, 1], 4}, {[fname3,0], "ok"}]),
+ ?line expect(1, [{[fStatus3, 1], 4}, {[fname3,0], "ok"}]),
+ s([{[fStatus3, 1], 4}, {[fname3,0], "hoj"}]),
+ ?line expect(2, ?v1_2(badValue, inconsistentValue), 2, any),
+ s([{[fStatus3, 3], 4}, {[fname3,0], "hoj"}]),
+ ?line expect(3, ?v1_2(genErr, undoFailed), 1, any),
+ s([{[fStatus3, 4], 4}, {[fname3,0], "ok"}]),
+ ?line expect(4, ?v1_2(genErr, commitFailed), 1, any),
+% unfortunatly we don't know if we'll get undoFailed or commitFailed.
+% it depends on which order the agent traverses the varbind list.
+% s([{[fStatus3, 4], 4}, {[fname3,0], "ufail"}]),
+% ?line expect(5, ?v1_2(genErr, undoFailed), 1, any),
+ s([{[fStatus3, 1], 4}, {[fname3,0], "xfail"}]),
+ ?line expect(6, genErr, 2, any).
+
+%% Req. Klas3, Klas4
+bad_return() ->
+ g([[fStatus4,4],
+ [fName4,4]]),
+ ?line expect(4, genErr, 2, any),
+ g([[fStatus4,5],
+ [fName4,5]]),
+ ?line expect(5, genErr, 1, any),
+ g([[fStatus4,6],
+ [fName4,6]]),
+ ?line expect(6, genErr, 2, any),
+ gn([[fStatus4,7],
+ [fName4,7]]),
+ ?line expect(7, genErr, 2, any),
+ gn([[fStatus4,8],
+ [fName4,8]]),
+ ?line expect(8, genErr, 1, any),
+ gn([[fStatus4,9],
+ [fName4,9]]),
+ ?line expect(9, genErr, 2, any).
+
+
+%%%-----------------------------------------------------------------
+%%% Test the implementation of standard mibs.
+%%% We should *at least* try to GET all variables, just to make
+%%% sure the instrumentation functions work.
+%%% Note that many of the functions in the standard mib is
+%%% already tested by the normal tests.
+%%%-----------------------------------------------------------------
+standard_mibs(suite) ->
+ [snmp_standard_mib, snmp_community_mib,
+ snmp_framework_mib,
+ snmp_target_mib, snmp_notification_mib,
+ snmp_view_based_acm_mib].
+
+standard_mibs_2(suite) ->
+ [snmpv2_mib_2, snmp_community_mib_2,
+ snmp_framework_mib_2,
+ snmp_target_mib_2, snmp_notification_mib_2,
+ snmp_view_based_acm_mib_2].
+
+standard_mibs_3(suite) ->
+ [snmpv2_mib_3,snmp_framework_mib_3, snmp_mpd_mib_3,
+ snmp_target_mib_3, snmp_notification_mib_3,
+ snmp_view_based_acm_mib_3, snmp_user_based_sm_mib_3].
+
+%%-----------------------------------------------------------------
+%% For this test, the agent is configured for v1.
+%% o Test the counters and control objects in SNMP-STANDARD-MIB
+%%-----------------------------------------------------------------
+snmp_standard_mib(suite) -> [];
+snmp_standard_mib(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?DBG("snmp_standard_mib -> std_mib_init", []),
+ try_test(std_mib_init),
+
+ ?DBG("snmp_standard_mib -> std_mib_a", []),
+ InBadVsns = try_test(std_mib_a),
+ put(vsn, v2),
+ ?DBG("snmp_standard_mib -> std_mib_read", []),
+ try_test(std_mib_read),
+ put(vsn, v1),
+
+ ?DBG("snmp_standard_mib -> std_mib_b (~w)", [InBadVsns]),
+ Bad = try_test(std_mib_b, [InBadVsns]),
+ ?DBG("snmp_standard_mib -> std_mib_read (community: 'bad community')", []),
+ try_test(std_mib_read, [], [{community, "bad community"}]),
+ ?DBG("snmp_standard_mib -> std_mib_write (community: 'public')", []),
+ try_test(std_mib_write, [], [{community, "public"}]),
+ ?DBG("snmp_standard_mib -> std_mib_asn_err", []),
+ try_test(std_mib_asn_err),
+ ?DBG("snmp_standard_mib -> std_mib_c (~w)", [Bad]),
+ try_test(std_mib_c, [Bad]),
+ ?DBG("snmp_standard_mib -> std_mib_a", []),
+ try_test(standard_mib_a),
+
+ ?DBG("snmp_standard_mib -> std_mib_finish", []),
+ try_test(std_mib_finish),
+ ?DBG("snmp_standard_mib -> std_mib_test_finish", []),
+ try_test(standard_mib_test_finish, [], [{community, "bad community"}]).
+
+%% Req. SNMP-STANDARD-MIB
+standard_mib_a() ->
+ ?line [OutPkts] = get_req(2, [[snmpOutPkts,0]]),
+ ?line [OutPkts2] = get_req(3, [[snmpOutPkts,0]]),
+ ?line OutPkts2 = OutPkts + 1,
+ %% There are some more counters we could test here, but it's not that
+ %% important, since they are removed from SNMPv2-MIB.
+ ok.
+
+%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB
+std_mib_init() ->
+ %% disable authentication failure traps. (otherwise w'd get many of
+ %% them - this is also a test to see that it works).
+ s([{[snmpEnableAuthenTraps,0], 2}]),
+ ?line expect(1, [{[snmpEnableAuthenTraps, 0], 2}]).
+
+%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB
+std_mib_finish() ->
+ %% enable again
+ s([{[snmpEnableAuthenTraps,0], 1}]),
+ ?line expect(1, [{[snmpEnableAuthenTraps, 0], 1}]).
+
+%% Req. SNMP-STANDARD-MIB
+standard_mib_test_finish() ->
+ %% force a authenticationFailure
+ std_mib_write(),
+ %% check that we got a trap
+ ?line expect(2, trap, [1,2,3], 4, 0, []).
+
+%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB
+std_mib_read() ->
+ ?DBG("std_mib_read -> entry", []),
+ g([[sysUpTime,0]]), % try a bad <something>; msg dropped, no reply
+ ?DBG("std_mib_read -> await timeout (i.e. no reply)", []),
+ ?line expect(1, timeout). % make sure we don't get a trap!
+
+
+%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB
+std_mib_write() ->
+ ?DBG("std_mib_write -> entry", []),
+ s([{[sysLocation, 0], "new_value"}]).
+
+%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB
+std_mib_asn_err() ->
+ snmp_test_mgr:send_bytes([48,99,67,12,0,0,0,0,0,0,5]).
+
+%%-----------------------------------------------------------------
+%% For this test, the agent is configured for v2 and v3.
+%% o Test the counters and control objects in SNMPv2-MIB
+%%-----------------------------------------------------------------
+snmpv2_mib_2(suite) -> [];
+snmpv2_mib_2(Config) when list(Config) ->
+ ?LOG("snmpv2_mib_2 -> start",[]),
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ ?DBG("snmpv2_mib_2 -> standard mib init",[]),
+ try_test(std_mib_init),
+
+ ?DBG("snmpv2_mib_2 -> get number of (so far) bad versions",[]),
+ InBadVsns = try_test(std_mib_a),
+
+ ?DBG("snmpv2_mib_2 -> make a bad version read",[]),
+ put(vsn, v1),
+ try_test(std_mib_read),
+
+ ?DBG("snmpv2_mib_2 -> bad version read",[]),
+ put(vsn, v2),
+ Bad = try_test(std_mib_b, [InBadVsns]),
+
+ ?DBG("snmpv2_mib_2 -> read with bad community",[]),
+ try_test(std_mib_read, [], [{community, "bad community"}]),
+
+ ?DBG("snmpv2_mib_2 -> write with public community",[]),
+ try_test(std_mib_write, [], [{community, "public"}]),
+
+ ?DBG("snmpv2_mib_2 -> asn err",[]),
+ try_test(std_mib_asn_err),
+
+ ?DBG("snmpv2_mib_2 -> check counters",[]),
+ try_test(std_mib_c, [Bad]),
+
+ ?DBG("snmpv2_mib_2 -> get som counters",[]),
+ try_test(snmpv2_mib_a),
+
+ ?DBG("snmpv2_mib_2 -> enable auth traps, and await some",[]),
+ try_test(std_mib_finish),
+
+ ?DBG("snmpv2_mib_2 -> force auth failure, and await trap, "
+ "then disable auth traps",[]),
+ try_test(snmpv2_mib_test_finish, [], [{community, "bad community"}]),
+
+ ?LOG("snmpv2_mib_2 -> done",[]).
+
+%% Req. SNMPv2-MIB
+snmpv2_mib_3(suite) -> [];
+snmpv2_mib_3(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ InBadVsns = try_test(std_mib_a),
+ put(vsn, v1),
+ try_test(std_mib_read),
+ put(vsn, v3),
+ _Bad = try_test(std_mib_b, [InBadVsns]),
+ try_test(snmpv2_mib_a),
+
+ try_test(std_mib_finish).
+
+-define(authenticationFailure, [1,3,6,1,6,3,1,1,5,5]).
+
+%% Req. SNMPv2-MIB
+snmpv2_mib_test_finish() ->
+ %% force a authenticationFailure
+ ?DBG("ma_v2_inform -> write to std mib",[]),
+ std_mib_write(),
+
+ %% check that we got a trap
+ ?DBG("ma_v2_inform -> await trap",[]),
+ ?line expect(2, v2trap, [{[sysUpTime,0], any},
+ {[snmpTrapOID,0], ?authenticationFailure}]),
+
+ %% and the the inform
+ ?DBG("ma_v2_inform -> await inform",[]),
+ ?line expect(2, {inform,true}, [{[sysUpTime,0], any},
+ {[snmpTrapOID,0],?authenticationFailure}]).
+
+%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB
+std_mib_a() ->
+ ?line [InPkts] = get_req(2, [[snmpInPkts,0]]),
+ ?line [InPkts2] = get_req(3, [[snmpInPkts,0]]),
+ ?line InPkts2 = InPkts + 1,
+
+ ?line [InBadVsns] = get_req(4, [[snmpInBadVersions,0]]),
+ InBadVsns.
+
+%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB
+std_mib_b(InBadVsns) ->
+ ?line [InBadVsns2] = get_req(1, [[snmpInBadVersions,0]]),
+ ?line InBadVsns2 = InBadVsns + 1,
+ ?line [InPkts] = get_req(2, [[snmpInPkts,0]]),
+ ?line [InPkts2] = get_req(3, [[snmpInPkts,0]]),
+ ?line InPkts2 = InPkts + 1,
+ ?line [InBadCommunityNames, InBadCommunityUses, InASNErrs] =
+ get_req(4, [[snmpInBadCommunityNames,0],
+ [snmpInBadCommunityUses,0],
+ [snmpInASNParseErrs, 0]]),
+ {InBadCommunityNames, InBadCommunityUses, InASNErrs}.
+
+%% Req. SNMP-STANDARD-MIB | SNMPv2-MIB
+std_mib_c({InBadCommunityNames, InBadCommunityUses, InASNErrs}) ->
+ ?line [InBadCommunityNames2, InBadCommunityUses2, InASNErrs2] =
+ get_req(1, [[snmpInBadCommunityNames,0],
+ [snmpInBadCommunityUses,0],
+ [snmpInASNParseErrs, 0]]),
+ ?line InBadCommunityNames2 = InBadCommunityNames + 1,
+ ?line InBadCommunityUses2 = InBadCommunityUses + 1,
+ ?line InASNErrs2 = InASNErrs + 1.
+
+%% Req. SNMPv2-MIB
+snmpv2_mib_a() ->
+ ?line [SetSerial] = get_req(2, [[snmpSetSerialNo,0]]),
+ s([{[snmpSetSerialNo,0], SetSerial}, {[sysLocation, 0], "val2"}]),
+ ?line expect(3, [{[snmpSetSerialNo,0], SetSerial},
+ {[sysLocation, 0], "val2"}]),
+ s([{[sysLocation, 0], "val3"}, {[snmpSetSerialNo,0], SetSerial}]),
+ ?line expect(4, inconsistentValue, 2,
+ [{[sysLocation, 0], "val3"},
+ {[snmpSetSerialNo,0], SetSerial}]),
+ ?line ["val2"] = get_req(5, [[sysLocation,0]]).
+
+
+%%-----------------------------------------------------------------
+%% o Bad community uses/name is tested already
+%% in SNMPv2-MIB and STANDARD-MIB.
+%% o Test add/deletion of rows.
+%%-----------------------------------------------------------------
+snmp_community_mib(suite) -> [];
+snmp_community_mib(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?line load_master_std("SNMP-COMMUNITY-MIB"),
+ try_test(snmp_community_mib),
+ ?line unload_master("SNMP-COMMUNITY-MIB").
+
+snmp_community_mib_2(X) -> snmp_community_mib(X).
+
+%% Req. SNMP-COMMUNITY-MIB
+snmp_community_mib() ->
+ ?INF("NOT YET IMPLEMENTED", []),
+ nyi.
+
+%%-----------------------------------------------------------------
+%% o Test engine boots / time
+%%-----------------------------------------------------------------
+snmp_framework_mib(suite) -> [];
+snmp_framework_mib(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?line load_master_std("SNMP-FRAMEWORK-MIB"),
+ try_test(snmp_framework_mib),
+ ?line unload_master("SNMP-FRAMEWORK-MIB").
+
+snmp_framework_mib_2(X) -> snmp_framework_mib(X).
+
+snmp_framework_mib_3(suite) -> [];
+snmp_framework_mib_3(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ try_test(snmp_framework_mib).
+
+
+%% Req. SNMP-FRAMEWORK-MIB
+snmp_framework_mib() ->
+ ?line ["agentEngine"] = get_req(1, [[snmpEngineID,0]]),
+ ?line [EngineTime] = get_req(2, [[snmpEngineTime,0]]),
+ sleep(5000),
+ ?line [EngineTime2] = get_req(3, [[snmpEngineTime,0]]),
+ if
+ EngineTime+7 < EngineTime2 ->
+ ?line ?FAIL({too_large_diff, EngineTime, EngineTime2});
+ EngineTime+4 > EngineTime2 ->
+ ?line ?FAIL({too_large_diff, EngineTime, EngineTime2});
+ true -> ok
+ end,
+ ?line case get_req(4, [[snmpEngineBoots,0]]) of
+ [Boots] when integer(Boots) -> ok;
+ Else -> ?FAIL(Else)
+ end,
+ ok.
+
+%%-----------------------------------------------------------------
+%% o Test the counters
+%%-----------------------------------------------------------------
+snmp_mpd_mib_3(suite) -> [];
+snmp_mpd_mib_3(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ UnknownPDUHs = try_test(snmp_mpd_mib_a),
+ try_test(snmp_mpd_mib_b, [], [{context_engine_id, "bad engine"}]),
+ try_test(snmp_mpd_mib_c, [UnknownPDUHs]).
+
+
+%% Req. SNMP-MPD-MIB
+snmp_mpd_mib_a() ->
+ ?line [UnknownSecs, InvalidMsgs] =
+ get_req(1, [[snmpUnknownSecurityModels,0],
+ [snmpInvalidMsgs,0]]),
+ Pdu = #pdu{type = 'get-request',
+ request_id = 23,
+ error_status = noError,
+ error_index = 0,
+ varbinds = []},
+ SPdu = #scopedPdu{contextEngineID = "agentEngine",
+ contextName = "",
+ data = Pdu},
+ ?line SPDUBytes = snmp_pdus:enc_scoped_pdu(SPdu),
+ V3Hdr1 = #v3_hdr{msgID = 21,
+ msgMaxSize = 484,
+ msgFlags = [7],
+ msgSecurityModel = 23, % bad sec model
+ msgSecurityParameters = []},
+ V3Hdr2 = #v3_hdr{msgID = 21,
+ msgMaxSize = 484,
+ msgFlags = [6], % bad flag combination
+ msgSecurityModel = 3,
+ msgSecurityParameters = []},
+ Message1 = #message{version = 'version-3', vsn_hdr = V3Hdr1,
+ data = SPDUBytes},
+ Message2 = #message{version = 'version-3', vsn_hdr = V3Hdr2,
+ data = SPDUBytes},
+ ?line MsgBytes1 = snmp_pdus:enc_message_only(Message1),
+ ?line MsgBytes2 = snmp_pdus:enc_message_only(Message2),
+ snmp_test_mgr:send_bytes(MsgBytes1),
+ snmp_test_mgr:send_bytes(MsgBytes2),
+
+ ?line [UnknownSecs2, InvalidMsgs2, UnknownPDUHs] =
+ get_req(1, [[snmpUnknownSecurityModels,0],
+ [snmpInvalidMsgs,0],
+ [snmpUnknownPDUHandlers, 0]]),
+ ?line UnknownSecs2 = UnknownSecs + 1,
+ ?line InvalidMsgs2 = InvalidMsgs + 1,
+ UnknownPDUHs.
+
+-define(snmpUnknownPDUHandlers_instance, [1,3,6,1,6,3,11,2,1,3,0]).
+snmp_mpd_mib_b() ->
+ g([[sysUpTime,0]]),
+ ?line expect(1, report, [{?snmpUnknownPDUHandlers_instance, any}]).
+
+
+snmp_mpd_mib_c(UnknownPDUHs) ->
+ ?line [UnknownPDUHs2] = get_req(1, [[snmpUnknownPDUHandlers, 0]]),
+ ?line UnknownPDUHs2 = UnknownPDUHs + 1.
+
+
+snmp_target_mib(suite) -> [];
+snmp_target_mib(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?line load_master_std("SNMP-TARGET-MIB"),
+ try_test(snmp_target_mib),
+ ?line unload_master("SNMP-TARGET-MIB").
+
+snmp_target_mib_2(X) -> snmp_target_mib(X).
+
+snmp_target_mib_3(X) -> snmp_target_mib(X).
+
+snmp_target_mib() ->
+ ?INF("NOT YET IMPLEMENTED", []),
+ nyi.
+
+snmp_notification_mib(suite) -> [];
+snmp_notification_mib(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?line load_master_std("SNMP-NOTIFICATION-MIB"),
+ try_test(snmp_notification_mib),
+ ?line unload_master("SNMP-NOTIFICATION-MIB").
+
+snmp_notification_mib_2(X) -> snmp_notification_mib(X).
+
+snmp_notification_mib_3(X) -> snmp_notification_mib(X).
+
+snmp_notification_mib() ->
+ ?INF("NOT YET IMPLEMENTED", []),
+ nyi.
+
+%%-----------------------------------------------------------------
+%% o add/delete views and try them
+%% o try boundaries
+%%-----------------------------------------------------------------
+snmp_view_based_acm_mib(suite) -> [];
+snmp_view_based_acm_mib(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"),
+ ?line load_master("Test2"),
+ snmp_view_based_acm_mib(),
+ ?line unload_master("Test2"),
+ ?line unload_master("SNMP-VIEW-BASED-ACM-MIB").
+
+snmp_view_based_acm_mib_2(X) -> snmp_view_based_acm_mib(X).
+
+snmp_view_based_acm_mib_3(X) -> snmp_view_based_acm_mib(X).
+
+snmp_view_based_acm_mib() ->
+ snmpa:verbosity(net_if,trace),
+ snmpa:verbosity(master_agent,trace),
+ ?LOG("start snmp_view_based_acm_mib test",[]),
+ %% The user "no-rights" is present in USM, and is mapped to security
+ %% name 'no-rights", which is not present in VACM.
+ %% So, we'll add rights for it, try them and delete them.
+ %% We'll give "no-rights" write access to tDescr.0 and read access
+ %% to tDescr2.0
+ %% These are the options we'll use to the mgr
+ Opts = [{user, "no-rights"}, {community, "no-rights"}],
+ %% Find the valid secmodel, and one invalid secmodel.
+ {SecMod, InvSecMod} =
+ case get(vsn) of
+ v1 -> {?SEC_V1, ?SEC_V2C};
+ v2 -> {?SEC_V2C, ?SEC_USM};
+ v3 -> {?SEC_USM, ?SEC_V1}
+ end,
+ ?DBG("assign rights for 'no-rights'",[]),
+ ?line try_test(use_no_rights, [], Opts),
+
+ %% Now, add a mapping from "no-rights" -> "no-rights-group"
+ GRow1Status = [vacmSecurityToGroupStatus,[SecMod, 9,"no-rights"]],
+ GRow1 =
+ [{[vacmGroupName, [SecMod, 9,"no-rights"]], "no-rights-group"},
+ {GRow1Status, ?createAndGo}],
+ ?DBG("set '~p'",[GRow1]),
+ ?line try_test(do_set, [GRow1]),
+
+ ?DBG("assign rights for 'no-rights'",[]),
+ ?line try_test(use_no_rights, [], Opts),
+
+ %% Create a mapping for another sec model, and make sure it dosn't
+ %% give us access
+ GRow2Status = [vacmSecurityToGroupStatus,[InvSecMod, 9,"no-rights"]],
+ GRow2 = [{[vacmGroupName, [InvSecMod, 9, "no-rights"]], "initial"},
+ {GRow2Status, ?createAndGo}],
+
+ ?DBG("set '~p'",[GRow2]),
+ ?line try_test(do_set, [GRow2]),
+
+ ?DBG("assign rights for 'no-rights'",[]),
+ ?line try_test(use_no_rights, [], Opts),
+
+ %% Delete that row
+ ?line try_test(del_row, [GRow2Status]),
+
+ RVName = "rv_name",
+ WVName = "wv_name",
+
+ %% Access row
+ ARow1Idx = [15 | "no-rights-group"] ++ [0, ?SEC_ANY, 1],
+ ARow1Status = [vacmAccessStatus, ARow1Idx],
+ ARow1 = [{[vacmAccessContextMatch, ARow1Idx], 1},
+ {[vacmAccessReadViewName, ARow1Idx], RVName},
+ {[vacmAccessWriteViewName, ARow1Idx], WVName},
+ {ARow1Status, ?createAndGo}],
+
+ %% This access row would give acces, if InvSecMod was valid.
+ ARow2Idx = [15 | "no-rights-group"] ++ [0, InvSecMod, 1],
+ ARow2Status = [vacmAccessStatus, ARow2Idx],
+ ARow2 = [{[vacmAccessContextMatch, ARow2Idx], 1},
+ {[vacmAccessReadViewName, ARow2Idx], "internet"},
+ {[vacmAccessWriteViewName, ARow2Idx], "internet"},
+ {ARow2Status, ?createAndGo}],
+
+ ?line try_test(do_set, [ARow2]),
+
+ ?line try_test(use_no_rights, [], Opts),
+
+ %% Delete that row
+ ?line try_test(del_row, [ARow2Status]),
+
+
+ %% Add valid row
+ ?line try_test(do_set, [ARow1]),
+
+ ?line try_test(use_no_rights, [], Opts),
+
+ %% Create the view family
+ VRow1Idx = mk_ln(RVName) ++ mk_ln(?xDescr), % object access
+ VRow2Idx = mk_ln(RVName) ++ mk_ln(?xDescr2 ++ [0]), % instance access
+ VRow3Idx = mk_ln(WVName) ++ mk_ln(?xDescr), % object access
+ VRow4Idx = mk_ln(WVName) ++ mk_ln(?xDescr ++ [0]), % instance access
+ VRow1Status = [vacmViewTreeFamilyStatus, VRow1Idx],
+ VRow2Status = [vacmViewTreeFamilyStatus, VRow2Idx],
+ VRow3Status = [vacmViewTreeFamilyStatus, VRow3Idx],
+ VRow4Status = [vacmViewTreeFamilyStatus, VRow4Idx],
+
+ ?line try_test(add_row, [VRow1Status]),
+ ?line try_test(add_row, [VRow2Status]),
+ ?line try_test(add_row, [VRow3Status]),
+
+ %% We're supposed to have access now...
+ ?line try_test(use_rights, [], Opts),
+
+ %% Change Row3 to Row4
+ ?line try_test(del_row, [VRow3Status]),
+ ?line try_test(add_row, [VRow4Status]),
+
+ %% We should still have access...
+ ?line try_test(use_rights, [], Opts),
+
+ %% Delete rows
+ ?line try_test(del_row, [GRow1Status]),
+
+ ?line try_test(use_no_rights, [], Opts),
+
+ %% Delete rest of rows
+ ?line try_test(del_row, [ARow1Status]),
+ ?line try_test(del_row, [VRow1Status]),
+ ?line try_test(del_row, [VRow2Status]),
+ ?line try_test(del_row, [VRow4Status]),
+
+ ?line try_test(use_no_rights, [], Opts),
+ snmpa:verbosity(master_agent,log).
+
+do_set(Row) ->
+ s(Row),
+ expect(1, Row).
+
+add_row(RowStatus) ->
+ s([{RowStatus, ?createAndGo}]),
+ expect(1, [{RowStatus, ?createAndGo}]).
+
+del_row(RowStatus) ->
+ s([{RowStatus, ?destroy}]),
+ expect(1, [{RowStatus, ?destroy}]).
+
+
+
+use_no_rights() ->
+ g([[xDescr,0]]),
+ ?v1_2_3(expect(11, noSuchName, 1, any),
+ expect(12, [{[xDescr,0], noSuchObject}]),
+ expect(13, authorizationError, 1, any)),
+ g([[xDescr2,0]]),
+ ?v1_2_3(expect(21, noSuchName, 1, any),
+ expect(22, [{[xDescr2,0], noSuchObject}]),
+ expect(23, authorizationError, 1, any)),
+ gn([[xDescr]]),
+ ?v1_2_3(expect(31, noSuchName, 1, any),
+ expect(32, [{[xDescr], endOfMibView}]),
+ expect(33, authorizationError, 1, any)),
+ s([{[xDescr,0], "tryit"}]),
+ ?v1_2_3(expect(41, noSuchName, 1, any),
+ expect(42, noAccess, 1, any),
+ expect(43, authorizationError, 1, any)).
+
+
+use_rights() ->
+ g([[xDescr,0]]),
+ expect(1, [{[xDescr,0], any}]),
+ g([[xDescr2,0]]),
+ expect(2, [{[xDescr2,0], any}]),
+ s([{[xDescr,0], "tryit"}]),
+ expect(3, noError, 0, any),
+ g([[xDescr,0]]),
+ expect(4, [{[xDescr,0], "tryit"}]).
+
+mk_ln(X) ->
+ [length(X) | X].
+
+%%-----------------------------------------------------------------
+%% o add/delete users and try them
+%% o test all secLevels
+%% o test all combinations of protocols
+%% o try bad ops; check counters
+%%-----------------------------------------------------------------
+snmp_user_based_sm_mib_3(suite) -> [];
+snmp_user_based_sm_mib_3(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ _AgentDir = ?config(agent_dir, Config),
+ ?line load_master_std("SNMP-USER-BASED-SM-MIB"),
+
+ %% The newUser used here already has VACM access.
+
+ %% Add a new user in the simplest way; just createAndGo
+ try_test(v3_sync, [[{usm_add_user1, []}]],
+ [{sec_level, authPriv}, {user, "privDES"}]),
+
+ %% Try to use the new user
+ ?line load_master("Test2"),
+ try_test(v3_sync, [[{usm_use_user, []}]],
+ [{sec_level, authPriv}, {user, "newUser"}]),
+ ?line unload_master("Test2"),
+
+ ShaKey1 = snmp:passwd2localized_key(sha, "new sha password", "agentEngine"),
+ DesKey1 = lists:sublist(ShaKey1, 16),
+
+ %% Change the new user's keys - 1
+ try_test(v3_sync, [[{usm_key_change1, [ShaKey1, DesKey1]}]],
+ [{sec_level, authPriv}, {user, "newUser"}]),
+
+ %% Try to use the new keys
+ MgrDir = ?config(mgr_dir, Config),
+ ?line rewrite_usm_mgr(MgrDir, ShaKey1, DesKey1),
+ ?line load_master("Test2"),
+ try_test(v3_sync, [[{usm_use_user, []}]],
+ [{sec_level, authPriv}, {user, "newUser"}]),
+ ?line unload_master("Test2"),
+
+ ShaKey2 = snmp:passwd2localized_key(sha, "newer password", "agentEngine"),
+ DesKey2 = lists:sublist(ShaKey2, 16),
+
+ %% Change the new user's keys - 2
+ ?line try_test(v3_sync,
+ [[{usm_key_change2, [ShaKey1, DesKey1, ShaKey2, DesKey2]}]],
+ [{sec_level, authPriv}, {user, "newUser"}]),
+
+ %% Try to use the new keys
+ reset_usm_mgr(MgrDir),
+ ?line rewrite_usm_mgr(MgrDir, ShaKey2, DesKey2),
+ ?line load_master("Test2"),
+ ?line try_test(v3_sync, [[{usm_use_user, []}]],
+ [{sec_level, authPriv}, {user, "newUser"}]),
+ ?line unload_master("Test2"),
+ reset_usm_mgr(MgrDir),
+
+ %% Change the new user's keys - 3
+ ?line try_test(v3_sync,
+ [[{usm_key_change3, [ShaKey2, DesKey2, ShaKey1, DesKey1]}]],
+ [{sec_level, authPriv}, {user, "privDES"}]),
+
+ %% Try to use the new keys
+ ?line rewrite_usm_mgr(MgrDir, ShaKey1, DesKey1),
+ ?line load_master("Test2"),
+ try_test(v3_sync, [[{usm_use_user, []}]],
+ [{sec_level, authPriv}, {user, "newUser"}]),
+ ?line unload_master("Test2"),
+ reset_usm_mgr(MgrDir),
+
+ %% Try some read requests
+ ?line try_test(v3_sync, [[{usm_read, []}]],
+ [{sec_level, authPriv}, {user, "privDES"}]),
+
+ %% Delete the new user
+ ?line try_test(v3_sync, [[{usm_del_user, []}]],
+ [{sec_level, authPriv}, {user, "privDES"}]),
+
+ %% Try some bad requests
+ ?line try_test(v3_sync, [[{usm_bad, []}]],
+ [{sec_level, authPriv}, {user, "privDES"}]),
+
+ ?line unload_master("SNMP-USER-BASED-SM-MIB").
+
+-define(usmUserSecurityName, [1,3,6,1,6,3,15,1,2,2,1,3]).
+
+usm_add_user1() ->
+ NewRowIndex = [11,"agentEngine", 7, "newUser"],
+ RowPointer = ?usmUserSecurityName ++ [11|"agentEngine"] ++ [7|"privDES"],
+ Vbs1 = [{[usmUserCloneFrom, NewRowIndex], RowPointer},
+ {[usmUserStatus, NewRowIndex], ?createAndGo}],
+ ?line s(Vbs1),
+ ?line expect(1, Vbs1),
+ ok.
+
+usm_use_user() ->
+ v2_proc().
+
+
+%% Change own public keys
+usm_key_change1(ShaKey, DesKey) ->
+ NewRowIndex = [11,"agentEngine", 7, "newUser"],
+ ShaKeyChange = snmp_user_based_sm_mib:mk_key_change(sha,
+ "passwd_shaxxxxxxxxxx",
+ ShaKey),
+ DesKeyChange = snmp_user_based_sm_mib:mk_key_change(sha,
+ "passwd_desxxxxxx",
+ DesKey),
+ Vbs1 = [{[usmUserAuthKeyChange, NewRowIndex], ShaKeyChange},
+ {[usmUserPrivKeyChange, NewRowIndex], DesKeyChange}],
+ s(Vbs1),
+ ?line expect(1, Vbs1).
+
+%% Change own private keys
+usm_key_change2(OldShaKey, OldDesKey, ShaKey, DesKey) ->
+ NewRowIndex = [11,"agentEngine", 7, "newUser"],
+ ShaKeyChange = snmp_user_based_sm_mib:mk_key_change(sha,
+ OldShaKey,
+ ShaKey),
+ DesKeyChange = snmp_user_based_sm_mib:mk_key_change(sha,
+ OldDesKey,
+ DesKey),
+ Vbs1 = [{[usmUserOwnAuthKeyChange, NewRowIndex], ShaKeyChange},
+ {[usmUserOwnPrivKeyChange, NewRowIndex], DesKeyChange}],
+ s(Vbs1),
+ ?line expect(1, Vbs1).
+
+%% Change other's public keys
+usm_key_change3(OldShaKey, OldDesKey, ShaKey, DesKey) ->
+ NewRowIndex = [11,"agentEngine", 7, "newUser"],
+ ShaKeyChange = snmp_user_based_sm_mib:mk_key_change(sha,
+ OldShaKey,
+ ShaKey),
+ DesKeyChange = snmp_user_based_sm_mib:mk_key_change(sha,
+ OldDesKey,
+ DesKey),
+ Vbs1 = [{[usmUserOwnAuthKeyChange, NewRowIndex], ShaKeyChange}],
+ s(Vbs1),
+ ?line expect(1, noAccess, 1, any),
+ Vbs2 = [{[usmUserOwnPrivKeyChange, NewRowIndex], DesKeyChange}],
+ s(Vbs2),
+ ?line expect(2, noAccess, 1, any),
+
+
+ Vbs3 = [{[usmUserAuthKeyChange, NewRowIndex], ShaKeyChange},
+ {[usmUserPrivKeyChange, NewRowIndex], DesKeyChange}],
+ s(Vbs3),
+ ?line expect(1, Vbs3).
+
+usm_read() ->
+ NewRowIndex = [11,"agentEngine", 7, "newUser"],
+ ?line g([[usmUserSecurityName, NewRowIndex],
+ [usmUserCloneFrom, NewRowIndex],
+ [usmUserAuthKeyChange, NewRowIndex],
+ [usmUserOwnAuthKeyChange, NewRowIndex],
+ [usmUserPrivKeyChange, NewRowIndex],
+ [usmUserOwnPrivKeyChange, NewRowIndex]]),
+ ?line expect(1,
+ [{[usmUserSecurityName, NewRowIndex], "newUser"},
+ {[usmUserCloneFrom, NewRowIndex], [0,0]},
+ {[usmUserAuthKeyChange, NewRowIndex], ""},
+ {[usmUserOwnAuthKeyChange, NewRowIndex], ""},
+ {[usmUserPrivKeyChange, NewRowIndex], ""},
+ {[usmUserOwnPrivKeyChange, NewRowIndex], ""}]),
+ ok.
+
+
+
+usm_del_user() ->
+ NewRowIndex = [11,"agentEngine", 7, "newUser"],
+ Vbs1 = [{[usmUserStatus, NewRowIndex], ?destroy}],
+ ?line s(Vbs1),
+ ?line expect(1, Vbs1),
+ ok.
+
+-define(usmUserCloneFrom, [1,3,6,1,6,3,15,1,2,2,1,4]).
+
+-define(usmNoAuthProtocol, [1,3,6,1,6,3,10,1,1,1]).
+
+-define(usmHMACMD5AuthProtocol, [1,3,6,1,6,3,10,1,1,2]).
+
+-define(usmHMACSHAAuthProtocol, [1,3,6,1,6,3,10,1,1,3]).
+
+-define(usmNoPrivProtocol, [1,3,6,1,6,3,10,1,2,1]).
+
+-define(usmDESPrivProtocol, [1,3,6,1,6,3,10,1,2,2]).
+
+usm_bad() ->
+ NewRowIndex = [11,"agentEngine", 7, "newUser"],
+ RowPointer1 = ?usmUserSecurityName ++ [11|"agentEngine"] ++ [7|"privDOS"],
+ Vbs1 = [{[usmUserCloneFrom, NewRowIndex], RowPointer1},
+ {[usmUserStatus, NewRowIndex], ?createAndGo}],
+ ?line s(Vbs1),
+ ?line expect(1, inconsistentName, 1, any),
+
+ RowPointer2 = ?usmUserCloneFrom ++ [11|"agentEngine"] ++ [7|"privDES"],
+ Vbs2 = [{[usmUserCloneFrom, NewRowIndex], RowPointer2},
+ {[usmUserStatus, NewRowIndex], ?createAndGo}],
+ ?line s(Vbs2),
+ ?line expect(2, wrongValue, 1, any),
+
+ RowPointer3 = ?usmUserSecurityName ++ [11|"agentEngine"] ++ [7|"privDES"],
+ Vbs3 = [{[usmUserCloneFrom, NewRowIndex], RowPointer3},
+ {[usmUserStatus, NewRowIndex], ?createAndGo}],
+ ?line s(Vbs3),
+ ?line expect(3, Vbs3),
+ ?line s([{[usmUserAuthProtocol, NewRowIndex], ?usmNoAuthProtocol}]),
+ ?line expect(4, inconsistentValue, 1, any),
+ ?line s([{[usmUserAuthProtocol, NewRowIndex], ?usmHMACMD5AuthProtocol}]),
+ ?line expect(5, inconsistentValue, 1, any),
+ ?line s([{[usmUserAuthProtocol, NewRowIndex], ?usmDESPrivProtocol}]),
+ ?line expect(6, wrongValue, 1, any),
+ ?line s([{[usmUserPrivProtocol, NewRowIndex], ?usmHMACSHAAuthProtocol}]),
+ ?line expect(7, wrongValue, 1, any),
+
+ Vbs4 = [{[usmUserStatus, NewRowIndex], ?destroy}],
+ ?line s(Vbs4),
+ ?line expect(1, Vbs4),
+
+ ok.
+
+
+%%-----------------------------------------------------------------
+%% Loop through entire MIB, to make sure that all instrum. funcs
+%% works.
+%% Load all std mibs that are not loaded by default.
+%%-----------------------------------------------------------------
+loop_mib(suite) -> [];
+loop_mib(Config) when list(Config) ->
+ ?LOG("loop_mib -> initiate case",[]),
+ %% snmpa:verbosity(master_agent,debug),
+ %% snmpa:verbosity(mib_server,info),
+ {SaNode, MgrNode, MibDir} = init_case(Config),
+ ?DBG("loop_mib -> ~n"
+ "\tSaNode: ~p~n"
+ "\tMgrNode: ~p~n"
+ "\tMibDir: ~p",[SaNode, MgrNode, MibDir]),
+ ?DBG("loop_mib -> load mib SNMP-COMMUNITY-MIB",[]),
+ ?line load_master_std("SNMP-COMMUNITY-MIB"),
+ ?DBG("loop_mib -> load mib SNMP-MPD-MIB",[]),
+ ?line load_master_std("SNMP-MPD-MIB"),
+ ?DBG("loop_mib -> load mib SNMP-TARGET-MIB",[]),
+ ?line load_master_std("SNMP-TARGET-MIB"),
+ ?DBG("loop_mib -> load mib SNMP-NOTIFICATION-MIB",[]),
+ ?line load_master_std("SNMP-NOTIFICATION-MIB"),
+ ?DBG("loop_mib -> load mib SNMP-FRAMEWORK-MIB",[]),
+ ?line load_master_std("SNMP-FRAMEWORK-MIB"),
+ ?DBG("loop_mib -> load mib SNMP-VIEW-BASED-ACM-MIB",[]),
+ ?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"),
+ ?DBG("loop_mib -> try",[]),
+ try_test(loop_mib_1),
+ ?DBG("loop_mib -> unload mib SNMP-COMMUNITY-MIB",[]),
+ ?line unload_master("SNMP-COMMUNITY-MIB"),
+ ?DBG("loop_mib -> unload mib SNMP-MPD-MIB",[]),
+ ?line unload_master("SNMP-MPD-MIB"),
+ ?DBG("loop_mib -> unload mib SNMP-TARGET-MIB",[]),
+ ?line unload_master("SNMP-TARGET-MIB"),
+ ?DBG("loop_mib -> unload mib SNMP-NOTIFICATION-MIB",[]),
+ ?line unload_master("SNMP-NOTIFICATION-MIB"),
+ ?DBG("loop_mib -> unload mib SNMP-FRAMEWORK-MIB",[]),
+ ?line unload_master("SNMP-FRAMEWORK-MIB"),
+ ?DBG("loop_mib -> unload mib SNMP-VIEW-BASED-ACM-MIB",[]),
+ ?line unload_master("SNMP-VIEW-BASED-ACM-MIB"),
+ %% snmpa:verbosity(master_agent,log),
+ %% snmpa:verbosity(mib_server,silence),
+ ?LOG("loop_mib -> done",[]).
+
+
+loop_mib_2(suite) -> [];
+loop_mib_2(Config) when list(Config) ->
+ ?LOG("loop_mib_2 -> initiate case",[]),
+ {SaNode, MgrNode, MibDir} = init_case(Config),
+ ?DBG("loop_mib_2 -> ~n"
+ "\tSaNode: ~p~n"
+ "\tMgrNode: ~p~n"
+ "\tMibDir: ~p",[SaNode, MgrNode, MibDir]),
+ ?DBG("loop_mib_2 -> load mibs",[]),
+ ?line load_master_std("SNMP-COMMUNITY-MIB"),
+ ?line load_master_std("SNMP-MPD-MIB"),
+ ?line load_master_std("SNMP-TARGET-MIB"),
+ ?line load_master_std("SNMP-NOTIFICATION-MIB"),
+ ?line load_master_std("SNMP-FRAMEWORK-MIB"),
+ ?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"),
+ try_test(loop_mib_2),
+ ?DBG("loop_mib_2 -> unload mibs",[]),
+ ?line unload_master("SNMP-COMMUNITY-MIB"),
+ ?line unload_master("SNMP-MPD-MIB"),
+ ?line unload_master("SNMP-TARGET-MIB"),
+ ?line unload_master("SNMP-NOTIFICATION-MIB"),
+ ?line unload_master("SNMP-FRAMEWORK-MIB"),
+ ?line unload_master("SNMP-VIEW-BASED-ACM-MIB"),
+ ?LOG("loop_mib_2 -> done",[]).
+
+
+loop_mib_3(suite) -> [];
+loop_mib_3(Config) when list(Config) ->
+ ?LOG("loop_mib_3 -> initiate case",[]),
+ {SaNode, MgrNode, MibDir} = init_case(Config),
+ ?DBG("loop_mib_3 -> ~n"
+ "\tSaNode: ~p~n"
+ "\tMgrNode: ~p~n"
+ "\tMibDir: ~p",[SaNode, MgrNode, MibDir]),
+ ?DBG("loop_mib_3 -> load mibs",[]),
+ ?line load_master_std("SNMP-TARGET-MIB"),
+ ?line load_master_std("SNMP-NOTIFICATION-MIB"),
+ ?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"),
+ ?line load_master_std("SNMP-USER-BASED-SM-MIB"),
+ try_test(loop_mib_2),
+ ?DBG("loop_mib_3 -> unload mibs",[]),
+ ?line unload_master("SNMP-TARGET-MIB"),
+ ?line unload_master("SNMP-NOTIFICATION-MIB"),
+ ?line unload_master("SNMP-VIEW-BASED-ACM-MIB"),
+ ?line unload_master("SNMP-USER-BASED-SM-MIB"),
+ ?LOG("loop_mib_3 -> done",[]).
+
+
+%% Req. As many mibs all possible
+loop_mib_1() ->
+ ?DBG("loop_mib_1 -> entry",[]),
+ N = loop_it_1([1,1], 0),
+ io:format(user, "found ~w varibles\n", [N]),
+ ?line N = if N < 100 -> 100;
+ true -> N
+ end.
+
+
+loop_it_1(Oid, N) ->
+ ?DBG("loop_it_1 -> entry with~n"
+ "\tOid: ~p~n"
+ "\tN: ~p",[Oid,N]),
+ case get_next_req([Oid]) of
+ #pdu{type='get-response', error_status=noError, error_index=0,
+ varbinds=[#varbind{oid = NOid,value = Value}]} when NOid > Oid ->
+ ?DBG("loop_it_1 -> ~n"
+ "\tNOid: ~p~n"
+ "\tValue: ~p",[NOid,Value]),
+ ?line [Value2] = get_req(1, [NOid]), % must not be same
+ ?DBG("loop_it_1 -> ~n"
+ "\tValue2: ~p",[Value2]),
+ loop_it_1(NOid, N+1);
+ #pdu{type='get-response', error_status=noSuchName, error_index=1,
+ varbinds=[_]} ->
+ ?DBG("loop_it_1 -> done",[]),
+ N;
+
+ #pdu{type = Type, error_status = Err, error_index = Idx,
+ varbinds = Vbs} ->
+ exit({unexpected_pdu, ?LINE, Type, Err, Idx, Vbs})
+ end.
+
+%% Req. As many mibs all possible
+loop_mib_2() ->
+ ?DBG("loop_mib_1 -> entry",[]),
+ N = loop_it_2([1,1], 0),
+ io:format(user, "found ~w varibles\n", [N]),
+ ?line N = if N < 100 -> 100;
+ true -> N
+ end.
+
+
+loop_it_2(Oid, N) ->
+ ?DBG("loop_it_2 -> entry with~n"
+ "\tOid: ~p~n"
+ "\tN: ~p",[Oid,N]),
+ case get_next_req([Oid]) of
+ #pdu{type='get-response', error_status=noError, error_index=0,
+ varbinds=[#varbind{oid = NOid, value = endOfMibView}]} ->
+ ?DBG("loop_it_2 -> ~n"
+ "\tNOid: ~p",[NOid]),
+ N;
+ #pdu{type='get-response', error_status=noError, error_index=0,
+ varbinds=[#varbind{oid = NOid,value = Value}]} when NOid > Oid ->
+ ?DBG("loop_it_2 -> ~n"
+ "\tNOid: ~p~n"
+ "\tValue: ~p",[NOid,Value]),
+ ?line [Value2] = get_req(1, [NOid]), % must not be same
+ ?DBG("loop_it_2 -> ~n"
+ "\tValue2: ~p",[Value2]),
+ loop_it_2(NOid, N+1)
+ end.
+
+
+%%%-----------------------------------------------------------------
+%%% Testing of reported bugs and other tickets.
+%%%-----------------------------------------------------------------
+
+reported_bugs(suite) ->
+ [otp_1128, otp_1129, otp_1131, otp_1162,
+ otp_1222, otp_1298, otp_1331, otp_1338,
+ otp_1342, otp_2776, otp_2979, otp_3187, otp_3725].
+
+reported_bugs_2(suite) ->
+ [otp_1128_2, otp_1129_2, otp_1131_2, otp_1162_2,
+ otp_1222_2, otp_1298_2, otp_1331_2, otp_1338_2,
+ otp_1342_2, otp_2776_2, otp_2979_2, otp_3187_2].
+
+reported_bugs_3(suite) ->
+ [otp_1128_3, otp_1129_3, otp_1131_3, otp_1162_3,
+ otp_1222_3, otp_1298_3, otp_1331_3, otp_1338_3,
+ otp_1342_3, otp_2776_3, otp_2979_3, otp_3187_3,
+ otp_3542].
+
+
+%% These are (ticket) test cases where the initiation has to be done
+%% individually.
+tickets(suite) ->
+ [otp_4394].
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-1128
+%% Slogan: Bug in handling of createAndWait set-requests.
+%%-----------------------------------------------------------------
+otp_1128(suite) -> [];
+otp_1128(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?line load_master("OLD-SNMPEA-MIB"),
+ ?line init_old(),
+ try_test(otp_1128),
+ ?line unload_master("OLD-SNMPEA-MIB").
+
+otp_1128_2(X) -> otp_1128(X).
+
+otp_1128_3(X) -> otp_1128(X).
+
+otp_1128() ->
+ io:format("Testing bug reported in ticket OTP-1128...~n"),
+
+ NewKeyc3 = [intCommunityViewIndex,get(mip),is("test")],
+ NewKeyc4 = [intCommunityAccess,get(mip),is("test")],
+ NewKeyc5 = [intCommunityStatus,get(mip),is("test")],
+
+ s([{NewKeyc5, ?createAndWait}, {NewKeyc4, 2}]),
+ ?line expect(28, [{NewKeyc5, ?createAndWait}, {NewKeyc4, 2}]),
+ g([NewKeyc5]),
+ ?line expect(29, [{NewKeyc5, ?notReady}]),
+ s([{NewKeyc5, ?active}, {NewKeyc3, 2}]),
+ ?line expect(30, [{NewKeyc5, ?active}, {NewKeyc3, 2}]),
+ g([NewKeyc5]),
+ ?line expect(31, [{NewKeyc5, ?active}]),
+ s([{NewKeyc5, ?destroy}]),
+ ?line expect(32, [{NewKeyc5, ?destroy}]).
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-1129, OTP-1169
+%% Slogan: snmpa:int_to_enum crashes on bad oids
+%%-----------------------------------------------------------------
+otp_1129(suite) -> [];
+otp_1129(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?line load_master("Klas3"),
+ try_test(otp_1129_i, [node()]),
+ ?line unload_master("Klas3").
+
+otp_1129_2(X) -> otp_1129(X).
+
+otp_1129_3(X) -> otp_1129(X).
+
+otp_1129_i(MaNode) ->
+ io:format("Testing bug reported in ticket OTP-1129...~n"),
+ false = rpc:call(MaNode, snmp, int_to_enum, [iso, 1]),
+ false = rpc:call(MaNode, snmp, int_to_enum, [isox, 1]).
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-1131
+%% Slogan: Agent crashes / erlang node halts if RowIndex in a
+%% setrequest is of bad type, e.g. an INDEX {INTEGER},
+%% and RowIdenx [3,2].
+%%-----------------------------------------------------------------
+otp_1131(suite) -> [];
+otp_1131(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?line load_master("Klas1"),
+ try_test(otp_1131),
+ ?line unload_master("Klas1").
+
+otp_1131_2(X) -> otp_1131(X).
+
+otp_1131_3(X) -> otp_1131(X).
+
+otp_1131() ->
+ io:format("Testing bug reported in ticket OTP-1131...~n"),
+ s([{[friendsEntry, [2, 3, 1]], s, "kompis3"},
+ {[friendsEntry, [3, 3, 1]], i, ?createAndGo}]),
+ ?line expect(1, ?v1_2(noSuchName, noCreation), 2, any).
+
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-1162
+%% Slogan: snmp_agent can't handle wrongValue from instrum.func
+%%-----------------------------------------------------------------
+otp_1162(suite) -> [];
+otp_1162(Config) when list(Config) ->
+ {SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?line {ok, SA} = start_subagent(SaNode, ?sa, "SA-MIB"),
+ try_test(otp_1162),
+ stop_subagent(SA).
+
+otp_1162_2(X) -> otp_1162(X).
+
+otp_1162_3(X) -> otp_1162(X).
+
+otp_1162() ->
+ s([{[sa, [2,0]], 6}]), % wrongValue (i is_set_ok)
+ ?line expect(1, ?v1_2(badValue, wrongValue), 1, any).
+
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-1222
+%% Slogan: snmp agent crash if faulty index is returned from instrum
+%%-----------------------------------------------------------------
+otp_1222(suite) -> [];
+otp_1222(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?line load_master("Klas3"),
+ ?line load_master("Klas4"),
+ try_test(otp_1222),
+ ?line unload_master("Klas3"),
+ ?line unload_master("Klas4").
+
+otp_1222_2(X) -> otp_1222(X).
+
+otp_1222_3(X) -> otp_1222(X).
+
+otp_1222() ->
+ io:format("Testing bug reported in ticket OTP-1222...~n"),
+ s([{[fStatus4,1], 4}, {[fName4,1], 1}]),
+ ?line expect(1, genErr, 0, any),
+ s([{[fStatus4,2], 4}, {[fName4,2], 1}]),
+ ?line expect(2, genErr, 0, any).
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-1298
+%% Slogan: Negative INTEGER values are treated as positive.
+%%-----------------------------------------------------------------
+otp_1298(suite) -> [];
+otp_1298(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?line load_master("Klas2"),
+ try_test(otp_1298),
+ ?line unload_master("Klas2").
+
+otp_1298_2(X) -> otp_1298(X).
+
+otp_1298_3(X) -> otp_1298(X).
+
+otp_1298() ->
+ io:format("Testing bug reported in ticket OTP-1298...~n"),
+ s([{[fint,0], -1}]),
+ ?line expect(1298, [{[fint,0], -1}]).
+
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-1331
+%% Slogan: snmp_generic should return noError when deleting non-ex row
+%%-----------------------------------------------------------------
+otp_1331(suite) -> [];
+otp_1331(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?line load_master("OLD-SNMPEA-MIB"),
+ ?line init_old(),
+ try_test(otp_1331),
+ ?line unload_master("OLD-SNMPEA-MIB").
+
+otp_1331_2(X) -> otp_1331(X).
+
+otp_1331_3(X) -> otp_1331(X).
+
+otp_1331() ->
+ NewKeyc5 = [intCommunityStatus,[127,32,0,0],is("test")],
+ s([{NewKeyc5, ?destroy}]),
+ ?line expect(1, [{NewKeyc5, ?destroy}]).
+
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-1338
+%% Slogan: snmp bug in initialisation of default values for mnesia tabs
+%%-----------------------------------------------------------------
+otp_1338(suite) -> [];
+otp_1338(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?line load_master("Klas2"),
+ try_test(otp_1338),
+ ?line unload_master("Klas2").
+
+otp_1338_2(X) -> otp_1338(X).
+
+otp_1338_3(X) -> otp_1338(X).
+
+otp_1338() ->
+ s([{[kStatus2, 7], i, ?createAndGo}]),
+ ?line expect(1, [{[kStatus2, 7], ?createAndGo}]),
+ g([[kName2, 7]]),
+ ?line expect(2, [{[kName2, 7], "JJJ"}]).
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-1342
+%% Slogan: default impl of snmp table can't handle bad index access,
+%% Set when INDEX is read-write gets into an infinite loop!
+%%-----------------------------------------------------------------
+otp_1342(suite) -> [];
+otp_1342(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?line load_master("Klas4"),
+ try_test(otp_1342),
+ ?line unload_master("Klas4").
+
+otp_1342_2(X) -> otp_1342(X).
+
+otp_1342_3(X) -> otp_1342(X).
+
+otp_1342() ->
+ s([{[fIndex5, 1], i, 1},
+ {[fName5, 1], i, 3},
+ {[fStatus5, 1], i, ?createAndGo}]),
+ ?line expect(1, ?v1_2(noSuchName, noCreation), 3, any).
+
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-1366
+%% Slogan: snmp traps not sent to all managers
+%% Note: NYI! We need a way to tell the test server that we need
+%% mgrs on two different machines.
+%%-----------------------------------------------------------------
+otp_1366(suite) -> [];
+otp_1366(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?line load_master("OLD-SNMPEA-MIB"),
+ ?line init_old(),
+ try_test(otp_1366),
+ ?line unload_master("OLD-SNMPEA-MIB").
+
+otp_1366_2(X) -> otp_1366(X).
+
+otp_1366_3(X) -> otp_1366(X).
+
+otp_1366() ->
+ ?INF("NOT YET IMPLEMENTED", []),
+ 'NYI'.
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-2776
+%% Slogan: snmp:validate_date_and_time() fails when time is 00:00
+%%-----------------------------------------------------------------
+otp_2776(suite) -> [];
+otp_2776(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ try_test(otp_2776).
+
+otp_2776_2(X) -> otp_2776(X).
+
+otp_2776_3(X) -> otp_2776(X).
+
+otp_2776() ->
+ io:format("Testing bug reported in ticket OTP-2776...~n"),
+
+ Dt01_valid = [19,98,9,1,1,0,23,0,43,0,0],
+ Dt02_valid = [19,98,9,1,0,0,0,0,43,0,0], % This is what is fixed: 00:00
+ Dt03_valid = [19,98,2,28,1,0,23,0,43,0,0],
+ Dt04_invalid = [19,98,2,29,1,0,23,0,43,0,0],
+ Dt05_valid = [19,96,2,29,1,0,23,0,43,0,0],
+ Dt06_valid = [20,0,2,29,1,0,23,0,43,0,0],
+ Dt07_invalid = [19,96,2,30,1,0,23,0,43,0,0], % This is also fixed: 30/2
+ Dt08_valid = [19,98,4,30,1,0,23,0,43,0,0],
+ Dt09_invalid = [19,98,4,31,1,0,23,0,43,0,0], % This is also fixed: 31/4
+ Dt10_invalid = [],
+ Dt11_invalid = [kalle,hobbe],
+ L = [{ 1, true, Dt01_valid},
+ { 2, true, Dt02_valid},
+ { 3, true, Dt03_valid},
+ { 4, false, Dt04_invalid},
+ { 5, true, Dt05_valid},
+ { 6, true, Dt06_valid},
+ { 7, false, Dt07_invalid},
+ { 8, true, Dt08_valid},
+ { 9, false, Dt09_invalid},
+ {10, false, Dt10_invalid},
+ {11, false, Dt11_invalid}],
+
+ ?line ok = validate_dat(L).
+
+
+validate_dat(L) -> validate_dat(L,[]).
+
+validate_dat([],V) ->
+ Fun = fun({_,X}) -> case X of
+ ok -> false;
+ _ -> true
+ end
+ end,
+ validate_dat1( lists:reverse( lists:filter(Fun,V) ) );
+validate_dat([{Id,E,Dat}|T],V) ->
+ validate_dat(T,[validate_dat2(Id,E,Dat) | V]).
+
+validate_dat1([]) -> ok;
+validate_dat1(L) -> {error,L}.
+
+validate_dat2(Id, E, Dat) ->
+ Res = case {E,snmp:validate_date_and_time(Dat)} of
+ {E,E} -> ok;
+ {E,A} -> {E,A}
+ end,
+ {Id, Res}.
+
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-2979
+%% Slogan: get-next on more than 1 column in an empty table
+%% returns bad response.
+%%-----------------------------------------------------------------
+otp_2979(suite) -> [];
+otp_2979(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?line load_master("Test1"),
+ ?line init_old(),
+ try_test(otp_2979),
+ ?line unload_master("Test1").
+
+otp_2979_2(X) -> otp_2979(X).
+
+otp_2979_3(X) -> otp_2979(X).
+
+otp_2979() ->
+ gn([[sparseDescr], [sparseStatus]]),
+ ?line expect(1, [{[sparseStr,0], "slut"},
+ {[sparseStr,0], "slut"}]).
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-3187
+%% Slogan: get-next on vacmAccessTable for colums > 5 returns
+%% endOfTable - should return value.
+%%-----------------------------------------------------------------
+otp_3187(suite) -> [];
+otp_3187(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ ?line load_master_std("SNMP-VIEW-BASED-ACM-MIB"),
+ otp_3187(),
+ ?line unload_master("SNMP-VIEW-BASED-ACM-MIB").
+
+otp_3187_2(X) -> otp_3187(X).
+
+otp_3187_3(X) -> otp_3187(X).
+
+otp_3187() ->
+ ?line Elements =
+ snmp_view_based_acm_mib:vacmAccessTable(get_next,[],[4,5,6]),
+ lists:foreach(fun(E) ->
+ ?line if E == endOfTable ->
+ ?FAIL(endOfTable);
+ true -> ok
+ end
+ end, Elements).
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-3542
+%% Slogan:
+%%-----------------------------------------------------------------
+otp_3542(suite) -> [];
+otp_3542(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ try_test(otp_3542).
+
+otp_3542() ->
+ io:format("SNMP v3 discovery...~n"),
+ ?line Res = snmp_test_mgr:d(),
+ io:format("SNMP v3 discovery result: ~p~n",[Res]).
+
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-3725
+%% Slogan: Slow response time on snmpa:int_to_enum
+%%-----------------------------------------------------------------
+otp_3725(suite) -> [];
+otp_3725(Config) when list(Config) ->
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+
+ ?line load_master("OLD-SNMPEA-MIB"),
+ ?line init_old(),
+ try_test(otp_3725_test, [node()]),
+ ?line unload_master("OLD-SNMPEA-MIB").
+
+%% Req. OLD-SNMPEA-MIB
+otp_3725_test(MaNode) ->
+ io:format("Testing feature requested in ticket OTP-3725...~n"),
+ ?line rpc:call(MaNode,snmpa,verbosity,[symbolic_store,trace]),
+ ?line Db = rpc:call(MaNode,snmp,get_symbolic_store_db,[]),
+ ?DBG("otp_3725_test -> Db = ~p",[Db]),
+
+ ?line {value, OID} = rpc:call(MaNode, snmp, name_to_oid,
+ [Db, intAgentIpAddress]),
+ ?DBG("otp_3725_test -> name_to_oid for ~p: ~p",[intAgentIpAddress,OID]),
+ ?line {value, intAgentIpAddress} = rpc:call(MaNode, snmp, oid_to_name,
+ [Db,OID]),
+ ?DBG("otp_3725_test -> oid_to_name for ~p: ~p",[OID,intAgentIpAddress]),
+ ?line false = rpc:call(MaNode, snmp, name_to_oid, [Db, intAgentIpAddres]),
+ ?line false = rpc:call(MaNode, snmp, oid_to_name,
+ [Db, [1,5,32,3,54,3,3,34,4]]),
+ ?line {value, 2} = rpc:call(MaNode, snmp, enum_to_int,
+ [Db, intViewType, excluded]),
+ ?line {value, excluded} = rpc:call(MaNode, snmp, int_to_enum,
+ [Db, intViewType, 2]),
+ ?line false = rpc:call(MaNode, snmp, enum_to_int,
+ [Db, intViewType, exclude]),
+ ?line false = rpc:call(MaNode, snmp, enum_to_int,
+ [Db, intAgentIpAddress, exclude]),
+ ?line false = rpc:call(MaNode, snmp, enum_to_int,
+ [Db, intAgentIpAddre, exclude]),
+ ?line false = rpc:call(MaNode, snmp, int_to_enum, [Db, intViewType, 3]),
+ ?line false = rpc:call(MaNode, snmp, int_to_enum,
+ [Db, intAgentIpAddress, 2]),
+ ?line false = rpc:call(MaNode, snmp, int_to_enum,
+ [Db, intAgentIpAddre, 2]),
+ ?line {value, active} = rpc:call(MaNode, snmp, int_to_enum,
+ [Db, 'RowStatus', ?active]),
+ ?line {value, ?destroy} = rpc:call(MaNode, snmp, enum_to_int,
+ [Db, 'RowStatus', destroy]),
+ ?line false = rpc:call(MaNode, snmp, enum_to_int,
+ [Db, 'RowStatus', xxxdestroy]),
+ ?line false = rpc:call(MaNode, snmp, enum_to_int,
+ [Db, 'xxRowStatus', destroy]),
+ ?line false = rpc:call(MaNode, snmp, int_to_enum, [Db, 'RowStatus', 25]),
+ ?line false = rpc:call(MaNode, snmp, int_to_enum, [Db, 'xxRowStatus', 1]),
+ ok.
+
+
+%%-----------------------------------------------------------------
+%% Ticket: OTP-4394
+%% Slogan: Target mib tag list check invalid
+%%-----------------------------------------------------------------
+
+
+otp_4394(suite) -> {req, [], {conf,
+ init_otp_4394,
+ [otp_4394_test],
+ finish_otp_4394}}.
+
+init_otp_4394(Config) when list(Config) ->
+ ?DBG("init_otp_4394 -> entry with"
+ "~n Config: ~p", [Config]),
+ ?line AgentDir = ?config(agent_dir, Config),
+ ?line MgrDir = ?config(mgr_dir, Config),
+ ?line Ip = ?config(ip, Config),
+ ?line otp_4394_config(AgentDir, MgrDir, Ip),
+ MasterAgentVerbosity = {master_agent_verbosity, trace},
+ NetIfVerbosity = {net_if_verbosity, trace},
+ Opts = [MasterAgentVerbosity,NetIfVerbosity],
+ [{vsn, v1} | start_v1_agent(Config,Opts)].
+
+otp_4394_config(AgentDir, MgrDir, Ip0) ->
+ ?DBG("otp_4394_config -> entry with"
+ "~n AgentDir: ~p"
+ "~n MgrDir: ~p"
+ "~n Ip0: ~p", [AgentDir, MgrDir, Ip0]),
+ Vsn = [v1],
+ Ip = tuple_to_list(Ip0),
+ ?line snmp_config:write_agent_snmp_files(AgentDir, Vsn, Ip,
+ ?TRAP_UDP, Ip, 4000,
+ "OTP-4394 test"),
+ ?line case update_usm(Vsn, AgentDir) of
+ true ->
+ ?line copy_file(filename:join(AgentDir, "usm.conf"),
+ filename:join(MgrDir, "usm.conf")),
+ ?line update_usm_mgr(Vsn, MgrDir);
+ false ->
+ ?line ok
+ end,
+ C1 = {"a", "all-rights", "initial", "", "pc"},
+ C2 = {"c", "secret", "secret_name", "", "secret_tag"},
+ ?line write_community_conf(AgentDir, [C1, C2]),
+ ?line update_vacm(Vsn, AgentDir),
+ Ta1 = {"shelob v1",
+ [134,138,177,177], 5000, 1500, 3, %% Anv�nd Ip och modda
+ "pc1",
+ "target_v1", "",
+ %% [255,255,255,255,0,0],
+ [],
+ 2048},
+ Ta2 = {"bifur v1",
+ [134,138,177,75], 5000, 1500, 3, %% Anv�nd Ip
+ "pc2",
+ "target_v1", "",
+ %% [255,255,255,255,0,0],
+ [], 2048},
+ ?line write_target_addr_conf(AgentDir, [Ta1, Ta2]),
+ ?line write_target_params_conf(AgentDir, Vsn),
+ ?line write_notify_conf(AgentDir),
+ ok.
+
+
+
+finish_otp_4394(Config) when list(Config) ->
+ ?DBG("finish_otp_4394 -> entry", []),
+ C1 = stop_agent(Config),
+ delete_files(C1),
+ erase(mgr_node),
+ lists:keydelete(vsn, 1, C1).
+
+otp_4394_test(suite) -> [];
+otp_4394_test(Config) ->
+ ?DBG("otp_4394_test -> entry", []),
+ {_SaNode, _MgrNode, _MibDir} = init_case(Config),
+ try_test(otp_4394_test1),
+ ?DBG("otp_4394_test -> done", []),
+ ok.
+
+otp_4394_test1() ->
+ ?DBG("otp_4394_test1 -> entry", []),
+ gn([[1,1]]),
+ Res =
+ case snmp_test_mgr:expect(1, [{[sysDescr,0], "Erlang SNMP agent"}]) of
+ %% {error, 1, {"?",[]}, {"~w",[timeout]}}
+ {error, 1, _, {_, [timeout]}} ->
+ ?DBG("otp_4394_test1 -> expected result: timeout", []),
+ ok;
+ Else ->
+ Else
+ end,
+ ?DBG("otp_4394_test1 -> done with: ~p", [Res]),
+ Res.
+
+
+%%%--------------------------------------------------
+%%% Used to test the standard mib with our
+%%% configuration.
+%%%--------------------------------------------------
+run(F, A, Opts) ->
+ M = get(mib_dir),
+ Dir = get(mgr_dir),
+ User = snmp_misc:get_option(user, Opts, "all-rights"),
+ SecLevel = snmp_misc:get_option(sec_level, Opts, noAuthNoPriv),
+ EngineID = snmp_misc:get_option(engine_id, Opts, "agentEngine"),
+ CtxEngineID = snmp_misc:get_option(context_engine_id, Opts, EngineID),
+ Community = snmp_misc:get_option(community, Opts, "all-rights"),
+ ?DBG("run -> start crypto app",[]),
+ Crypto = case os:type() of
+ vxworks ->
+ no_crypto;
+ _ ->
+ ?CRYPTO_START()
+ end,
+ ?DBG("run -> Crypto: ~p",[Crypto]),
+ catch snmp_test_mgr:stop(), % If we had a running mgr from a failed case
+ StdM = filename:join(code:priv_dir(snmp), "mibs") ++ "/",
+ ?DBG("run -> config:~n"
+ "\tM: ~p~n"
+ "\tDir: ~p~n"
+ "\tUser: ~p~n"
+ "\tSecLevel: ~p~n"
+ "\tEngineID: ~p~n"
+ "\tCtxEngineID: ~p~n"
+ "\tCommunity: ~p~n"
+ "\tStdM: ~p",
+ [M,Dir,User,SecLevel,EngineID,CtxEngineID,Community,StdM]),
+ case snmp_test_mgr:start([%% {agent, snmp_test_lib:hostname()},
+ {packet_server_debug,true},
+ {debug,true},
+ {agent, get(master_host)},
+ {agent_udp, 4000},
+ {trap_udp, 5000},
+ {recbuf,65535},
+ quiet,
+ get(vsn),
+ {community, Community},
+ {user, User},
+ {sec_level, SecLevel},
+ {engine_id, EngineID},
+ {context_engine_id, CtxEngineID},
+ {dir, Dir},
+ {mibs, mibs(StdM, M)}]) of
+ {ok, _Pid} ->
+ Res = apply(?MODULE, F, A),
+ catch snmp_test_mgr:stop(),
+ Res;
+ Err ->
+ io:format("Error starting manager: ~p\n", [Err]),
+ catch snmp_test_mgr:stop(),
+ ?line exit({mgr_start, Err})
+ end.
+
+
+mibs(StdMibDir,MibDir) ->
+ [join(StdMibDir, ?v1_2("STANDARD-MIB.bin", "SNMPv2-MIB.bin")),
+ join(MibDir, "OLD-SNMPEA-MIB.bin"),
+ join(StdMibDir, "SNMP-FRAMEWORK-MIB"),
+ join(StdMibDir, "SNMP-MPD-MIB"),
+ join(StdMibDir, "SNMP-VIEW-BASED-ACM-MIB"),
+ join(StdMibDir, "SNMP-USER-BASED-SM-MIB"),
+ join(StdMibDir, "SNMP-TARGET-MIB"),
+ join(StdMibDir, "SNMP-NOTIFICATION-MIB"),
+ join(MibDir, "Klas1.bin"),
+ join(MibDir, "Klas2.bin"),
+ join(MibDir, "Klas3.bin"),
+ join(MibDir, "Klas4.bin"),
+ join(MibDir, "SA-MIB.bin"),
+ join(MibDir, "TestTrap.bin"),
+ join(MibDir, "Test1.bin"),
+ join(MibDir, "Test2.bin"),
+ join(MibDir, "TestTrapv2.bin")].
+
+join(D,F) ->
+ filename:join(D,F).
+
+%% string used in index
+is(S) -> [length(S) | S].
+
+try_test(Func) ->
+ call(get(mgr_node), ?MODULE, run, [Func, [], []]).
+
+try_test(Func, A) ->
+ call(get(mgr_node), ?MODULE, run, [Func, A, []]).
+
+try_test(Func, A, Opts) ->
+ call(get(mgr_node), ?MODULE, run, [Func, A, Opts]).
+
+call(N,M,F,A) ->
+ ?DBG("call -> entry with~n"
+ " N: ~p~n"
+ " M: ~p~n"
+ " F: ~p~n"
+ " A: ~p~n"
+ " when~n"
+ " get(): ~p",
+ [N,M,F,A,get()]),
+ spawn(N, ?MODULE, wait, [self(),get(),M,F,A]),
+ receive
+ {done, {'EXIT', Rn}, Loc} ->
+ ?DBG("call -> returned ~p",[{done, {'EXIT', Rn}, Loc}]),
+ put(test_server_loc, Loc),
+ exit(Rn);
+ {done, Ret, Zed} ->
+ ?DBG("call -> returned ~p~n",[{done, Ret, Zed}]),
+ Ret
+ end.
+
+wait(From, Env, M, F, A) ->
+ ?DBG("wait -> entry with ~n"
+ "\tFrom: ~p~n"
+ "\tEnv: ~p",[From,Env]),
+ lists:foreach(fun({K,V}) -> put(K,V) end, Env),
+ Rn = (catch apply(M, F, A)),
+ ?DBG("wait -> Rn: ~n~p", [Rn]),
+ From ! {done, Rn, get(test_server_loc)},
+ exit(Rn).
+
+expect(A,B) -> ok = snmp_test_mgr:expect(A,B).
+expect(A,B,C) -> ok = snmp_test_mgr:expect(A,B,C).
+expect(A,B,C,D) -> ok = snmp_test_mgr:expect(A,B,C,D).
+expect(A,B,C,D,E,F) -> ok = snmp_test_mgr:expect(A,B,C,D,E,F).
+
+get_req(Id, Vars) ->
+ ?DBG("get_req -> entry with~n"
+ "\tId: ~p~n"
+ "\tVars: ~p",[Id,Vars]),
+ g(Vars),
+ ?DBG("get_req -> await response",[]),
+ {ok, Val} = snmp_test_mgr:get_response(Id, Vars),
+ ?DBG("get_req -> response: ~p",[Val]),
+ Val.
+
+get_next_req(Vars) ->
+ ?DBG("get_next_req -> entry with Vars '~p', send request",[Vars]),
+ gn(Vars),
+ ?DBG("get_next_req -> await response",[]),
+ Response = snmp_test_mgr:receive_response(),
+ ?DBG("get_next_req -> response: ~p",[Response]),
+ Response.
+
+
+
+start_node(Name) ->
+ ?LOG("start_node -> entry with Name: ~p",[Name]),
+ M = list_to_atom(?HOSTNAME(node())),
+ ?DBG("start_node -> M: ~p",[M]),
+ Pa = filename:dirname(code:which(?MODULE)),
+ ?DBG("start_node -> Pa: ~p",[Pa]),
+
+ Args = case init:get_argument('CC_TEST') of
+ {ok, [[]]} ->
+ " -pa /clearcase/otp/libraries/snmp/ebin ";
+ {ok, [[Path]]} ->
+ " -pa " ++ Path;
+ error ->
+ ""
+ end,
+ %% Do not use start_link!!! (the proc that calls this one is tmp)
+ ?DBG("start_node -> Args: ~p~n",[Args]),
+ A = Args ++ " -pa " ++ Pa,
+ case (catch ?START_NODE(Name, A)) of
+ {ok, Node} ->
+ %% Tell the test_server to not clean up things it never started.
+ ?DBG("start_node -> Node: ~p",[Node]),
+ {ok, Node};
+ Else ->
+ ?ERR("start_node -> failed with(other): Else: ~p",[Else]),
+ ?line ?FAIL(Else)
+ end.
+
+
+stop_node(Node) ->
+ ?LOG("stop_node -> Node: ~p",[Node]),
+ rpc:cast(Node, erlang, halt, []).
+
+p(X) ->
+ io:format(user, X++"\n", []).
+
+sleep(X) ->
+ receive
+ after
+ X -> ok
+ end.
+
+%%%-----------------------------------------------------------------
+%%% Configuration
+%%%-----------------------------------------------------------------
+config(Vsns, MgrDir, AgentDir, MIp, AIp) ->
+ ?line snmp_config:write_agent_snmp_files(AgentDir, Vsns, MIp,
+ ?TRAP_UDP, AIp, 4000,
+ "test"),
+ ?line case update_usm(Vsns, AgentDir) of
+ true ->
+ ?line copy_file(filename:join(AgentDir, "usm.conf"),
+ filename:join(MgrDir, "usm.conf")),
+ ?line update_usm_mgr(Vsns, MgrDir);
+ false ->
+ ?line ok
+ end,
+ ?line update_community(Vsns, AgentDir),
+ ?line update_vacm(Vsns, AgentDir),
+ ?line write_target_addr_conf(AgentDir, MIp, ?TRAP_UDP, Vsns),
+ ?line write_target_params_conf(AgentDir, Vsns),
+ ?line write_notify_conf(AgentDir),
+ ok.
+
+delete_files(Config) ->
+ Dir = ?config(agent_dir, Config),
+ {ok, List} = file:list_dir(Dir),
+ lists:foreach(fun(FName) -> file:delete(filename:join(Dir, FName)) end,
+ List).
+
+update_usm(Vsns, Dir) ->
+ case lists:member(v3, Vsns) of
+ true ->
+ {ok, Fid} = file:open(filename:join(Dir,"usm.conf"),[read,write]),
+ file:position(Fid, eof),
+ ok = io:format(Fid, "{\"agentEngine\", \"all-rights\", "
+ "\"all-rights\", zeroDotZero, "
+ "usmNoAuthProtocol, \"\", \"\", "
+ "usmNoPrivProtocol, \"\", \"\", \"\", "
+ "\"\", \"\"}.\n", []),
+ ok = io:format(Fid, "{\"agentEngine\", \"no-rights\", "
+ "\"no-rights\", zeroDotZero, "
+ "usmNoAuthProtocol, \"\", \"\", "
+ "usmNoPrivProtocol, \"\", \"\", \"\", "
+ "\"\", \"\"}.\n", []),
+ ok = io:format(Fid, "{\"agentEngine\", \"authMD5\", "
+ "\"authMD5\", zeroDotZero, "
+ "usmHMACMD5AuthProtocol, \"\", \"\", "
+ "usmNoPrivProtocol, \"\", \"\", \"\", "
+ "\"passwd_md5xxxxxx\", \"\"}.\n", []),
+ ok = io:format(Fid, "{\"agentEngine\", \"authSHA\", "
+ "\"authSHA\", zeroDotZero, "
+ "usmHMACSHAAuthProtocol, \"\", \"\", "
+ "usmNoPrivProtocol, \"\", \"\", \"\", "
+ "\"passwd_shaxxxxxxxxxx\", \"\"}.\n", []),
+ ok = io:format(Fid, "{\"agentEngine\", \"privDES\", "
+ "\"privDES\", zeroDotZero, "
+ "usmHMACSHAAuthProtocol, \"\", \"\", "
+ "usmDESPrivProtocol, \"\", \"\", \"\", "
+ "\"passwd_shaxxxxxxxxxx\", \"passwd_desxxxxxx\"}.\n",
+ []),
+ ok = io:format(Fid, "{\"mgrEngine\", \"all-rights\", "
+ "\"all-rights\", zeroDotZero, "
+ "usmNoAuthProtocol, \"\", \"\", "
+ "usmNoPrivProtocol, \"\", \"\", \"\", "
+ "\"\", \"\"}.\n", []),
+ ok = io:format(Fid, "{\"mgrEngine\", \"no-rights\", "
+ "\"no-rights\", zeroDotZero, "
+ "usmNoAuthProtocol, \"\", \"\", "
+ "usmNoPrivProtocol, \"\", \"\", \"\", "
+ "\"\", \"\"}.\n", []),
+ ok = io:format(Fid, "{\"mgrEngine\", \"authMD5\", "
+ "\"authMD5\", zeroDotZero, "
+ "usmHMACMD5AuthProtocol, \"\", \"\", "
+ "usmNoPrivProtocol, \"\", \"\", \"\", "
+ "\"passwd_md5xxxxxx\", \"\"}.\n", []),
+ ok = io:format(Fid, "{\"mgrEngine\", \"authSHA\", "
+ "\"authSHA\", zeroDotZero, "
+ "usmHMACSHAAuthProtocol, \"\", \"\", "
+ "usmNoPrivProtocol, \"\", \"\", \"\", "
+ "\"passwd_shaxxxxxxxxxx\", \"\"}.\n", []),
+ ok = io:format(Fid, "{\"mgrEngine\", \"privDES\", "
+ "\"privDES\", zeroDotZero, "
+ "usmHMACSHAAuthProtocol, \"\", \"\", "
+ "usmDESPrivProtocol, \"\", \"\", \"\", "
+ "\"passwd_shaxxxxxxxxxx\", \"passwd_desxxxxxx\"}.\n",
+ []),
+ file:close(Fid),
+ true;
+ false ->
+ false
+ end.
+
+update_usm_mgr(Vsns, Dir) ->
+ case lists:member(v3, Vsns) of
+ true ->
+ {ok, Fid} = file:open(filename:join(Dir,"usm.conf"),[read,write]),
+ file:position(Fid, eof),
+ ok = io:format(Fid, "{\"agentEngine\", \"newUser\", "
+ "\"newUser\", zeroDotZero, "
+ "usmHMACSHAAuthProtocol, \"\", \"\", "
+ "usmDESPrivProtocol, \"\", \"\", \"\", "
+ "\"passwd_shaxxxxxxxxxx\", \"passwd_desxxxxxx\"}.\n",
+ []),
+ ok = io:format(Fid, "{\"mgrEngine\", \"newUser\", "
+ "\"newUser\", zeroDotZero, "
+ "usmHMACSHAAuthProtocol, \"\", \"\", "
+ "usmDESPrivProtocol, \"\", \"\", \"\", "
+ "\"passwd_shaxxxxxxxxxx\", \"passwd_desxxxxxx\"}.\n",
+ []),
+ file:close(Fid),
+ true;
+ false ->
+ false
+ end.
+
+rewrite_usm_mgr(Dir, ShaKey, DesKey) ->
+ ?line ok = file:rename(filename:join(Dir,"usm.conf"),
+ filename:join(Dir,"usm.old")),
+ ?line {ok, Fid} = file:open(filename:join(Dir,"usm.conf"),write),
+ ok = io:format(Fid, "{\"agentEngine\", \"newUser\", "
+ "\"newUser\", zeroDotZero, "
+ "usmHMACSHAAuthProtocol, \"\", \"\", "
+ "usmDESPrivProtocol, \"\", \"\", \"\", "
+ "\"~s\", \"~s\"}.\n",
+ [ShaKey, DesKey]),
+ ok = io:format(Fid, "{\"mgrEngine\", \"newUser\", "
+ "\"newUser\", zeroDotZero, "
+ "usmHMACSHAAuthProtocol, \"\", \"\", "
+ "usmDESPrivProtocol, \"\", \"\", \"\", "
+ "\"~s\", \"~s\"}.\n",
+ [ShaKey, DesKey]),
+ file:close(Fid).
+
+reset_usm_mgr(Dir) ->
+ ?line ok = file:rename(filename:join(Dir,"usm.old"),
+ filename:join(Dir,"usm.conf")).
+
+
+update_community([v3], _Dir) -> ok;
+update_community(_, Dir) ->
+ {ok, Fid} = file:open(filename:join(Dir,"community.conf"),[read,write]),
+ file:position(Fid, eof),
+ ok=io:format(Fid,"{\"no-rights\",\"no-rights\",\"no-rights\",\"\",\"\"}.\n",
+ []),
+ file:close(Fid).
+
+
+-define(tDescr_instance, [1,3,6,1,2,1,16,1,0]).
+update_vacm(_Vsn, Dir) ->
+ {ok, Fid} = file:open(filename:join(Dir,"vacm.conf"),[read,write]),
+ file:position(Fid, eof),
+ ok=io:format(Fid,"{vacmSecurityToGroup,usm,\"authMD5\",\"initial\"}.\n",[]),
+ ok=io:format(Fid,"{vacmSecurityToGroup,usm,\"authSHA\",\"initial\"}.\n",[]),
+ ok=io:format(Fid,"{vacmSecurityToGroup,usm,\"privDES\",\"initial\"}.\n",[]),
+ ok=io:format(Fid,"{vacmSecurityToGroup,usm,\"newUser\",\"initial\"}.\n",[]),
+ ok = io:format(Fid, "{vacmViewTreeFamily, \"internet\", "
+ "~w, excluded, null}.\n", [?tDescr_instance]),
+ file:close(Fid).
+
+
+vacm_ver(v1) -> v1;
+vacm_ver(v2) -> v2c;
+vacm_ver(v3) -> usm.
+
+
+write_community_conf(Dir, Confs) ->
+ {ok, Fid} = file:open(filename:join(Dir,"community.conf"),write),
+ ok = write_community_conf1(Fid, Confs),
+ file:close(Fid).
+
+write_community_conf1(_, []) ->
+ ok;
+write_community_conf1(Fid, [{ComIdx, ComName, SecName, CtxName, TransTag}|Confs]) ->
+ ok = io:format(Fid, "{\"~s\", \"~s\", \"~s\", \"~s\", \"~s\"}.~n",
+ [ComIdx, ComName, SecName, CtxName, TransTag]),
+ write_community_conf1(Fid, Confs).
+
+
+write_target_addr_conf(Dir, Confs) ->
+ {ok, Fid} = file:open(filename:join(Dir,"target_addr.conf"),write),
+ ok = write_target_addr_conf1(Fid, Confs),
+ file:close(Fid).
+
+
+write_target_addr_conf1(_, []) ->
+ ok;
+write_target_addr_conf1(Fid,
+ [{Name, Ip, Port, Timeout, Retry, TagList, ParamName,
+ EngineId, TMask, MaxMsgSz}|Confs]) ->
+ ok = io:format(Fid, "{\"~s\", ~w, ~w, ~w, ~w, \"~s\", \"~s\", \"~s\", ~w, ~w}.~n",
+ [Name, Ip, Port, Timeout, Retry, TagList, ParamName,
+ EngineId, TMask, MaxMsgSz]),
+ write_target_addr_conf1(Fid, Confs).
+
+write_target_addr_conf(Dir, ManagerIp, UDP, Vsns) ->
+ {ok, Fid} = file:open(filename:join(Dir,"target_addr.conf"),write),
+ lists:foreach(fun(Vsn) ->
+ ok = io:format(Fid,
+ "{\"~s\", ~w, ~w, 1500, 3, "
+ "\"std_trap\", \"~s\"}.~n",
+ [mk_ip(ManagerIp, Vsn),
+ ManagerIp, UDP, mk_param(Vsn)]),
+ case Vsn of
+ v1 -> ok;
+ v2 ->
+ ok = io:format(Fid,
+ "{\"~s.2\",~w,~w,1500,3, "
+ "\"std_inform\", \"~s\"}.~n",
+ [mk_ip(ManagerIp, Vsn),
+ ManagerIp, UDP,
+ mk_param(Vsn)]);
+ v3 ->
+ ok = io:format(Fid,
+ "{\"~s.3\",~w,~w,1500,3, "
+ "\"std_inform\", \"~s\", "
+ "\"mgrEngine\", [], 1024}.~n",
+ [mk_ip(ManagerIp, Vsn),
+ ManagerIp, UDP,
+ mk_param(Vsn)])
+ end
+ end,
+ Vsns),
+ file:close(Fid).
+
+mk_param(v1) -> "target_v1";
+mk_param(v2) -> "target_v2";
+mk_param(v3) -> "target_v3".
+
+mk_ip([A,B,C,D], Vsn) ->
+ io_lib:format("~w.~w.~w.~w ~w", [A,B,C,D,Vsn]).
+
+
+rewrite_target_addr_conf(Dir,NewPort) ->
+ TAFile = filename:join(Dir, "target_addr.conf"),
+ ?DBG("rewrite_target_addr_conf -> read target file info of address config file",[]),
+ case file:read_file_info(TAFile) of
+ {ok, _} -> ok;
+ {error, R} -> ?ERR("failure reading file info of "
+ "target address config file: ~p",[R]),
+ ok
+ end,
+
+ ?line [TrapAddr|Addrs] =
+ snmp_conf:read(TAFile,fun(R) -> rewrite_target_addr_conf1(R) end),
+
+ ?DBG("rewrite_target_addr_conf -> TrapAddr: ~p",[TrapAddr]),
+
+ NewAddrs = [rewrite_target_addr_conf2(NewPort,TrapAddr)|Addrs],
+
+ ?DBG("rewrite_target_addr_conf -> NewAddrs: ~p",[NewAddrs]),
+
+ ?line ok = file:rename(filename:join(Dir,"target_addr.conf"),
+ filename:join(Dir,"target_addr.old")),
+ ?line {ok, Fid} = file:open(filename:join(Dir,"target_addr.conf"),write),
+
+ ?line ok = rewrite_target_addr_conf3(Fid,NewAddrs),
+
+ file:close(Fid).
+
+rewrite_target_addr_conf1(O) ->
+ {ok,O}.
+
+rewrite_target_addr_conf2(NewPort,{Name,Ip,_Port,Timeout,Retry,
+ "std_trap",EngineId}) ->
+ ?LOG("rewrite_target_addr_conf2 -> entry with std_trap",[]),
+ {Name,Ip,NewPort,Timeout,Retry,"std_trap",EngineId};
+rewrite_target_addr_conf2(_NewPort,O) ->
+ ?LOG("rewrite_target_addr_conf2 -> entry with "
+ "~n O: ~p",[O]),
+ O.
+
+
+rewrite_target_addr_conf3(_,[]) -> ok;
+rewrite_target_addr_conf3(Fid,[{Name,Ip,Port,Timeout,Retry,
+ ParamName,EngineId}|T]) ->
+ ?LOG("rewrite_target_addr_conf3 -> write(1) ~s",[ParamName]),
+ io:format(Fid,
+ "{\"~s\", " % Name
+ "~p, " % Ip
+ "~p, " % Port
+ "~p, " % Timeout
+ "~p, " % Retry
+ "\"~s\", " % ParamsName
+ "\"~s\"}.", % EngineId
+ [Name,Ip,Port,Timeout,Retry,ParamName,EngineId]),
+ rewrite_target_addr_conf3(Fid,T);
+rewrite_target_addr_conf3(Fid,[{Name,Ip,Port,Timeout,Retry,TagList,
+ ParamName,EngineId,TMask,MMS}|T]) ->
+ ?LOG("rewrite_target_addr_conf3 -> write(2) ~s",[ParamName]),
+ io:format(Fid,
+ "{\"~s\", " % Name
+ "~p, " % Ip
+ "~p, " % Port
+ "~p, " % Timeout
+ "~p, " % Retry
+ "\"~s\", " % TagList
+ "\"~s\", " % ParamsName
+ "\"~s\"," % EngineId
+ "~p, " % TMask
+ "~p}.", % MMS
+ [Name,Ip,Port,Timeout,Retry,TagList,ParamName,
+ EngineId,TMask,MMS]),
+ rewrite_target_addr_conf3(Fid,T).
+
+reset_target_addr_conf(Dir) ->
+ ?line ok = file:rename(filename:join(Dir,"target_addr.old"),
+ filename:join(Dir,"target_addr.conf")).
+
+write_target_params_conf(Dir, Vsns) ->
+ {ok, Fid} = file:open(filename:join(Dir,"target_params.conf"),write),
+ lists:foreach(fun(Vsn) ->
+ MP = if Vsn == v1 -> v1;
+ Vsn == v2 -> v2c;
+ Vsn == v3 -> v3
+ end,
+ SM = if Vsn == v1 -> v1;
+ Vsn == v2 -> v2c;
+ Vsn == v3 -> usm
+ end,
+ ok = io:format(Fid, "{\"target_~w\", ~w, ~w, "
+ "\"all-rights\", noAuthNoPriv}.~n",
+ [Vsn, MP, SM])
+ end,
+ Vsns),
+ file:close(Fid).
+
+rewrite_target_params_conf(Dir, SecName, SecLevel) ->
+ ?line ok = file:rename(filename:join(Dir,"target_params.conf"),
+ filename:join(Dir,"target_params.old")),
+ ?line {ok, Fid} = file:open(filename:join(Dir,"target_params.conf"),write),
+ ?line ok = io:format(Fid, "{\"target_v3\", v3, usm, \"~s\", ~w}.~n",
+ [SecName, SecLevel]),
+ file:close(Fid).
+
+reset_target_params_conf(Dir) ->
+ ?line ok = file:rename(filename:join(Dir,"target_params.old"),
+ filename:join(Dir,"target_params.conf")).
+
+write_notify_conf(Dir) ->
+ {ok, Fid} = file:open(filename:join(Dir,"notify.conf"),write),
+ ok = io:format(Fid, "{\"standard trap\", \"std_trap\", trap}.~n", []),
+ ok = io:format(Fid, "{\"standard inform\", \"std_inform\",inform}.~n", []),
+ file:close(Fid).
+
+ver_to_trap_str([v1]) -> "v1";
+ver_to_trap_str([v2]) -> "v2";
+% default is to use the latest snmp version
+ver_to_trap_str([v1,v2]) -> "v2".
+
+
+
+write_view_conf(Dir) ->
+ {ok, Fid} = file:open(a(Dir,"view.conf"),write),
+ ok = io:format(Fid, "{2, [1,3,6], included, null}.~n", []),
+ ok = io:format(Fid, "{2, ~w, excluded, null}.~n", [?tDescr_instance]),
+ file:close(Fid).
+
+a(A,B) -> lists:append(A,B).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+copy_file(From, To) ->
+ {ok, Bin} = file:read_file(From),
+ ok = file:write_file(To, Bin).
+
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+display_memory_usage() ->
+ Info = snmpa:info(snmp_master_agent),
+ TreeSize = lists_key1search(tree_size_bytes, Info),
+ ProcMem = lists_key1search(process_memory, Info),
+ MibDbSize = lists_key1search([db_memory,mib], Info),
+ NodeDbSize = lists_key1search([db_memory,node], Info),
+ TreeDbSize = lists_key1search([db_memory,tree], Info),
+ ?INF("Memory usage: "
+ "~n Tree size: ~p"
+ "~n Process memory size: ~p"
+ "~n Mib db size: ~p"
+ "~n Node db size: ~p"
+ "~n Tree db size: ~p",
+ [TreeSize, ProcMem, MibDbSize, NodeDbSize, TreeDbSize]).
+
+lists_key1search([], Res) ->
+ Res;
+lists_key1search([Key|Keys], List) when atom(Key), list(List) ->
+ case lists:keysearch(Key, 1, List) of
+ {value, {Key, Val}} ->
+ lists_key1search(Keys, Val);
+ false ->
+ undefined
+ end;
+lists_key1search(Key, List) when atom(Key) ->
+ case lists:keysearch(Key, 1, List) of
+ {value, {Key, Val}} ->
+ Val;
+ false ->
+ undefined
+ end.
+
+
+regs() ->
+ lists:sort(registered()).
diff --git a/lib/snmp/test/snmp_app_test.erl b/lib/snmp/test/snmp_app_test.erl
new file mode 100644
index 0000000000..5c5a5285a0
--- /dev/null
+++ b/lib/snmp/test/snmp_app_test.erl
@@ -0,0 +1,430 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2003-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%
+%%
+
+%%----------------------------------------------------------------------
+%% Purpose: Verify the application specifics of the snmp application
+%%----------------------------------------------------------------------
+-module(snmp_app_test).
+
+-export([
+ all/1, init_suite/1, fin_suite/1,
+ init_per_testcase/2, fin_per_testcase/2,
+
+ fields/1,
+ modules/1,
+ exportall/1,
+ app_depend/1,
+ undef_funcs/1,
+
+ start_and_stop/1,
+ start_and_stop_empty/1,
+ start_and_stop_with_agent/1,
+ start_and_stop_with_manager/1,
+ start_and_stop_with_agent_and_manager/1,
+ start_epmty_and_then_agent_and_manager_and_stop/1,
+ start_with_agent_and_then_manager_and_stop/1,
+ start_with_manager_and_then_agent_and_stop/1
+ ]).
+
+
+-include_lib("kernel/include/file.hrl").
+-include("test_server.hrl").
+-include("snmp_test_lib.hrl").
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+all(suite) ->
+ Cases =
+ [
+ fields,
+ modules,
+ exportall,
+ app_depend,
+ undef_funcs,
+ start_and_stop
+ ],
+ {conf, init_suite, Cases, fin_suite}.
+
+init_suite(Config) when is_list(Config) ->
+ ?DISPLAY_SUITE_INFO(),
+ PrivDir = ?config(priv_dir, Config),
+ TopDir = filename:join(PrivDir, app),
+ case file:make_dir(TopDir) of
+ ok ->
+ ok;
+ Error ->
+ fail({failed_creating_subsuite_top_dir, Error})
+ end,
+ AppFile =
+ case is_app() of
+ {ok, File} ->
+ io:format("File: ~n~p~n", [File]),
+ snmp:print_version_info(),
+ File;
+ {error, Reason} ->
+ fail(Reason)
+ end,
+ [{app_topdir, TopDir}, {app_file, AppFile} | Config].
+
+
+is_app() ->
+ is_app(?APPLICATION).
+
+is_app(App) ->
+ LibDir = code:lib_dir(App),
+ File = filename:join([LibDir, "ebin", atom_to_list(App) ++ ".app"]),
+ case file:consult(File) of
+ {ok, [{application, App, AppFile}]} ->
+ {ok, AppFile};
+ Error ->
+ {error, {invalid_format, Error}}
+ end.
+
+fin_suite(suite) -> [];
+fin_suite(doc) -> [];
+fin_suite(Config) when is_list(Config) ->
+ Config.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Test server callbacks
+init_per_testcase(undef_funcs, Config) ->
+ Config2 = lists:keydelete(watchdog, 1, Config),
+ [{watchdog, ?WD_START(?MINS(10))} | Config2];
+init_per_testcase(_Case, Config) ->
+ Config.
+
+fin_per_testcase(_Case, Config) ->
+ Config.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+fields(suite) ->
+ [];
+fields(doc) ->
+ [];
+fields(Config) when is_list(Config) ->
+ AppFile = key1search(app_file, Config),
+ Fields = [vsn, description, modules, registered, applications],
+ case check_fields(Fields, AppFile, []) of
+ [] ->
+ ok;
+ Missing ->
+ fail({missing_fields, Missing})
+ end.
+
+check_fields([], _AppFile, Missing) ->
+ Missing;
+check_fields([Field|Fields], AppFile, Missing) ->
+ check_fields(Fields, AppFile, check_field(Field, AppFile, Missing)).
+
+check_field(Name, AppFile, Missing) ->
+ io:format("checking field: ~p~n", [Name]),
+ case lists:keymember(Name, 1, AppFile) of
+ true ->
+ Missing;
+ false ->
+ [Name|Missing]
+ end.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+modules(suite) ->
+ [];
+modules(doc) ->
+ [];
+modules(Config) when is_list(Config) ->
+ AppFile = key1search(app_file, Config),
+ Mods = key1search(modules, AppFile),
+ EbinList = get_ebin_mods(snmp),
+ case missing_modules(Mods, EbinList, []) of
+ [] ->
+ ok;
+ Missing ->
+ fail({missing_modules, Missing})
+ end,
+ Allowed = [snmpc,
+ snmpc_lib,
+ snmpc_misc,
+ snmpc_mib_gram,
+ snmpc_mib_to_hrl,
+ snmpc_tok],
+ case extra_modules(Mods, EbinList, Allowed, []) of
+ [] ->
+ ok;
+ Extra ->
+ fail({extra_modules, Extra})
+ end,
+ {ok, Mods}.
+
+get_ebin_mods(App) ->
+ LibDir = code:lib_dir(App),
+ EbinDir = filename:join([LibDir,"ebin"]),
+ {ok, Files0} = file:list_dir(EbinDir),
+ Files1 = [lists:reverse(File) || File <- Files0],
+ [list_to_atom(lists:reverse(Name)) || [$m,$a,$e,$b,$.|Name] <- Files1].
+
+
+missing_modules([], _Ebins, Missing) ->
+ Missing;
+missing_modules([Mod|Mods], Ebins, Missing) ->
+ case lists:member(Mod, Ebins) of
+ true ->
+ missing_modules(Mods, Ebins, Missing);
+ false ->
+ io:format("missing module: ~p~n", [Mod]),
+ missing_modules(Mods, Ebins, [Mod|Missing])
+ end.
+
+
+extra_modules(_Mods, [], Allowed, Extra) ->
+ Extra--Allowed;
+extra_modules(Mods, [Mod|Ebins], Allowed, Extra) ->
+ case lists:member(Mod, Mods) of
+ true ->
+ extra_modules(Mods, Ebins, Allowed, Extra);
+ false ->
+ io:format("superfluous module: ~p~n", [Mod]),
+ extra_modules(Mods, Ebins, Allowed, [Mod|Extra])
+ end.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+
+exportall(suite) ->
+ [];
+exportall(doc) ->
+ [];
+exportall(Config) when is_list(Config) ->
+ AppFile = key1search(app_file, Config),
+ Mods = key1search(modules, AppFile),
+ check_export_all(Mods).
+
+
+check_export_all([]) ->
+ ok;
+check_export_all([Mod|Mods]) ->
+ case (catch apply(Mod, module_info, [compile])) of
+ {'EXIT', {undef, _}} ->
+ check_export_all(Mods);
+ O ->
+ case lists:keysearch(options, 1, O) of
+ false ->
+ check_export_all(Mods);
+ {value, {options, List}} ->
+ case lists:member(export_all, List) of
+ true ->
+ fail({export_all, Mod});
+ false ->
+ check_export_all(Mods)
+ end
+ end
+ end.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+app_depend(suite) ->
+ [];
+app_depend(doc) ->
+ [];
+app_depend(Config) when is_list(Config) ->
+ AppFile = key1search(app_file, Config),
+ Apps = key1search(applications, AppFile),
+ check_apps(Apps).
+
+
+check_apps([]) ->
+ ok;
+check_apps([App|Apps]) ->
+ case is_app(App) of
+ {ok, _} ->
+ check_apps(Apps);
+ Error ->
+ throw({error, {missing_app, {App, Error}}})
+ end.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+undef_funcs(suite) ->
+ [];
+undef_funcs(doc) ->
+ [];
+undef_funcs(Config) when is_list(Config) ->
+ App = snmp,
+ AppFile = key1search(app_file, Config),
+ Mods = key1search(modules, AppFile),
+ Root = code:root_dir(),
+ LibDir = code:lib_dir(App),
+ EbinDir = filename:join([LibDir,"ebin"]),
+ XRefTestName = undef_funcs_make_name(App, xref_test_name),
+ {ok, XRef} = xref:start(XRefTestName),
+ ok = xref:set_default(XRef,
+ [{verbose,false},{warnings,false}]),
+ XRefName = undef_funcs_make_name(App, xref_name),
+ {ok, XRefName} = xref:add_release(XRef, Root, {name,XRefName}),
+ {ok, App} = xref:replace_application(XRef, App, EbinDir),
+ {ok, Undefs} = xref:analyze(XRef, undefined_function_calls),
+ xref:stop(XRef),
+ analyze_undefined_function_calls(Undefs, Mods, []).
+
+analyze_undefined_function_calls([], _, []) ->
+ ok;
+analyze_undefined_function_calls([], _, AppUndefs) ->
+ exit({suite_failed, {undefined_function_calls, AppUndefs}});
+analyze_undefined_function_calls([{{Mod, _F, _A}, _C} = AppUndef|Undefs],
+ AppModules, AppUndefs) ->
+ %% Check that this module is our's
+ case lists:member(Mod,AppModules) of
+ true ->
+ {Calling,Called} = AppUndef,
+ {Mod1,Func1,Ar1} = Calling,
+ {Mod2,Func2,Ar2} = Called,
+ io:format("undefined function call: "
+ "~n ~w:~w/~w calls ~w:~w/~w~n",
+ [Mod1,Func1,Ar1,Mod2,Func2,Ar2]),
+ analyze_undefined_function_calls(Undefs, AppModules,
+ [AppUndef|AppUndefs]);
+ false ->
+ io:format("dropping ~p~n", [Mod]),
+ analyze_undefined_function_calls(Undefs, AppModules, AppUndefs)
+ end.
+
+%% This function is used simply to avoid cut-and-paste errors later...
+undef_funcs_make_name(App, PostFix) ->
+ list_to_atom(atom_to_list(App) ++ "_" ++ atom_to_list(PostFix)).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+start_and_stop(suite) ->
+ [
+ start_and_stop_empty,
+ start_and_stop_with_agent,
+ start_and_stop_with_manager,
+ start_and_stop_with_agent_and_manager,
+ start_epmty_and_then_agent_and_manager_and_stop,
+ start_with_agent_and_then_manager_and_stop,
+ start_with_manager_and_then_agent_and_stop
+ ].
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+start_and_stop_empty(suite) ->
+ [];
+start_and_stop_empty(doc) ->
+ ["Start and stop the application empty (no configured components)"];
+start_and_stop_empty(Config) when is_list(Config) ->
+ ?line false = ?IS_SNMP_RUNNING(),
+
+ ?line ok = snmp:start(),
+
+ ?line true = ?IS_SNMP_RUNNING(),
+
+ ?line ok = snmp:stop(),
+
+ ?line false = ?IS_SNMP_RUNNING(),
+
+ ok.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+start_and_stop_with_agent(suite) ->
+ [];
+start_and_stop_with_agent(doc) ->
+ ["Start and stop the application with the agent pre-configured"];
+start_and_stop_with_agent(Config) when is_list(Config) ->
+ ?SKIP(not_implemented_yet).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+start_and_stop_with_manager(suite) ->
+ [];
+start_and_stop_with_manager(doc) ->
+ ["Start and stop the application with the manager pre-configured"];
+start_and_stop_with_manager(Config) when is_list(Config) ->
+ ?SKIP(not_implemented_yet).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+start_and_stop_with_agent_and_manager(suite) ->
+ [];
+start_and_stop_with_agent_and_manager(doc) ->
+ ["Start and stop the application with both the agent "
+ "and the manager pre-configured"];
+start_and_stop_with_agent_and_manager(Config) when is_list(Config) ->
+ ?SKIP(not_implemented_yet).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+start_epmty_and_then_agent_and_manager_and_stop(suite) ->
+ [];
+start_epmty_and_then_agent_and_manager_and_stop(doc) ->
+ ["Start the application empty, then start the agent and then "
+ "the manager and then stop the application"];
+start_epmty_and_then_agent_and_manager_and_stop(Config) when is_list(Config) ->
+ ?SKIP(not_implemented_yet).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+start_with_agent_and_then_manager_and_stop(suite) ->
+ [];
+start_with_agent_and_then_manager_and_stop(doc) ->
+ ["Start the application with the agent pre-configured, "
+ "then start the manager and then stop the application"];
+start_with_agent_and_then_manager_and_stop(Config) when is_list(Config) ->
+ ?SKIP(not_implemented_yet).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+start_with_manager_and_then_agent_and_stop(suite) ->
+ [];
+start_with_manager_and_then_agent_and_stop(doc) ->
+ ["Start the application with the manager pre-configured, "
+ "then start the agent and then stop the application"];
+start_with_manager_and_then_agent_and_stop(Config) when is_list(Config) ->
+ ?SKIP(not_implemented_yet).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+
+fail(Reason) ->
+ exit({suite_failed, Reason}).
+
+key1search(Key, L) ->
+ case lists:keysearch(Key, 1, L) of
+ undefined ->
+ fail({not_found, Key, L});
+ {value, {Key, Value}} ->
+ Value
+ end.
diff --git a/lib/snmp/test/snmp_appup_mgr.erl b/lib/snmp/test/snmp_appup_mgr.erl
new file mode 100644
index 0000000000..271d6a2847
--- /dev/null
+++ b/lib/snmp/test/snmp_appup_mgr.erl
@@ -0,0 +1,280 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2003-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%
+%%
+
+%%----------------------------------------------------------------------
+%% Purpose: Simple (snmp) manager used when performing appup tests.
+%%----------------------------------------------------------------------
+-module(snmp_appup_mgr).
+
+-behaviour(snmpm_user).
+
+-include_lib("snmp/include/STANDARD-MIB.hrl").
+-include_lib("snmp/include/snmp_types.hrl").
+
+-export([start/0, start/1, start/2]).
+-export([handle_error/3,
+ handle_agent/4,
+ handle_pdu/5,
+ handle_trap/4,
+ handle_inform/4,
+ handle_report/4]).
+-export([main/2]).
+
+-record(agent, {host, port, conf}).
+-record(state, {timer, reqs, ids, agent}).
+
+-define(USER_ID, ?MODULE).
+-define(REQ_TIMEOUT, 10000).
+-define(POLL_TIMEOUT, 5000).
+-define(DEFAULT_PORT, 4000).
+%% -define(DEFAULT_PORT, 161).
+
+-define(v1_2(V1,V2),
+ case get(vsn) of
+ v1 -> V1;
+ _ -> V2
+ end).
+
+
+start() ->
+ {ok, AgentHost} = inet:gethostname(),
+ AgentPort = ?DEFAULT_PORT,
+ start(AgentHost, AgentPort).
+
+start(AgentPort) when is_integer(AgentPort) ->
+ {ok, AgentHost} = inet:gethostname(),
+ start(AgentHost, AgentPort);
+start(AgentHost) when is_list(AgentHost) ->
+ AgentPort = 161,
+ start(AgentHost, AgentPort).
+
+start(AgentHost, AgentPort)
+ when is_list(AgentHost) and is_integer(AgentPort) ->
+ ensure_started(snmp),
+ Pid = erlang:spawn_link(?MODULE, main, [AgentHost, AgentPort]),
+ receive
+ {'EXIT', Pid, normal} ->
+ ok;
+ {'EXIT', Pid, Reason} ->
+ {error, {unexpected_exit, Reason}}
+ end.
+
+ensure_started(App) ->
+ case application:start(App) of
+ ok ->
+ ok;
+ {error, {already_started, _}} ->
+ ok;
+ {error, Reason} ->
+ exit(Reason)
+ end.
+
+poll_timer() ->
+ poll_timer(first).
+
+poll_timer(How) ->
+ erlang:send_after(?POLL_TIMEOUT, self(), {poll_timeout, How}).
+
+next_poll_type(first) ->
+ all;
+next_poll_type(all) ->
+ first.
+
+main(AgentHost, AgentPort) ->
+ ok = snmpm:register_user_monitor(?USER_ID, ?MODULE, self()),
+ AgentConf = [{community, "all-rights"},
+ {engine_id, "agentEngine"},
+ {sec_level, noAuthNoPriv},
+ {version, v1}],
+ ok = snmpm:register_agent(?USER_ID, AgentHost, AgentPort, AgentConf),
+ Reqs = [{"sysDescr", get, ?sysDescr_instance},
+ {"sysObjectID", get, ?sysObjectID_instance},
+ {"sysUpTime", get, ?sysUpTime_instance}],
+ Agent = #agent{host = AgentHost, port = AgentPort, conf = AgentConf},
+ State = #state{timer = poll_timer(), reqs = Reqs, agent = Agent},
+ loop(State).
+
+loop(State) ->
+ receive
+ {poll_timeout, How} ->
+ NewState = handle_poll_timeout(State, How),
+ loop(NewState#state{timer = poll_timer(next_poll_type(How))});
+
+ {req_timeout, ReqId} ->
+ NewState = handle_req_timeout(State, ReqId),
+ loop(NewState);
+
+ {snmp_callback, Info} ->
+ NewState = handle_snmp(State, Info),
+ loop(NewState)
+ end.
+
+
+handle_poll_timeout(#state{agent = Agent, reqs = [Req|Reqs], ids = IDs} = S,
+ first) ->
+ ReqId = handle_req(Agent, [Req]),
+ S#state{reqs = Reqs ++ [Req], ids = [ReqId|IDs]};
+handle_poll_timeout(#state{agent = Agent, reqs = Reqs, ids = IDs} = S, all) ->
+ ReqId = handle_req(Agent, Reqs),
+ S#state{ids = [ReqId|IDs]}.
+
+handle_req(#agent{host = Host, port = Port}, Reqs) ->
+ Oids = [Oid || {_Desc, Op, Oid} <- Reqs, Op == get],
+ Descs = [Desc || {Desc, Op, _Oid} <- Reqs, Op == get],
+ {ok, ReqId} = snmpm:ag(?USER_ID, Host, Port, Oids),
+ p("issued get-request (~w) for: ~s", [ReqId, oid_descs(Descs)]),
+ ReqTimer = erlang:send_after(?REQ_TIMEOUT, self(), {req_timeout, ReqId}),
+ {ReqId, erlang:now(), ReqTimer}.
+
+oid_descs([]) ->
+ [];
+oid_descs([Desc]) ->
+ lists:flatten(io_lib:format("~s", [Desc]));
+oid_descs([Desc|Descs]) ->
+ lists:flatten(io_lib:format("~s, ", [Desc])) ++ oid_descs(Descs).
+
+handle_req_timeout(#state{ids = IDs0} = State, ReqId) ->
+ case lists:keysearch(ReqId, 1, IDs0) of
+ {value, {ReqId, _T, _Ref}} ->
+ e("Request timeout for request ~w", [ReqId]),
+ IDs = lists:keydelete(ReqId, 1, IDs0),
+ State#state{ids = IDs};
+ false ->
+ w("Did not find request corresponding to id ~w", [ReqId]),
+ State
+ end.
+
+handle_snmp(#state{ids = IDs0} = S, {error, ReqId, Reason}) ->
+ case lists:keysearch(ReqId, 1, IDs0) of
+ {value, {ReqId, T, Ref}} ->
+ Diff = timer:now_diff(erlang:now(), T),
+ p("SNMP error regarding outstanding request after ~w microsec:"
+ "~n ReqId: ~w"
+ "~n Reason: ~w", [Diff, ReqId, Reason]),
+ IDs = lists:keydelete(ReqId, 1, IDs0),
+ erlang:cancel_timer(Ref),
+ S#state{ids = IDs};
+ false ->
+ w("SNMP error regarding unknown request:"
+ "~n ReqId: ~w"
+ "~n Reason: ~w", [ReqId, Reason]),
+ S
+ end;
+
+handle_snmp(State, {agent, Addr, Port, SnmpInfo}) ->
+ p("Received agent info:"
+ "~n Addr: ~w"
+ "~n Port: ~w"
+ "~n SnmpInfo: ~w", [Addr, Port, SnmpInfo]),
+ State;
+
+handle_snmp(#state{ids = IDs0} = S, {pdu, Addr, Port, ReqId, SnmpResponse}) ->
+ case lists:keysearch(ReqId, 1, IDs0) of
+ {value, {ReqId, T, Ref}} ->
+ Diff = timer:now_diff(erlang:now(), T),
+ p("SNMP pdu regarding outstanding request after ~w microsec:"
+ "~n ReqId: ~w"
+ "~n Addr: ~w"
+ "~n Port: ~w"
+ "~n SnmpResponse: ~w",
+ [Diff, ReqId, Addr, Port, SnmpResponse]),
+ IDs = lists:keydelete(ReqId, 1, IDs0),
+ erlang:cancel_timer(Ref),
+ S#state{ids = IDs};
+ false ->
+ w("SNMP pdu regarding unknown request:"
+ "~n ReqId: ~w"
+ "~n Addr: ~w"
+ "~n Port: ~w"
+ "~n SnmpResponse: ~w", [ReqId, Addr, Port, SnmpResponse]),
+ S
+ end;
+
+handle_snmp(State, {trap, Addr, Port, SnmpTrapInfo}) ->
+ p("Received trap:"
+ "~n Addr: ~w"
+ "~n Port: ~w"
+ "~n SnmpTrapInfo: ~w", [Addr, Port, SnmpTrapInfo]),
+ State;
+
+handle_snmp(State, {inform, Addr, Port, SnmpInform}) ->
+ p("Received inform:"
+ "~n Addr: ~w"
+ "~n Port: ~w"
+ "~n SnmpInform: ~w", [Addr, Port, SnmpInform]),
+ State;
+
+handle_snmp(State, {report, Addr, Port, SnmpReport}) ->
+ p("Received report:"
+ "~n Addr: ~w"
+ "~n Port: ~w"
+ "~n SnmpReport: ~w", [Addr, Port, SnmpReport]),
+ State;
+
+handle_snmp(State, Unknown) ->
+ p("Received unknown snmp info:"
+ "~n Unknown: ~w", [Unknown]),
+ State.
+
+
+%% -----------------------------------------------------------------------
+%%
+%% Manager user callback API
+%%
+%% -----------------------------------------------------------------------
+
+
+handle_error(ReqId, Reason, Pid) ->
+ Pid ! {snmp_callback, {error, ReqId, Reason}},
+ ignore.
+
+handle_agent(Addr, Port, SnmpInfo, Pid) ->
+ Pid ! {snmp_callback, {agent, Addr, Port, SnmpInfo}},
+ ignore.
+
+handle_pdu(Addr, Port, ReqId, SnmpResponse, Pid) ->
+ Pid ! {snmp_callback, {pdu, Addr, Port, ReqId, SnmpResponse}},
+ ignore.
+
+handle_trap(Addr, Port, SnmpTrapInfo, Pid) ->
+ Pid ! {snmp_callback, {trap, Addr, Port, SnmpTrapInfo}},
+ ignore.
+
+handle_inform(Addr, Port, SnmpInform, Pid) ->
+ Pid ! {snmp_callback, {inform, Addr, Port, SnmpInform}},
+ ignore.
+
+handle_report(Addr, Port, SnmpReport, Pid) ->
+ Pid ! {snmp_callback, {report, Addr, Port, SnmpReport}},
+ ignore.
+
+
+%% -----------------------------------------------------------------------
+
+e(F, A) ->
+ p("*** ERROR ***", F, A).
+
+w(F, A) ->
+ p("*** WARNING ***", F, A).
+
+p(F, A) ->
+ p("*** INFO ***", F, A).
+
+p(P, F, A) ->
+ io:format("~s~nMGR: " ++ F ++ "~n~n", [P|A]).
diff --git a/lib/snmp/test/snmp_appup_test.erl b/lib/snmp/test/snmp_appup_test.erl
new file mode 100644
index 0000000000..18509526cf
--- /dev/null
+++ b/lib/snmp/test/snmp_appup_test.erl
@@ -0,0 +1,560 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2003-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%
+%%
+
+%%----------------------------------------------------------------------
+%% Purpose: Verify the application specifics of the Megaco application
+%%----------------------------------------------------------------------
+-module(snmp_appup_test).
+
+-export([
+ all/1, init_suite/1, fin_suite/1,
+ init_per_testcase/2, fin_per_testcase/2,
+
+ appup_file/1
+
+ ]).
+
+-include("test_server.hrl").
+-include("snmp_test_lib.hrl").
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+all(suite) ->
+ Cases =
+ [
+ appup_file
+ ],
+ {conf, init_suite, Cases, fin_suite}.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+init_suite(suite) -> [];
+init_suite(doc) -> [];
+init_suite(Config) when is_list(Config) ->
+ PrivDir = ?config(priv_dir, Config),
+ TopDir = filename:join(PrivDir, appup),
+ case file:make_dir(TopDir) of
+ ok ->
+ ok;
+ Error ->
+ fail({failed_creating_subsuite_top_dir, Error})
+ end,
+ AppFile = file_name(?APPLICATION, ".app"),
+ AppupFile = file_name(?APPLICATION, ".appup"),
+ [{app_file, AppFile},
+ {appup_file, AppupFile},
+ {appup_topdir, TopDir} | Config].
+
+
+file_name(App, Ext) ->
+ Env = init:get_arguments(),
+ LibDir =
+ case lists:keysearch(clearcase, 1, Env) of
+ false ->
+ code:lib_dir(App);
+ _ ->
+ ".."
+ end,
+ filename:join([LibDir, "ebin", atom_to_list(App) ++ Ext]).
+
+
+fin_suite(suite) -> [];
+fin_suite(doc) -> [];
+fin_suite(Config) when is_list(Config) ->
+ Config.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+%% Test server callbacks
+init_per_testcase(_Case, Config) when is_list(Config) ->
+ Config.
+
+fin_per_testcase(_Case, Config) when is_list(Config) ->
+ Config.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+appup_file(suite) ->
+ [];
+appup_file(doc) ->
+ "Perform a simple check of the appup file";
+appup_file(Config) when is_list(Config) ->
+ AppupFile = key1search(appup_file, Config),
+ AppFile = key1search(app_file, Config),
+ Modules = modules(AppFile),
+ check_appup(AppupFile, Modules).
+
+modules(File) ->
+ case file:consult(File) of
+ {ok, [{application,snmp,Info}]} ->
+ case lists:keysearch(modules,1,Info) of
+ {value, {modules, Modules}} ->
+ Modules;
+ false ->
+ fail({bad_appinfo, Info})
+ end;
+ Error ->
+ fail({bad_appfile, Error, File})
+ end.
+
+
+check_appup(AppupFile, Modules) ->
+ case file:consult(AppupFile) of
+ {ok, [{V, UpFrom, DownTo}]} ->
+ check_appup(V, UpFrom, DownTo, Modules);
+ Else ->
+ fail({bad_appupfile, Else})
+ end.
+
+
+check_appup(V, UpFrom, DownTo, Modules) ->
+ check_version(V),
+ check_depends(up, UpFrom, Modules),
+ check_depends(down, DownTo, Modules),
+ check_module_subset(up, UpFrom),
+ check_module_subset(down, DownTo),
+ ok.
+
+check_depends(_, [], _) ->
+ ok;
+check_depends(UpDown, [Dep|Deps], Modules) ->
+ check_depend(UpDown, Dep, Modules),
+ check_depends(UpDown, Deps, Modules).
+
+
+check_depend(up = UpDown, {add_application, ?APPLICATION} = Instr, Modules) ->
+ d("check_instructions(~w) -> entry with"
+ "~n Instruction: ~p"
+ "~n Modules: ~p", [UpDown, Instr, Modules]),
+ ok;
+check_depend(down = UpDown, {remove_application, ?APPLICATION} = Instr,
+ Modules) ->
+ d("check_instructions(~w) -> entry with"
+ "~n Instruction: ~p"
+ "~n Modules: ~p", [UpDown, Instr, Modules]),
+ ok;
+check_depend(UpDown, {V, Instructions}, Modules) ->
+ d("check_instructions(~w) -> entry with"
+ "~n V: ~p"
+ "~n Modules: ~p", [UpDown, V, Modules]),
+ check_version(V),
+ case check_instructions(UpDown,
+ Instructions, Instructions, [], [], Modules) of
+ {_Good, []} ->
+ ok;
+ {_, Bad} ->
+ fail({bad_instructions, Bad, UpDown})
+ end.
+
+
+check_instructions(_, [], _, Good, Bad, _) ->
+ {lists:reverse(Good), lists:reverse(Bad)};
+check_instructions(UpDown, [Instr|Instrs], AllInstr, Good, Bad, Modules) ->
+ d("check_instructions(~w) -> entry with"
+ "~n Instr: ~p", [UpDown,Instr]),
+ case (catch check_instruction(UpDown, Instr, AllInstr, Modules)) of
+ ok ->
+ check_instructions(UpDown, Instrs, AllInstr,
+ [Instr|Good], Bad, Modules);
+ {error, Reason} ->
+ check_instructions(UpDown, Instrs, AllInstr, Good,
+ [{Instr, Reason}|Bad], Modules)
+ end;
+check_instructions(UpDown, Instructions, _, _, _, _) ->
+ fail({bad_instructions, {UpDown, Instructions}}).
+
+check_instruction(_, {restart_application, ?APPLICATION}, _, _Modules) ->
+ d("check_instruction -> entry when restart_application instruction"),
+ ok;
+
+%% A new module is added
+check_instruction(up, {add_module, Module}, _, Modules)
+ when is_atom(Module) ->
+ d("check_instruction -> entry when up-add_module instruction with"
+ "~n Module: ~p", [Module]),
+ check_module(Module, Modules);
+
+%% An old module is re-added
+check_instruction(down, {add_module, Module}, _, Modules)
+ when is_atom(Module) ->
+ d("check_instruction -> entry when down-add_module instruction with"
+ "~n Module: ~p", [Module]),
+ case (catch check_module(Module, Modules)) of
+ {error, {unknown_module, Module, Modules}} ->
+ ok;
+ ok ->
+ error({existing_readded_module, Module})
+ end;
+
+check_instruction(up, {delete_module, Module}, _, Modules)
+ when is_atom(Module) ->
+ d("check_instruction -> entry when up-delete_module instruction with"
+ "~n Module: ~p", [Module]),
+ case (catch check_module(Module, Modules)) of
+ {error, {unknown_module, Module, Modules}} ->
+ ok;
+ ok ->
+ error({module_cannot_be_deleted, Module})
+ end;
+
+%% An new module is deleted
+check_instruction(down, {delete_module, Module}, _, Modules)
+ when is_atom(Module) ->
+ d("check_instruction -> entry when down-delete_module instruction with"
+ "~n Module: ~p", [Module]),
+ check_module(Module, Modules);
+
+%% Removing a module on upgrade:
+%% - the module has been removed from the app-file.
+%% - check that no module depends on this (removed) module
+check_instruction(up, {remove, {Module, Pre, Post}}, _, Modules)
+ when is_atom(Module) and is_atom(Pre) and is_atom(Post) ->
+ d("check_instruction -> entry when up-remove instruction with"
+ "~n Module: ~p"
+ "~n Pre: ~p"
+ "~n Post: ~p", [Module, Pre, Post]),
+ case (catch check_module(Module, Modules)) of
+ {error, {unknown_module, Module, Modules}} ->
+ check_purge(Pre),
+ check_purge(Post);
+ ok ->
+ error({existing_removed_module, Module})
+ end;
+
+%% Removing a module on downgrade: the module exist
+%% in the app-file.
+check_instruction(down, {remove, {Module, Pre, Post}}, AllInstr, Modules)
+ when is_atom(Module) and is_atom(Pre) and is_atom(Post) ->
+ d("check_instruction -> entry when down-remove instruction with"
+ "~n Module: ~p"
+ "~n Pre: ~p"
+ "~n Post: ~p", [Module, Pre, Post]),
+ case (catch check_module(Module, Modules)) of
+ ok ->
+ check_purge(Pre),
+ check_purge(Post),
+ check_no_remove_depends(Module, AllInstr);
+ {error, {unknown_module, Module, Modules}} ->
+ error({nonexisting_removed_module, Module})
+ end;
+
+check_instruction(_, {load_module, Module, Pre, Post, Depend},
+ AllInstr, Modules)
+ when is_atom(Module) and
+ is_atom(Pre) and
+ is_atom(Post) and
+ is_list(Depend) ->
+ d("check_instruction -> entry when load_module instruction with"
+ "~n Module: ~p"
+ "~n Pre: ~p"
+ "~n Post: ~p"
+ "~n Depend: ~p", [Module, Pre, Post, Depend]),
+ check_module(Module, Modules),
+ check_module_depend(Module, Depend, Modules),
+ check_module_depend(Module, Depend, updated_modules(AllInstr, [])),
+ check_purge(Pre),
+ check_purge(Post);
+
+check_instruction(_, {update, Module, Change, Pre, Post, Depend},
+ AllInstr, Modules)
+ when is_atom(Module) and
+ is_atom(Pre) and
+ is_atom(Post) and
+ is_list(Depend) ->
+ d("check_instruction -> entry when update instruction with"
+ "~n Module: ~p"
+ "~n Change: ~p"
+ "~n Pre: ~p"
+ "~n Post: ~p"
+ "~n Depend: ~p", [Module, Change, Pre, Post, Depend]),
+ check_module(Module, Modules),
+ check_module_depend(Module, Depend, Modules),
+ check_module_depend(Module, Depend, updated_modules(AllInstr, [])),
+ check_change(Change),
+ check_purge(Pre),
+ check_purge(Post);
+
+check_instruction(_, {update, Module, supervisor}, _, Modules)
+ when is_atom(Module) ->
+ d("check_instruction -> entry when supervisor update instruction with"
+ "~n Module: ~p", [Module]),
+ check_module(Module, Modules);
+
+check_instruction(_, {apply, {Module, Function, Args}}, _, _Modules)
+ when is_atom(Module) and is_atom(Function) and is_list(Args) ->
+ d("check_instruction -> entry when apply instruction with"
+ "~n Module: ~p"
+ "~n Function: ~p"
+ "~n Args: ~p", [Module, Function, Args]),
+ check_apply(Module, Function, Args);
+
+check_instruction(_, Instr, _AllInstr, _Modules) ->
+ error({error, {unknown_instruction, Instr}}).
+
+%% If Module X depends on Module Y, then module Y must have an update
+%% instruction of some sort (otherwise the depend is faulty).
+updated_modules([], Modules) ->
+ d("updated_modules -> entry when done with"
+ "~n Modules: ~p", [Modules]),
+ Modules;
+updated_modules([Instr|Instrs], Modules) ->
+ d("updated_modules -> entry with"
+ "~n Instr: ~p"
+ "~n Modules: ~p", [Instr,Modules]),
+ case instruction_module(Instr) of
+ {module, Module} ->
+ d("updated_modules -> Module: ~p", [Module]),
+ updated_modules(Instrs, [Module|Modules]);
+ no_module ->
+ updated_modules(Instrs, Modules)
+ end.
+
+instruction_module({add_module, Module}) ->
+ {module, Module};
+instruction_module({delete_module, Module}) ->
+ {module, Module};
+instruction_module({remove, {Module, _, _}}) ->
+ {module, Module};
+instruction_module({load_module, Module, _, _, _}) ->
+ {module, Module};
+instruction_module({update, Module, _, _, _, _}) ->
+ {module, Module};
+instruction_module({update, Module, _}) ->
+ {module, Module};
+instruction_module({apply, {_, _, _}}) ->
+ no_module;
+instruction_module(Instr) ->
+ d("instruction_module -> entry when unknown instruction with"
+ "~n Instr: ~p", [Instr]),
+ error({error, {unknown_instruction, Instr}}).
+
+
+%% Check that the modules handled in an instruction set for version X
+%% is a subset of the instruction set for version X-1.
+check_module_subset(Direction, Instructions) ->
+ d("check_module_subset(~w) -> entry when"
+ "~n Instructions: ~p", [Direction,Instructions]),
+ do_check_module_subset(modules_of(Instructions)).
+
+do_check_module_subset([]) ->
+ ok;
+do_check_module_subset([_]) ->
+ ok;
+do_check_module_subset([{_V1, Mods1}|T]) ->
+ d("do_check_module_subset -> entry with"
+ "~n V1: ~s"
+ "~n Mods1: ~p", [_V1, Mods1]),
+ {V2, Mods2} = hd(T),
+ d("do_check_module_subset -> "
+ "~n V2: ~s"
+ "~n Mods2: ~p", [V2, Mods2]),
+ %% Check that the modules in V1 is a subset of V2
+ case do_check_module_subset2(Mods1, Mods2) of
+ ok ->
+ do_check_module_subset(T);
+ {error, Modules} ->
+ fail({subset_missing_instructions, V2, Modules})
+ end.
+
+do_check_module_subset2(_Mods1, [{restart_application, ?APPLICATION}]) ->
+ ok;
+do_check_module_subset2(Mods1, Mods2) ->
+ do_check_module_subset2(Mods1, Mods2, []).
+
+do_check_module_subset2([], _, []) ->
+ ok;
+do_check_module_subset2([], _, Acc) ->
+ {error, lists:reverse(Acc)};
+do_check_module_subset2([Mod|Mods], Mods2, Acc) ->
+ case lists:member(Mod, Mods2) of
+ true ->
+ do_check_module_subset2(Mods, Mods2, Acc);
+ false ->
+ do_check_module_subset2(Mods, Mods2, [Mod|Acc])
+ end.
+
+
+modules_of(Instructions) ->
+ modules_of(Instructions, []).
+
+modules_of([], Acc) ->
+ lists:reverse(Acc);
+modules_of([{_V,[{restart_application, ?APPLICATION}]}|T], Acc) ->
+ modules_of(T, Acc);
+modules_of([{V,Instructions}|T], Acc) ->
+ Mods = modules_of2(Instructions, []),
+ modules_of(T, [{V, Mods}|Acc]).
+
+modules_of2([], Acc) ->
+ lists:reverse(Acc);
+modules_of2([Instr|Instructions], Acc) ->
+ d("module_of -> entry with"
+ "~n Instr: ~p", [Instr]),
+ case module_of(Instr) of
+ {value, Mod} ->
+ d("module_of -> Mod: ~p", [Mod]),
+ modules_of2(Instructions, [Mod|Acc]);
+ false ->
+ modules_of2(Instructions, Acc)
+ end.
+
+module_of({add_module, Module}) ->
+ {value, Module};
+module_of({delete_module, Module}) ->
+ {value, Module};
+module_of({remove, {Module, _Pre, _Post}}) ->
+ {value, Module};
+module_of({load_module, Module, _Pre, _Post, _Depend}) ->
+ {value, Module};
+module_of({update, Module, _Change, _Pre, _Post, _Depend}) ->
+ {value, Module};
+module_of({update, Module, supervisor}) ->
+ {value, Module};
+module_of(_) ->
+ false.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+check_version(V) when is_list(V) ->
+ ok;
+check_version(V) ->
+ error({bad_version, V}).
+
+
+check_module(M, Modules) when is_atom(M) ->
+ case lists:member(M, Modules) of
+ true ->
+ ok;
+ false ->
+ error({unknown_module, M, Modules})
+ end;
+check_module(M, _) ->
+ error({bad_module, M}).
+
+
+check_module_depend(M, [], _) when is_atom(M) ->
+ ok;
+check_module_depend(M, Deps, Modules) when is_atom(M) and is_list(Deps) ->
+ case [Dep || Dep <- Deps, lists:member(Dep, Modules) == false] of
+ [] ->
+ ok;
+ Unknown ->
+ error({unknown_depend_modules, Unknown})
+ end;
+check_module_depend(_M, D, _Modules) ->
+ error({bad_depend, D}).
+
+
+check_no_remove_depends(_Module, []) ->
+ ok;
+check_no_remove_depends(Module, [Instr|Instrs]) ->
+ check_no_remove_depend(Module, Instr),
+ check_no_remove_depends(Module, Instrs).
+
+check_no_remove_depend(Module, {load_module, Mod, _Pre, _Post, Depend}) ->
+ case lists:member(Module, Depend) of
+ true ->
+ error({removed_module_in_depend, load_module, Mod, Module});
+ false ->
+ ok
+ end;
+check_no_remove_depend(Module, {update, Mod, _Change, _Pre, _Post, Depend}) ->
+ case lists:member(Module, Depend) of
+ true ->
+ error({removed_module_in_depend, update, Mod, Module});
+ false ->
+ ok
+ end;
+check_no_remove_depend(_, _) ->
+ ok.
+
+
+check_change(soft) ->
+ ok;
+check_change({advanced, _Something}) ->
+ ok;
+check_change(Change) ->
+ error({bad_change, Change}).
+
+
+check_purge(soft_purge) ->
+ ok;
+check_purge(brutal_purge) ->
+ ok;
+check_purge(Purge) ->
+ error({bad_purge, Purge}).
+
+check_apply(Module, Function, Args) ->
+ case (catch Module:module_info()) of
+ Info when is_list(Info) ->
+ check_exported(Function, Args, Info);
+ {'EXIT', {undef, _}} ->
+ error({not_existing_module, Module})
+ end.
+
+check_exported(Function, Args, Info) ->
+ case lists:keysearch(exports, 1, Info) of
+ {value, {exports, FuncList}} ->
+ Arity = length(Args),
+ Arities = [A || {F, A} <- FuncList, F == Function],
+ case lists:member(Arity, Arities) of
+ true ->
+ ok;
+ false ->
+ fail({not_exported_function, Function, Arity})
+ end;
+ _ ->
+ error({bad_export, Info})
+ end.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+error(Reason) ->
+ throw({error, Reason}).
+
+fail(Reason) ->
+ exit({suite_failed, Reason}).
+
+key1search(Key, L) ->
+ case lists:keysearch(Key, 1, L) of
+ undefined ->
+ fail({not_found, Key, L});
+ {value, {Key, Value}} ->
+ Value
+ end.
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+d(F) ->
+ d(F, []).
+
+d(F, A) ->
+ d(true, F, A).
+
+d(true, F, A) ->
+ io:format(F ++ "~n", A);
+d(_, _, _) ->
+ ok.
+
diff --git a/lib/snmp/test/snmp_compiler_test.erl b/lib/snmp/test/snmp_compiler_test.erl
new file mode 100644
index 0000000000..9a9127a130
--- /dev/null
+++ b/lib/snmp/test/snmp_compiler_test.erl
@@ -0,0 +1,391 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2003-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%
+%%
+
+%%----------------------------------------------------------------------
+%% Purpose: Test the snmp mib compiler
+%%
+%% Run test: ts:run(snmp, snmp_compiler_test, [batch]).
+%%
+%%----------------------------------------------------------------------
+-module(snmp_compiler_test).
+
+%%----------------------------------------------------------------------
+%% Include files
+%%----------------------------------------------------------------------
+-include("test_server.hrl").
+-include("snmp_test_lib.hrl").
+-include_lib("snmp/include/snmp_types.hrl").
+
+
+%%----------------------------------------------------------------------
+%% External exports
+%%----------------------------------------------------------------------
+-export([
+ all/1,
+ init_per_testcase/2, fin_per_testcase/2,
+
+ description/1,
+ oid_conflicts/1,
+ imports/1,
+ module_identity/1,
+
+ tickets/1,
+ otp_6150/1
+
+ ]).
+
+%%----------------------------------------------------------------------
+%% Internal exports
+%%----------------------------------------------------------------------
+-export([
+ ]).
+
+%%----------------------------------------------------------------------
+%% Macros
+%%----------------------------------------------------------------------
+
+%%----------------------------------------------------------------------
+%% Records
+%%----------------------------------------------------------------------
+
+%%======================================================================
+%% External functions
+%%======================================================================
+
+init_per_testcase(_Case, Config) when is_list(Config) ->
+ Dir = ?config(priv_dir, Config),
+ DataDir = ?config(data_dir, Config),
+ [_|RL] = lists:reverse(filename:split(DataDir)),
+ MibDir = join(lists:reverse(["snmp_test_data"|RL])),
+ CompDir = join(Dir, "comp_dir/"),
+ ?line ok = file:make_dir(CompDir),
+ [{comp_dir, CompDir},{mib_dir, MibDir}|Config].
+
+fin_per_testcase(_Case, Config) when is_list(Config) ->
+ CompDir = ?config(comp_dir, Config),
+ ?line ok = ?DEL_DIR(CompDir),
+ lists:keydelete(comp_dir, 1, Config).
+
+
+%%======================================================================
+%% Test case definitions
+%%======================================================================
+
+all(suite) ->
+ [
+ description,
+ oid_conflicts,
+ imports,
+ module_identity,
+ tickets
+ ].
+
+tickets(suite) ->
+ [
+ otp_6150
+ ].
+
+
+%%======================================================================
+%% Test functions
+%%======================================================================
+
+description(suite) -> [];
+description(Config) when is_list(Config) ->
+ put(tname,desc),
+ p("starting with Config: ~p~n", [Config]),
+
+ Dir = ?config(comp_dir, Config),
+ Filename = join(Dir,"test"),
+ MibSrcName = Filename ++ ".mib",
+ MibBinName = Filename ++ ".bin",
+ Desctext = "This is a test description",
+ Oid = [1,3,6,1,2,1,15,1],
+ write_mib(MibSrcName,Desctext),
+ ?line {ok,_} = snmpc:compile(MibSrcName, [{outdir, Dir},
+ {group_check, false},
+ {warnings, false},
+ {description, false}]),
+ MIB1 = read_mib(MibBinName),
+ %% io:format("description -> MIB1: ~n~p~n", [MIB1]),
+ check_mib(MIB1#mib.mes, Oid, undefined),
+ ?line {ok,_} = snmpc:compile(MibSrcName, [{outdir, Dir},
+ {group_check, false},
+ {warnings, false},
+ {description, true}]),
+ MIB2 = read_mib(MibBinName),
+ %% io:format("description -> MIB2: ~n~p~n", [MIB2]),
+ check_mib(MIB2#mib.mes, Oid, Desctext),
+
+ %% Cleanup
+ file:delete(MibSrcName),
+ file:delete(MibBinName),
+ ok.
+
+
+oid_conflicts(suite) -> [];
+oid_conflicts(Config) when is_list(Config) ->
+ put(tname,oid_conflicts),
+ p("starting with Config: ~p~n", [Config]),
+
+ Dir = ?config(comp_dir, Config),
+ Mib = join(Dir,"TESTv2.mib"),
+ ?line ok = write_oid_conflict_mib(Mib),
+ ?line {error,compilation_failed} =
+ snmpc:compile(Mib,[{outdir, Dir},{verbosity,trace}]),
+ ok.
+
+
+imports(suite) ->
+ [];
+imports(Config) when is_list(Config) ->
+ ?SKIP(not_yet_implemented).
+
+
+module_identity(suite) ->
+ [];
+module_identity(Config) when is_list(Config) ->
+ ?SKIP(not_yet_implemented).
+
+
+otp_6150(suite) ->
+ [];
+otp_6150(Config) when is_list(Config) ->
+ put(tname,otp_6150),
+ p("starting with Config: ~p~n", [Config]),
+
+ Dir = ?config(comp_dir, Config),
+ MibDir = ?config(mib_dir, Config),
+ MibFile = join(MibDir, "ERICSSON-TOP-MIB.mib"),
+ ?line {ok, Mib} = snmpc:compile(MibFile, [{outdir, Dir}, {verbosity, trace}]),
+ io:format("otp_6150 -> Mib: ~n~p~n", [Mib]),
+ ok.
+
+
+%%======================================================================
+%% Internal functions
+%%======================================================================
+
+write_oid_conflict_mib(Filename) ->
+ MibText = "TESTv2 DEFINITIONS ::= BEGIN
+
+IMPORTS
+ MODULE-IDENTITY, OBJECT-TYPE, NOTIFICATION-TYPE,
+ Integer32, snmpModules ,experimental
+ FROM SNMPv2-SMI
+ MODULE-COMPLIANCE, OBJECT-GROUP, NOTIFICATION-GROUP
+ FROM SNMPv2-CONF
+ DisplayString
+ FROM SNMPv2-TC
+ RowStatus
+ FROM STANDARD-MIB;
+
+
+exampleModule MODULE-IDENTITY
+LAST-UPDATED \"0005290000Z\"
+ ORGANIZATION \"Erlang\"
+ CONTACT-INFO \" test mib
+ Ericsson Utvecklings AB
+Open System
+Box 1505
+SE-125 25 �LVSJ�\"
+
+DESCRIPTION
+\" Objects for management \"
+ REVISION \"0005290000Z\"
+ DESCRIPTION
+\"The initial version\"
+ ::= { snmpModules 1 }
+
+example1 OBJECT IDENTIFIER ::= { experimental 7}
+-- example2 OBJECT IDENTIFIER ::= { experimental 7}
+
+
+myName OBJECT-TYPE
+SYNTAX DisplayString
+MAX-ACCESS read-write
+STATUS current
+DESCRIPTION
+\"My own name\"
+ ::= { example1 1 }
+
+myNotification NOTIFICATION-TYPE
+STATUS current
+DESCRIPTION
+\"test trap.\"
+ ::= { example1 1 }
+
+friendsTable OBJECT-TYPE
+SYNTAX SEQUENCE OF FriendsEntry
+MAX-ACCESS not-accessible
+STATUS current
+DESCRIPTION
+\"A list of friends.\"
+ ::= { example1 4 }
+
+friendsEntry OBJECT-TYPE
+SYNTAX FriendsEntry
+MAX-ACCESS not-accessible
+STATUS current
+DESCRIPTION
+\"\"
+ INDEX { fIndex }
+::= { friendsTable 1 }
+
+FriendsEntry ::= SEQUENCE {
+ fIndex INTEGER,
+ fName DisplayString,
+ fAddress DisplayString,
+ fStatus RowStatus
+ }
+
+fIndex OBJECT-TYPE
+SYNTAX INTEGER
+MAX-ACCESS read-only
+STATUS current
+DESCRIPTION
+\"number of friend\"
+ ::= { friendsEntry 1 }
+
+fName OBJECT-TYPE
+SYNTAX DisplayString (SIZE (0..255))
+MAX-ACCESS read-write
+STATUS current
+DESCRIPTION
+\"Name of a friend\"
+ ::= { friendsEntry 2 }
+
+fAddress OBJECT-TYPE
+SYNTAX DisplayString (SIZE (0..255))
+MAX-ACCESS read-write
+STATUS current
+DESCRIPTION
+\"Address of a friend\"
+ ::= { friendsEntry 3 }
+
+fStatus OBJECT-TYPE
+SYNTAX RowStatus
+MAX-ACCESS read-write
+STATUS current
+DESCRIPTION
+\"The status of this conceptual row.\"
+ ::= { friendsEntry 4 }
+
+-- myName2 OBJECT IDENTIFIER ::= { example1 1 }
+
+friendGroup OBJECT-GROUP
+OBJECTS { myName, fIndex, fName,fAddress, fStatus }
+STATUS current
+DESCRIPTION \" A object group\"
+ ::= { example1 2 }
+
+myNotificationGroup NOTIFICATION-GROUP
+NOTIFICATIONS { myNotification }
+STATUS current
+DESCRIPTION
+\"Test notification group\"
+ ::= { example1 3 }
+END",
+
+ file:write_file(Filename, MibText).
+
+
+write_mib(Filename,Desc) ->
+ Binary = "Test DEFINITIONS ::= BEGIN
+
+IMPORTS
+ MODULE-IDENTITY, OBJECT-TYPE,
+ snmpModules, mib-2
+ FROM SNMPv2-SMI ;
+
+snmpMIB MODULE-IDENTITY
+LAST-UPDATED \"9511090000Z\"
+ ORGANIZATION \"\"
+ CONTACT-INFO \"\"
+ DESCRIPTION
+::= { snmpModules 1 }
+
+
+test OBJECT IDENTIFIER ::= { mib-2 15 }
+
+bits1 OBJECT-TYPE
+SYNTAX BITS { b0(0), b1(1), b2(2) }
+MAX-ACCESS read-write
+STATUS current
+DESCRIPTION \"" ++ Desc ++ "\"
+ ::= { test 1 }
+
+END",
+ Message = file:write_file(Filename ,Binary),
+case Message of
+ ok -> ok;
+ {error, Reason} ->
+ exit({failed_writing_mib,Reason})
+end.
+
+
+read_mib(Filename) ->
+ case file:read_file(Filename) of
+ {ok,Bin} ->
+ binary_to_term(Bin);
+ {error,Reason} ->
+ exit({failed_reading_mib,Filename,Reason})
+ end.
+
+check_mib([],_,_) ->
+ not_found;
+check_mib([#me{oid = Oid, description = Description}| _T], Oid, Testdata) ->
+ check_desc(Description, Testdata);
+check_mib([_H|T], Oid, Testdata ) ->
+ check_mib(T, Oid, Testdata ).
+
+check_desc(Desc, Desc) ->
+ ok;
+check_desc(Desc1, Desc2) ->
+ exit({'description not equal', Desc1, Desc2}).
+
+
+join(Comp) ->
+ filename:join(Comp).
+
+join(A,B) ->
+ filename:join(A,B).
+
+
+%% ------
+
+%% p(F) ->
+%% p(F, []).
+
+p(F, A) ->
+ p(get(tname), F, A).
+
+p(TName, F, A) ->
+ io:format("*** [~w][~s] ***"
+ "~n" ++ F ++ "~n", [TName,format_timestamp(now())|A]).
+
+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).
+
diff --git a/lib/snmp/test/snmp_conf_test.erl b/lib/snmp/test/snmp_conf_test.erl
new file mode 100644
index 0000000000..d2f9631947
--- /dev/null
+++ b/lib/snmp/test/snmp_conf_test.erl
@@ -0,0 +1,680 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2003-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%
+%%
+
+%%
+%%----------------------------------------------------------------------
+%% Purpose:
+%%----------------------------------------------------------------------
+-module(snmp_conf_test).
+
+%%----------------------------------------------------------------------
+%% Include files
+%%----------------------------------------------------------------------
+-include("test_server.hrl").
+-include("snmp_test_lib.hrl").
+
+-include_lib("snmp/include/STANDARD-MIB.hrl").
+-include_lib("snmp/include/OTP-SNMPEA-MIB.hrl").
+
+
+%%----------------------------------------------------------------------
+%% External exports
+%%----------------------------------------------------------------------
+-export([
+ all/1,
+ init_per_testcase/2, fin_per_testcase/2,
+
+ check_mandatory/1,
+ check_integer1/1,
+ check_integer2/1,
+ check_string1/1,
+ check_string2/1,
+ check_atom/1,
+ check_ip/1,
+ check_taddress/1,
+ check_packet_size/1,
+ check_oid/1,
+ check_sec_model1/1,
+ check_sec_model2/1,
+ check_sec_level/1,
+ check_timer/1,
+
+ read/1,
+ read_files/1
+ ]).
+
+%%----------------------------------------------------------------------
+%% Internal exports
+%%----------------------------------------------------------------------
+-export([
+ ]).
+
+%%----------------------------------------------------------------------
+%% Macros
+%%----------------------------------------------------------------------
+
+%%----------------------------------------------------------------------
+%% Records
+%%----------------------------------------------------------------------
+
+%%======================================================================
+%% External functions
+%%======================================================================
+
+init_per_testcase(_Case, Config) when is_list(Config) ->
+ Config.
+
+fin_per_testcase(_Case, Config) when is_list(Config) ->
+ Config.
+
+%%======================================================================
+%% Test case definitions
+%%======================================================================
+all(suite) ->
+ [
+ check_mandatory,
+ check_integer1,
+ check_integer2,
+ check_string1,
+ check_string2,
+ check_atom,
+ check_ip,
+ check_taddress,
+ check_packet_size,
+ check_oid,
+ check_sec_model1,
+ check_sec_model2,
+ check_sec_level,
+ check_timer,
+
+ read,
+ read_files
+ ].
+
+
+%%======================================================================
+%% Test functions
+%%======================================================================
+
+check_mandatory(suite) -> [];
+check_mandatory(Config) when is_list(Config) ->
+ ?P(check_mandatory),
+ %% d("check_mandatory -> entry"),
+ A1 = [{a, hej}, {b, hopp}, {c, 10}, {d, 10101}, {f, 10.88}],
+ B1 = [{a, {value, hejsan}},
+ {b, mandatory},
+ {d, {value, 20202}},
+ {e, {value, "kalle"}}],
+ ?line {ok, L1} = verify_mandatory(A1, B1),
+ ?DBG("check_mandatory -> L1: ~p", [L1]),
+ A2 = [{a, hej}, {c, 10}, {d, 10101}, {f, 10.88}],
+ B2 = [{a, {value, hejsan}},
+ {b, mandatory},
+ {d, {value, 20202}},
+ {e, {value, "kalle"}}],
+ ?line ok = verify_not_mandatory(A2, B2),
+ ok.
+
+verify_mandatory(A, B) ->
+ case (catch snmp_conf:check_mandatory(A, B)) of
+ {'EXIT', Reason} ->
+ ?FAIL({mandatory_fail, A, B, Reason});
+ {ok, A} ->
+ ?FAIL({mandatory_not_updated, A, B});
+ {ok, L} when A /= L ->
+ verify_mandatory2(B, L)
+ end.
+
+verify_mandatory2([], L) ->
+ {ok, L};
+verify_mandatory2([{Key, _}|T], L) ->
+ case lists:keysearch(Key, 1, L) of
+ false ->
+ ?FAIL({missing_key, Key, L});
+ {value, _} ->
+ verify_mandatory2(T, L)
+ end.
+
+verify_not_mandatory(A, B) ->
+ case (catch snmp_conf:check_mandatory(A, B)) of
+ {error, _Reason} ->
+ ok;
+ Else ->
+ ?FAIL({mandatory_not_fail, Else})
+ end.
+
+
+%%======================================================================
+
+check_integer1(suite) -> [];
+check_integer1(Config) when is_list(Config) ->
+ ?P(check_integer1),
+ ?line ok = verify_int(0),
+ ?line ok = verify_int(16#FF),
+ ?line ok = verify_int(16#FFFF),
+ ?line ok = verify_int(16#FFFFFFFF),
+ ?line ok = verify_int(-1),
+ ?line ok = verify_int(-333),
+
+ ?line ok = verify_not_int("kalle & hobbe"),
+ ?line ok = verify_not_int(kalle_och_hobbe),
+ ?line ok = verify_not_int(1.5),
+
+ ok.
+
+verify_int(Val) ->
+ case (catch snmp_conf:check_integer(Val)) of
+ {error, Reason} ->
+ ?FAIL({verify_int, Val, Reason});
+ ok ->
+ ok
+ end.
+
+verify_not_int(Val) ->
+ case (catch snmp_conf:check_integer(Val)) of
+ ok ->
+ ?FAIL({verify_int, Val});
+ {error, _Reason} ->
+ ok
+ end.
+
+%%======================================================================
+
+check_integer2(suite) -> [];
+check_integer2(Config) when is_list(Config) ->
+ ?P(check_integer2),
+
+ ?line ok = verify_int(0, any),
+ ?line ok = verify_int(-22222, any),
+ ?line ok = verify_int(33333, any),
+ ?line ok = verify_int(1, pos),
+ ?line ok = verify_int(9999, pos),
+ ?line ok = verify_int(-1, neg),
+ ?line ok = verify_int(-9999, neg),
+ ?line ok = verify_int(1, {gt, 0}),
+ ?line ok = verify_int(88888, {gt, -255}),
+ ?line ok = verify_int(88888, {gte, -255}),
+ ?line ok = verify_int(88888, {gte, 88888}),
+ ?line ok = verify_int(88888, {lt, 88889}),
+ ?line ok = verify_int(88888, {lte, 88888}),
+ ?line ok = verify_int(88888, {eq, 88888}),
+ ?line ok = verify_int(88888, {range, 88887,88889}),
+
+ ?line ok = verify_not_int("kalle & hobbe", any),
+ ?line ok = verify_not_int(kalle_och_hobbe, any),
+ ?line ok = verify_not_int(1.5, any),
+
+ ?line ok = verify_not_int(0, pos),
+ ?line ok = verify_not_int(-22222, pos),
+ ?line ok = verify_not_int(33333, neg),
+ ?line ok = verify_not_int(0, {gt, 0}),
+ ?line ok = verify_not_int(33333, {gt, 99999}),
+ ?line ok = verify_not_int(33333, {gt, 33333}),
+ ?line ok = verify_not_int(33333, {gte, 33334}),
+ ?line ok = verify_not_int(33333, {lt, 33333}),
+ ?line ok = verify_not_int(33333, {lte, 33332}),
+ ?line ok = verify_not_int(33333, {eq, 33332}),
+ ?line ok = verify_not_int(33333, {eq, -33333}),
+ ?line ok = verify_not_int(33333, {range, 33334, 33338}),
+ ?line ok = verify_not_int(33339, {range, 33334, 33338}),
+ ?line ok = verify_not_int(33333, {gt, kalle}),
+ ?line ok = verify_not_int(33333, {gt, 1.55}),
+ ?line ok = verify_not_int(33333, {gte, "hejsan"}),
+ ?line ok = verify_not_int(33333, {lt, hobbe}),
+ ?line ok = verify_not_int(33333, {lte, 1.7666}),
+ ?line ok = verify_not_int(33333, {eq, 33333.0}),
+ ?line ok = verify_not_int(33333, {eq, -33333.0}),
+ ?line ok = verify_not_int(33333, {range, kalle, 33338}),
+ ?line ok = verify_not_int(33339, {range, 33334, kalle}),
+ ?line ok = verify_not_int(33339, {kalle, 33334, kalle}),
+
+ ok.
+
+verify_int(Val, Cond) ->
+ case (catch snmp_conf:check_integer(Val, Cond)) of
+ {error, Reason} ->
+ ?FAIL({verify_int, Val, Cond, Reason});
+ ok ->
+ ok
+ end.
+
+verify_not_int(Val, Cond) ->
+ case (catch snmp_conf:check_integer(Val, Cond)) of
+ ok ->
+ ?FAIL({verify_int, Val, Cond});
+ {error, _Reason} ->
+ ok
+ end.
+
+%%======================================================================
+
+check_string1(suite) -> [];
+check_string1(Config) when is_list(Config) ->
+ ?P(check_string1),
+ ?line ok = verify_string("kalle & hobbe"),
+ ?line ok = verify_not_string(kalle_hobbe),
+ ?line ok = verify_not_string(1000),
+ ?line ok = verify_not_string(1.0),
+ ok.
+
+verify_string(Val) ->
+ case (catch snmp_conf:check_string(Val)) of
+ {error, Reason} ->
+ ?FAIL({verify_string, Val, Reason});
+ ok ->
+ ok
+ end.
+
+verify_not_string(Val) ->
+ case (catch snmp_conf:check_string(Val)) of
+ ok ->
+ ?FAIL({verify_string, Val});
+ {error, _Reason} ->
+ ok
+ end.
+
+
+%%======================================================================
+
+check_string2(suite) -> [];
+check_string2(Config) when is_list(Config) ->
+ ?P(check_string2),
+ Str = "kalle & hobbe",
+ ?line ok = verify_string(Str, any),
+ ?line ok = verify_string(Str, {gt, length(Str) - 1}),
+ ?line ok = verify_string(Str, {gte, length(Str)}),
+ ?line ok = verify_string(Str, {lt, length(Str) + 1}),
+ ?line ok = verify_string(Str, {lte, length(Str)}),
+ ?line ok = verify_string(Str, length(Str)),
+
+ ?line ok = verify_not_string(kalle_hobbe, any),
+ ?line ok = verify_not_string(1000, any),
+ ?line ok = verify_not_string(1.0, any),
+ ?line ok = verify_not_string(Str, {gt, length(Str)}),
+ ?line ok = verify_not_string(Str, {gte, length(Str) + 1}),
+ ?line ok = verify_not_string(Str, {lt, length(Str)}),
+ ?line ok = verify_not_string(Str, {lte, length(Str) - 1}),
+ ?line ok = verify_not_string(Str, length(Str) + 1),
+ ok.
+
+verify_string(Val, Limit) ->
+ case (catch snmp_conf:check_string(Val, Limit)) of
+ {error, Reason} ->
+ ?FAIL({verify_string, Val, Limit, Reason});
+ ok ->
+ ok
+ end.
+
+verify_not_string(Val, Limit) ->
+ case (catch snmp_conf:check_string(Val, Limit)) of
+ ok ->
+ ?FAIL({verify_string, Val, Limit});
+ {error, _Reason} ->
+ ok
+ end.
+
+
+%%======================================================================
+
+check_atom(suite) -> [];
+check_atom(Config) when is_list(Config) ->
+ ?P(check_atom),
+ Atoms = [{kalle, "kalle"}, {hobbe, "hobbe"}, {dummy, "dummy"}],
+ ?line ok = verify_atom(kalle, Atoms),
+ ?line ok = verify_not_atom(anka, Atoms),
+ ?line ok = verify_not_atom("kalle", Atoms),
+ ?line ok = verify_not_atom(1000, Atoms),
+ ok.
+
+verify_atom(Val, Atoms) ->
+ case (catch snmp_conf:check_atom(Val, Atoms)) of
+ {error, Reason} ->
+ ?FAIL({verify_atom, Val, Atoms, Reason});
+ {ok, _} ->
+ ok
+ end.
+
+verify_not_atom(Val, Atoms) ->
+ case (catch snmp_conf:check_atom(Val, Atoms)) of
+ ok ->
+ ?FAIL({verify_atom, Val, Atoms});
+ {error, _Reason} ->
+ ok
+ end.
+
+
+%%======================================================================
+
+check_ip(suite) -> [];
+check_ip(Config) when is_list(Config) ->
+ ?P(check_ip),
+ ?line ok = verify_ip([1,2,3,4]),
+ ?line ok = verify_not_ip([1,2,3]),
+ ?line ok = verify_not_ip([1,2,3,4,5]),
+ ?line ok = verify_not_ip(kalle),
+ ?line ok = verify_not_ip(1000),
+ ?line ok = verify_not_ip([1,2,3.0,4]),
+ ?line ok = verify_not_ip([1,two,3,4]),
+ ok.
+
+verify_ip(Val) ->
+ case (catch snmp_conf:check_ip(Val)) of
+ {error, Reason} ->
+ ?FAIL({verify_ip, Val, Reason});
+ ok ->
+ ok
+ end.
+
+verify_not_ip(Val) ->
+ case (catch snmp_conf:check_ip(Val)) of
+ ok ->
+ ?FAIL({verify_ip, Val});
+ {error, _Reason} ->
+ ok
+ end.
+
+
+%%======================================================================
+
+check_taddress(suite) -> [];
+check_taddress(Config) when is_list(Config) ->
+ ?P(check_taddress),
+ ?line ok = verify_taddress([1,2,3,4,5,6]),
+ ?line ok = verify_not_taddress([1,2,3,4,5]),
+ ?line ok = verify_not_taddress([1,2,3,4,5,6,7]),
+ ?line ok = verify_not_taddress(kalle),
+ ?line ok = verify_not_taddress(1000),
+ ?line ok = verify_not_taddress([1,2,3.0,4,5,6]),
+ ?line ok = verify_not_taddress([1,two,3,4,5,6]),
+ ok.
+
+verify_taddress(Val) ->
+ case (catch snmp_conf:check_taddress(Val)) of
+ {error, Reason} ->
+ ?FAIL({verify_taddress, Val, Reason});
+ ok ->
+ ok
+ end.
+
+verify_not_taddress(Val) ->
+ case (catch snmp_conf:check_taddress(Val)) of
+ ok ->
+ ?FAIL({verify_taddress, Val});
+ {error, _Reason} ->
+ ok
+ end.
+
+
+%%======================================================================
+
+check_packet_size(suite) -> [];
+check_packet_size(Config) when is_list(Config) ->
+ ?P(check_packet_size),
+ Min = 484,
+ Max = 2147483647,
+ ?line ok = verify_packet_size(Min),
+ ?line ok = verify_packet_size(2*Min),
+ ?line ok = verify_packet_size(Max),
+ ?line ok = verify_not_packet_size(Min-1),
+ ?line ok = verify_not_packet_size(Max+1),
+ ?line ok = verify_not_packet_size(kalle),
+ ?line ok = verify_not_packet_size("kalle"),
+ ?line ok = verify_not_packet_size(1.0),
+ ?line ok = verify_not_packet_size(1.0*Max),
+ ok.
+
+verify_packet_size(Val) ->
+ case (catch snmp_conf:check_packet_size(Val)) of
+ {error, Reason} ->
+ ?FAIL({verify_packet_size, Val, Reason});
+ ok ->
+ ok
+ end.
+
+verify_not_packet_size(Val) ->
+ case (catch snmp_conf:check_packet_size(Val)) of
+ ok ->
+ ?FAIL({verify_packet_size, Val});
+ {error, _Reason} ->
+ ok
+ end.
+
+
+%%======================================================================
+
+check_oid(suite) -> [];
+check_oid(Config) when is_list(Config) ->
+ ?P(check_oid),
+ [_,_|Rest] = ?otpSnmpeaModule,
+ ErrOid = [6,16|Rest],
+ ?line ok = verify_oid(?system),
+ ?line ok = verify_oid(?sysDescr_instance),
+ ?line ok = verify_oid(?otpSnmpeaModule),
+ ?line ok = verify_not_oid(kalle),
+ ?line ok = verify_not_oid("kalle"),
+ ?line ok = verify_not_oid(1000),
+ ?line ok = verify_not_oid(1.0),
+ ?line ok = verify_not_oid(ErrOid),
+ ok.
+
+verify_oid(Val) ->
+ case (catch snmp_conf:check_oid(Val)) of
+ {error, Reason} ->
+ ?FAIL({verify_oid, Val, Reason});
+ ok ->
+ ok
+ end.
+
+verify_not_oid(Val) ->
+ case (catch snmp_conf:check_oid(Val)) of
+ ok ->
+ ?FAIL({verify_oid, Val});
+ {error, _Reason} ->
+ ok
+ end.
+
+
+%%======================================================================
+
+check_sec_model1(suite) -> [];
+check_sec_model1(Config) when is_list(Config) ->
+ ?P(check_sec_model1),
+ Exclude1 = [],
+ Exclude2 = [v1],
+ Exclude3 = [v1,usm],
+ ?line ok = verify_sec_model(any, Exclude1),
+ ?line ok = verify_sec_model(v1, Exclude1),
+ ?line ok = verify_sec_model(v2c, Exclude1),
+ ?line ok = verify_sec_model(usm, Exclude1),
+ ?line ok = verify_sec_model(any, Exclude2),
+ ?line ok = verify_sec_model(v2c, Exclude2),
+ ?line ok = verify_not_sec_model(v1, Exclude2),
+ ?line ok = verify_not_sec_model(v1, Exclude3),
+ ?line ok = verify_not_sec_model(usm, Exclude3),
+ ok.
+
+verify_sec_model(Val, Exclude) ->
+ case (catch snmp_conf:check_sec_model(Val, Exclude)) of
+ {error, Reason} ->
+ ?FAIL({verify_sec_model, Val, Reason});
+ {ok, _} ->
+ ok
+ end.
+
+verify_not_sec_model(Val, Exclude) ->
+ case (catch snmp_conf:check_sec_model(Val, Exclude)) of
+ {ok, Res} ->
+ ?FAIL({verify_sec_model, Val, Res});
+ {error, _Reason} ->
+ ok
+ end.
+
+
+%%======================================================================
+
+check_sec_model2(suite) -> [];
+check_sec_model2(Config) when is_list(Config) ->
+ ?P(check_sec_model2),
+ ?line ok = verify_sec_model(v1, v1, []),
+ ?line ok = verify_sec_model(v1, v1, [v2c]),
+ ?line ok = verify_sec_model(v2c, v2c, []),
+ ?line ok = verify_sec_model(v2c, v2c, [v1]),
+ ?line ok = verify_sec_model(v3, usm, []),
+ ?line ok = verify_sec_model(v3, usm, [v2c]),
+ ?line ok = verify_not_sec_model(v1, v2c, []),
+ ?line ok = verify_not_sec_model(v1, v3, [v2c]),
+ ?line ok = verify_not_sec_model(v1, v1, [v1]),
+ ?line ok = verify_not_sec_model(v2c, v1, []),
+ ?line ok = verify_not_sec_model(v2c, v3, [v3]),
+ ?line ok = verify_not_sec_model(v2c, v2c, [v2c]),
+ ?line ok = verify_not_sec_model(v3, v1, []),
+ ?line ok = verify_not_sec_model(v3, v2c, [v1]),
+ ?line ok = verify_not_sec_model(v3, v3, [v2c]),
+ ?line ok = verify_not_sec_model(kalle, v3, []),
+ ?line ok = verify_not_sec_model(1000, v3, []),
+ ?line ok = verify_not_sec_model(1.0, v3, []),
+ ok.
+
+
+verify_sec_model(M1, M2, Exclude) ->
+ case (catch snmp_conf:check_sec_model(M1, M2, Exclude)) of
+ {error, Reason} ->
+ ?FAIL({verify_sec_model, M1, M2, Reason});
+ {ok, _} ->
+ ok
+ end.
+
+verify_not_sec_model(M1, M2, Exclude) ->
+ case (catch snmp_conf:check_sec_model(M1, M2, Exclude)) of
+ {ok, Res} ->
+ ?FAIL({verify_sec_model, M1, M2, Res});
+ {error, _Reason} ->
+ ok
+ end.
+
+
+%%======================================================================
+
+check_sec_level(suite) -> [];
+check_sec_level(Config) when is_list(Config) ->
+ ?P(check_sec_level),
+ ?line ok = verify_sec_level(noAuthNoPriv),
+ ?line ok = verify_sec_level(authNoPriv),
+ ?line ok = verify_sec_level(authPriv),
+ ?line ok = verify_not_sec_level(kalle),
+ ?line ok = verify_not_sec_level("noAuthNoPriv"),
+ ?line ok = verify_not_sec_level(1000),
+ ?line ok = verify_not_sec_level(1.0),
+ ok.
+
+
+verify_sec_level(Val) ->
+ case (catch snmp_conf:check_sec_level(Val)) of
+ {error, Reason} ->
+ ?FAIL({verify_sec_level, Val, Reason});
+ {ok, _} ->
+ ok;
+ Error ->
+ ?FAIL({verify_sec_level, Val, Error})
+ end.
+
+verify_not_sec_level(Val) ->
+ case (catch snmp_conf:check_sec_level(Val)) of
+ {ok, Res} ->
+ ?FAIL({verify_sec_level, Val, Res});
+ {error, _Reason} ->
+ ok;
+ {'EXIT', _Reason} ->
+ ok
+ end.
+
+
+%%======================================================================
+
+check_timer(suite) -> [];
+check_timer(Config) when is_list(Config) ->
+ ?P(check_timer),
+ ?line ok = verify_timer(infinity),
+ ?line ok = verify_timer(1),
+ ?line ok = verify_timer(10),
+ ?line ok = verify_timer(2147483647),
+ ?line ok = verify_timer(2*2147483647),
+ ?line ok = verify_timer({1,1,0,0}),
+ ?line ok = verify_timer({10,10,10,10}),
+ ?line ok = verify_timer({2147483647,2147483647,2147483647,2147483647}),
+ ?line ok = verify_not_timer(ytinifni),
+ ?line ok = verify_not_timer("ytinifni"),
+ ?line ok = verify_not_timer(0),
+ ?line ok = verify_not_timer(-10),
+ ?line ok = verify_not_timer({0,1,0,0}),
+ ?line ok = verify_not_timer({1,0,0,0}),
+ ?line ok = verify_not_timer({1,1,-1,0}),
+ ?line ok = verify_not_timer({1,1,0,-1}),
+ ?line ok = verify_not_timer({1.0,1,0,0}),
+ ?line ok = verify_not_timer({1,1.0,0,0}),
+ ?line ok = verify_not_timer({1,1,1.0,0}),
+ ?line ok = verify_not_timer({1,1,0,1.0}),
+ ?line ok = verify_not_timer({"1",1,0,0}),
+ ?line ok = verify_not_timer({1,"1",0,0}),
+ ?line ok = verify_not_timer({1,1,"0",0}),
+ ?line ok = verify_not_timer({1,1,0,"0"}),
+ ok.
+
+verify_timer(Val) ->
+ case (catch snmp_conf:check_timer(Val)) of
+ {error, Reason} ->
+ ?FAIL({verify_timer, Val, Reason});
+ {ok, _} ->
+ ok
+ end.
+
+verify_not_timer(Val) ->
+ case (catch snmp_conf:check_timer(Val)) of
+ {ok, Res} ->
+ ?FAIL({verify_timer, Val, Res});
+ {error, _Reason} ->
+ ok
+ end.
+
+
+%%======================================================================
+
+read(suite) -> [];
+read(Config) when is_list(Config) ->
+ ?P(read),
+ ?SKIP(not_implemented_yet).
+
+
+%%======================================================================
+
+read_files(suite) -> [];
+read_files(Config) when is_list(Config) ->
+ ?P(read_files),
+ ?SKIP(not_implemented_yet).
+
+
+%%======================================================================
+%% Internal functions
+%%======================================================================
+
+% d(F) ->
+% d(F, []).
+
+% d(F, A) ->
+% io:format("~w:" ++ F ++ "~n", [?MODULE|A]).
diff --git a/lib/snmp/test/snmp_log_test.erl b/lib/snmp/test/snmp_log_test.erl
new file mode 100644
index 0000000000..b4694fd9ab
--- /dev/null
+++ b/lib/snmp/test/snmp_log_test.erl
@@ -0,0 +1,941 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2003-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%
+%%
+
+%%----------------------------------------------------------------------
+%% Purpose:
+%%
+%% Test: ts:run(snmp, snmp_log_test, [batch]).
+%% Test: ts:run(snmp, snmp_log_test, log_to_txt2, [batch]).
+%%
+%%----------------------------------------------------------------------
+-module(snmp_log_test).
+
+%%----------------------------------------------------------------------
+%% Include files
+%%----------------------------------------------------------------------
+-include("test_server.hrl").
+-include("snmp_test_lib.hrl").
+-define(SNMP_USE_V3, true).
+-include_lib("snmp/include/snmp_types.hrl").
+-include_lib("kernel/include/file.hrl").
+
+
+%%----------------------------------------------------------------------
+%% External exports
+%%----------------------------------------------------------------------
+-export([
+ init_per_testcase/2, fin_per_testcase/2,
+
+ all/1,
+ open_and_close/1,
+ open_write_and_close/1,
+ log_to_io1/1,
+ log_to_io2/1,
+ log_to_txt1/1,
+ log_to_txt2/1
+ ]).
+
+%%----------------------------------------------------------------------
+%% Internal exports
+%%----------------------------------------------------------------------
+-export([
+ log_writer_main/5,
+ log_reader_main/1
+ ]).
+
+%%----------------------------------------------------------------------
+%% Macros
+%%----------------------------------------------------------------------
+
+%%----------------------------------------------------------------------
+%% Records
+%%----------------------------------------------------------------------
+
+%%======================================================================
+%% External functions
+%%======================================================================
+
+init_per_testcase(Case, Config) when is_list(Config) ->
+ Dir = ?config(priv_dir, Config),
+ LogTestDir = join(Dir, ?MODULE),
+ CaseDir = join(LogTestDir, Case),
+ case file:make_dir(LogTestDir) of
+ ok ->
+ ok;
+ {error, eexist} ->
+ ok;
+ Error ->
+ ?FAIL({failed_creating_subsuite_top_dir, Error})
+ end,
+ ?line ok = file:make_dir(CaseDir),
+ Dog = ?WD_START(?MINS(5)),
+ [{log_dir, CaseDir}, {watchdog, Dog}|Config].
+
+fin_per_testcase(_Case, Config) when is_list(Config) ->
+ %% Leave the dirs created above (enable debugging of the test case(s))
+ Dog = ?config(watchdog, Config),
+ ?WD_STOP(Dog),
+ lists:keydelete(watchdog, 1, Config).
+
+
+%%======================================================================
+%% Test case definitions
+%%======================================================================
+%% ?SKIP(not_yet_implemented).
+all(suite) ->
+ [
+ open_and_close,
+ open_write_and_close,
+ log_to_io1,
+ log_to_io2,
+ log_to_txt1,
+ log_to_txt2
+ ].
+
+
+%%======================================================================
+%% Test functions
+%%======================================================================
+
+open_and_close(suite) -> [];
+open_and_close(Config) when is_list(Config) ->
+ p(open_and_close),
+ put(sname,open_and_close),
+ put(verbosity,trace),
+ Dir = ?config(log_dir, Config),
+ Name = "snmp_test",
+ File = join(Dir, "snmp_test.log"),
+ Size = {1024, 10},
+ Repair = true,
+ ?line {ok, Log} = snmp_log:create(Name, File, Size, Repair),
+ ?line ok = snmp_log:sync(Log),
+ ?line {ok, Info} = snmp_log:info(Log),
+ display_info(Info),
+ ?line ok = snmp_log:close(Log).
+
+
+%%======================================================================
+
+open_write_and_close(suite) -> [];
+open_write_and_close(Config) when is_list(Config) ->
+ p(open_write_and_close),
+ put(sname,open_write_and_close),
+ put(verbosity,trace),
+ ?DBG("open_write_and_close -> start", []),
+ Dir = ?config(log_dir, Config),
+ Name = "snmp_test",
+ File = join(Dir, "snmp_test.log"),
+ Size = {1024, 10},
+ Repair = true,
+ ?DBG("open_write_and_close -> create log", []),
+ ?line {ok, Log} = snmp_log:create(Name, File, Size, Repair),
+
+ Vsn = 'version-2',
+ Community = "all-rights",
+
+ ?DBG("open_write_and_close -> create messages to log", []),
+ %% A request
+ ?line Req = get_next_request(Vsn, Community, [1,1], 1, 235779012),
+
+ %% A reply
+ ?line Rep = get_response(Vsn, Community,
+ [1,3,6,1,2,1,1,1,0], 'OCTET STRING',
+ "Erlang SNMP agent", 1, 235779012),
+
+ %% Create a list of messages to log:
+ Msgs = lists:flatten(lists:duplicate(1002,[Req,Rep])),
+
+ %% And now log them:
+ ?DBG("open_write_and_close -> log ~p messages, ~p bytes",
+ [length(Msgs), size(list_to_binary(Msgs))]),
+ Addr = ?LOCALHOST(),
+ Port = 162,
+ Logger = fun(Packet) ->
+ ?line ok = snmp_log:log(Log, Packet, Addr, Port)
+ end,
+ lists:foreach(Logger, Msgs),
+ check_notify(),
+
+ ?DBG("open_write_and_close -> display info", []),
+ ?line {ok, Info} = snmp_log:info(Log),
+ display_info(Info),
+
+ ?DBG("open_write_and_close -> close log", []),
+ ?line ok = snmp_log:close(Log),
+
+ ?DBG("open_write_and_close -> done", []),
+ ok.
+
+
+
+%%======================================================================
+
+log_to_io1(suite) -> [];
+log_to_io1(doc) -> "Log to io from the same process that opened "
+ "and wrote the log";
+log_to_io1(Config) when is_list(Config) ->
+ p(log_to_io1),
+ put(sname,l2i1),
+ put(verbosity,trace),
+ ?DBG("log_to_io1 -> start", []),
+ Dir = ?config(log_dir, Config),
+ Name = "snmp_test_l2i1",
+ File = join(Dir, "snmp_test_l2i1.log"),
+ Size = {1024, 10},
+ Repair = true,
+ ?DBG("log_to_io1 -> create log", []),
+ ?line {ok, Log} = snmp_log:create(Name, File, Size, Repair),
+
+ ?DBG("log_to_io1 -> create messages to log", []),
+ Msgs = messages(),
+
+ ?DBG("log_to_io1 -> create logger funs", []),
+ Addr = ?LOCALHOST(),
+ Port = 162,
+ Logger = fun(Packet) ->
+ ?line ok = snmp_log:log(Log, Packet, Addr, Port)
+ end,
+ BatchLogger = fun(Time) ->
+ lists:foreach(Logger, Msgs),
+ ?SLEEP(Time),
+ ok
+ end,
+ To = lists:duplicate(100, 100),
+
+ ?DBG("log_to_io1 -> log the messages", []),
+ lists:foreach(BatchLogger, To),
+
+ ?DBG("log_to_io1 -> display info", []),
+ ?line {ok, Info} = snmp_log:info(Log),
+ display_info(Info),
+
+ ?DBG("log_to_io1 -> do the convert to io (stdout)", []),
+ ? line ok = snmp_log:log_to_io(Log, File, Dir, []),
+
+ ?DBG("log_to_io1 -> close log", []),
+ ?line ok = snmp_log:close(Log),
+
+ ?DBG("log_to_io1 -> done", []),
+ ok.
+
+
+%%======================================================================
+%% Starta en logger-process som med ett visst intervall loggar
+%% meddelanden. Starta en reader-process som vid ett viss tillf�lle
+%% l�ser fr�n loggen.
+
+log_to_io2(suite) -> [];
+log_to_io2(doc) -> "Log to io from a different process than which "
+ "opened and wrote the log";
+log_to_io2(Config) when is_list(Config) ->
+ process_flag(trap_exit, true),
+ p(log_to_io2),
+ put(sname, l2i2),
+ put(verbosity,trace),
+ ?DBG("log_to_io2 -> start", []),
+ Dir = ?config(log_dir, Config),
+ Name = "snmp_test_l2i2",
+ File = join(Dir, "snmp_test_l2i2.log"),
+ Size = {1024, 10},
+ Repair = true,
+
+ ?DBG("log_to_io2 -> create log writer process", []),
+ ?line {ok, Log, Logger} = log_writer_start(Name, File, Size, Repair),
+
+ ?DBG("log_to_io2 -> create log reader process", []),
+ ?line {ok, Reader} = log_reader_start(),
+
+ ?DBG("log_to_io2 -> wait some time", []),
+ ?SLEEP(5000),
+
+ ?DBG("log_to_io2 -> display log info", []),
+ ?line log_writer_info(Logger),
+
+ ?DBG("log_to_io2 -> instruct the log writer to sleep some", []),
+ ?line ok = log_writer_sleep(Logger, 5000),
+
+ ?DBG("log_to_io2 -> instruct the log reader to log to io", []),
+ Res =
+ log_reader_log_to(Reader,
+ fun() ->
+ I = disk_log:info(Log),
+ R = snmp_log:log_to_io(Log, File, Dir, []),
+ {R, I}
+ end),
+
+ case Res of
+ {ok, Info} ->
+ ?DBG("log_to_io2 -> ~n Info: ~p", [Info]),
+ ok;
+ {Error, Info} ->
+ ?DBG("log_to_io2 -> log to io failed: "
+ "~n Error: ~p"
+ "~n Info: ~p", [Error, Info]),
+ ?line ?FAIL({log_lo_io_failed, Error, Info})
+ end,
+
+ ?DBG("log_to_io2 -> instruct the log writer to stop", []),
+ ?line log_writer_stop(Logger),
+
+ ?DBG("log_to_io2 -> instruct the log reader to stop", []),
+ ?line log_reader_stop(Reader),
+
+ ?DBG("log_to_io2 -> done", []),
+ ok.
+
+
+%%======================================================================
+
+log_to_txt1(suite) -> [];
+log_to_txt1(Config) when is_list(Config) ->
+ p(log_to_txt1),
+ put(sname,l2t1),
+ put(verbosity,trace),
+ ?DBG("log_to_txt1 -> start", []),
+ Dir = ?config(log_dir, Config),
+ Name = "snmp_test_l2t1",
+ File = join(Dir, "snmp_test_l2t1.log"),
+ Size = {10240, 10},
+ Repair = true,
+ ?DBG("log_to_txt1 -> create log", []),
+ ?line {ok, Log} = snmp_log:create(Name, File, Size, Repair),
+
+ ?DBG("log_to_txt1 -> create messages to log", []),
+ Msgs = messages(),
+
+ ?DBG("log_to_txt1 -> create logger funs", []),
+ Addr = ?LOCALHOST(),
+ Port = 162,
+ Logger = fun(Packet) ->
+ ?line ok = snmp_log:log(Log, Packet, Addr, Port)
+ end,
+ BatchLogger = fun(Time) ->
+ lists:foreach(Logger, Msgs),
+ ?SLEEP(Time),
+ ok
+ end,
+ To = lists:duplicate(20, 5000),
+
+ ?DBG("log_to_txt1 -> log the messages", []),
+ Start = calendar:local_time(),
+ lists:foreach(BatchLogger, To),
+ Stop = calendar:local_time(),
+
+ ?DBG("log_to_txt1 -> display info", []),
+ ?line {ok, Info} = snmp_log:info(Log),
+ display_info(Info),
+
+ Out1 = join(Dir, "snmp_text-1.txt"),
+ ?DBG("log_to_txt1 -> do the convert to a text file when"
+ "~n Out1: ~p", [Out1]),
+ ?line ok = snmp:log_to_txt(Dir, [], Out1, Log, File),
+
+ ?line {ok, #file_info{size = Size1}} = file:read_file_info(Out1),
+ ?DBG("log_to_txt1 -> text file size: ~p", [Size1]),
+ validate_size(Size1),
+
+ Out2 = join(Dir, "snmp_text-2.txt"),
+ ?DBG("log_to_txt1 -> do the convert to a text file when"
+ "~n Start: ~p"
+ "~n Stop: ~p"
+ "~n Out2: ~p", [Start, Stop, Out2]),
+ ?line ok = snmp:log_to_txt(Dir, [], Out2, Log, File, Start, Stop),
+
+ ?line {ok, #file_info{size = Size2}} = file:read_file_info(Out2),
+ ?DBG("log_to_txt1 -> text file size: ~p", [Size2]),
+ validate_size(Size2, {le, Size1}),
+
+ %% Calculate new start / stop times...
+ GStart = calendar:datetime_to_gregorian_seconds(Start),
+ ?DBG("log_to_txt1 -> GStart: ~p", [GStart]),
+ GStop = calendar:datetime_to_gregorian_seconds(Stop),
+ ?DBG("log_to_txt1 -> GStop: ~p", [GStop]),
+ Diff4 = (GStop - GStart) div 4,
+ ?DBG("log_to_txt1 -> Diff4: ~p", [Diff4]),
+ GStart2 = GStart + Diff4,
+ GStop2 = GStop - Diff4,
+ if
+ GStop2 > GStart2 ->
+ ok;
+ true ->
+ ?FAIL({date_calc_failure, GStart2, GStop2})
+ end,
+
+ Start2 = calendar:gregorian_seconds_to_datetime(GStart2),
+ Stop2 = calendar:gregorian_seconds_to_datetime(GStop2),
+
+ Out3 = join(Dir, "snmp_text-3.txt"),
+ ?DBG("log_to_txt1 -> do the convert to a text file when"
+ "~n Start2: ~p"
+ "~n Stop2: ~p"
+ "~n Out3: ~p", [Start2, Stop2, Out3]),
+ ?line ok = snmp:log_to_txt(Dir, [], Out3, Log, File, Start2, Stop2),
+
+ ?line {ok, #file_info{size = Size3}} = file:read_file_info(Out3),
+ ?DBG("log_to_txt1 -> text file size: ~p", [Size3]),
+ validate_size(Size3, {l, Size1}),
+
+ ?DBG("log_to_txt1 -> close log", []),
+ ?line ok = snmp_log:close(Log),
+
+ ?DBG("log_to_txt1 -> done", []),
+ ok.
+
+
+%%======================================================================
+%% Starta en logger-process som med ett visst intervall loggar
+%% meddelanden. Starta en reader-process som vid ett viss tillf�lle
+%% l�ser fr�n loggen.
+%%
+%% Test: ts:run(snmp, snmp_log_test, log_to_txt2, [batch]).
+
+log_to_txt2(suite) -> [];
+log_to_txt2(doc) -> "Log to txt file from a different process than which "
+ "opened and wrote the log";
+log_to_txt2(Config) when is_list(Config) ->
+ process_flag(trap_exit, true),
+ p(log_to_txt2),
+ put(sname,l2t2),
+ put(verbosity,trace),
+ ?DBG("log_to_txt2 -> start", []),
+ Dir = ?config(log_dir, Config),
+ Name = "snmp_test_l2t2",
+ LogFile = join(Dir, "snmp_test_l2t2.log"),
+ TxtFile = join(Dir, "snmp_test_l2t2.txt"),
+ Meg = 1024*1024,
+ Size = {10*Meg, 10},
+ Repair = true,
+
+ StdMibDir = filename:join(code:priv_dir(snmp), "mibs") ++ "/",
+ Mibs = [join(StdMibDir, "SNMPv2-MIB")],
+
+ ?DBG("log_to_txt2 -> create log writer process", []),
+ ?line {ok, Log, Logger} = log_writer_start(Name, LogFile, Size, Repair),
+
+ ?DBG("log_to_txt2 -> create log reader process", []),
+ ?line {ok, Reader} = log_reader_start(),
+
+ ?DBG("log_to_txt2 -> wait some time", []),
+ ?SLEEP(5000),
+
+ ?DBG("log_to_txt2 -> display log info", []),
+ ?line log_writer_info(Logger),
+
+ ?DBG("log_to_txt2 -> instruct the log writer to sleep some", []),
+ ?line ok = log_writer_sleep(Logger, 5000),
+
+ ?DBG("log_to_txt2 -> instruct the log reader to log to txt", []),
+ Res =
+ log_reader_log_to(Reader,
+ fun() ->
+ I = disk_log:info(Log),
+ T1 = t(),
+ R = snmp_log:log_to_txt(Log, LogFile, Dir,
+ Mibs, TxtFile),
+ T2 = t(),
+ io:format(user,
+ "Time converting file: ~w ms~n",
+ [T2 - T1]),
+ {R, I}
+ end),
+
+ case Res of
+ {ok, Info} ->
+ ?DBG("log_to_txt2 -> ~n Info: ~p", [Info]),
+ ?line {ok, #file_info{size = FileSize}} =
+ file:read_file_info(TxtFile),
+ ?DBG("log_to_txt2 -> text file size: ~p", [FileSize]),
+ validate_size(FileSize);
+ {Error, Info} ->
+ ?DBG("log_to_txt2 -> log to txt failed: "
+ "~n Error: ~p"
+ "~n Info: ~p", [Error, Info]),
+ ?line ?FAIL({log_lo_txt_failed, Error, Info})
+ end,
+
+ ?DBG("log_to_txt2 -> instruct the log writer to stop", []),
+ ?line log_writer_stop(Logger),
+
+ ?DBG("log_to_txt2 -> instruct the log reader to stop", []),
+ ?line log_reader_stop(Reader),
+
+ ?DBG("log_to_txt2 -> done", []),
+ ok.
+
+
+validate_size(0) ->
+ ?FAIL(invalid_size);
+validate_size(_) ->
+ ok.
+
+validate_size(0, _) ->
+ ?FAIL(invalid_size);
+validate_size(A, {le, B}) when A =< B ->
+ ok;
+validate_size(A, {l, B}) when A < B ->
+ ok;
+validate_size(A, B) ->
+ ?FAIL({invalid_size, A, B}).
+
+
+%%======================================================================
+%% Internal functions
+%%======================================================================
+
+log_writer_start(Name, File, Size, Repair) ->
+ Pid = spawn_link(?MODULE, log_writer_main,
+ [Name, File, Size, Repair, self()]),
+ receive
+ {log, Log, Pid} ->
+ {ok, Log, Pid};
+ {'EXIT', Pid, Reason} ->
+ {error, Reason}
+ after 60000 ->
+ Msg = receive Any -> Any after 0 -> nothing end,
+ Info = (catch process_info(Pid)),
+ exit({failed_starting_writer, timeout, Msg, Info})
+ end.
+
+log_writer_stop(Pid) ->
+ Pid ! {stop, self()},
+ T1 = t(),
+ receive
+ {'EXIT', Pid, normal} ->
+ T2 = t(),
+ ?DBG("it took ~w ms to stop the writer", [T2 - T1]),
+ ok
+ after 60000 ->
+ Msg = receive Any -> Any after 0 -> nothing end,
+ Info = (catch process_info(Pid)),
+ exit({failed_stopping_writer, timeout, Msg, Info})
+ end.
+
+log_writer_info(Pid) ->
+ Pid ! {info, self()}.
+
+log_writer_sleep(Pid, Time) ->
+ Pid ! {sleep, Time, self()},
+ T1 = t(),
+ receive
+ {sleeping, Pid} ->
+ T2 = t(),
+ ?DBG("it took ~w ms to put the writer to sleep", [T2 - T1]),
+ ok;
+ {'EXIT', Pid, Reason} ->
+ {error, Reason}
+ after 60000 ->
+ Msg = receive Any -> Any after 0 -> nothing end,
+ Info = (catch process_info(Pid)),
+ exit({failed_put_writer_to_sleep, timeout, Msg, Info})
+ end.
+
+log_writer_main(Name, File, Size, Repair, P) ->
+ process_flag(trap_exit, true),
+ %% put(sname,log_writer),
+ %% put(verbosity,trace),
+ {ok, Log} = snmp_log:create(Name, File, Size, Repair),
+ P ! {log, Log, self()},
+ Msgs = lists:flatten(lists:duplicate(10, messages())),
+ Addr = ?LOCALHOST(),
+ Port = 162,
+ Logger = fun(Packet) ->
+ ?line ok = snmp_log:log(Log, Packet, Addr, Port)
+ end,
+ BatchLogger = fun(Time) ->
+ lists:foreach(Logger, Msgs),
+ ?SLEEP(Time),
+ ok
+ end,
+ log_writer(Log, BatchLogger, P).
+
+log_writer(Log, Fun, P) ->
+ lp("entry"),
+ receive
+ {stop, P} ->
+ lp("received stop request"),
+ ok = snmp_log:close(Log),
+ exit(normal);
+ {info, P} ->
+ lp("received info request"),
+ {ok, Info} = snmp_log:info(Log),
+ display_info(Info),
+ log_writer(Log, Fun, P);
+ {sleep, Time, P} ->
+ lp("received sleep (~w) request", [Time]),
+ P ! {sleeping, self()},
+ ?SLEEP(Time),
+ lp("done sleeping"),
+ log_writer(Log, Fun, P);
+ ELSE ->
+ io:format("ERROR:logger - received unknown message: "
+ "~n ~p~n", [ELSE]),
+ log_writer(Log, Fun, P)
+ after 1000 ->
+ lp("log some messages"),
+ To = lists:duplicate(100, 100),
+ lists:foreach(Fun, To),
+ log_writer(Log, Fun, P)
+ end.
+
+lp(F) ->
+ lp(F, []).
+
+lp(F, A) ->
+ io:format(user,"writer [~w] " ++ F ++ "~n", [self()|A]).
+
+%% --
+
+log_reader_start() ->
+ Pid = spawn_link(?MODULE, log_reader_main, [self()]),
+ T1 = t(),
+ receive
+ {started, Pid} ->
+ T2 = t(),
+ ?DBG("it took ~w ms to start the reader", [T2 - T1]),
+ {ok, Pid};
+ {'EXIT', Pid, Reason} ->
+ {error, Reason}
+ after 1000 ->
+ error
+ end.
+
+log_reader_stop(Pid) ->
+ Pid ! {stop, self()},
+ T1 = t(),
+ receive
+ {'EXIT', Pid, normal} ->
+ T2 = t(),
+ ?DBG("it took ~w ms to put the reader to eleep", [T2 - T1]),
+ ok
+ after 1000 ->
+ Msg = receive Any -> Any after 0 -> nothing end,
+ exit({failed_stopping_reader, timeout, Msg})
+ end.
+
+log_reader_log_to(Pid, LogToFun) when is_function(LogToFun) ->
+ Pid ! {log_to, LogToFun, self()},
+ receive
+ {log_to_reply, Res, Pid} ->
+ Res
+ end.
+
+log_reader_main(P) ->
+ put(sname,log_reader),
+ put(verbosity,trace),
+ P ! {started, self()},
+ log_reader(P).
+
+log_reader(P) ->
+ rp("entry"),
+ receive
+ {stop, P} ->
+ rp("received stop request"),
+ exit(normal);
+ {log_to, F, P} ->
+ rp("received log_to request"),
+ Res = F(),
+ rp("done with log_to - sending reply"),
+ P ! {log_to_reply, Res, self()},
+ log_reader(P);
+ ELSE ->
+ io:format("ERROR:reader - received unknown message: "
+ "~n ~p~n", [ELSE]),
+ log_reader(P)
+ end.
+
+rp(F) ->
+ rp(F, []).
+
+rp(F, A) ->
+ io:format(user, "reader [~w] " ++ F ++ "~n", [self()|A]).
+
+
+%%======================================================================
+
+check_notify() ->
+ receive
+ {disk_log, Node, LogName, Info} ->
+ io:format("disk_log notify: "
+ "~n Node: ~p"
+ "~n LogName: ~s"
+ "~n Info: ~p"
+ "~n", [Node, LogName, Info]),
+ check_notify()
+ after 1000 ->
+ done
+ end.
+
+
+messages() ->
+ [get_next_request('version-1', "all-rights",
+ [1,13], 1, 1101),
+ get_response('version-1', "all-rights",
+ [1,3,6,1,2,1,1,1,0],
+ 'OCTET STRING', "Erlang SNMP agent",
+ 1, 1101),
+ get_request('version-1', "all-rights",
+ [1,3,6,1,2,1,1,1,0], 1, 1102),
+ get_response('version-1', "all-rights",
+ [1,3,6,1,2,1,1,1,0],
+ 'OCTET STRING', "Erlang SNMP agent",
+ 1, 1102),
+ set_request('version-1', "all-rights",
+ [1,3,6,1,2,1,1,6,0],
+ 'OCTET STRING', "new_value",
+ 1, 1003),
+ get_response('version-1', "all-rights",
+ [1,3,6,1,2,1,1,6,0],
+ 'OCTET STRING', "new_value",
+ 1, 1103),
+ get_bulk_request("all-rights", 1104),
+ bulk_get_response('version-1', "all-rights",
+ [48,29,6,8,43,6,1,2,1,1,1,0,4,17,69,114,108,97,
+ 110,103,32,83,78,77,80,32,97,103,101,110,116,
+ 48,7,6,3,43,7,1,130,0], 1104),
+ inform_request("all-rights", 1105),
+ get_response('version-1', "all-rights",
+ [{[1,3,6,1,2,1,1,3,0],
+ 'TimeTicks',
+ 4046,
+ 1},
+ {[1,3,6,1,6,3,1,1,4,1,0],
+ 'OBJECT IDENTIFIER',
+ [1,3,6,1,2,1,1,0,1],2}],
+ 1105),
+ snmpv2_trap("all-rights", 1106),
+ trap("all-rights")].
+
+
+get_request(Vsn, Community, Oid, OrgIdx, ReqId) ->
+ Varbind = #varbind{oid = Oid,
+ variabletype = 'NULL',
+ value = 'NULL',
+ org_index = OrgIdx},
+ Pdu = #pdu{type = 'get-response',
+ request_id = ReqId,
+ error_status = noError,
+ error_index = 0,
+ varbinds = [Varbind]},
+ enc_message(Vsn, Community, Pdu).
+
+get_next_request(Vsn, Community, Oid, OrgIdx, ReqId) ->
+ Varbind = #varbind{oid = Oid,
+ variabletype = 'NULL',
+ value = 'NULL',
+ org_index = OrgIdx},
+ Pdu = #pdu{type = 'get-next-request',
+ request_id = ReqId,
+ error_status = noError,
+ error_index = 0,
+ varbinds = [Varbind]},
+ enc_message(Vsn, Community, Pdu).
+
+bulk_get_response(Vsn, Community, Bulk, ReqId) ->
+ Pdu = #pdu{type = 'get-response',
+ request_id = ReqId,
+ error_status = noError,
+ error_index = 0,
+ varbinds = Bulk},
+ enc_message(Vsn, Community, Pdu).
+
+get_response(Vsn, Community, VarbindData, ReqId) ->
+ Varbinds = varbinds(VarbindData, []),
+ Pdu = #pdu{type = 'get-response',
+ request_id = ReqId,
+ error_status = noError,
+ error_index = 0,
+ varbinds = Varbinds},
+ enc_message(Vsn, Community, Pdu).
+
+get_response(Vsn, Community, Oid, Type, Value, OrgIdx, ReqId) ->
+ Varbind = #varbind{oid = Oid,
+ variabletype = Type,
+ value = Value,
+ org_index = OrgIdx},
+ Pdu = #pdu{type = 'get-response',
+ request_id = ReqId,
+ error_status = noError,
+ error_index = 0,
+ varbinds = [Varbind]},
+ enc_message(Vsn, Community, Pdu).
+
+set_request(Vsn, Community, Oid, Type, Value, OrgIdx, ReqId) ->
+ Varbind = #varbind{oid = Oid,
+ variabletype = Type,
+ value = Value,
+ org_index = OrgIdx},
+ Pdu = #pdu{type = 'set-request',
+ request_id = ReqId,
+ error_status = noError,
+ error_index = 0,
+ varbinds = [Varbind]},
+ enc_message(Vsn, Community, Pdu).
+
+
+get_bulk_request(Community, ReqId) ->
+ Varbinds = [#varbind{oid = [1,3,6,1,2,1,1,1],
+ variabletype = 'NULL',
+ value = 'NULL',
+ org_index = 1},
+ #varbind{oid = [1,3,7,1],
+ variabletype = 'NULL',
+ value = 'NULL',
+ org_index = 2}],
+ Pdu = #pdu{type = 'get-bulk-request',
+ request_id = ReqId,
+ error_status = 1,
+ error_index = 1,
+ varbinds = Varbinds},
+ enc_message('version-2', Community, Pdu).
+
+inform_request(Community, ReqId) ->
+ Varbinds = [#varbind{oid = [1,3,6,1,2,1,1,3,0],
+ variabletype = 'TimeTicks',
+ value = 4046,
+ org_index = 1},
+ #varbind{oid = [1,3,6,1,6,3,1,1,4,1,0],
+ variabletype = 'OBJECT IDENTIFIER',
+ value = [1,3,6,1,2,1,1,0,1],
+ org_index = 2}],
+ Pdu = #pdu{type = 'inform-request',
+ request_id = ReqId,
+ error_status = noError,
+ error_index = 0,
+ varbinds = Varbinds},
+ enc_message('version-2', Community, Pdu).
+
+snmpv2_trap(Community, ReqId) ->
+ Varbinds = [#varbind{oid = [1,3,6,1,2,1,1,3,0],
+ variabletype = 'TimeTicks',
+ value = 3945,
+ org_index = 1},
+ #varbind{oid = [1,3,6,1,6,3,1,1,4,1,0],
+ variabletype = 'OBJECT IDENTIFIER',
+ value = [1,3,6,1,2,1,11,1],
+ org_index = 2}],
+ Pdu = #pdu{type = 'snmpv2-trap',
+ request_id = ReqId,
+ error_status = noError,
+ error_index = 0,
+ varbinds = Varbinds},
+ enc_message('version-2', Community, Pdu).
+
+% report() ->
+% Varbind = #varbind{oid = ?snmpUnknownPDUHandlers,
+% variabletype = 'Counter32',
+% value = 111},
+% Pdu = #pdu{type = report,
+% request_id = 991199,
+% error_status = noError,
+% error_index = 0,
+% varbinds = [Varbind]},
+% enc_message('version-3', Community, Pdu).
+
+trap(Community) ->
+ Enterp = [1,3,6,1,2,1,1],
+ Oid = [1,3,6,1,2,1,1,4,0],
+ Type = 'OCTET STRING',
+ Value = "{mbj,eklas}@erlang.ericsson.se",
+ SysUpTime = 4379,
+ Spec = 1,
+ Generic = 6,
+ AgentIp = [127,0,0,1],
+ trap(Community, Enterp, Oid, Type, Value, SysUpTime,
+ Spec, Generic, AgentIp, 1).
+
+%% V1 trap
+trap(Community, Enterp, Oid, Type, Value, SysUpTime,
+ Spec, Generic, AgentIp, OrgIdx) ->
+ Varbind = #varbind{oid = Oid,
+ variabletype = Type,
+ value = Value,
+ org_index = OrgIdx},
+ Trap = #trappdu{enterprise = Enterp,
+ agent_addr = AgentIp,
+ generic_trap = Generic,
+ specific_trap = Spec,
+ time_stamp = SysUpTime,
+ varbinds = [Varbind]},
+ enc_message('version-1', Community, Trap).
+
+varbinds([], Varbinds) ->
+ lists:reverse(Varbinds);
+varbinds([{Oid, Type, Value, Idx}|T], Acc) ->
+ Varbind = #varbind{oid = Oid,
+ variabletype = Type,
+ value = Value,
+ org_index = Idx},
+ varbinds(T, [Varbind|Acc]).
+
+% enc_message('version-3' = Vsn, Community, Pdu) ->
+% ScopedPDU = #scopedPdu{contextEngineID = ContextEngineID,
+% contextName = ContextName,
+% data = Pdu},
+% NUsmSecParams =
+% UsmSecParams#usmSecurityParameters{msgAuthenticationParameters =
+% AuthParams},
+% SecBytes = snmp_pdus:enc_usm_security_parameters(NUsmSecParams),
+% V3Hdr = #v3_hdr{msgID = MsgID,
+% msgMaxSize = AgentMS,
+% msgFlags = snmp_misc:mk_msg_flags(Type, SecLevel),
+% msgSecurityParameters = SecBytes
+% msgSecurityModel = MsgSecurityModel},
+% Msg = #message{version = Vsn, vsn_hdr = V3Hdr,
+% data = ScopedPDUBytes},
+% snmp_pdus:enc_message_only(Message2);
+
+enc_message(Vsn, Community, Pdu) ->
+ PduBytes = snmp_pdus:enc_pdu(Pdu),
+ Msg = #message{version = Vsn,
+ vsn_hdr = Community,
+ data = PduBytes},
+ list_to_binary(snmp_pdus:enc_message_only(Msg)).
+
+display_info(Info) ->
+ {SinceOpened, SinceLastInfo} = get_info(no_overflows, Info, {-1,-1}),
+ CurrentFile = get_info(current_file, Info, -1),
+ NoItems = get_info(no_current_items, Info, -1),
+ NoBytes = get_info(no_current_bytes, Info, -1),
+ io:format(user, "Disk log info: "
+ "~n Number of filled since opened: ~p"
+ "~n Number of filled since last info: ~p"
+ "~n Current file: ~p"
+ "~n Number of items in file: ~p"
+ "~n Number of bytes in file: ~p"
+ "~n",
+ [SinceOpened, SinceLastInfo, CurrentFile, NoItems, NoBytes]).
+
+get_info(Key, Info, Def) ->
+ case lists:keysearch(Key, 1, Info) of
+ {value, {Key, Val}} ->
+ Val;
+ false ->
+ Def
+ end.
+
+join(D, F) ->
+ filename:join(D, F).
+
+p(Case) ->
+ io:format(user, "test case: ~w~n", [Case]).
+
+%% Time in milli sec
+t() ->
+ {A,B,C} = erlang:now(),
+ A*1000000000+B*1000+(C div 1000).
diff --git a/lib/snmp/test/snmp_manager_config_test.erl b/lib/snmp/test/snmp_manager_config_test.erl
new file mode 100644
index 0000000000..51325996e6
--- /dev/null
+++ b/lib/snmp/test/snmp_manager_config_test.erl
@@ -0,0 +1,2535 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2004-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%
+%%
+
+%%----------------------------------------------------------------------
+%% Purpose:
+%%
+%% Test:
+%% ts:run().
+%% ts:run(snmp, [batch]).
+%% ts:run(snmp, snmp_manager_config_test, [batch]).
+%%
+%%----------------------------------------------------------------------
+-module(snmp_manager_config_test).
+
+%%----------------------------------------------------------------------
+%% Include files
+%%----------------------------------------------------------------------
+-include("test_server.hrl").
+-include("snmp_test_lib.hrl").
+-include_lib("snmp/src/manager/snmpm_usm.hrl").
+
+
+%%----------------------------------------------------------------------
+%% External exports
+%%----------------------------------------------------------------------
+%% -compile(export_all).
+
+-export([
+ all/1,
+ init_per_testcase/2, fin_per_testcase/2,
+
+ start_and_stop/1,
+
+ simple_start_and_stop/1,
+ start_without_mandatory_opts1/1,
+ start_without_mandatory_opts2/1,
+ start_with_all_valid_opts/1,
+ start_with_unknown_opts/1,
+ start_with_incorrect_opts/1,
+ start_with_invalid_manager_conf_file1/1,
+ start_with_invalid_users_conf_file1/1,
+ start_with_invalid_agents_conf_file1/1,
+ start_with_invalid_usm_conf_file1/1,
+
+ normal_op/1,
+
+ system/1,
+ simple_system_op/1,
+
+ users/1,
+ register_user_using_file/1,
+ register_user_using_function/1,
+ register_user_failed_using_function1/1,
+
+ agents/1,
+ register_agent_using_file/1,
+ register_agent_using_function/1,
+ register_agent_failed_using_function1/1,
+
+ usm_users/1,
+ register_usm_user_using_file/1,
+ register_usm_user_using_function/1,
+ register_usm_user_failed_using_function1/1,
+ update_usm_user_info/1,
+
+ counter/1,
+ create_and_increment/1,
+
+ stats_counter/1,
+ stats_create_and_increment/1,
+
+ tickets/1,
+ otp_7219/1
+
+ ]).
+
+%%----------------------------------------------------------------------
+%% Internal exports
+%%----------------------------------------------------------------------
+-export([
+ ]).
+
+
+%%----------------------------------------------------------------------
+%% Macros
+%%----------------------------------------------------------------------
+
+
+%%----------------------------------------------------------------------
+%% Records
+%%----------------------------------------------------------------------
+
+
+%%======================================================================
+%% External functions
+%%======================================================================
+
+init_per_testcase(Case, Config) when is_list(Config) ->
+ p("init_per_testcase -> Case: ~p", [Case]),
+ SnmpPrivDir = ?config(priv_dir, Config),
+ p("init_per_testcase -> SnmpPrivDir: ~p", [SnmpPrivDir]),
+ SuiteDir = atom_to_list(?MODULE),
+ SuiteTopDir = filename:join(SnmpPrivDir, SuiteDir),
+ case file:make_dir(SuiteTopDir) of
+ ok ->
+ ok;
+ {error, eexist} ->
+ ok;
+ {error, Reason} ->
+ ?FAIL({failed_creating, SuiteTopDir, Reason})
+ end,
+ p("init_per_testcase -> SuiteTopDir: ~p", [SuiteTopDir]),
+ CaseDir = atom_to_list(Case),
+ ?line ok =
+ file:make_dir(CaseTopDir = filename:join(SuiteTopDir, CaseDir)),
+ p("init_per_testcase -> CaseTopDir: ~p", [CaseTopDir]),
+ ?line ok =
+ file:make_dir(MgrTopDir = filename:join(CaseTopDir, "manager/")),
+ ?line ok =
+ file:make_dir(MgrConfDir = filename:join(MgrTopDir, "conf/")),
+ ?line ok =
+ file:make_dir(MgrDbDir = filename:join(MgrTopDir, "db/")),
+ ?line ok =
+ file:make_dir(MgrLogDir = filename:join(MgrTopDir, "log/")),
+ [{case_top_dir, CaseTopDir},
+ {manager_dir, MgrTopDir},
+ {manager_conf_dir, MgrConfDir},
+ {manager_db_dir, MgrDbDir},
+ {manager_log_dir, MgrLogDir} | Config].
+
+
+fin_per_testcase(Case, Config) when is_list(Config) ->
+ p("fin_per_testcase -> Case: ~p", [Case]),
+ %% The cleanup is removed due to some really discusting NFS behaviour...
+ %% CaseTopDir = ?config(manager_dir, Config),
+ %% ?line ok = ?DEL_DIR(CaseTopDir),
+ Config.
+
+
+%%======================================================================
+%% Test case definitions
+%%======================================================================
+% all(doc) ->
+% "The top snmp manager config test case";
+all(suite) ->
+ [
+ start_and_stop,
+ normal_op,
+ tickets
+ ].
+
+
+%%======================================================================
+%% Test functions
+%%======================================================================
+
+start_and_stop(doc) ->
+ "A collection of start and stop tests";
+start_and_stop(suite) ->
+ [
+ simple_start_and_stop,
+ start_without_mandatory_opts1,
+ start_without_mandatory_opts2,
+ start_with_all_valid_opts,
+ start_with_unknown_opts,
+ start_with_incorrect_opts,
+ start_with_invalid_manager_conf_file1,
+ start_with_invalid_users_conf_file1,
+ start_with_invalid_agents_conf_file1,
+ start_with_invalid_usm_conf_file1
+ ].
+
+
+%%
+%% ---
+%%
+
+simple_start_and_stop(suite) -> [];
+simple_start_and_stop(doc) ->
+ "Start the snmp manager config process with the \n"
+ "minimum setof options (config dir).";
+simple_start_and_stop(Conf) when is_list(Conf) ->
+ put(tname,ssas),
+ p("start"),
+ process_flag(trap_exit, true),
+ ConfDir = ?config(manager_conf_dir, Conf),
+ DbDir = ?config(manager_db_dir, Conf),
+
+ write_manager_conf(ConfDir),
+
+ Opts = [{versions, [v1]},
+ {config, [{verbosity, trace}, {dir, ConfDir}, {db_dir, DbDir}]}],
+
+ ?line {ok, _Pid} = snmpm_config:start_link(Opts),
+ ?line ok = snmpm_config:stop(),
+
+ ok.
+
+
+%%
+%% ---
+%%
+
+start_without_mandatory_opts1(suite) -> [];
+start_without_mandatory_opts1(doc) ->
+ "Start the snmp manager config process with some of the \n"
+ "mandatory options missing.";
+start_without_mandatory_opts1(Conf) when is_list(Conf) ->
+ put(tname,swomo1),
+ put(verbosity,trace),
+ p("start"),
+ process_flag(trap_exit, true),
+ ConfDir = ?config(manager_conf_dir, Conf),
+ DbDir = ?config(manager_db_dir, Conf),
+
+ write_manager_conf(ConfDir),
+
+
+ %% config, but no dir:
+ p("config option, but no dir"),
+ Opts = [{priority, normal},
+ {config, [{verbosity, trace}, {db_dir, DbDir}]}, {mibs, []}],
+ ?line {error, {missing_mandatory,dir}} = config_start(Opts),
+
+ p("done"),
+ ok.
+
+
+%%
+%% ---
+%%
+
+start_without_mandatory_opts2(suite) -> [];
+start_without_mandatory_opts2(doc) ->
+ "Start the snmp manager config process with some of the \n"
+ "mandatory options missing.";
+start_without_mandatory_opts2(Conf) when is_list(Conf) ->
+ put(tname,swomo2),
+ put(verbosity,trace),
+ p("start"),
+ process_flag(trap_exit, true),
+ ConfDir = ?config(manager_conf_dir, Conf),
+
+ write_manager_conf(ConfDir),
+
+
+ %% Second set of options (no config):
+ p("no config option"),
+ Opts = [{priority, normal},
+ {mibs, []}],
+ ?line {error, {missing_mandatory,config,[dir, db_dir]}} =
+ config_start(Opts),
+
+ p("done"),
+ ok.
+
+
+%%
+%% ---
+%%
+
+start_with_all_valid_opts(suite) -> [];
+start_with_all_valid_opts(doc) ->
+ "Start the snmp manager config process with the \n"
+ "complete set of all the valid options.";
+start_with_all_valid_opts(Conf) when is_list(Conf) ->
+ put(tname,swavo),
+ p("start"),
+ process_flag(trap_exit, true),
+ ConfDir = ?config(manager_conf_dir, Conf),
+ DbDir = ?config(manager_db_dir, Conf),
+ LogDir = ?config(manager_log_dir, Conf),
+ StdMibDir = filename:join(code:priv_dir(snmp), "mibs") ++ "/",
+
+ write_manager_conf(ConfDir),
+
+
+ %% Third set of options (no versions):
+ p("all options"),
+ NetIfOpts = [{module, snmpm_net_if},
+ {verbosity, trace},
+ {options, [{recbuf, 30000},
+ {bind_to, false},
+ {no_reuse, false}]}],
+ ServerOpts = [{timeout, 10000}, {verbosity, trace}],
+ NoteStoreOpts = [{timeout, 20000}, {verbosity, trace}],
+ ConfigOpts = [{dir, ConfDir}, {verbosity, trace}, {db_dir, DbDir}],
+ Mibs = [join(StdMibDir, "SNMP-NOTIFICATION-MIB"),
+ join(StdMibDir, "SNMP-USER-BASED-SM-MIB")],
+ Prio = normal,
+ ATL = [{type, read_write},
+ {dir, LogDir},
+ {size, {10,10240}},
+ {repair, true}],
+ Vsns = [v1,v2,v3],
+ Opts = [{config, ConfigOpts},
+ {net_if, NetIfOpts},
+ {server, ServerOpts},
+ {note_store, NoteStoreOpts},
+ {audit_trail_log, ATL},
+ {priority, Prio},
+ {mibs, Mibs},
+ {versions, Vsns}],
+ ?line {ok, _Pid} = config_start(Opts),
+ ?line ok = config_stop(),
+
+ p("done"),
+ ok.
+
+
+%%
+%% ---
+%%
+
+start_with_unknown_opts(suite) -> [];
+start_with_unknown_opts(doc) ->
+ "Start the snmp manager config process when some of\n"
+ "the options are unknown.";
+start_with_unknown_opts(Conf) when is_list(Conf) ->
+ put(tname,swuo),
+ p("start"),
+ process_flag(trap_exit, true),
+ ConfDir = ?config(manager_conf_dir, Conf),
+ DbDir = ?config(manager_db_dir, Conf),
+ LogDir = ?config(manager_log_dir, Conf),
+ StdMibDir = filename:join(code:priv_dir(snmp), "mibs") ++ "/",
+
+ write_manager_conf(ConfDir),
+
+
+ %% Third set of options (no versions):
+ p("all options"),
+ NetIfOpts = [{module, snmpm_net_if},
+ {verbosity, trace},
+ {options, [{recbuf, 30000},
+ {bind_to, false},
+ {no_reuse, false}]}],
+ ServerOpts = [{timeout, 10000}, {verbosity, trace}],
+ NoteStoreOpts = [{timeout, 20000}, {verbosity, trace}],
+ ConfigOpts = [{dir, ConfDir}, {verbosity, trace}, {db_dir, DbDir}],
+ Mibs = [join(StdMibDir, "SNMP-NOTIFICATION-MIB"),
+ join(StdMibDir, "SNMP-USER-BASED-SM-MIB")],
+ Prio = normal,
+ ATL = [{type, read_write},
+ {dir, LogDir},
+ {size, {10,10240}},
+ {repair, true}],
+ Vsns = [v1,v2,v3],
+ Opts = [{config, ConfigOpts},
+ {net_if, NetIfOpts},
+ {server, ServerOpts},
+ {note_store, NoteStoreOpts},
+ {audit_trail_log, ATL},
+ {unknown_option, "dummy value"},
+ {priority, Prio},
+ {mibs, Mibs},
+ {versions, Vsns}],
+ ?line {ok, _Pid} = config_start(Opts),
+
+ p("done"),
+ ok.
+
+
+%%
+%% ---
+%%
+
+start_with_incorrect_opts(suite) -> [];
+start_with_incorrect_opts(doc) ->
+ "Start the snmp manager config process when some of\n"
+ "the options has incorrect values.";
+start_with_incorrect_opts(Conf) when is_list(Conf) ->
+ put(tname,swio),
+ p("start"),
+ process_flag(trap_exit, true),
+ ConfDir = ?config(manager_conf_dir, Conf),
+ DbDir = ?config(manager_db_dir, Conf),
+ LogDir = ?config(manager_log_dir, Conf),
+ StdMibDir = filename:join(code:priv_dir(snmp), "mibs") ++ "/",
+
+ write_manager_conf(ConfDir),
+
+ ConfigOpts = [{verbosity,trace}, {dir, ConfDir}, {db_dir, DbDir}],
+
+ p("net-if - incorrect module"),
+ NetIfOpts1 = [{module, snmpm_user}], %% Behaviour check will fail
+ Opts01 = [{config, ConfigOpts}, {versions, [v1]},
+ {net_if, NetIfOpts1}],
+ ?line {error, Reason01} = config_start(Opts01),
+ p("net-if (module) res: ~p", [Reason01]),
+
+ p("net-if - incorrect verbosity"),
+ NetIfOpts2 = [{verbosity, invalid_verbosity}],
+ Opts02 = [{config, ConfigOpts}, {versions, [v1]},
+ {net_if, NetIfOpts2}],
+ ?line {error, Reason02} = config_start(Opts02),
+ p("net-if (verbosity) res: ~p", [Reason02]),
+
+ p("net-if - incorrect options"),
+ NetIfOpts3 = [{options, invalid_options}],
+ Opts03 = [{config, ConfigOpts}, {versions, [v1]},
+ {net_if, NetIfOpts3}],
+ ?line {error, Reason03} = config_start(Opts03),
+ p("net-if (options) res: ~p", [Reason03]),
+
+ p("server - incorrect timeout (1)"),
+ ServerOpts1 = [{timeout, invalid_timeout}],
+ Opts08 = [{config, ConfigOpts}, {versions, [v1]},
+ {server, ServerOpts1}],
+ ?line {error, Reason08} = config_start(Opts08),
+ p("server (timeout) res: ~p", [Reason08]),
+
+ p("server - incorrect timeout (2)"),
+ ServerOpts2 = [{timeout, 0}],
+ Opts09 = [{config, ConfigOpts}, {versions, [v1]},
+ {server, ServerOpts2}],
+ ?line {error, Reason09} = config_start(Opts09),
+ p("server (timeout) res: ~p", [Reason09]),
+
+ p("server - incorrect timeout (3)"),
+ ServerOpts3 = [{timeout, -1000}],
+ Opts10 = [{config, ConfigOpts},
+ {versions, [v1]},
+ {server, ServerOpts3}],
+ ?line {error, Reason10} = config_start(Opts10),
+ p("server (timeout) res: ~p", [Reason10]),
+
+ p("server - incorrect verbosity"),
+ ServerOpts4 = [{verbosity, invalid_verbosity}],
+ Opts11 = [{config, ConfigOpts},
+ {versions, [v1]},
+ {server, ServerOpts4}],
+ ?line {error, Reason11} = config_start(Opts11),
+ p("server (verbosity) res: ~p", [Reason11]),
+
+ p("note-store - incorrect timeout (1)"),
+ NoteStoreOpts1 = [{timeout, invalid_timeout}],
+ Opts12 = [{config, ConfigOpts},
+ {versions, [v1]},
+ {note_store, NoteStoreOpts1}],
+ ?line {error, Reason12} = config_start(Opts12),
+ p("note-store (timeout) res: ~p", [Reason12]),
+
+ p("note-store - incorrect timeout (2)"),
+ NoteStoreOpts2 = [{timeout, 0}],
+ Opts13 = [{config, ConfigOpts},
+ {versions, [v1]},
+ {note_store, NoteStoreOpts2}],
+ ?line {error, Reason13} = config_start(Opts13),
+ p("note-store (timeout) res: ~p", [Reason13]),
+
+ p("note-store - incorrect timeout (3)"),
+ NoteStoreOpts3 = [{timeout, -2000}],
+ Opts14 = [{config, ConfigOpts},
+ {versions, [v1]},
+ {note_store, NoteStoreOpts3}],
+ ?line {error, Reason14} = config_start(Opts14),
+ p("note-store (timeout) res: ~p", [Reason14]),
+
+ p("note-store - incorrect verbosity"),
+ NoteStoreOpts4 = [{timeout, 20000}, {verbosity, invalid_verbosity}],
+ Opts15 = [{config, ConfigOpts},
+ {versions, [v1]},
+ {note_store, NoteStoreOpts4}],
+ ?line {error, Reason15} = config_start(Opts15),
+ p("note-store (verbosity) res: ~p", [Reason15]),
+
+ p("config - incorrect dir (1)"),
+ ConfigOpts1 = [{dir, invalid_dir}],
+ Opts16 = [{config, ConfigOpts1},
+ {versions, [v1]}],
+ ?line {error, Reason16} = config_start(Opts16),
+ p("config (dir) res: ~p", [Reason16]),
+
+ p("config - incorrect dir (2)"),
+ ConfigOpts2 = [{dir, "/invalid/dir"}],
+ Opts17 = [{config, ConfigOpts2},
+ {versions, [v1]}],
+ ?line {error, Reason17} = config_start(Opts17),
+ p("config (dir) res: ~p", [Reason17]),
+
+ p("config - incorrect verbosity"),
+ ConfigOpts3 = [{dir, ConfDir}, {verbosity, invalid_verbosity}],
+ Opts18 = [{config, ConfigOpts3},
+ {versions, [v1]}],
+ ?line {error, Reason18} = config_start(Opts18),
+ p("config (verbosity) res: ~p", [Reason18]),
+
+ p("mibs - incorrect mibs (1)"),
+ Mibs1 = invalid_mibs,
+ Opts19 = [{config, ConfigOpts},
+ {versions, [v1]},
+ {mibs, Mibs1}],
+ ?line {error, Reason19} = config_start(Opts19),
+ p("mibs (mibs) res: ~p", [Reason19]),
+
+ p("mibs - incorrect mibs (2)"),
+ Mibs2 = [join(StdMibDir, "INVALID-MIB")],
+ Opts20 = [{config, ConfigOpts},
+ {versions, [v1]},
+ {mibs, Mibs2}],
+ ?line {error, Reason20} = config_start(Opts20),
+ p("mibs (mibs) res: ~p", [Reason20]),
+
+ p("prio - incorrect prio"),
+ Prio1 = invalid_prio,
+ Opts21 = [{config, ConfigOpts},
+ {versions, [v1]},
+ {priority, Prio1}],
+ ?line {error, Reason21} = config_start(Opts21),
+ p("prio (prio) res: ~p", [Reason21]),
+
+ p("atl - incorrect type"),
+ ATL1 = [{type, invalid_type},
+ {dir, LogDir},
+ {size, {10,10240}},
+ {repair, true}],
+ Opts22 = [{config, ConfigOpts},
+ {versions, [v1]},
+ {audit_trail_log, ATL1}],
+ ?line {error, Reason22} = config_start(Opts22),
+ p("atl (type) res: ~p", [Reason22]),
+
+ p("atl - incorrect dir (1)"),
+ ATL2 = [{type, read_write},
+ {dir, invalid_dir},
+ {size, {10,10240}},
+ {repair, true}],
+ Opts23 = [{config, ConfigOpts},
+ {versions, [v1]},
+ {audit_trail_log, ATL2}],
+ ?line {error, Reason23} = config_start(Opts23),
+ p("atl (dir) res: ~p", [Reason23]),
+
+ p("atl - incorrect dir (2)"),
+ ATL3 = [{type, read_write},
+ {dir, "/invalid/dir"},
+ {size, {10,10240}},
+ {repair, true}],
+ Opts24 = [{config, ConfigOpts},
+ {versions, [v1]},
+ {audit_trail_log, ATL3}],
+ ?line {error, Reason24} = config_start(Opts24),
+ p("atl (dir) res: ~p", [Reason24]),
+
+ p("atl - incorrect size (1)"),
+ ATL4 = [{type, read_write},
+ {dir, LogDir},
+ {size, invalid_size},
+ {repair, true}],
+ Opts25 = [{config, ConfigOpts},
+ {versions, [v1]},
+ {audit_trail_log, ATL4}],
+ ?line {error, Reason25} = config_start(Opts25),
+ p("atl (size) res: ~p", [Reason25]),
+
+ p("atl - incorrect size (2)"),
+ ATL5 = [{type, read_write},
+ {dir, LogDir},
+ {size, {10,invalid_file_size}},
+ {repair, true}],
+ Opts26 = [{config, ConfigOpts},
+ {versions, [v1]},
+ {audit_trail_log, ATL5}],
+ ?line {error, Reason26} = config_start(Opts26),
+ p("atl (size) res: ~p", [Reason26]),
+
+ p("atl - incorrect size (3)"),
+ ATL6 = [{type, read_write},
+ {dir, LogDir},
+ {size, {invalid_file_num,10240}},
+ {repair, true}],
+ Opts27 = [{config, ConfigOpts},
+ {versions, [v1]},
+ {audit_trail_log, ATL6}],
+ ?line {error, Reason27} = config_start(Opts27),
+ p("atl (size) res: ~p", [Reason27]),
+
+ p("atl - incorrect repair"),
+ ATL7 = [{type, read_write},
+ {dir, LogDir},
+ {size, {10,10240}},
+ {repair, invalid_repair}],
+ Opts28 = [{config, ConfigOpts},
+ {versions, [v1]},
+ {audit_trail_log, ATL7}],
+ ?line {error, Reason28} = config_start(Opts28),
+ p("atl (repair) res: ~p", [Reason28]),
+
+ p("version - incorrect versions (1)"),
+ Vsns1 = invalid_vsns,
+ Opts29 = [{config, ConfigOpts},
+ {versions, Vsns1}],
+ ?line {error, Reason29} = config_start(Opts29),
+ p("versions (versions) res: ~p", [Reason29]),
+
+ p("version - incorrect versions (2)"),
+ Vsns2 = [v1,v2,v3,v9],
+ Opts30 = [{config, ConfigOpts},
+ {versions, Vsns2}],
+ ?line {error, Reason30} = config_start(Opts30),
+ p("versions (versions) res: ~p", [Reason30]),
+
+ p("done"),
+ ok.
+
+
+%%
+%% ---
+%%
+
+start_with_invalid_manager_conf_file1(suite) -> [];
+start_with_invalid_manager_conf_file1(doc) ->
+ "Start with invalid manager config file (1).";
+start_with_invalid_manager_conf_file1(Conf) when is_list(Conf) ->
+ put(tname,swimcf),
+ p("start"),
+ process_flag(trap_exit, true),
+ ConfDir = ?config(manager_conf_dir, Conf),
+ DbDir = ?config(manager_db_dir, Conf),
+
+ Opts = [{versions, [v1]},
+ {config, [{verbosity, trace}, {dir, ConfDir}, {db_dir, DbDir}]}],
+
+ %% --
+ p("write manager config file with invalid IP address (1)"),
+ write_manager_conf(ConfDir,
+ "arne-anka", "4001", "500", "\"bmkEngine\""),
+ ?line {error, Reason11} = config_start(Opts),
+ p("start failed (as expected): ~p", [Reason11]),
+ ?line {failed_reading, _, _, 1, {parse_error, _}} = Reason11,
+ await_config_not_running(),
+
+ %% --
+ p("write manager config file with invalid IP address (2)"),
+ write_manager_conf(ConfDir,
+ "arne_anka", "4001", "500", "\"bmkEngine\""),
+ ?line {error, Reason12} = config_start(Opts),
+ p("start failed (as expected): ~p", [Reason12]),
+ ?line {failed_check, _, _, 2, {invalid_ip_address, _}} = Reason12,
+ await_config_not_running(),
+
+ %% --
+ p("write manager config file with invalid IP address (3)"),
+ write_manager_conf(ConfDir,
+ "9999", "4001", "500", "\"bmkEngine\""),
+ ?line {error, Reason13} = config_start(Opts),
+ p("start failed (as expected): ~p", [Reason13]),
+ ?line {failed_check, _, _, 2, {invalid_ip_address, _}} = Reason13,
+ await_config_not_running(),
+
+ %% --
+ p("write manager config file with invalid port (2)"),
+ write_manager_conf(ConfDir,
+ "[134,138,177,189]", "kalle-anka", "500", "\"bmkEngine\""),
+ ?line {error, Reason21} = config_start(Opts),
+ p("start failed (as expected): ~p", [Reason21]),
+ ?line {failed_reading, _, _, 2, {parse_error, _}} = Reason21,
+ await_config_not_running(),
+
+ %% --
+ p("write manager config file with invalid port (1)"),
+ write_manager_conf(ConfDir,
+ "[134,138,177,189]", "-1", "500", "\"bmkEngine\""),
+ ?line {error, Reason22} = config_start(Opts),
+ p("start failed (as expected): ~p", [Reason22]),
+ ?line {failed_check, _, _, 3, {invalid_integer, _}} = Reason22,
+ await_config_not_running(),
+
+ %% --
+ p("write manager config file with invalid port (3)"),
+ write_manager_conf(ConfDir,
+ "[134,138,177,189]", "\"kalle-anka\"", "500", "\"bmkEngine\""),
+ ?line {error, Reason23} = config_start(Opts),
+ p("start failed (as expected): ~p", [Reason23]),
+ ?line {failed_check, _, _, 3, {invalid_integer, _}} = Reason23,
+ await_config_not_running(),
+
+ %% --
+ p("write manager config file with invalid EngineID (1)"),
+ write_manager_conf(ConfDir,
+ "[134,138,177,189]", "4001", "500", "bmkEngine"),
+ ?line {error, Reason31} = config_start(Opts),
+ p("start failed (as expected): ~p", [Reason31]),
+ ?line {failed_check, _, _, 5, {invalid_string, _}} = Reason31,
+ await_config_not_running(),
+
+ %% --
+ p("write manager config file with invalid EngineID (2)"),
+ write_manager_conf(ConfDir,
+ "[134,138,177,189]", "4001", "500", "{1,2,3}"),
+ ?line {error, Reason32} = config_start(Opts),
+ p("start failed (as expected): ~p", [Reason32]),
+ ?line {failed_check, _, _, 5, {invalid_string, _}} = Reason32,
+ await_config_not_running(),
+
+ %% --
+ p("write manager config file with invalid EngineID (3)"),
+ write_manager_conf(ConfDir,
+ "[134,138,177,189]", "4001", "500", "10101"),
+ ?line {error, Reason33} = config_start(Opts),
+ p("start failed (as expected): ~p", [Reason33]),
+ ?line {failed_check, _, _, 5, {invalid_string, _}} = Reason33,
+ await_config_not_running(),
+
+ %% --
+ p("write manager config file with invalid MMS (1)"),
+ write_manager_conf(ConfDir,
+ "[134,138,177,189]", "4001", "483", "\"bmkEngine\""),
+ ?line {error, Reason41} = config_start(Opts),
+ p("start failed (as expected): ~p", [Reason41]),
+ ?line {failed_check, _, _, 4, {invalid_integer, _}} = Reason41,
+ await_config_not_running(),
+
+ %% --
+ p("write manager config file with invalid MMS (2)"),
+ write_manager_conf(ConfDir,
+ "[134,138,177,189]", "4001", "-1", "\"bmkEngine\""),
+ ?line {error, Reason42} = config_start(Opts),
+ p("start failed (as expected): ~p", [Reason42]),
+ ?line {failed_check, _, _, 4, {invalid_integer, _}} = Reason42,
+ await_config_not_running(),
+
+ %% --
+ p("write manager config file with invalid MMS (3)"),
+ write_manager_conf(ConfDir,
+ "[134,138,177,189]", "4001", "\"kalle-anka\"", "\"bmkEngine\""),
+ ?line {error, Reason43} = config_start(Opts),
+ p("start failed (as expected): ~p", [Reason43]),
+ ?line {failed_check, _, _, 4, {invalid_integer, _}} = Reason43,
+ await_config_not_running(),
+
+ %% --
+ p("write manager config file with invalid MMS (4)"),
+ write_manager_conf(ConfDir,
+ "[134,138,177,189]", "4001", "kalle_anka", "\"bmkEngine\""),
+ ?line {error, Reason44} = config_start(Opts),
+ p("start failed (as expected): ~p", [Reason44]),
+ ?line {failed_check, _, _, 4, {invalid_integer, _}} = Reason44,
+ await_config_not_running(),
+
+ %% --
+ p("write manager config file with unknown option"),
+ write_manager_conf(ConfDir,
+ "{kalle, anka}."),
+ ?line {error, Reason51} = config_start(Opts),
+ p("start failed (as expected): ~p", [Reason51]),
+ ?line {failed_check, _, _, 1, {unknown_config, _}} = Reason51,
+ await_config_not_running(),
+
+ %% --
+ p("write manager config file with unknown option"),
+ write_manager_conf(ConfDir,
+ "kalle_anka."),
+ ?line {error, Reason52} = config_start(Opts),
+ p("start failed (as expected): ~p", [Reason52]),
+ ?line {failed_check, _, _, 1, {unknown_config, _}} = Reason52,
+ await_config_not_running(),
+
+ p("done"),
+ ok.
+
+
+%%
+%% ---
+%%
+
+start_with_invalid_users_conf_file1(suite) -> [];
+start_with_invalid_users_conf_file1(doc) ->
+ "Start with invalid users config file.";
+start_with_invalid_users_conf_file1(Conf) when is_list(Conf) ->
+ put(tname,swiucf),
+ p("start"),
+ process_flag(trap_exit, true),
+ ConfDir = ?config(manager_conf_dir, Conf),
+ DbDir = ?config(manager_db_dir, Conf),
+
+ Opts = [{versions, [v1]},
+ {config, [{verbosity, trace}, {dir, ConfDir}, {db_dir, DbDir}]}],
+
+ write_manager_conf(ConfDir),
+
+ %% --
+ p("write users config file with invalid module (1)"),
+ write_users_conf(ConfDir, [{"kalle", "kalle", "dummy"}]),
+ ?line {error, Reason11} = config_start(Opts),
+ p("start failed (as expected): ~p", [Reason11]),
+ ?line {failed_check, _, _, _, {bad_module, kalle}} = Reason11,
+ await_config_not_running(),
+
+ %% --
+ p("write users config file with invalid module (1)"),
+ write_users_conf(ConfDir, [{"kalle", "snmpm", "dummy"}]),
+ ?line {error, Reason12} = config_start(Opts),
+ p("start failed (as expected): ~p", [Reason12]),
+ ?line {failed_check, _, _, _, {bad_module, _}} = Reason12,
+ await_config_not_running(),
+
+ %% --
+ p("write users config file with invalid module (2)"),
+ write_users_conf(ConfDir, [{"kalle1", "10101", "dummy"}]),
+ ?line {error, Reason13} = config_start(Opts),
+ p("start failed (as expected): ~p", [Reason13]),
+ ?line {failed_check, _, _, _, {bad_module, _}} = Reason13,
+ await_config_not_running(),
+
+ %% --
+ p("write users config file with invalid user tuple (1)"),
+ write_users_conf2(ConfDir, "{kalle, snmpm_user_default}."),
+ ?line {error, Reason21} = config_start(Opts),
+ p("start failed (as expected): ~p", [Reason21]),
+ ?line {failed_check, _, _, _, {bad_user_config, _}} = Reason21,
+ await_config_not_running(),
+
+ %% --
+ p("write users config file with invalid user tuple (2)"),
+ write_users_conf2(ConfDir, "{kalle, snmpm_user_default, kalle, [], olle}."),
+ ?line {error, Reason22} = config_start(Opts),
+ p("start failed (as expected): ~p", [Reason22]),
+ ?line {failed_check, _, _, _, {bad_user_config, _}} = Reason22,
+ await_config_not_running(),
+
+ %% --
+ p("write users config file with invalid user tuple (3)"),
+ write_users_conf2(ConfDir, "snmpm_user_default."),
+ ?line {error, Reason23} = config_start(Opts),
+ p("start failed (as expected): ~p", [Reason23]),
+ ?line {failed_check, _, _, _, {bad_user_config, _}} = Reason23,
+ await_config_not_running(),
+
+ %% --
+ p("write users config file with invalid user tuple (4)"),
+ write_users_conf2(ConfDir, "[kalle, snmpm_user_default, kalle]."),
+ ?line {error, Reason24} = config_start(Opts),
+ p("start failed (as expected): ~p", [Reason24]),
+ ?line {failed_check, _, _, _, {bad_user_config, _}} = Reason24,
+ await_config_not_running(),
+
+ %% --
+ p("write users config file with invalid user agent default config (1)"),
+ write_users_conf2(ConfDir, "{kalle, snmpm_user_default, kalle, olle}."),
+ ?line {error, Reason31} = config_start(Opts),
+ p("start failed (as expected): ~p", [Reason31]),
+ ?line {failed_check, _, _, _, {bad_default_agent_config, _}} = Reason31,
+ await_config_not_running(),
+
+ %% --
+ p("write users config file with invalid user agent default config (2)"),
+ write_users_conf2(ConfDir, "{kalle, snmpm_user_default, kalle, [olle]}."),
+ ?line {error, Reason32} = config_start(Opts),
+ p("start failed (as expected): ~p", [Reason32]),
+ %% ?line {failed_check, _, _, _, {bad_default_agent_config, _}} = Reason32,
+ case Reason32 of
+ {failed_check, _, _, _, {bad_default_agent_config, _}} ->
+ ok;
+ {A, B, C, D} ->
+ exit({bad_error, A, B, C, D})
+ end,
+ await_config_not_running(),
+
+ p("done"),
+ ok.
+
+
+%%
+%% ---
+%%
+
+start_with_invalid_agents_conf_file1(suite) -> [];
+start_with_invalid_agents_conf_file1(doc) ->
+ "Start with invalid agents config file.";
+start_with_invalid_agents_conf_file1(Conf) when is_list(Conf) ->
+ put(tname, swiacf),
+ p("start"),
+ process_flag(trap_exit, true),
+ ConfDir = ?config(manager_conf_dir, Conf),
+ DbDir = ?config(manager_db_dir, Conf),
+
+ Opts = [{versions, [v1]},
+ {config, [{verbosity, trace}, {dir, ConfDir}, {db_dir, DbDir}]}],
+
+ write_manager_conf(ConfDir),
+
+ write_users_conf(ConfDir, [{"swiacf", "snmpm_user_default", "dummy"}]),
+
+ Agent0 = {"swiacf", "\"targ-hobbes\"", "\"comm1\"",
+ "[192,168,0,100]", "162", "\"bmkEngine\"", "1500", "484", "v1",
+ "any", "\"initial\"", "noAuthNoPriv"},
+
+ %% --
+ p("[test 11] write agents config file with invalid user (1)"),
+ Agent11 = setelement(1, Agent0, "kalle-anka"),
+ write_agents_conf(ConfDir, [Agent11]),
+ case config_start(Opts) of
+ {error, Reason11} ->
+ p("start failed (as expected): ~p", [Reason11]),
+ ?line {failed_reading, _, _, _, {parse_error, _}} = Reason11,
+ await_config_not_running();
+ OK_11 ->
+ exit({error, {unexpected_success, "11", OK_11}})
+ end,
+
+ %% --
+ p("[test 21] write agents config file with invalid target name (1)"),
+ Agent21 = setelement(2, Agent0, "targ-hobbes"),
+ write_agents_conf(ConfDir, [Agent21]),
+ case config_start(Opts) of
+ {error, Reason21} ->
+ p("start failed (as expected): ~p", [Reason21]),
+ ?line {failed_reading, _, _, _, {parse_error, _}} = Reason21,
+ await_config_not_running();
+ OK_21 ->
+ exit({error, {unexpected_success, "21", OK_21}})
+ end,
+
+ %% --
+ p("[test 22] write agents config file with invalid target name (2)"),
+ Agent22 = setelement(2, Agent0, "targ_hobbes"),
+ write_agents_conf(ConfDir, [Agent22]),
+ case config_start(Opts) of
+ {error, Reason22} ->
+ p("start failed (as expected): ~p", [Reason22]),
+ ?line {failed_check, _, _, _, {invalid_string, _}} = Reason22,
+ await_config_not_running();
+ OK_22 ->
+ exit({error, {unexpected_success, "22", OK_22}})
+ end,
+
+ %% --
+ p("[test 23] write agents config file with invalid target name (3)"),
+ Agent23 = setelement(2, Agent0, "10101"),
+ write_agents_conf(ConfDir, [Agent23]),
+ case config_start(Opts) of
+ {error, Reason23} ->
+ p("start failed (as expected): ~p", [Reason23]),
+ ?line {failed_check, _, _, _, {invalid_string, _}} = Reason23,
+ await_config_not_running();
+ OK_23 ->
+ exit({error, {unexpected_success, "23", OK_23}})
+ end,
+
+ %% --
+ p("[test 31] write agents config file with invalid community (1)"),
+ Agent31 = setelement(3, Agent0, "targ-hobbes"),
+ write_agents_conf(ConfDir, [Agent31]),
+ case config_start(Opts) of
+ {error, Reason31} ->
+ p("start failed (as expected): ~p", [Reason31]),
+ ?line {failed_reading, _, _, _, {parse_error, _}} = Reason31,
+ await_config_not_running();
+ OK_31 ->
+ exit({error, {unexpected_success, "31", OK_31}})
+ end,
+
+ %% --
+ p("[test 32] write agents config file with invalid community (2)"),
+ Agent32 = setelement(3, Agent0, "targ_hobbes"),
+ write_agents_conf(ConfDir, [Agent32]),
+ case config_start(Opts) of
+ {error, Reason32} ->
+ p("start failed (as expected): ~p", [Reason32]),
+ ?line {failed_check, _, _, _, {invalid_string, _}} = Reason32,
+ await_config_not_running();
+ OK_32 ->
+ exit({error, {unexpected_success, "32", OK_32}})
+ end,
+
+ %% --
+ p("[test 33] write agents config file with invalid community (3)"),
+ Agent33 = setelement(3, Agent0, "10101"),
+ write_agents_conf(ConfDir, [Agent33]),
+ case config_start(Opts) of
+ {error, Reason33} ->
+ p("start failed (as expected): ~p", [Reason33]),
+ ?line {failed_check, _, _, _, {invalid_string, _}} = Reason33,
+ await_config_not_running();
+ OK_33 ->
+ exit({error, {unexpected_success, "33", OK_33}})
+ end,
+
+ %% --
+ p("[test 51] write agents config file with invalid ip (1)"),
+ Agent51 = setelement(4, Agent0, "kalle_anka"),
+ write_agents_conf(ConfDir, [Agent51]),
+ case config_start(Opts) of
+ {error, Reason51} ->
+ p("start failed (as expected): ~p", [Reason51]),
+ ?line {failed_check, _, _, _, {bad_address, _}} = Reason51,
+ await_config_not_running();
+ OK_51 ->
+ exit({error, {unexpected_success, "51", OK_51}})
+ end,
+
+ %% --
+ p("[test 52] write agents config file with invalid ip (2)"),
+ Agent52 = setelement(4, Agent0, "10101"),
+ write_agents_conf(ConfDir, [Agent52]),
+ case config_start(Opts) of
+ {error, Reason52} ->
+ p("start failed (as expected): ~p", [Reason52]),
+ ?line {failed_check, _, _, _, {bad_address, _}} = Reason52,
+ await_config_not_running();
+ OK_52 ->
+ exit({error, {unexpected_success, "52", OK_52}})
+ end,
+
+ %% --
+ p("[test 53] write agents config file with invalid ip (3)"),
+ Agent53 = setelement(4, Agent0, "[192,168,0]"),
+ write_agents_conf(ConfDir, [Agent53]),
+ case config_start(Opts) of
+ {error, Reason53} ->
+ p("start failed (as expected): ~p", [Reason53]),
+ ?line {failed_check, _, _, _, {invalid_ip_address, _}} = Reason53,
+ await_config_not_running();
+ OK_53 ->
+ exit({error, {unexpected_success, "53", OK_53}})
+ end,
+
+ %% --
+ p("[test 54] write agents config file with invalid ip (4)"),
+ Agent54 = setelement(4, Agent0, "[192,168,0,100,99]"),
+ write_agents_conf(ConfDir, [Agent54]),
+ case config_start(Opts) of
+ {error, Reason54} ->
+ p("start failed (as expected): ~p", [Reason54]),
+ ?line {failed_check, _, _, _, {invalid_ip_address, _}} = Reason54,
+ await_config_not_running();
+ OK_54 ->
+ exit({error, {unexpected_success, "54", OK_54}})
+ end,
+
+ %% --
+ p("[test 55] write agents config file with invalid ip (5)"),
+ Agent55 = setelement(4, Agent0, "[192,168,0,arne]"),
+ write_agents_conf(ConfDir, [Agent55]),
+ ?line {error, Reason55} = config_start(Opts),
+ p("start failed (as expected): ~p", [Reason55]),
+ ?line {failed_check, _, _, _, {invalid_ip_address, _}} = Reason55,
+ await_config_not_running(),
+
+ %% --
+ p("[test 61] write agents config file with invalid port (1)"),
+ Agent61 = setelement(5, Agent0, "kalle_anka"),
+ write_agents_conf(ConfDir, [Agent61]),
+ ?line {error, Reason61} = config_start(Opts),
+ p("start failed (as expected): ~p", [Reason61]),
+ ?line {failed_check, _, _, _, {invalid_integer, _}} = Reason61,
+ await_config_not_running(),
+
+ %% --
+ p("[test 62] write agents config file with invalid port (2)"),
+ Agent62 = setelement(5, Agent0, "-1"),
+ write_agents_conf(ConfDir, [Agent62]),
+ ?line {error, Reason62} = config_start(Opts),
+ p("start failed (as expected): ~p", [Reason62]),
+ ?line {failed_check, _, _, _, {invalid_integer, _}} = Reason62,
+ await_config_not_running(),
+
+ %% --
+ p("[test 63] write agents config file with invalid port (3)"),
+ Agent63 = setelement(5, Agent0, "\"100\""),
+ write_agents_conf(ConfDir, [Agent63]),
+ ?line {error, Reason63} = config_start(Opts),
+ p("start failed (as expected): ~p", [Reason63]),
+ ?line {failed_check, _, _, _, {invalid_integer, _}} = Reason63,
+ await_config_not_running(),
+
+ %% --
+ p("[test 71] write agents config file with invalid engine-id (1)"),
+ Agent71 = setelement(6, Agent0, "kalle_anka"),
+ write_agents_conf(ConfDir, [Agent71]),
+ ?line {error, Reason71} = config_start(Opts),
+ p("start failed (as expected): ~p", [Reason71]),
+ ?line {failed_check, _, _, _, {invalid_string, _}} = Reason71,
+ await_config_not_running(),
+
+ %% --
+ p("[test 72] write agents config file with invalid engine-id (2)"),
+ Agent72 = setelement(6, Agent0, "10101"),
+ write_agents_conf(ConfDir, [Agent72]),
+ ?line {error, Reason72} = config_start(Opts),
+ p("start failed (as expected): ~p", [Reason72]),
+ ?line {failed_check, _, _, _, {invalid_string, _}} = Reason72,
+ await_config_not_running(),
+
+ %% --
+ p("[test 81] write agents config file with invalid timeout (1)"),
+ Agent81 = setelement(7, Agent0, "kalle_anka"),
+ write_agents_conf(ConfDir, [Agent81]),
+ ?line {error, Reason81} = config_start(Opts),
+ p("start failed (as expected): ~p", [Reason81]),
+ ?line {failed_check, _, _, _, {invalid_timer, _}} = Reason81,
+ await_config_not_running(),
+
+ %% --
+ p("[test 82] write agents config file with invalid timeout (2)"),
+ Agent82 = setelement(7, Agent0, "-1"),
+ write_agents_conf(ConfDir, [Agent82]),
+ ?line {error, Reason82} = config_start(Opts),
+ p("start failed (as expected): ~p", [Reason82]),
+ ?line {failed_check, _, _, _, {invalid_timer, _}} = Reason82,
+ await_config_not_running(),
+
+ %% --
+ p("[test 83] write agents config file with invalid timeout (3)"),
+ Agent83 = setelement(7, Agent0, "{1000, 1, 10, kalle}"),
+ write_agents_conf(ConfDir, [Agent83]),
+ ?line {error, Reason83} = config_start(Opts),
+ p("start failed (as expected): ~p", [Reason83]),
+ ?line {failed_check, _, _, _, {invalid_timer, _}} = Reason83,
+ await_config_not_running(),
+
+ %% --
+ p("[test 84] write agents config file with invalid timeout (4)"),
+ Agent84 = setelement(7, Agent0, "{1000, -1, 10, 10}"),
+ write_agents_conf(ConfDir, [Agent84]),
+ ?line {error, Reason84} = config_start(Opts),
+ p("start failed (as expected): ~p", [Reason84]),
+ ?line {failed_check, _, _, _, {invalid_timer, _}} = Reason84,
+ await_config_not_running(),
+
+ %% --
+ p("[test 85] write agents config file with invalid timeout (5)"),
+ Agent85 = setelement(7, Agent0, "{1000, 1, -100, 10}"),
+ write_agents_conf(ConfDir, [Agent85]),
+ ?line {error, Reason85} = config_start(Opts),
+ p("start failed (as expected): ~p", [Reason85]),
+ ?line {failed_check, _, _, _, {invalid_timer, _}} = Reason85,
+ await_config_not_running(),
+
+ %% --
+ p("[test 86] write agents config file with invalid timeout (6)"),
+ Agent86 = setelement(7, Agent0, "{1000, 1, 100, -1}"),
+ write_agents_conf(ConfDir, [Agent86]),
+ ?line {error, Reason86} = config_start(Opts),
+ p("start failed (as expected): ~p", [Reason86]),
+ ?line {failed_check, _, _, _, {invalid_timer, _}} = Reason86,
+ await_config_not_running(),
+
+ %% --
+ p("[test 91] write agents config file with invalid max-message-size (1)"),
+ Agent91 = setelement(8, Agent0, "483"),
+ write_agents_conf(ConfDir, [Agent91]),
+ ?line {error, Reason91} = config_start(Opts),
+ p("start failed (as expected): ~p", [Reason91]),
+ ?line {failed_check, _, _, _, {invalid_packet_size, _}} = Reason91,
+ await_config_not_running(),
+
+ %% --
+ p("[test 92] write agents config file with invalid max-message-size (2)"),
+ Agent92 = setelement(8, Agent0, "kalle_anka"),
+ write_agents_conf(ConfDir, [Agent92]),
+ ?line {error, Reason92} = config_start(Opts),
+ p("start failed (as expected): ~p", [Reason92]),
+ ?line {failed_check, _, _, _, {invalid_packet_size, _}} = Reason92,
+ await_config_not_running(),
+
+ %% --
+ p("[test A1] write agents config file with invalid version (1)"),
+ AgentA1 = setelement(9, Agent0, "1"),
+ write_agents_conf(ConfDir, [AgentA1]),
+ ?line {error, ReasonA1} = config_start(Opts),
+ p("start failed (as expected): ~p", [ReasonA1]),
+ ?line {failed_check, _, _, _, {bad_version, _}} = ReasonA1,
+ await_config_not_running(),
+
+ %% --
+ p("[test A2] write agents config file with invalid version (2)"),
+ AgentA2 = setelement(9, Agent0, "v30"),
+ write_agents_conf(ConfDir, [AgentA2]),
+ ?line {error, ReasonA2} = config_start(Opts),
+ p("start failed (as expected): ~p", [ReasonA2]),
+ ?line {failed_check, _, _, _, {bad_version, _}} = ReasonA2,
+ await_config_not_running(),
+
+ %% --
+ p("[test B1] write agents config file with invalid sec-model (1)"),
+ AgentB1 = setelement(10, Agent0, "\"any\""),
+ write_agents_conf(ConfDir, [AgentB1]),
+ ?line {error, ReasonB1} = config_start(Opts),
+ p("start failed (as expected): ~p", [ReasonB1]),
+ ?line {failed_check, _, _, _, {invalid_sec_model, _}} = ReasonB1,
+ await_config_not_running(),
+
+ %% --
+ p("[test B2] write agents config file with invalid sec-model (2)"),
+ AgentB2 = setelement(10, Agent0, "v3"),
+ write_agents_conf(ConfDir, [AgentB2]),
+ ?line {error, ReasonB2} = config_start(Opts),
+ p("start failed (as expected): ~p", [ReasonB2]),
+ ?line {failed_check, _, _, _, {invalid_sec_model, _}} = ReasonB2,
+ await_config_not_running(),
+
+ %% --
+ p("[test C1] write agents config file with invalid sec-name (1)"),
+ AgentC1 = setelement(11, Agent0, "initial"),
+ write_agents_conf(ConfDir, [AgentC1]),
+ case config_start(Opts) of
+ {error, ReasonC1} ->
+ p("start failed (as expected): ~p", [ReasonC1]),
+ ?line {failed_check, _, _, _, {bad_sec_name, _}} = ReasonC1,
+ await_config_not_running();
+ OK_C1 ->
+ exit({error, {unexpected_success, "C1", OK_C1}})
+ end,
+
+ %% --
+ p("[test C2] write agents config file with invalid sec-name (2)"),
+ AgentC2 = setelement(11, Agent0, "10101"),
+ write_agents_conf(ConfDir, [AgentC2]),
+ case config_start(Opts) of
+ {error, ReasonC2} ->
+ p("start failed (as expected): ~p", [ReasonC2]),
+ ?line {failed_check, _, _, _, {bad_sec_name, _}} = ReasonC2,
+ await_config_not_running();
+ OK_C2 ->
+ exit({error, {unexpected_success, "C2", OK_C2}})
+ end,
+
+ %% --
+ p("[test D1] write agents config file with invalid sec-level (1)"),
+ AgentD1 = setelement(12, Agent0, "\"noAuthNoPriv\""),
+ write_agents_conf(ConfDir, [AgentD1]),
+ case config_start(Opts) of
+ {error, ReasonD1} ->
+ p("start failed (as expected): ~p", [ReasonD1]),
+ ?line {failed_check, _, _, _, {invalid_sec_level, _}} = ReasonD1,
+ await_config_not_running();
+ OK_D1 ->
+ exit({error, {unexpected_success, "D1", OK_D1}})
+ end,
+
+ %% --
+ p("[test D2] write agents config file with invalid sec-level (2)"),
+ AgentD2 = setelement(12, Agent0, "99"),
+ write_agents_conf(ConfDir, [AgentD2]),
+ case config_start(Opts) of
+ {error, ReasonD2} ->
+ p("start failed (as expected): ~p", [ReasonD2]),
+ ?line {failed_check, _, _, _, {invalid_sec_level, _}} = ReasonD2,
+ await_config_not_running();
+ OK_D2 ->
+ exit({error, {unexpected_success, "D2", OK_D2}})
+ end,
+
+ %% --
+ p("[test E1] write agents config file with invalid agent (1)"),
+ write_agents_conf2(ConfDir, "{swiacf, \"targ-hobbes\"}."),
+ case config_start(Opts) of
+ {error, ReasonE1} ->
+ p("start failed (as expected): ~p", [ReasonE1]),
+ ?line {failed_check, _, _, _, {bad_agent_config, _}} = ReasonE1,
+ await_config_not_running();
+ OK_E1 ->
+ exit({error, {unexpected_success, "E1", OK_E1}})
+ end,
+
+ p("done"),
+ ok.
+
+
+%%
+%% ---
+%%
+
+start_with_invalid_usm_conf_file1(suite) -> [];
+start_with_invalid_usm_conf_file1(doc) ->
+ "Start with invalid usm config file.";
+start_with_invalid_usm_conf_file1(Conf) when is_list(Conf) ->
+ put(tname,swiusmcf),
+ p("start"),
+ process_flag(trap_exit, true),
+
+ case ?CRYPTO_START() of
+ ok ->
+ case ?CRYPTO_SUPPORT() of
+ {no, Reason} ->
+ ?SKIP({unsupported_encryption, Reason});
+ yes ->
+ ok
+ end;
+ {error, Reason} ->
+ ?SKIP({failed_starting_crypto, Reason})
+ end,
+
+ ConfDir = ?config(manager_conf_dir, Conf),
+ DbDir = ?config(manager_db_dir, Conf),
+
+ Opts = [{versions, [v1,v2,v3]},
+ {config, [{verbosity, trace}, {dir, ConfDir}, {db_dir, DbDir}]}],
+
+ write_manager_conf(ConfDir),
+
+ write_users_conf(ConfDir, [{"swiacf", "snmpm_user_default", "dummy"}]),
+
+ Usm0 = {"\"bmkEngine\"", "\"swiusmcf\"",
+ "usmNoAuthProtocol", "[]",
+ "usmNoPrivProtocol", "[]"},
+
+ Usm1 = {"\"bmkEngine\"", "\"swiusmcf\"", "\"kalle\"",
+ "usmNoAuthProtocol", "[]",
+ "usmNoPrivProtocol", "[]"},
+
+ %% --
+ p("[test 11] write usm config file with invalid engine-id (1)"),
+ Usm11 = setelement(1, Usm0, "kalle-anka"),
+ write_usm_conf(ConfDir, [Usm11]),
+ ?line {error, Reason11} = config_start(Opts),
+ p("start failed (as expected): ~p", [Reason11]),
+ ?line {failed_reading, _, _, _, {parse_error, _}} = Reason11,
+ await_config_not_running(),
+
+ %% --
+ p("[test 12] write usm config file with invalid engine-id (2)"),
+ Usm12 = setelement(1, Usm0, "kalle_anka"),
+ write_usm_conf(ConfDir, [Usm12]),
+ ?line {error, Reason12} = config_start(Opts),
+ p("start failed (as expected): ~p", [Reason12]),
+ ?line {failed_check, _, _, _, {bad_usm_engine_id, _}} = Reason12,
+ await_config_not_running(),
+
+ %% --
+ p("[test 13] write usm config file with invalid engine-id (3)"),
+ Usm13 = setelement(1, Usm1, "10101"),
+ write_usm_conf(ConfDir, [Usm13]),
+ ?line {error, Reason13} = config_start(Opts),
+ p("start failed (as expected): ~p", [Reason13]),
+ ?line {failed_check, _, _, _, {bad_usm_engine_id, _}} = Reason13,
+ await_config_not_running(),
+
+ %% --
+ p("[test 21] write usm config file with invalid user-name (1)"),
+ Usm21 = setelement(2, Usm0, "kalle_anka"),
+ write_usm_conf(ConfDir, [Usm21]),
+ ?line {error, Reason21} = config_start(Opts),
+ p("start failed (as expected): ~p", [Reason21]),
+ ?line {failed_check, _, _, _, {bad_usm_user_name, _}} = Reason21,
+ await_config_not_running(),
+
+ %% --
+ p("[test 22] write usm config file with invalid user-name (1)"),
+ Usm22 = setelement(2, Usm1, "10101"),
+ write_usm_conf(ConfDir, [Usm22]),
+ ?line {error, Reason22} = config_start(Opts),
+ p("start failed (as expected): ~p", [Reason22]),
+ ?line {failed_check, _, _, _, {bad_usm_user_name, _}} = Reason22,
+ await_config_not_running(),
+
+ %% --
+ p("[test 31] write usm config file with invalid sec-name (1)"),
+ Usm31 = setelement(3, Usm1, "kalle_anka"),
+ write_usm_conf(ConfDir, [Usm31]),
+ ?line {error, Reason31} = config_start(Opts),
+ p("start failed (as expected): ~p", [Reason31]),
+ ?line {failed_check, _, _, _, {bad_usm_sec_name, _}} = Reason31,
+ await_config_not_running(),
+
+ %% --
+ p("[test 32] write usm config file with invalid sec-name (2)"),
+ Usm32 = setelement(3, Usm1, "10101"),
+ write_usm_conf(ConfDir, [Usm32]),
+ ?line {error, Reason32} = config_start(Opts),
+ p("start failed (as expected): ~p", [Reason32]),
+ ?line {failed_check, _, _, _, {bad_usm_sec_name, _}} = Reason32,
+ await_config_not_running(),
+
+ %% --
+ p("[test 41] write usm config file with invalid auth-protocol (1)"),
+ Usm41 = setelement(3, Usm0, "\"usmNoAuthProtocol\""),
+ write_usm_conf(ConfDir, [Usm41]),
+ ?line {error, Reason41} = config_start(Opts),
+ p("start failed (as expected): ~p", [Reason41]),
+ ?line {failed_check, _, _, _, {invalid_auth_protocol, _}} = Reason41,
+ await_config_not_running(),
+
+ %% --
+ p("[test 42] write usm config file with invalid auth-protocol (2)"),
+ Usm42 = setelement(3, Usm0, "kalle"),
+ write_usm_conf(ConfDir, [Usm42]),
+ ?line {error, Reason42} = config_start(Opts),
+ p("start failed (as expected): ~p", [Reason42]),
+ ?line {failed_check, _, _, _, {invalid_auth_protocol, _}} = Reason42,
+ await_config_not_running(),
+
+ %% --
+ p("[test 43] write usm config file with invalid auth-protocol (3)"),
+ Usm43 = setelement(3, Usm0, "10101"),
+ write_usm_conf(ConfDir, [Usm43]),
+ ?line {error, Reason43} = config_start(Opts),
+ p("start failed (as expected): ~p", [Reason43]),
+ ?line {failed_check, _, _, _, {invalid_auth_protocol, _}} = Reason43,
+ await_config_not_running(),
+
+ %% --
+ p("[test 51] write usm config file with invalid auth-key (1)"),
+ Usm51 = setelement(3, Usm0, "usmHMACMD5AuthProtocol"),
+ write_usm_conf(ConfDir, [Usm51]),
+ ?line {error, Reason51} = config_start(Opts),
+ p("start failed (as expected): ~p", [Reason51]),
+ ?line {failed_check, _, _, _, {invalid_auth_key, _, _}} = Reason51,
+ await_config_not_running(),
+
+ %% --
+ p("[test 52] write usm config file with invalid auth-key (2)"),
+ Usm52 = setelement(4, Usm51, "[1,2,3,4,5,6,7,8,9,0,1,2,3,4,5]"),
+ write_usm_conf(ConfDir, [Usm52]),
+ ?line {error, Reason52} = config_start(Opts),
+ p("start failed (as expected): ~p", [Reason52]),
+ ?line {failed_check, _, _, _, {invalid_auth_key, _, 15}} = Reason52,
+ await_config_not_running(),
+
+ %% --
+ p("[test 53] write usm config file with invalid auth-key (3)"),
+ Usm53 = setelement(4, Usm51, "[1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7]"),
+ write_usm_conf(ConfDir, [Usm53]),
+ ?line {error, Reason53} = config_start(Opts),
+ p("start failed (as expected): ~p", [Reason53]),
+ ?line {failed_check, _, _, _, {invalid_auth_key, _, 17}} = Reason53,
+ await_config_not_running(),
+
+ %% --
+ p("[test 54] write usm config file with invalid auth-key (4)"),
+ Usm54 = setelement(4, Usm51, "[1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,kalle]"),
+ write_usm_conf(ConfDir, [Usm54]),
+ %% ?line ok = crypto:start(), %% Varf�r k�r den redan?
+ ?line crypto:start(), %% Make sure it's started...
+ ?line {error, Reason54} = config_start(Opts),
+ ?line ok = crypto:stop(),
+ p("start failed (as expected): ~p", [Reason54]),
+ ?line {failed_check, _, _, _, {invalid_auth_key, _}} = Reason54,
+ await_config_not_running(),
+
+ %% --
+ p("[test 55] write usm config file with invalid auth-key (5)"),
+ Usm55 = setelement(4, Usm51, "arne_anka"),
+ write_usm_conf(ConfDir, [Usm55]),
+ ?line {error, Reason55} = config_start(Opts),
+ p("start failed (as expected): ~p", [Reason55]),
+ ?line {failed_check, _, _, _, {invalid_auth_key, _}} = Reason55,
+ await_config_not_running(),
+
+ %% --
+ p("[test 56] write usm config file with invalid auth-key (6)"),
+ Usm56 = setelement(4, Usm51, "10101"),
+ write_usm_conf(ConfDir, [Usm56]),
+ ?line {error, Reason56} = config_start(Opts),
+ p("start failed (as expected): ~p", [Reason56]),
+ ?line {failed_check, _, _, _, {invalid_auth_key, _}} = Reason56,
+ await_config_not_running(),
+
+ %% --
+ p("[test 57] write usm config file with invalid auth-key (7)"),
+ Usm57 = setelement(3, Usm0, "usmHMACSHAAuthProtocol"),
+ write_usm_conf(ConfDir, [Usm57]),
+ ?line {error, Reason57} = config_start(Opts),
+ p("start failed (as expected): ~p", [Reason57]),
+ ?line {failed_check, _, _, _, {invalid_auth_key, _, _}} = Reason57,
+ await_config_not_running(),
+
+ %% --
+ p("[test 58] write usm config file with invalid auth-key (8)"),
+ Usm58 = setelement(4, Usm57, "[1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6]"),
+ write_usm_conf(ConfDir, [Usm58]),
+ ?line {error, Reason58} = config_start(Opts),
+ p("start failed (as expected): ~p", [Reason58]),
+ ?line {failed_check, _, _, _, {invalid_auth_key, _, 16}} = Reason58,
+ await_config_not_running(),
+
+ %% --
+ p("[test 59] write usm config file with invalid auth-key (9)"),
+ Usm59 = setelement(4, Usm57, "[1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,ka]"),
+ write_usm_conf(ConfDir, [Usm59]),
+ ?line ok = crypto:start(),
+ ?line {error, Reason59} = config_start(Opts),
+ ?line ok = crypto:stop(),
+ p("start failed (as expected): ~p", [Reason59]),
+ ?line {failed_check, _, _, _, {invalid_auth_key, _}} = Reason59,
+ await_config_not_running(),
+
+ %% --
+ p("[test 5A] write usm config file with valid auth-key when crypto not started (10)"),
+ Usm5A = setelement(4, Usm57, "[1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0]"),
+ write_usm_conf(ConfDir, [Usm5A]),
+ ?line {error, Reason5A} = config_start(Opts),
+ p("start failed (as expected): ~p", [Reason5A]),
+ ?line {failed_check, _, _, _, {unsupported_crypto, _}} = Reason5A,
+ await_config_not_running(),
+
+ %% --
+ p("[test 61] write usm config file with invalid priv-protocol (1)"),
+ Usm61 = setelement(5, Usm0, "\"usmNoPrivProtocol\""),
+ write_usm_conf(ConfDir, [Usm61]),
+ ?line {error, Reason61} = config_start(Opts),
+ p("start failed (as expected): ~p", [Reason61]),
+ ?line {failed_check, _, _, _, {invalid_priv_protocol, _}} = Reason61,
+ await_config_not_running(),
+
+ %% --
+ p("[test 62] write usm config file with invalid priv-protocol (2)"),
+ Usm62 = setelement(5, Usm0, "kalle"),
+ write_usm_conf(ConfDir, [Usm62]),
+ ?line {error, Reason62} = config_start(Opts),
+ p("start failed (as expected): ~p", [Reason62]),
+ ?line {failed_check, _, _, _, {invalid_priv_protocol, _}} = Reason62,
+ await_config_not_running(),
+
+ %% --
+ p("[test 63] write usm config file with invalid priv-protocol (3)"),
+ Usm63 = setelement(5, Usm0, "10101"),
+ write_usm_conf(ConfDir, [Usm63]),
+ ?line {error, Reason63} = config_start(Opts),
+ p("start failed (as expected): ~p", [Reason63]),
+ ?line {failed_check, _, _, _, {invalid_priv_protocol, _}} = Reason63,
+ await_config_not_running(),
+
+ %% --
+ p("[test 71] write usm config file with invalid priv-key (1)"),
+ Usm71 = setelement(5, Usm0, "usmDESPrivProtocol"),
+ write_usm_conf(ConfDir, [Usm71]),
+ ?line {error, Reason71} = config_start(Opts),
+ p("start failed (as expected): ~p", [Reason71]),
+ ?line {failed_check, _, _, _, {invalid_priv_key, _, _}} = Reason71,
+ await_config_not_running(),
+
+ %% --
+ p("[test 72] write usm config file with invalid priv-key (2)"),
+ Usm72 = setelement(6, Usm71, "[1,2,3,4,5,6,7,8,9,0,1,2,3,4,5]"),
+ write_usm_conf(ConfDir, [Usm72]),
+ ?line {error, Reason72} = config_start(Opts),
+ p("start failed (as expected): ~p", [Reason72]),
+ ?line {failed_check, _, _, _, {invalid_priv_key, _, 15}} = Reason72,
+ await_config_not_running(),
+
+ %% --
+ p("[test 73] write usm config file with invalid priv-key (3)"),
+ Usm73 = setelement(6, Usm71, "[1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7]"),
+ write_usm_conf(ConfDir, [Usm73]),
+ ?line {error, Reason73} = config_start(Opts),
+ p("start failed (as expected): ~p", [Reason73]),
+ ?line {failed_check, _, _, _, {invalid_priv_key, _, 17}} = Reason73,
+ await_config_not_running(),
+
+ %% --
+ p("[test 74] write usm config file with invalid priv-key (4)"),
+ Usm74 = setelement(6, Usm71, "[1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,kalle]"),
+ write_usm_conf(ConfDir, [Usm74]),
+ ?line ok = crypto:start(),
+ ?line {error, Reason74} = config_start(Opts),
+ ?line ok = crypto:stop(),
+ p("start failed (as expected): ~p", [Reason74]),
+ ?line {failed_check, _, _, _, {invalid_priv_key, _}} = Reason74,
+ await_config_not_running(),
+
+ %% --
+ p("[test 75] write usm config file with invalid priv-key (5)"),
+ Usm75 = setelement(6, Usm71, "arne_anka"),
+ write_usm_conf(ConfDir, [Usm75]),
+ ?line {error, Reason75} = config_start(Opts),
+ p("start failed (as expected): ~p", [Reason75]),
+ ?line {failed_check, _, _, _, {invalid_priv_key, _}} = Reason75,
+ await_config_not_running(),
+
+ %% --
+ p("[test 76] write usm config file with invalid priv-key (6)"),
+ Usm76 = setelement(6, Usm71, "10101"),
+ write_usm_conf(ConfDir, [Usm76]),
+ ?line {error, Reason76} = config_start(Opts),
+ p("start failed (as expected): ~p", [Reason76]),
+ ?line {failed_check, _, _, _, {invalid_priv_key, _}} = Reason76,
+ await_config_not_running(),
+
+ %% --
+ p("[test 77] write usm config file with valid priv-key when crypto not started (7)"),
+ Usm77 = setelement(6, Usm71, "[1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6]"),
+ write_usm_conf(ConfDir, [Usm77]),
+ ?line {error, Reason77} = config_start(Opts),
+ p("start failed (as expected): ~p", [Reason77]),
+ ?line {failed_check, _, _, _, {unsupported_crypto, _}} = Reason77,
+ await_config_not_running(),
+
+ %% --
+ p("[test 78] write usm config file with invalid usm (1)"),
+ write_usm_conf2(ConfDir, "{\"bmkEngine\", \"swiusmcf\"}."),
+ ?line {error, Reason81} = config_start(Opts),
+ p("start failed (as expected): ~p", [Reason81]),
+ ?line {failed_check, _, _, _, {bad_usm_config, _}} = Reason81,
+ await_config_not_running(),
+
+ p("done"),
+ ok.
+
+
+%%
+%% ---
+%%
+
+normal_op(doc) ->
+ "A collection of tests for normal operation";
+normal_op(suite) ->
+ [
+ system,
+ agents,
+ users,
+ usm_users,
+ counter,
+ stats_counter
+ ].
+
+
+%%
+%% ---
+%%
+
+system(doc) ->
+ "Various system related operations with the snmp manager config";
+system(suite) ->
+ [
+ simple_system_op
+ ].
+
+simple_system_op(suite) -> [];
+simple_system_op(doc) ->
+ "Access some of the known system info and some \n"
+ "system info that does not exist.";
+simple_system_op(Conf) when is_list(Conf) ->
+ put(tname,sso),
+ p("start"),
+ ConfDir = ?config(manager_conf_dir, Conf),
+ DbDir = ?config(manager_db_dir, Conf),
+
+ write_manager_conf(ConfDir),
+
+ Opts = [{versions, [v1]},
+ {config, [{verbosity, trace}, {dir, ConfDir}, {db_dir, DbDir}]}],
+
+ p("start config"),
+ ?line {ok, _Pid} = config_start(Opts),
+
+ p("retreive various configs"),
+ ?line {ok, _Time} = snmpm_config:system_start_time(),
+ ?line {ok, _EngineId} = snmpm_config:get_engine_id(),
+ ?line {ok, _MMS} = snmpm_config:get_engine_max_message_size(),
+
+ p("attempt to retreive nonexisting"),
+ ?line {error, not_found} = snmpm_config:system_info(kalle),
+
+ ?line ok = config_stop(),
+ await_config_not_running(),
+
+ p("done"),
+ ok.
+
+
+%%
+%% ---
+%%
+
+users(doc) ->
+ "Various users related operations with the snmp manager config";
+users(suite) ->
+ [
+ register_user_using_file,
+ register_user_using_function,
+ register_user_failed_using_function1
+ ].
+
+
+%%
+%% ---
+%%
+
+register_user_using_file(suite) -> [];
+register_user_using_file(doc) ->
+ "Register user using the 'users.conf' file.";
+register_user_using_file(Conf) when is_list(Conf) ->
+ put(tname,ruufi),
+ p("start"),
+ process_flag(trap_exit, true),
+ _ConfDir = ?config(manager_conf_dir, Conf),
+ _DbDir = ?config(manager_db_dir, Conf),
+ ?SKIP(not_yet_implemented).
+
+
+%%
+%% ---
+%%
+
+register_user_using_function(suite) -> [];
+register_user_using_function(doc) ->
+ "Register user using the API (function).";
+register_user_using_function(Conf) when is_list(Conf) ->
+ put(tname,ruufu),
+ p("start"),
+ process_flag(trap_exit, true),
+ _ConfDir = ?config(manager_conf_dir, Conf),
+ _DbDir = ?config(manager_db_dir, Conf),
+ ?SKIP(not_yet_implemented).
+
+
+%%
+%% ---
+%%
+
+register_user_failed_using_function1(suite) -> [];
+register_user_failed_using_function1(doc) ->
+ "Register user failed using incorrect arguments to API (function).";
+register_user_failed_using_function1(Conf) when is_list(Conf) ->
+ put(tname,rufufu1),
+ p("start"),
+ process_flag(trap_exit, true),
+ _ConfDir = ?config(manager_conf_dir, Conf),
+ _DbDir = ?config(manager_db_dir, Conf),
+ ?SKIP(not_yet_implemented).
+
+
+%%
+%% ---
+%%
+
+agents(doc) ->
+ "Various agents related operations with the snmp manager config";
+agents(suite) ->
+ [
+ register_agent_using_file,
+ register_agent_using_function,
+ register_agent_failed_using_function1
+ ].
+
+
+%%
+%% ---
+%%
+
+register_agent_using_file(suite) -> [];
+register_agent_using_file(doc) ->
+ "Register agents using the 'agents'conf' file.";
+register_agent_using_file(Conf) when is_list(Conf) ->
+ put(tname,raufi),
+ p("start"),
+ process_flag(trap_exit, true),
+ ConfDir = ?config(manager_conf_dir, Conf),
+ DbDir = ?config(manager_db_dir, Conf),
+
+ Opts = [{versions, [v1]},
+ {config, [{verbosity, trace}, {dir, ConfDir}, {db_dir, DbDir}]}],
+
+
+ %% --
+ p("write manager config file"),
+ write_manager_conf(ConfDir),
+
+ %% --
+ p("write users config file"),
+ UserId1 = raufi1,
+ UserId1Str = str(UserId1),
+ UserId2 = raufi2,
+ UserId2Str = str(UserId2),
+ User1 = {UserId1Str, "snmpm_user_default", "dummy1"},
+ User2 = {UserId2Str, "snmpm_user_default", "dummy2", "[{version, v1}]"},
+ write_users_conf(ConfDir, [User1, User2]),
+
+ %% --
+ p("write agents config file"),
+ AgentAddr1 = [192,168,0,101],
+ AgentAddr1Str = str(AgentAddr1),
+ AgentPort1 = 162,
+ AgentPort1Str = str(AgentPort1),
+ EngineID1 = "bmkEngine1",
+ EngineID1Str = str(EngineID1),
+ MMS1 = 1024,
+ MMS1Str = str(MMS1),
+ AgentAddr2 = [192,168,0,102],
+ AgentAddr2Str = str(AgentAddr2),
+ AgentPort2 = 162,
+ AgentPort2Str = str(AgentPort2),
+ EngineID2 = "bmkEngine2",
+ EngineID2Str = str(EngineID2),
+ MMS2 = 512,
+ MMS2Str = str(MMS2),
+ Agent1Str = {UserId1Str, "\"targ-hobbes1\"", "\"comm\"",
+ AgentAddr1Str, AgentPort1Str, EngineID1Str,
+ "1000", MMS1Str, "v1",
+ "any", "\"initial\"", "noAuthNoPriv"},
+ Agent2Str = {UserId2Str, "\"targ-hobbes2\"", "\"comm\"",
+ AgentAddr2Str, AgentPort2Str, EngineID2Str,
+ "1500", MMS2Str, "v1",
+ "any", "\"initial\"", "noAuthNoPriv"},
+ write_agents_conf(ConfDir, [Agent1Str, Agent2Str]),
+
+ %% --
+ p("start the config process"),
+ ?line {ok, _Pid} = config_start(Opts),
+
+ %% --
+ p("which agents"),
+ ?line [_, _] = All = snmpm_config:which_agents(),
+ p("all agents: ~n ~p", [All]),
+ ?line [A1] = snmpm_config:which_agents(UserId1),
+ p("agents belonging to ~w: ~n ~p", [UserId1, A1]),
+ ?line [A2] = snmpm_config:which_agents(UserId2),
+ p("agents belonging to ~w: ~n ~p", [UserId2, A2]),
+
+ %% --
+ p("All info for agent <~w,~w>", [AgentAddr1, AgentPort1]),
+ ?line {ok, AllInfo1} =
+ snmpm_config:agent_info(AgentAddr1, AgentPort1, all),
+ p("all agent info for agent: ~n ~p", [AllInfo1]),
+
+ %% --
+ p("EngineID (~p) for agent <~w,~w>", [EngineID1, AgentAddr1, AgentPort1]),
+ ?line {ok, EngineID1} =
+ snmpm_config:agent_info(AgentAddr1, AgentPort1, engine_id),
+
+
+ %% --
+ p("All info for agent <~w,~w>", [AgentAddr2, AgentPort2]),
+ ?line {ok, AllInfo2} =
+ snmpm_config:agent_info(AgentAddr2, AgentPort2, all),
+ p("all agent info for agent: ~n ~p", [AllInfo2]),
+
+ %% --
+ p("EngineID (~p) for agent <~w,~w>", [EngineID2, AgentAddr2, AgentPort2]),
+ ?line {ok, EngineID2} =
+ snmpm_config:agent_info(AgentAddr2, AgentPort2, engine_id),
+
+ %% --
+ ?line {ok, MMS2} =
+ snmpm_config:agent_info(AgentAddr2, AgentPort2, max_message_size),
+ NewMMS21 = 2048,
+ p("try update agent info max-message-size to ~w for agent <~w,~w>",
+ [NewMMS21, AgentAddr2, AgentPort2]),
+ ?line ok = snmpm_config:update_agent_info(UserId2, AgentAddr2, AgentPort2,
+ max_message_size, NewMMS21),
+ ?line {ok, NewMMS21} =
+ snmpm_config:agent_info(AgentAddr2, AgentPort2, max_message_size),
+
+ %% --
+ p("try (and fail) to update agent info max-message-size to ~w "
+ "for agent <~w,~w> "
+ "with user ~w (not owner)",
+ [NewMMS21, AgentAddr2, AgentPort2, UserId1]),
+ ?line {error, Reason01} =
+ snmpm_config:update_agent_info(UserId1, AgentAddr2, AgentPort2,
+ max_message_size, NewMMS21),
+ p("expected failure. Reason01: ~p", [Reason01]),
+ ?line {ok, NewMMS21} =
+ snmpm_config:agent_info(AgentAddr2, AgentPort2, max_message_size),
+
+ %% --
+ NewMMS22 = 400,
+ p("try (and fail) to update agent info max-message-size to ~w "
+ "for agent <~w,~w>",
+ [NewMMS22, AgentAddr2, AgentPort2]),
+ ?line {error, Reason02} =
+ snmpm_config:update_agent_info(UserId1, AgentAddr2, AgentPort2,
+ max_message_size, NewMMS22),
+ p("expected failure. Reason02: ~p", [Reason02]),
+
+ %% --
+ p("stop config process"),
+ ?line ok = snmpm_config:stop(),
+ await_config_not_running(),
+
+ %% --
+ p("done"),
+ ok.
+
+
+%%
+%% ---
+%%
+
+register_agent_using_function(suite) -> [];
+register_agent_using_function(doc) ->
+ "Register agents using the API (function).";
+register_agent_using_function(Conf) when is_list(Conf) ->
+ put(tname,raufu),
+ p("start"),
+ process_flag(trap_exit, true),
+ _ConfDir = ?config(manager_conf_dir, Conf),
+ _DbDir = ?config(manager_db_dir, Conf),
+ ?SKIP(not_yet_implemented).
+
+
+%%
+%% ---
+%%
+
+register_agent_failed_using_function1(suite) -> [];
+register_agent_failed_using_function1(doc) ->
+ "Register agents failng using the API (function) with incorrect "
+ "config (1).";
+register_agent_failed_using_function1(Conf) when is_list(Conf) ->
+ put(tname,rafuf1),
+ p("start"),
+ process_flag(trap_exit, true),
+ _ConfDir = ?config(manager_conf_dir, Conf),
+ _DbDir = ?config(manager_db_dir, Conf),
+ ?SKIP(not_yet_implemented).
+
+
+%%
+%% ---
+%%
+
+usm_users(doc) ->
+ "Various USM users related operations with the snmp manager config";
+usm_users(suite) ->
+ [
+ register_usm_user_using_file,
+ register_usm_user_using_function,
+ register_usm_user_failed_using_function1,
+ update_usm_user_info
+ ].
+
+
+%%
+%% ---
+%%
+
+register_usm_user_using_file(suite) -> [];
+register_usm_user_using_file(doc) ->
+ "Register usm user using the 'usm.conf' file.";
+register_usm_user_using_file(Conf) when is_list(Conf) ->
+ put(tname,ruuufi),
+ p("start"),
+ process_flag(trap_exit, true),
+
+ case ?CRYPTO_START() of
+ ok ->
+ case ?CRYPTO_SUPPORT() of
+ {no, Reason} ->
+ ?SKIP({unsupported_encryption, Reason});
+ yes ->
+ ok
+ end;
+ {error, Reason} ->
+ ?SKIP({failed_starting_crypto, Reason})
+ end,
+
+ ConfDir = ?config(manager_conf_dir, Conf),
+ DbDir = ?config(manager_db_dir, Conf),
+
+ Opts = [{versions, [v3]},
+ {config, [{verbosity, trace}, {dir, ConfDir}, {db_dir, DbDir}]}],
+
+ %% --
+ p("write manager config file"),
+ write_manager_conf(ConfDir),
+
+ %% --
+ p("write usm user config file"),
+ SecEngineID = "loctzp's engine",
+ SecName1 = "samu_auth1",
+ UserName1 = SecName1,
+ UsmUser1 = {"\"" ++ SecEngineID ++ "\"",
+ "\"" ++ UserName1 ++ "\"",
+ "\"" ++ SecName1 ++ "\"",
+ "usmHMACMD5AuthProtocol", "[1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6]",
+ "usmNoPrivProtocol", "[]"},
+
+ SecName2 = "samu_auth2",
+ UserName2 = "samu",
+ UsmUser2 = {"\"" ++ SecEngineID ++ "\"",
+ "\"" ++ UserName2 ++ "\"",
+ "\"" ++ SecName2 ++ "\"",
+ "usmHMACMD5AuthProtocol", "[1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6]",
+ "usmNoPrivProtocol", "[]"},
+ write_usm_conf(ConfDir, [UsmUser1, UsmUser2]),
+
+ %% --
+ p("start the config process"),
+ ?line {ok, _Pid} = config_start(Opts),
+
+ %% --
+ p("lookup 1 (ok)"),
+ ?line {ok, #usm_user{name = UserName1} = User1} =
+ snmpm_config:get_usm_user_from_sec_name(SecEngineID, SecName1),
+ p("User: ~p", [User1]),
+
+ p("lookup 2 (ok)"),
+ ?line {ok, #usm_user{name = UserName2} = User2} =
+ snmpm_config:get_usm_user_from_sec_name(SecEngineID, SecName2),
+ p("User: ~p", [User2]),
+
+ p("lookup 3 (error)"),
+ ?line {error, not_found} =
+ snmpm_config:get_usm_user_from_sec_name(SecEngineID, SecName2 ++ "_1"),
+
+ %% --
+ p("stop config process"),
+ ?line ok = snmpm_config:stop(),
+ await_config_not_running(),
+
+ %% --
+ p("done"),
+ ok.
+%% ?SKIP(not_yet_implemented).
+
+
+%%
+%% ---
+%%
+
+register_usm_user_using_function(suite) -> [];
+register_usm_user_using_function(doc) ->
+ "Register usm user using the API (function).";
+register_usm_user_using_function(Conf) when is_list(Conf) ->
+ put(tname,ruuufu),
+ p("start"),
+ process_flag(trap_exit, true),
+
+ case ?CRYPTO_START() of
+ ok ->
+ case ?CRYPTO_SUPPORT() of
+ {no, Reason} ->
+ ?SKIP({unsupported_encryption, Reason});
+ yes ->
+ ok
+ end;
+ {error, Reason} ->
+ ?SKIP({failed_starting_crypto, Reason})
+ end,
+
+ ConfDir = ?config(manager_conf_dir, Conf),
+ DbDir = ?config(manager_db_dir, Conf),
+
+ Opts = [{versions, [v3]},
+ {config, [{verbosity, trace}, {dir, ConfDir}, {db_dir, DbDir}]}],
+
+ %% --
+ p("write manager config file"),
+ write_manager_conf(ConfDir),
+
+ %% --
+ p("start the config process"),
+ ?line {ok, _Pid} = config_start(Opts),
+
+ %% --
+ p("register usm user's"),
+ EngineID = "loctzp's engine",
+
+ p("register user 1 (ok)"),
+ UserName1 = "samu_auth1",
+ SecName1 = UserName1,
+ UsmConfig1 = [{sec_name, SecName1},
+ {auth, usmHMACMD5AuthProtocol},
+ {auth_key, [1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6]},
+ {priv, usmNoPrivProtocol}],
+ ?line ok = snmpm_config:register_usm_user(EngineID, UserName1, UsmConfig1),
+ p("try register user 1 again (error)"),
+ ?line {error, {already_registered, EngineID, UserName1}} =
+ snmpm_config:register_usm_user(EngineID, UserName1, UsmConfig1),
+
+ p("register user 2 (ok)"),
+ UserName2 = "samu_auth2",
+ SecName2 = UserName2,
+ UsmConfig2 = [{auth, usmHMACMD5AuthProtocol},
+ {auth_key, [1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6]},
+ {priv, usmNoPrivProtocol}],
+ ?line ok = snmpm_config:register_usm_user(EngineID, UserName2, UsmConfig2),
+
+ p("register user 3 (ok)"),
+ UserName3 = "samu3",
+ SecName3 = "samu_auth3",
+ UsmConfig3 = [{sec_name, SecName3},
+ {auth, usmHMACMD5AuthProtocol},
+ {auth_key, [1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6]},
+ {priv, usmNoPrivProtocol}],
+ ?line ok = snmpm_config:register_usm_user(EngineID, UserName3, UsmConfig3),
+
+ p("lookup 1 (ok)"),
+ ?line {ok, #usm_user{name = UserName1} = User1} =
+ snmpm_config:get_usm_user_from_sec_name(EngineID, SecName1),
+ p("User: ~p", [User1]),
+
+ p("lookup 2 (ok)"),
+ ?line {ok, #usm_user{name = UserName2} = User2} =
+ snmpm_config:get_usm_user_from_sec_name(EngineID, SecName2),
+ p("User: ~p", [User2]),
+
+ p("lookup 3 (ok)"),
+ ?line {ok, #usm_user{name = UserName3} = User3} =
+ snmpm_config:get_usm_user_from_sec_name(EngineID, SecName3),
+ p("User: ~p", [User3]),
+
+ p("lookup 4 (error)"),
+ ?line {error, not_found} =
+ snmpm_config:get_usm_user_from_sec_name(EngineID, SecName3 ++ "_1"),
+
+ %% --
+ p("stop config process"),
+ ?line ok = snmpm_config:stop(),
+ await_config_not_running(),
+
+ %% --
+ p("done"),
+ ok.
+%% ?SKIP(not_yet_implemented).
+
+
+%%
+%% ---
+%%
+
+register_usm_user_failed_using_function1(suite) -> [];
+register_usm_user_failed_using_function1(doc) ->
+ "Register usm user failed using incorrect arguments to API (function).";
+register_usm_user_failed_using_function1(Conf) when is_list(Conf) ->
+ put(tname,ruufufu1),
+ p("start"),
+ process_flag(trap_exit, true),
+
+ case ?CRYPTO_START() of
+ ok ->
+ case ?CRYPTO_SUPPORT() of
+ {no, Reason} ->
+ ?SKIP({unsupported_encryption, Reason});
+ yes ->
+ ok
+ end;
+ {error, Reason} ->
+ ?SKIP({failed_starting_crypto, Reason})
+ end,
+
+ _ConfDir = ?config(manager_conf_dir, Conf),
+ _DbDir = ?config(manager_db_dir, Conf),
+ ?SKIP(not_yet_implemented).
+
+
+%%
+%% ---
+%%
+
+update_usm_user_info(suite) -> [];
+update_usm_user_info(doc) ->
+ "Update usm user info.";
+update_usm_user_info(Conf) when is_list(Conf) ->
+ put(tname,ruufufu1),
+ p("start"),
+ process_flag(trap_exit, true),
+
+ case ?CRYPTO_START() of
+ ok ->
+ case ?CRYPTO_SUPPORT() of
+ {no, Reason} ->
+ ?SKIP({unsupported_encryption, Reason});
+ yes ->
+ ok
+ end;
+ {error, Reason} ->
+ ?SKIP({failed_starting_crypto, Reason})
+ end,
+
+ _ConfDir = ?config(manager_conf_dir, Conf),
+ _DbDir = ?config(manager_db_dir, Conf),
+ ?SKIP(not_yet_implemented).
+
+
+%%
+%% ---
+%%
+
+counter(doc) ->
+ "Various counter related operations with the snmp manager config";
+counter(suite) ->
+ [
+ create_and_increment
+ ].
+
+
+%%
+%% ---
+%%
+
+create_and_increment(suite) -> [];
+create_and_increment(doc) ->
+ "Craete and increment counters.";
+create_and_increment(Conf) when is_list(Conf) ->
+ put(tname,cai),
+ p("start"),
+ process_flag(trap_exit, true),
+
+ ConfDir = ?config(manager_conf_dir, Conf),
+ DbDir = ?config(manager_db_dir, Conf),
+
+ write_manager_conf(ConfDir),
+
+ Opts = [{versions, [v1]},
+ {config, [{verbosity, trace}, {dir, ConfDir}, {db_dir, DbDir}]}],
+
+ ?line {ok, _Pid} = snmpm_config:start_link(Opts),
+
+ %% Random init
+ {A,B,C} = erlang:now(),
+ random:seed(A,B,C),
+
+ StartVal = random:uniform(2147483647),
+ IncVal = 42,
+ EndVal = StartVal + IncVal,
+
+ ?line StartVal = snmpm_config:cre_counter(test_id, StartVal),
+ ?line EndVal = snmpm_config:incr_counter(test_id, IncVal),
+
+ ?line ok = snmpm_config:stop(),
+ await_config_not_running(),
+ ok.
+
+
+%%
+%% ---
+%%
+
+stats_counter(doc) ->
+ "Various statistic counter related operations with the "
+ "snmp manager config";
+stats_counter(suite) ->
+ [
+ stats_create_and_increment
+ ].
+
+
+%%
+%% ---
+%%
+
+stats_create_and_increment(suite) -> [];
+stats_create_and_increment(doc) ->
+ "Create and increment statistics counters.";
+stats_create_and_increment(Conf) when is_list(Conf) ->
+ put(tname,scai),
+ p("start"),
+ process_flag(trap_exit, true),
+
+ ConfDir = ?config(manager_conf_dir, Conf),
+ DbDir = ?config(manager_db_dir, Conf),
+
+ write_manager_conf(ConfDir),
+
+ Opts = [{versions, [v1]},
+ {config, [{verbosity, trace}, {dir, ConfDir}, {db_dir, DbDir}]}],
+
+ ?line {ok, _Pid} = snmpm_config:start_link(Opts),
+
+ p("stats table (1): ~p", [ets:tab2list(snmpm_stats_table)]),
+ ?line 0 = snmpm_config:maybe_cre_stats_counter(stats1, 0),
+ p("stats table (2): ~p", [ets:tab2list(snmpm_stats_table)]),
+ ?line ok = snmpm_config:maybe_cre_stats_counter(stats1, 0),
+ p("stats table (3): ~p", [ets:tab2list(snmpm_stats_table)]),
+ ?line 1 = snmpm_config:maybe_cre_stats_counter(stats2, 1),
+ p("stats table (4): ~p", [ets:tab2list(snmpm_stats_table)]),
+ ?line 10 = snmpm_config:cre_stats_counter(stats3, 10),
+ p("stats table (5): ~p", [ets:tab2list(snmpm_stats_table)]),
+
+ Stats1Inc = fun() -> snmpm_config:incr_stats_counter(stats1, 1) end,
+ ?line 10 = loop(10, -1, Stats1Inc),
+ p("stats table (6): ~p", [ets:tab2list(snmpm_stats_table)]),
+
+ ?line ok = snmpm_config:reset_stats_counter(stats1),
+
+ ?line 10 = loop(10, -1, Stats1Inc),
+
+ ?line ok = snmpm_config:stop(),
+ await_config_not_running(),
+ ok.
+
+
+loop(0, Acc, _) ->
+ Acc;
+loop(N, _, F) when (N > 0) andalso is_function(F) ->
+ Acc = F(),
+ loop(N-1, Acc, F).
+
+
+%%======================================================================
+%% Ticket test-cases
+%%======================================================================
+
+tickets(suite) ->
+ [
+ otp_7219
+ ].
+
+
+otp_7219(suite) ->
+ [];
+otp_7219(doc) ->
+ "Test-case for ticket OTP-7219";
+otp_7219(Config) when is_list(Config) ->
+ put(tname, otp7219),
+ p("start"),
+ process_flag(trap_exit, true),
+
+ ConfDir = ?config(manager_conf_dir, Config),
+ DbDir = ?config(manager_db_dir, Config),
+
+ p("write manager configuration"),
+ write_manager_conf(ConfDir),
+
+ Opts1 = [{versions, [v1]},
+ {inform_request_behaviour, user},
+ {config, [{verbosity, trace}, {dir, ConfDir}, {db_dir, DbDir}]}],
+
+ p("start manager config"),
+ ?line {ok, _Pid1} = snmpm_config:start_link(Opts1),
+
+ p("get some manager config"),
+ {ok, {user, _}} = snmpm_config:system_info(net_if_irb),
+
+ p("stop manager config"),
+ ?line ok = snmpm_config:stop(),
+ await_config_not_running(),
+
+ IRB_TO = 15322,
+ Opts2 = [{versions, [v1]},
+ {inform_request_behaviour, {user, IRB_TO}},
+ {config, [{verbosity, trace}, {dir, ConfDir}, {db_dir, DbDir}]}],
+
+ p("start manager config"),
+ ?line {ok, _Pid2} = snmpm_config:start_link(Opts2),
+
+ p("get some manager config"),
+ {ok, {user, IRB_TO}} = snmpm_config:system_info(net_if_irb),
+
+ p("stop manager config"),
+ ?line ok = snmpm_config:stop(),
+ await_config_not_running(),
+
+ p("done"),
+ ok.
+
+
+%%======================================================================
+%% Internal functions
+%%======================================================================
+
+await_config_not_running() ->
+ await_not_running(snmpm_config, 5).
+
+await_not_running(Name, 0) ->
+ p("await_not_running -> done waiting for ~w to die - try kill it", [Name]),
+ %% Ok, we tried it the nice way, now use brute force
+ await_killed(Name, 5);
+await_not_running(Name, N) when N > 0 ->
+ p("await_not_running -> is process ~w still running (~w)", [Name, N]),
+ case erlang:whereis(Name) of
+ undefined ->
+ p("await_not_running -> no such (~w) process - sleep some",[Name]),
+ ?SLEEP(1000),
+ p("await_not_running -> no such (~w) process - done", [Name]),
+ ok;
+ Pid when is_pid(Pid) ->
+ p("~w process still running", [Name]),
+ ?SLEEP(500),
+ await_not_running(Name, N-1)
+ end.
+
+await_killed(Name, 0) ->
+ p("await_killed -> could not kill ~w => giving up", [Name]),
+ exit({error, {failed_terminating, Name}});
+await_killed(Name, N) when N > 0 ->
+ p("await_killed -> is process ~w still running (~w)", [Name, N]),
+ case whereis(Name) of
+ undefined ->
+ p("await_killed -> no such (~w) process - sleep some", [Name]),
+ ?SLEEP(1000),
+ p("await_killed -> no such (~w) process - done", [Name]),
+ ok;
+ Pid when is_pid(Pid) ->
+ p("await_killed -> ~w still running - try kill it", [Name]),
+ exit(Pid, kill),
+ ?SLEEP(1000),
+ await_killed(Name, N-1)
+ end.
+
+
+config_start(Opts) ->
+ (catch snmpm_config:start_link(Opts)).
+
+config_stop() ->
+ (catch snmpm_config:stop()).
+
+
+%% ------
+
+join(Dir, File) ->
+ filename:join(Dir, File).
+
+
+%% ------
+
+write_manager_conf(Dir) ->
+ Port = "5000",
+ MMS = "484",
+ EngineID = "\"mgrEngine\"",
+ Str = lists:flatten(
+ io_lib:format("%% Minimum manager config file\n"
+ "{port, ~s}.\n"
+ "{max_message_size, ~s}.\n"
+ "{engine_id, ~s}.\n",
+ [Port, MMS, EngineID])),
+ write_manager_conf(Dir, Str).
+
+write_manager_conf(Dir, IP, Port, MMS, EngineID) ->
+ Str = lists:flatten(
+ io_lib:format("{address, ~s}.\n"
+ "{port, ~s}.\n"
+ "{max_message_size, ~s}.\n"
+ "{engine_id, ~s}.\n",
+ [IP, Port, MMS, EngineID])),
+ write_manager_conf(Dir, Str).
+
+write_manager_conf(Dir, Str) ->
+ write_conf_file(Dir, "manager.conf", Str).
+
+
+write_users_conf(Dir, Users) ->
+ F = fun({UserId, UserMod, UserData}) -> %% Old format
+ lists:flatten(
+ io_lib:format("{~s, ~s, ~s, ~s}.~n",
+ [UserId, UserMod, UserData, "[]"]));
+ ({UserId, UserMod, UserData, DefaultAgentConfig}) -> %% New format
+ lists:flatten(
+ io_lib:format("{~s, ~s, ~s, ~s}.~n",
+ [UserId, UserMod, UserData, DefaultAgentConfig]))
+ end,
+ Str = lists:flatten([F(User) || User <- Users]),
+ write_conf_file(Dir, "users.conf", Str).
+
+write_users_conf2(Dir, Str) ->
+ write_conf_file(Dir, "users.conf", Str).
+
+
+write_agents_conf(Dir, Agents) ->
+ F = fun({UserId,
+ TargetName, Comm,
+ Ip, Port, EngineID,
+ Timeout, MMS,
+ Version, SecModel, SecName, SecLevel}) ->
+ lists:flatten(
+ io_lib:format("{~s, ~n"
+ " ~s, ~s, ~n"
+ " ~s, ~s, ~s, ~n"
+ " ~s, ~s, ~n"
+ " ~s, ~s, ~s, ~s}.~n",
+ [UserId,
+ TargetName, Comm,
+ Ip, Port, EngineID,
+ Timeout, MMS,
+ Version, SecModel, SecName, SecLevel]))
+ end,
+ Str = lists:flatten([F(Agent) || Agent <- Agents]),
+ write_conf_file(Dir, "agents.conf", Str).
+
+write_agents_conf2(Dir, Str) ->
+ write_conf_file(Dir, "agents.conf", Str).
+
+
+write_usm_conf(Dir, Usms) ->
+ F = fun({EngineID, UserName, SecName, AuthP, AuthKey, PrivP, PrivKey}) ->
+ lists:flatten(
+ io_lib:format("{~s, ~s, ~s, ~n"
+ " ~s, ~s, ~n"
+ " ~s, ~s}.~n",
+ [EngineID, UserName, SecName,
+ AuthP, AuthKey,
+ PrivP, PrivKey]));
+ ({EngineID, UserName, AuthP, AuthKey, PrivP, PrivKey}) ->
+ lists:flatten(
+ io_lib:format("{~s, ~s, ~n"
+ " ~s, ~s, ~n"
+ " ~s, ~s}.~n",
+ [EngineID, UserName,
+ AuthP, AuthKey,
+ PrivP, PrivKey]));
+ (Usm) ->
+ exit({invalid_usm, Usm})
+ end,
+ Str = lists:flatten([F(Usm) || Usm <- Usms]),
+ write_conf_file(Dir, "usm.conf", Str).
+
+write_usm_conf2(Dir, Str) ->
+ write_conf_file(Dir, "usm.conf", Str).
+
+
+write_conf_file(Dir, File, Str) ->
+ ?line {ok, Fd} = file:open(filename:join(Dir, File), write),
+ ?line ok = io:format(Fd, "~s", [Str]),
+ file:close(Fd).
+
+
+%% ------
+
+str(X) ->
+ lists:flatten(io_lib:format("~w", [X])).
+
+
+%% ------
+
+p(F) ->
+ p(F, []).
+
+p(F, A) ->
+ p(get(tname), F, A).
+
+p(TName, F, A) ->
+ io:format("*** [~s] ***"
+ " ~w -> " ++ F ++ "~n", [format_timestamp(now()),TName|A]).
+
+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).
+
diff --git a/lib/snmp/test/snmp_manager_test.erl b/lib/snmp/test/snmp_manager_test.erl
new file mode 100644
index 0000000000..31cc095349
--- /dev/null
+++ b/lib/snmp/test/snmp_manager_test.erl
@@ -0,0 +1,5436 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2003-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%
+%%
+
+%%----------------------------------------------------------------------
+%% Purpose:
+%%
+%% Test: ts:run(snmp, snmp_manager_test, [batch]).
+%% Test: ts:run(snmp, snmp_manager_test, event_tests, [batch]).
+%% Test: ts:run(snmp, snmp_manager_test, inform_swarm, [batch]).
+%%
+%%----------------------------------------------------------------------
+-module(snmp_manager_test).
+
+%%----------------------------------------------------------------------
+%% Include files
+%%----------------------------------------------------------------------
+
+-include("test_server.hrl").
+-include("snmp_test_lib.hrl").
+-include("snmp_test_data/Test2.hrl").
+
+-include_lib("snmp/include/snmp_types.hrl").
+-include_lib("snmp/include/STANDARD-MIB.hrl").
+
+
+%%----------------------------------------------------------------------
+%% External exports
+%%----------------------------------------------------------------------
+-export([
+ all/1,
+ init_per_testcase/2, fin_per_testcase/2,
+
+ start_and_stop_tests/1,
+ simple_start_and_stop1/1,
+ simple_start_and_stop2/1,
+ simple_start_and_monitor_crash1/1,
+ simple_start_and_monitor_crash2/1,
+ notify_started01/1,
+ notify_started02/1,
+
+ user_tests/1,
+ register_user1/1,
+
+ agent_tests/1,
+ register_agent1/1,
+ register_agent2/1,
+
+ misc_tests/1,
+ info/1,
+
+ request_tests/1,
+
+ get_tests/1,
+ simple_sync_get1/1,
+ simple_sync_get2/1,
+ simple_async_get1/1,
+ simple_async_get2/1,
+
+ get_next_tests/1,
+ simple_sync_get_next1/1,
+ simple_sync_get_next2/1,
+ simple_async_get_next1/1,
+ simple_async_get_next2/1,
+
+ set_tests/1,
+ simple_sync_set1/1,
+ simple_sync_set2/1,
+ simple_async_set1/1,
+ simple_async_set2/1,
+
+ bulk_tests/1,
+ simple_sync_get_bulk1/1,
+ simple_sync_get_bulk2/1,
+ simple_async_get_bulk1/1,
+ simple_async_get_bulk2/1,
+
+ misc_request_tests/1,
+ misc_async1/1,
+ misc_async2/1,
+
+ discovery/1,
+
+ event_tests/1,
+
+ trap1/1,
+ trap2/1,
+
+ inform1/1,
+ inform2/1,
+ inform3/1,
+ inform4/1,
+ inform_swarm/1,
+
+ report/1,
+
+ tickets/1,
+ otp8015/1,
+ otp8015_1/1
+
+ ]).
+
+
+%%----------------------------------------------------------------------
+%% Internal exports
+%%----------------------------------------------------------------------
+
+%% -export([async_exec/2]).
+
+
+%%----------------------------------------------------------------------
+%% Macros and constants
+%%----------------------------------------------------------------------
+
+-define(AGENT_PORT, 4000).
+-define(AGENT_MMS, 1024).
+-define(AGENT_ENGINE_ID, "agentEngine").
+
+-define(MGR_PORT, 5000).
+-define(MGR_MMS, 1024).
+-define(MGR_ENGINE_ID, "mgrEngine").
+
+-define(NS_TIMEOUT, 10000).
+
+
+%%----------------------------------------------------------------------
+%% Records
+%%----------------------------------------------------------------------
+
+%%======================================================================
+%% External functions
+%%======================================================================
+
+init_per_testcase(Case, Config) when is_list(Config) ->
+ io:format(user, "~n~n*** INIT ~w:~w ***~n~n", [?MODULE,Case]),
+ init_per_testcase2(Case, Config).
+
+init_per_testcase2(Case, Config) ->
+ ?DBG("init [~w] Nodes [1]: ~p", [Case, erlang:nodes()]),
+
+ %% Fix a correct data dir (points to the wrong location):
+ DataDir0 = ?config(data_dir, Config),
+ DataDir1 = filename:split(filename:absname(DataDir0)),
+ [_|DataDir2] = lists:reverse(DataDir1),
+ DataDir = filename:join(lists:reverse(DataDir2) ++ [?snmp_test_data]),
+
+ PrivDir = ?config(priv_dir, Config),
+
+ TopDir = filename:join(PrivDir, ?MODULE),
+ case file:make_dir(TopDir) of
+ ok ->
+ ok;
+ {error, eexist} ->
+ ok;
+ Error ->
+ ?FAIL({failed_creating_subsuite_top_dir, Error})
+ end,
+
+ CaseTopDir = filename:join(TopDir, Case),
+ ?line ok = file:make_dir(CaseTopDir),
+
+ %% -- Manager dirs --
+ MgrTopDir = filename:join(CaseTopDir, "manager/"),
+ ?line ok = file:make_dir(MgrTopDir),
+
+ MgrConfDir = filename:join(MgrTopDir, "conf/"),
+ ?line ok = file:make_dir(MgrConfDir),
+
+ MgrDbDir = filename:join(MgrTopDir, "db/"),
+ ?line ok = file:make_dir(MgrDbDir),
+
+ MgrLogDir = filename:join(MgrTopDir, "log/"),
+ ?line ok = file:make_dir(MgrLogDir),
+
+ %% -- Agent dirs --
+ AgTopDir = filename:join(CaseTopDir, "agent/"),
+ ?line ok = file:make_dir(AgTopDir),
+
+ AgConfDir = filename:join(AgTopDir, "conf/"),
+ ?line ok = file:make_dir(AgConfDir),
+
+ AgDbDir = filename:join(AgTopDir, "db/"),
+ ?line ok = file:make_dir(AgDbDir),
+
+ AgLogDir = filename:join(AgTopDir, "log/"),
+ ?line ok = file:make_dir(AgLogDir),
+
+ Conf = [{snmp_data_dir, DataDir},
+ {watchdog, ?WD_START(?MINS(5))},
+ {ip, ?LOCALHOST()},
+ {top_dir, TopDir},
+ {agent_dir, AgTopDir},
+ {agent_conf_dir, AgConfDir},
+ {agent_db_dir, AgDbDir},
+ {agent_log_dir, AgLogDir},
+ {manager_agent_target_name, "agent01"},
+ {manager_dir, MgrTopDir},
+ {manager_conf_dir, MgrConfDir},
+ {manager_db_dir, MgrDbDir},
+ {manager_log_dir, MgrLogDir} | Config],
+ Conf2 = init_per_testcase3(Case, Conf),
+ ?DBG("init [~w] Nodes [2]: ~p", [Case, erlang:nodes()]),
+ Conf2.
+
+init_per_testcase3(Case, Config) ->
+ OldApiCases =
+ [
+ simple_sync_get1,
+ simple_async_get1,
+ simple_sync_get_next1,
+ simple_async_get_next1,
+ simple_sync_set1,
+ simple_async_set1,
+ simple_sync_get_bulk1,
+ simple_async_get_bulk1,
+ misc_async1
+ ],
+ NewApiCases =
+ [
+ simple_sync_get2,
+ simple_async_get2,
+ simple_sync_get_next2,
+ simple_async_get_next2,
+ simple_sync_set2,
+ simple_async_set2,
+ simple_sync_get_bulk2,
+ simple_async_get_bulk2,
+ misc_async2
+ ],
+ Cases = [
+ trap1,
+ trap2,
+ inform1,
+ inform2,
+ inform3,
+ inform4,
+ inform_swarm,
+ report
+ ] ++ OldApiCases ++ NewApiCases,
+ case lists:member(Case, Cases) of
+ true ->
+ NoAutoInformCases = [inform1, inform2, inform3, inform_swarm],
+ AutoInform = not lists:member(Case, NoAutoInformCases),
+ Conf1 = if
+ Case =:= inform_swarm ->
+ Verb = [{manager_config_verbosity, silence},
+ {manager_note_store_verbosity, silence},
+ {manager_server_verbosity, info},
+ {manager_net_if_verbosity, info},
+ {agent_verbosity, info},
+ {agent_net_if_verbosity, info}],
+ Verb ++ Config;
+ true ->
+ Config
+ end,
+ Conf2 = init_agent(Conf1),
+ Conf3 = init_manager(AutoInform, Conf2),
+ Conf4 = init_mgr_user(Conf3),
+ case lists:member(Case, NewApiCases) of
+ true ->
+ init_mgr_user_data2(Conf4);
+ false ->
+ init_mgr_user_data1(Conf4)
+ end;
+ false ->
+ Config
+ end.
+
+fin_per_testcase(Case, Config) when is_list(Config) ->
+ ?DBG("fin [~w] Nodes [1]: ~p", [Case, erlang:nodes()]),
+ Dog = ?config(watchdog, Config),
+ ?WD_STOP(Dog),
+ Conf1 = lists:keydelete(watchdog, 1, Config),
+ Conf2 = fin_per_testcase2(Case, Conf1),
+ ?DBG("fin [~w] Nodes [2]: ~p", [Case, erlang:nodes()]),
+ %% TopDir = ?config(top_dir, Conf2),
+ %% ?DEL_DIR(TopDir),
+ Conf2.
+
+fin_per_testcase2(Case, Config) ->
+ OldApiCases =
+ [
+ simple_sync_get1,
+ simple_async_get1,
+ simple_sync_get_next1,
+ simple_async_get_next1,
+ simple_sync_set1,
+ simple_async_set1,
+ simple_sync_get_bulk1,
+ simple_async_get_bulk1,
+ misc_async1
+ ],
+ NewApiCases =
+ [
+ simple_sync_get2,
+ simple_async_get2,
+ simple_sync_get_next2,
+ simple_async_get_next2,
+ simple_sync_set2,
+ simple_async_set2,
+ simple_sync_get_bulk2,
+ simple_async_get_bulk2,
+ misc_async2
+ ],
+ Cases = [
+ trap1,
+ trap2,
+ inform1,
+ inform2,
+ inform3,
+ inform4,
+ inform_swarm,
+ report
+ ] ++ OldApiCases ++ NewApiCases,
+ case lists:member(Case, Cases) of
+ true ->
+ Conf1 = case lists:member(Case, NewApiCases) of
+ true ->
+ fin_mgr_user_data2(Config);
+ false ->
+ fin_mgr_user_data1(Config)
+ end,
+ Conf2 = fin_mgr_user(Conf1),
+ Conf3 = fin_manager(Conf2),
+ fin_agent(Conf3);
+ false ->
+ Config
+ end.
+
+
+%%======================================================================
+%% Test case definitions
+%%======================================================================
+
+all(suite) ->
+ [
+ start_and_stop_tests,
+ misc_tests,
+ user_tests,
+ agent_tests,
+ request_tests,
+ event_tests,
+ discovery,
+ tickets
+ ].
+
+start_and_stop_tests(suite) ->
+ [
+ simple_start_and_stop1,
+ simple_start_and_stop2,
+ simple_start_and_monitor_crash1,
+ simple_start_and_monitor_crash2,
+ notify_started01,
+ notify_started02
+ ].
+
+misc_tests(suite) ->
+ [
+ info
+ ].
+
+user_tests(suite) ->
+ [
+ register_user1
+ ].
+
+agent_tests(suite) ->
+ [
+ register_agent1,
+ register_agent2
+ ].
+
+request_tests(suite) ->
+ [
+ get_tests,
+ get_next_tests,
+ set_tests,
+ bulk_tests,
+ misc_request_tests
+ ].
+
+get_tests(suite) ->
+ [
+ simple_sync_get1,
+ simple_sync_get2,
+ simple_async_get1,
+ simple_async_get2
+ ].
+
+get_next_tests(suite) ->
+ [
+ simple_sync_get_next1,
+ simple_sync_get_next2,
+ simple_async_get_next1,
+ simple_async_get_next2
+ ].
+
+set_tests(suite) ->
+ [
+ simple_sync_set1,
+ simple_sync_set2,
+ simple_async_set1,
+ simple_async_set2
+ ].
+
+bulk_tests(suite) ->
+ [
+ simple_sync_get_bulk1,
+ simple_sync_get_bulk2,
+ simple_async_get_bulk1,
+ simple_async_get_bulk2
+ ].
+
+misc_request_tests(suite) ->
+ [
+ misc_async1,
+ misc_async2
+ ].
+
+event_tests(suite) ->
+ [
+ trap1,
+ trap2,
+ inform1,
+ inform2,
+ inform3,
+ inform4,
+ inform_swarm,
+ report
+ ].
+
+tickets(suite) ->
+ [
+ otp8015
+ ].
+
+otp8015(suite) ->
+ [
+ otp8015_1
+ ].
+
+
+%%======================================================================
+%% Test functions
+%%======================================================================
+
+simple_start_and_stop1(suite) -> [];
+simple_start_and_stop1(Config) when is_list(Config) ->
+ %% ?SKIP(not_yet_implemented),
+ process_flag(trap_exit, true),
+ put(tname,ssas1),
+ p("starting with Config: ~n~p", [Config]),
+
+ ConfDir = ?config(manager_conf_dir, Config),
+ DbDir = ?config(manager_db_dir, Config),
+
+ write_manager_conf(ConfDir),
+
+ Opts = [{server, [{verbosity, trace}]},
+ {net_if, [{verbosity, trace}]},
+ {note_store, [{verbosity, trace}]},
+ {config, [{verbosity, trace}, {dir, ConfDir}, {db_dir, DbDir}]}],
+
+ p("try starting manager"),
+ ok = snmpm:start_link(Opts),
+
+ ?SLEEP(1000),
+
+ p("manager started, now try to stop"),
+ ok = snmpm:stop(),
+
+ ?SLEEP(1000),
+
+ p("end"),
+ ok.
+
+
+%%======================================================================
+
+simple_start_and_stop2(suite) -> [];
+simple_start_and_stop2(Config) when is_list(Config) ->
+ %% ?SKIP(not_yet_implemented),
+ process_flag(trap_exit, true),
+ put(tname,ssas2),
+ p("starting with Config: ~p~n", [Config]),
+
+ ManagerNode = start_manager_node(),
+
+ ConfDir = ?config(manager_conf_dir, Config),
+ DbDir = ?config(manager_db_dir, Config),
+
+ write_manager_conf(ConfDir),
+
+ Opts = [{server, [{verbosity, trace}]},
+ {net_if, [{verbosity, trace}]},
+ {note_store, [{verbosity, trace}]},
+ {config, [{verbosity, trace}, {dir, ConfDir}, {db_dir, DbDir}]}],
+
+
+ p("try load snmp application"),
+ ?line ok = load_snmp(ManagerNode),
+
+ p("try set manager env for the snmp application"),
+ ?line ok = set_mgr_env(ManagerNode, Opts),
+
+ p("try starting snmp application (with only manager)"),
+ ?line ok = start_snmp(ManagerNode),
+
+ p("started"),
+
+ ?SLEEP(1000),
+
+ p("try stopping snmp application (with only manager)"),
+ ?line ok = stop_snmp(ManagerNode),
+
+ ?SLEEP(1000),
+
+ stop_node(ManagerNode),
+
+ ?SLEEP(1000),
+
+ p("end"),
+ ok.
+
+
+%%======================================================================
+
+simple_start_and_monitor_crash1(suite) -> [];
+simple_start_and_monitor_crash1(Config) when is_list(Config) ->
+ process_flag(trap_exit, true),
+ put(tname,ssamc1),
+ p("starting with Config: ~n~p", [Config]),
+
+ ConfDir = ?config(manager_conf_dir, Config),
+ DbDir = ?config(manager_db_dir, Config),
+
+ write_manager_conf(ConfDir),
+
+ Opts = [{server, [{verbosity, trace}]},
+ {net_if, [{verbosity, trace}]},
+ {note_store, [{verbosity, trace}]},
+ {config, [{verbosity, trace}, {dir, ConfDir}, {db_dir, DbDir}]}],
+
+ p("try starting manager"),
+ ok = snmpm:start(Opts),
+
+ ?SLEEP(1000),
+
+ p("create the monitor"),
+ Ref = snmpm:monitor(),
+
+ p("make sure it has not already crashed..."),
+ receive
+ {'DOWN', Ref, process, Obj1, Reason1} ->
+ ?FAIL({unexpected_down, Obj1, Reason1})
+ after 1000 ->
+ ok
+ end,
+
+ p("stop the manager"),
+ ok = snmpm:stop(),
+
+ p("await the down-message"),
+ receive
+ {'DOWN', Ref, process, Obj2, Reason2} ->
+ p("received expected down-message: "
+ "~n Obj2: ~p"
+ "~n Reason2: ~p",
+ [Obj2, Reason2]),
+ ok
+ after 1000 ->
+ ?FAIL(timeout)
+ end,
+
+ p("end"),
+ ok.
+
+
+%%======================================================================
+
+simple_start_and_monitor_crash2(suite) -> [];
+simple_start_and_monitor_crash2(Config) when is_list(Config) ->
+ process_flag(trap_exit, true),
+ put(tname,ssamc2),
+ p("starting with Config: ~n~p", [Config]),
+
+ ConfDir = ?config(manager_conf_dir, Config),
+ DbDir = ?config(manager_db_dir, Config),
+
+ write_manager_conf(ConfDir),
+
+ Opts = [{restart_type, permanent},
+ {server, [{verbosity, trace}]},
+ {net_if, [{verbosity, trace}]},
+ {note_store, [{verbosity, trace}]},
+ {config, [{verbosity, trace}, {dir, ConfDir}, {db_dir, DbDir}]}],
+
+ p("try starting manager"),
+ ok = snmpm:start(Opts),
+
+ ?SLEEP(1000),
+
+ p("create the monitor"),
+ Ref = snmpm:monitor(),
+
+ p("make sure it has not already crashed..."),
+ receive
+ {'DOWN', Ref, process, Obj1, Reason1} ->
+ ?FAIL({unexpected_down, Obj1, Reason1})
+ after 1000 ->
+ ok
+ end,
+
+ p("crash the manager"),
+ simulate_crash(),
+
+ p("await the down-message"),
+ receive
+ {'DOWN', Ref, process, Obj2, Reason2} ->
+ p("received expected down-message: "
+ "~n Obj2: ~p"
+ "~n Reason2: ~p",
+ [Obj2, Reason2]),
+ ok
+ after 1000 ->
+ ?FAIL(timeout)
+ end,
+
+ p("end"),
+ ok.
+
+
+%% The server supervisor allow 5 restarts in 500 msec.
+server_pid() ->
+ whereis(snmpm_server).
+
+-define(MAX_KILLS, 6).
+
+simulate_crash() ->
+ simulate_crash(0, server_pid()).
+
+simulate_crash(?MAX_KILLS, _) ->
+ ?SLEEP(1000),
+ case server_pid() of
+ P when is_pid(P) ->
+ exit({error, {still_alive, P}});
+ _ ->
+ ok
+ end;
+simulate_crash(NumKills, Pid) when (NumKills < ?MAX_KILLS) and is_pid(Pid) ->
+ p("similate_crash -> ~w, ~p", [NumKills, Pid]),
+ Ref = erlang:monitor(process, Pid),
+ exit(Pid, kill),
+ receive
+ {'DOWN', Ref, process, _Object, _Info} ->
+ p("received expected 'DOWN' message"),
+ simulate_crash(NumKills + 1, server_pid())
+ after 1000 ->
+ case server_pid() of
+ P when is_pid(P) ->
+ exit({error, {no_down_from_server, P}});
+ _ ->
+ ok
+ end
+ end;
+simulate_crash(NumKills, _) ->
+ ?SLEEP(10),
+ simulate_crash(NumKills, server_pid()).
+
+
+%%======================================================================
+
+notify_started01(suite) -> [];
+notify_started01(Config) when is_list(Config) ->
+ process_flag(trap_exit, true),
+ put(tname,ns01),
+ p("starting with Config: ~n~p", [Config]),
+
+ ConfDir = ?config(manager_conf_dir, Config),
+ DbDir = ?config(manager_db_dir, Config),
+
+ write_manager_conf(ConfDir),
+
+ Opts = [{server, [{verbosity, log}]},
+ {net_if, [{verbosity, silence}]},
+ {note_store, [{verbosity, silence}]},
+ {config, [{verbosity, log}, {dir, ConfDir}, {db_dir, DbDir}]}],
+
+ p("request start notification (1)"),
+ Pid1 = snmpm:notify_started(10000),
+ receive
+ {snmpm_start_timeout, Pid1} ->
+ p("received expected start timeout"),
+ ok;
+ Any1 ->
+ ?FAIL({unexpected_message, Any1})
+ after 15000 ->
+ ?FAIL({unexpected_timeout, Pid1})
+ end,
+
+ p("request start notification (2)"),
+ Pid2 = snmpm:notify_started(10000),
+
+ p("start the snmpm starter"),
+ Pid = snmpm_starter(Opts, 5000),
+
+ p("await the start notification"),
+ Ref =
+ receive
+ {snmpm_started, Pid2} ->
+ p("received started message -> create the monitor"),
+ snmpm:monitor();
+ Any2 ->
+ ?FAIL({unexpected_message, Any2})
+ after 15000 ->
+ ?FAIL({unexpected_timeout, Pid2})
+ end,
+
+ p("[~p] make sure it has not already crashed...", [Ref]),
+ receive
+ {'DOWN', Ref, process, Obj1, Reason1} ->
+ ?FAIL({unexpected_down, Obj1, Reason1})
+ after 1000 ->
+ ok
+ end,
+
+ p("stop the manager"),
+ Pid ! {stop, self()}, %ok = snmpm:stop(),
+
+ p("await the down-message"),
+ receive
+ {'DOWN', Ref, process, Obj2, Reason2} ->
+ p("received expected down-message: "
+ "~n Obj2: ~p"
+ "~n Reason2: ~p",
+ [Obj2, Reason2]),
+ ok
+ after 5000 ->
+ ?FAIL(down_timeout)
+ end,
+
+ p("end"),
+ ok.
+
+
+snmpm_starter(Opts, To) ->
+ Parent = self(),
+ spawn(
+ fun() ->
+ ?SLEEP(To),
+ ok = snmpm:start(Opts),
+ receive
+ {stop, Parent} ->
+ snmpm:stop()
+ end
+ end).
+
+
+%%======================================================================
+
+notify_started02(suite) -> [];
+notify_started02(Config) when is_list(Config) ->
+ process_flag(trap_exit, true),
+ put(tname,ns02),
+ p("starting with Config: ~n~p", [Config]),
+
+ ConfDir = ?config(manager_conf_dir, Config),
+ DbDir = ?config(manager_db_dir, Config),
+
+ write_manager_conf(ConfDir),
+
+ Opts = [{server, [{verbosity, log}]},
+ {net_if, [{verbosity, silence}]},
+ {note_store, [{verbosity, silence}]},
+ {config, [{verbosity, log}, {dir, ConfDir}, {db_dir, DbDir}]}],
+
+ p("start snmpm client process"),
+ Pid1 = ns02_loop1_start(),
+
+ p("start snmpm starter process"),
+ Pid2 = ns02_loop2_start(Opts),
+
+ p("await snmpm client process exit"),
+ receive
+ {'EXIT', Pid1, normal} ->
+ ok;
+ {'EXIT', Pid1, Reason1} ->
+ ?FAIL(Reason1)
+ after 25000 ->
+ ?FAIL(timeout)
+ end,
+
+ p("await snmpm starter process exit"),
+ receive
+ {'EXIT', Pid2, normal} ->
+ ok;
+ {'EXIT', Pid2, Reason2} ->
+ ?FAIL(Reason2)
+ after 5000 ->
+ ?FAIL(timeout)
+ end,
+
+ p("end"),
+ ok.
+
+
+ns02_loop1_start() ->
+ spawn_link(fun() -> ns02_loop1() end).
+
+ns02_loop1() ->
+ put(tname,ns02_loop1),
+ p("starting"),
+ ns02_loop1(dummy, snmpm:notify_started(?NS_TIMEOUT), 5).
+
+ns02_loop1(_Ref, _Pid, 0) ->
+ p("done"),
+ exit(normal);
+ns02_loop1(Ref, Pid, N) ->
+ p("entry when"
+ "~n Ref: ~p"
+ "~n Pid: ~p"
+ "~n N: ~p", [Ref, Pid, N]),
+ receive
+ {snmpm_started, Pid} ->
+ p("received expected started message (~w)", [N]),
+ ns02_loop1(snmpm:monitor(), dummy, N);
+ {snmpm_start_timeout, Pid} ->
+ p("unexpected timout"),
+ ?FAIL({unexpected_start_timeout, Pid});
+ {'DOWN', Ref, process, Obj, Reason} ->
+ p("received expected DOWN message (~w) with"
+ "~n Obj: ~p"
+ "~n Reason: ~p", [N, Obj, Reason]),
+ ns02_loop1(dummy, snmpm:notify_started(?NS_TIMEOUT), N-1)
+ after 10000 ->
+ ?FAIL(timeout)
+ end.
+
+
+ns02_loop2_start(Opts) ->
+ spawn_link(fun() -> ns02_loop2(Opts) end).
+
+ns02_loop2(Opts) ->
+ put(tname,ns02_loop2),
+ p("starting"),
+ ns02_loop2(Opts, 5).
+
+ns02_loop2(_Opts, 0) ->
+ p("done"),
+ exit(normal);
+ns02_loop2(Opts, N) ->
+ p("entry when N: ~p", [N]),
+ ?SLEEP(2000),
+ p("start manager"),
+ snmpm:start(Opts),
+ ?SLEEP(2000),
+ p("stop manager"),
+ snmpm:stop(),
+ ns02_loop2(Opts, N-1).
+
+
+%%======================================================================
+
+info(suite) -> [];
+info(Config) when is_list(Config) ->
+ process_flag(trap_exit, true),
+ put(tname,info),
+ p("starting with Config: ~n~p", [Config]),
+
+ ConfDir = ?config(manager_conf_dir, Config),
+ DbDir = ?config(manager_db_dir, Config),
+
+ write_manager_conf(ConfDir),
+
+ Opts = [{server, [{verbosity, trace}]},
+ {net_if, [{verbosity, trace}]},
+ {note_store, [{verbosity, trace}]},
+ {config, [{verbosity, trace}, {dir, ConfDir}, {db_dir, DbDir}]}],
+
+ p("try starting manager"),
+ ok = snmpm:start(Opts),
+
+ ?SLEEP(1000),
+
+ p("manager started, now get info"),
+ Info = snmpm:info(),
+ p("got info, now verify: ~n~p", [Info]),
+ ok = verify_info( Info ),
+
+ p("info verified, now try to stop"),
+ ok = snmpm:stop(),
+
+ ?SLEEP(1000),
+
+ p("end"),
+ ok.
+
+verify_info(Info) when is_list(Info) ->
+ Keys = [{server, [process_memory, db_memory]},
+ {config, [process_memory, db_memory]},
+ {net_if, [process_memory, port_info]},
+ {note_store, [process_memory, db_memory]},
+ stats_counters],
+ verify_info(Keys, Info);
+verify_info(BadInfo) ->
+ {error, {bad_info, BadInfo}}.
+
+verify_info([], _) ->
+ ok;
+verify_info([Key|Keys], Info) when is_atom(Key) ->
+ case lists:keymember(Key, 1, Info) of
+ true ->
+ verify_info(Keys, Info);
+ false ->
+ {error, {missing_info, {Key, Info}}}
+ end;
+verify_info([{Key, SubKeys}|Keys], Info) ->
+ case lists:keysearch(Key, 1, Info) of
+ {value, {Key, SubInfo}} ->
+ case verify_info(SubKeys, SubInfo) of
+ ok ->
+ verify_info(Keys, Info);
+ {error, {missing_info, {SubKey, _}}} ->
+ {error, {missing_subinfo, {Key, SubKey, Info}}}
+ end;
+ false ->
+ {error, {missing_info, {Key, Info}}}
+ end.
+
+
+%%======================================================================
+
+register_user1(suite) -> [];
+register_user1(Config) when is_list(Config) ->
+ %% ?SKIP(not_yet_implemented).
+ process_flag(trap_exit, true),
+ put(tname,ru1),
+ p("starting with Config: ~p~n", [Config]),
+
+ ManagerNode = start_manager_node(),
+
+ ConfDir = ?config(manager_conf_dir, Config),
+ DbDir = ?config(manager_db_dir, Config),
+
+ write_manager_conf(ConfDir),
+
+ Opts = [{server, [{verbosity, trace}]},
+ {net_if, [{verbosity, trace}]},
+ {note_store, [{verbosity, trace}]},
+ {config, [{verbosity, trace}, {dir, ConfDir}, {db_dir, DbDir}]}],
+
+
+ p("load snmp application"),
+ ?line ok = load_snmp(ManagerNode),
+
+ p("set manager env for the snmp application"),
+ ?line ok = set_mgr_env(ManagerNode, Opts),
+
+ p("starting snmp application (with only manager)"),
+ ?line ok = start_snmp(ManagerNode),
+
+ p("started"),
+
+ ?SLEEP(1000),
+
+ p("manager info: ~p~n", [mgr_info(ManagerNode)]),
+
+ p("try register user(s)"),
+ ?line ok = mgr_register_user(ManagerNode, calvin, snmpm_user_default,
+ [self(), "various misc info"]),
+
+ Users1 = mgr_which_users(ManagerNode),
+ p("users: ~p~n", [Users1]),
+ ?line ok = verify_users(Users1, [calvin]),
+ p("manager info: ~p~n", [mgr_info(ManagerNode)]),
+
+ ?line ok = mgr_register_user(ManagerNode, hobbe, snmpm_user_default,
+ {"misc info", self()}),
+
+ Users2 = mgr_which_users(ManagerNode),
+ p("users: ~p~n", [Users2]),
+ ?line ok = verify_users(Users2, [calvin, hobbe]),
+ p("manager info: ~p~n", [mgr_info(ManagerNode)]),
+
+ p("try unregister user(s)"),
+ ?line ok = mgr_unregister_user(ManagerNode, calvin),
+
+ Users3 = mgr_which_users(ManagerNode),
+ p("users: ~p~n", [Users3]),
+ ?line ok = verify_users(Users3, [hobbe]),
+ p("manager info: ~p~n", [mgr_info(ManagerNode)]),
+
+ ?line ok = mgr_unregister_user(ManagerNode, hobbe),
+
+ Users4 = mgr_which_users(ManagerNode),
+ p("users: ~p~n", [Users4]),
+ ?line ok = verify_users(Users4, []),
+ p("manager info: ~p~n", [mgr_info(ManagerNode)]),
+
+ ?SLEEP(1000),
+
+ p("stop snmp application (with only manager)"),
+ ?line ok = stop_snmp(ManagerNode),
+
+ ?SLEEP(1000),
+
+ stop_node(ManagerNode),
+
+ ?SLEEP(1000),
+
+ p("end"),
+ ok.
+
+verify_users([], []) ->
+ ok;
+verify_users(ActualUsers, []) ->
+ {error, {unexpected_users, ActualUsers}};
+verify_users(ActualUsers0, [User|RegUsers]) ->
+ case lists:delete(User, ActualUsers0) of
+ ActualUsers0 ->
+ {error, {not_registered, User}};
+ ActualUsers ->
+ verify_users(ActualUsers, RegUsers)
+ end.
+
+
+%%======================================================================
+
+register_agent1(doc) ->
+ ["Test registration of agents with the OLD interface functions"];
+register_agent1(suite) ->
+ [];
+register_agent1(Config) when is_list(Config) ->
+ process_flag(trap_exit, true),
+ put(tname,ra1),
+ p("starting with Config: ~p~n", [Config]),
+
+ ManagerNode = start_manager_node(),
+
+ ConfDir = ?config(manager_conf_dir, Config),
+ DbDir = ?config(manager_db_dir, Config),
+
+ write_manager_conf(ConfDir),
+
+ Opts = [{server, [{verbosity, trace}]},
+ {net_if, [{verbosity, trace}]},
+ {note_store, [{verbosity, trace}]},
+ {config, [{verbosity, trace}, {dir, ConfDir}, {db_dir, DbDir}]}],
+
+
+ p("load snmp application"),
+ ?line ok = load_snmp(ManagerNode),
+
+ p("set manager env for the snmp application"),
+ ?line ok = set_mgr_env(ManagerNode, Opts),
+
+ p("starting snmp application (with only manager)"),
+ ?line ok = start_snmp(ManagerNode),
+
+ p("started"),
+
+ ?SLEEP(1000),
+
+ p("manager info: ~p~n", [mgr_info(ManagerNode)]),
+
+ p("register user(s) calvin & hobbe"),
+ ?line ok = mgr_register_user(ManagerNode, user_alfa, snmpm_user_default, []),
+ ?line ok = mgr_register_user(ManagerNode, user_beta, snmpm_user_default, []),
+ p("manager info: ~p~n", [mgr_info(ManagerNode)]),
+
+ p("register agent(s)"),
+ ?line ok = mgr_register_agent(ManagerNode, user_alfa, 5000, []),
+ ?line ok = mgr_register_agent(ManagerNode, user_alfa, 5001, []),
+ ?line ok = mgr_register_agent(ManagerNode, user_beta, 5002, []),
+ ?line ok = mgr_register_agent(ManagerNode, user_beta, 5003, []),
+
+ p("verify all agent(s): expect 4"),
+ case mgr_which_agents(ManagerNode) of
+ Agents1 when length(Agents1) =:= 4 ->
+ p("all agents: ~p~n", [Agents1]),
+ ok;
+ Agents1 ->
+ ?FAIL({agent_registration_failure, Agents1})
+ end,
+
+ p("verify user_alfa agent(s)"),
+ case mgr_which_agents(ManagerNode, user_alfa) of
+ Agents2 when length(Agents2) =:= 2 ->
+ p("calvin agents: ~p~n", [Agents2]),
+ ok;
+ Agents2 ->
+ ?FAIL({agent_registration_failure, Agents2})
+ end,
+
+ p("verify user_beta agent(s)"),
+ case mgr_which_agents(ManagerNode, user_beta) of
+ Agents3 when length(Agents3) =:= 2 ->
+ p("hobbe agents: ~p~n", [Agents3]),
+ ok;
+ Agents3 ->
+ ?FAIL({agent_registration_failure, Agents3})
+ end,
+
+ p("manager info: ~p~n", [mgr_info(ManagerNode)]),
+
+ p("unregister user user_alfa"),
+ ?line ok = mgr_unregister_user(ManagerNode, user_alfa),
+
+ p("verify all agent(s): expect 2"),
+ case mgr_which_agents(ManagerNode) of
+ Agents4 when length(Agents4) =:= 2 ->
+ p("all agents: ~p~n", [Agents4]),
+ ok;
+ Agents4 ->
+ ?FAIL({agent_unregistration_failure, Agents4})
+ end,
+ p("manager info: ~p~n", [mgr_info(ManagerNode)]),
+
+ p("unregister user_beta agents"),
+ ?line ok = mgr_unregister_agent(ManagerNode, user_beta, 5002),
+ ?line ok = mgr_unregister_agent(ManagerNode, user_beta, 5003),
+
+ p("verify all agent(s): expect 0"),
+ case mgr_which_agents(ManagerNode) of
+ [] ->
+ ok;
+ Agents5 ->
+ p("all agents: ~p~n", [Agents5]),
+ ?FAIL({agent_unregistration_failure, Agents5})
+ end,
+
+ p("manager info: ~p~n", [mgr_info(ManagerNode)]),
+
+ p("unregister user hobbe"),
+ ?line ok = mgr_unregister_user(ManagerNode, user_beta),
+
+ p("manager info: ~p~n", [mgr_info(ManagerNode)]),
+
+ ?SLEEP(1000),
+
+ p("stop snmp application (with only manager)"),
+ ?line ok = stop_snmp(ManagerNode),
+
+ ?SLEEP(1000),
+
+ stop_node(ManagerNode),
+
+ ?SLEEP(1000),
+
+ p("end"),
+ ok.
+
+
+%%======================================================================
+
+register_agent2(doc) ->
+ ["Test registration of agents with the NEW interface functions"];
+register_agent2(suite) ->
+ [];
+register_agent2(Config) when is_list(Config) ->
+ process_flag(trap_exit, true),
+ put(tname, ra2),
+ p("starting with Config: ~p~n", [Config]),
+
+ ManagerNode = start_manager_node(),
+
+ ConfDir = ?config(manager_conf_dir, Config),
+ DbDir = ?config(manager_db_dir, Config),
+ LocalHost = snmp_test_lib:localhost(),
+
+
+ write_manager_conf(ConfDir),
+
+ Opts = [{server, [{verbosity, trace}]},
+ {net_if, [{verbosity, trace}]},
+ {note_store, [{verbosity, trace}]},
+ {config, [{verbosity, trace}, {dir, ConfDir}, {db_dir, DbDir}]}],
+
+
+ p("load snmp application"),
+ ?line ok = load_snmp(ManagerNode),
+
+ p("set manager env for the snmp application"),
+ ?line ok = set_mgr_env(ManagerNode, Opts),
+
+ p("starting snmp application (with only manager)"),
+ ?line ok = start_snmp(ManagerNode),
+
+ p("started"),
+
+ ?SLEEP(1000),
+
+ p("manager info: ~p~n", [mgr_info(ManagerNode)]),
+
+ p("register user(s) calvin & hobbe"),
+ ?line ok = mgr_register_user(ManagerNode, user_alfa, snmpm_user_default, []),
+ ?line ok = mgr_register_user(ManagerNode, user_beta, snmpm_user_default, []),
+ p("manager info: ~p~n", [mgr_info(ManagerNode)]),
+
+ p("register agent(s)"),
+ TargetName1 = "agent1",
+ ?line ok = mgr_register_agent(ManagerNode, user_alfa, TargetName1,
+ [{address, LocalHost},
+ {port, 5001},
+ {engine_id, "agentEngineId-1"}]),
+ TargetName2 = "agent2",
+ ?line ok = mgr_register_agent(ManagerNode, user_alfa, TargetName2,
+ [{address, LocalHost},
+ {port, 5002},
+ {engine_id, "agentEngineId-2"}]),
+ TargetName3 = "agent3",
+ ?line ok = mgr_register_agent(ManagerNode, user_beta, TargetName3,
+ [{address, LocalHost},
+ {port, 5003},
+ {engine_id, "agentEngineId-3"}]),
+ TargetName4 = "agent4",
+ ?line ok = mgr_register_agent(ManagerNode, user_beta, TargetName4,
+ [{address, LocalHost},
+ {port, 5004},
+ {engine_id, "agentEngineId-4"}]),
+
+ p("verify all agent(s): expect 4"),
+ case mgr_which_agents(ManagerNode) of
+ Agents1 when length(Agents1) =:= 4 ->
+ p("all agents: ~p~n", [Agents1]),
+ ok;
+ Agents1 ->
+ ?FAIL({agent_registration_failure, Agents1})
+ end,
+
+ p("verify user_alfa agent(s)"),
+ case mgr_which_agents(ManagerNode, user_alfa) of
+ Agents2 when length(Agents2) =:= 2 ->
+ p("calvin agents: ~p~n", [Agents2]),
+ ok;
+ Agents2 ->
+ ?FAIL({agent_registration_failure, Agents2})
+ end,
+
+ p("verify user_beta agent(s)"),
+ case mgr_which_agents(ManagerNode, user_beta) of
+ Agents3 when length(Agents3) =:= 2 ->
+ p("hobbe agents: ~p~n", [Agents3]),
+ ok;
+ Agents3 ->
+ ?FAIL({agent_registration_failure, Agents3})
+ end,
+
+ p("manager info: ~p~n", [mgr_info(ManagerNode)]),
+
+ p("unregister user user_alfa"),
+ ?line ok = mgr_unregister_user(ManagerNode, user_alfa),
+
+ p("verify all agent(s): expect 2"),
+ case mgr_which_agents(ManagerNode) of
+ Agents4 when length(Agents4) =:= 2 ->
+ p("all agents: ~p~n", [Agents4]),
+ ok;
+ Agents4 ->
+ ?FAIL({agent_unregistration_failure, Agents4})
+ end,
+ p("manager info: ~p~n", [mgr_info(ManagerNode)]),
+
+ p("unregister user_beta agents"),
+ ?line ok = mgr_unregister_agent(ManagerNode, user_beta, TargetName3),
+ ?line ok = mgr_unregister_agent(ManagerNode, user_beta, TargetName4),
+
+ p("verify all agent(s): expect 0"),
+ case mgr_which_agents(ManagerNode) of
+ [] ->
+ ok;
+ Agents5 ->
+ p("all agents: ~p~n", [Agents5]),
+ ?FAIL({agent_unregistration_failure, Agents5})
+ end,
+
+ p("manager info: ~p~n", [mgr_info(ManagerNode)]),
+
+ p("unregister user hobbe"),
+ ?line ok = mgr_unregister_user(ManagerNode, user_beta),
+
+ p("manager info: ~p~n", [mgr_info(ManagerNode)]),
+
+ ?SLEEP(1000),
+
+ p("stop snmp application (with only manager)"),
+ ?line ok = stop_snmp(ManagerNode),
+
+ ?SLEEP(1000),
+
+ stop_node(ManagerNode),
+
+ ?SLEEP(1000),
+
+ p("end"),
+ ok.
+
+
+%%======================================================================
+
+simple_sync_get1(doc) -> ["Simple sync get-request - Old style (Addr & Port)"];
+simple_sync_get1(suite) -> [];
+simple_sync_get1(Config) when is_list(Config) ->
+ process_flag(trap_exit, true),
+ put(tname, ssg1),
+ p("starting with Config: ~p~n", [Config]),
+
+ Node = ?config(manager_node, Config),
+ Addr = ?config(ip, Config),
+ Port = ?AGENT_PORT,
+
+ p("issue get-request without loading the mib"),
+ Oids1 = [?sysObjectID_instance, ?sysDescr_instance, ?sysUpTime_instance],
+ ?line ok = do_simple_get(Node, Addr, Port, Oids1),
+
+ p("issue get-request after first loading the mibs"),
+ ?line ok = mgr_user_load_mib(Node, std_mib()),
+ Oids2 = [[sysObjectID, 0], [sysDescr, 0], [sysUpTime, 0]],
+ ?line ok = do_simple_get(Node, Addr, Port, Oids2),
+ ok.
+
+do_simple_get(Node, Addr, Port, Oids) ->
+ ?line {ok, Reply, Rem} = mgr_user_sync_get(Node, Addr, Port, Oids),
+
+ ?DBG("~n Reply: ~p"
+ "~n Rem: ~w", [Reply, Rem]),
+
+ %% verify that the operation actually worked:
+ %% The order should be the same, so no need to seach
+ ?line ok = case Reply of
+ {noError, 0, [#varbind{oid = ?sysObjectID_instance,
+ value = SysObjectID},
+ #varbind{oid = ?sysDescr_instance,
+ value = SysDescr},
+ #varbind{oid = ?sysUpTime_instance,
+ value = SysUpTime}]} ->
+ p("expected result from get: "
+ "~n SysObjectID: ~p"
+ "~n SysDescr: ~s"
+ "~n SysUpTime: ~w",
+ [SysObjectID, SysDescr, SysUpTime]),
+ ok;
+ {noError, 0, Vbs} ->
+ p("unexpected varbinds: ~n~p", [Vbs]),
+ {error, {unexpected_vbs, Vbs}};
+ Else ->
+ p("unexpected reply: ~n~p", [Else]),
+ {error, {unexpected_response, Else}}
+ end,
+ ok.
+
+
+%%======================================================================
+
+simple_sync_get2(doc) -> ["Simple sync get-request - New style (TargetName)"];
+simple_sync_get2(suite) -> [];
+simple_sync_get2(Config) when is_list(Config) ->
+ process_flag(trap_exit, true),
+ put(tname, ssg2),
+ p("starting with Config: ~p~n", [Config]),
+
+ Node = ?config(manager_node, Config),
+ TargetName = ?config(manager_agent_target_name, Config),
+
+ p("issue get-request without loading the mib"),
+ Oids1 = [?sysObjectID_instance, ?sysDescr_instance, ?sysUpTime_instance],
+ ?line ok = do_simple_get(Node, TargetName, Oids1),
+
+ p("issue get-request after first loading the mibs"),
+ ?line ok = mgr_user_load_mib(Node, std_mib()),
+ Oids2 = [[sysObjectID, 0], [sysDescr, 0], [sysUpTime, 0]],
+ ?line ok = do_simple_get(Node, TargetName, Oids2),
+ ok.
+
+do_simple_get(Node, TargetName, Oids) ->
+ ?line {ok, Reply, Rem} = mgr_user_sync_get(Node, TargetName, Oids),
+
+ ?DBG("~n Reply: ~p"
+ "~n Rem: ~w", [Reply, Rem]),
+
+ %% verify that the operation actually worked:
+ %% The order should be the same, so no need to seach
+ ?line ok = case Reply of
+ {noError, 0, [#varbind{oid = ?sysObjectID_instance,
+ value = SysObjectID},
+ #varbind{oid = ?sysDescr_instance,
+ value = SysDescr},
+ #varbind{oid = ?sysUpTime_instance,
+ value = SysUpTime}]} ->
+ p("expected result from get: "
+ "~n SysObjectID: ~p"
+ "~n SysDescr: ~s"
+ "~n SysUpTime: ~w",
+ [SysObjectID, SysDescr, SysUpTime]),
+ ok;
+ {noError, 0, Vbs} ->
+ p("unexpected varbinds: ~n~p", [Vbs]),
+ {error, {unexpected_vbs, Vbs}};
+ Else ->
+ p("unexpected reply: ~n~p", [Else]),
+ {error, {unexpected_response, Else}}
+ end,
+ ok.
+
+
+%%======================================================================
+
+simple_async_get1(doc) -> ["Simple (async) get-request - "
+ "Old style (Addr & Port)"];
+simple_async_get1(suite) -> [];
+simple_async_get1(Config) when is_list(Config) ->
+ process_flag(trap_exit, true),
+ put(tname, sag1),
+ p("starting with Config: ~p~n", [Config]),
+
+ MgrNode = ?config(manager_node, Config),
+ AgentNode = ?config(agent_node, Config),
+ Addr = ?config(ip, Config),
+ Port = ?AGENT_PORT,
+
+ ?line ok = mgr_user_load_mib(MgrNode, std_mib()),
+ Test2Mib = test2_mib(Config),
+ ?line ok = mgr_user_load_mib(MgrNode, Test2Mib),
+ ?line ok = agent_load_mib(AgentNode, Test2Mib),
+
+ Exec = fun(Data) ->
+ async_g_exec1(MgrNode, Addr, Port, Data)
+ end,
+
+ Requests = [
+ { 1,
+ [?sysObjectID_instance],
+ Exec,
+ fun(X) -> sag_verify(X, [?sysObjectID_instance]) end},
+ { 2,
+ [?sysDescr_instance, ?sysUpTime_instance],
+ Exec,
+ fun(X) ->
+ sag_verify(X, [?sysObjectID_instance,
+ ?sysUpTime_instance])
+ end},
+ { 3,
+ [[sysObjectID, 0], [sysDescr, 0], [sysUpTime, 0]],
+ Exec,
+ fun(X) ->
+ sag_verify(X, [?sysObjectID_instance,
+ ?sysDescr_instance,
+ ?sysUpTime_instance])
+ end},
+ { 4,
+ [?sysObjectID_instance,
+ ?sysDescr_instance,
+ ?sysUpTime_instance],
+ Exec,
+ fun(X) ->
+ sag_verify(X, [?sysObjectID_instance,
+ ?sysDescr_instance,
+ ?sysUpTime_instance])
+ end}
+ ],
+
+ p("manager info when starting test: ~n~p", [mgr_info(MgrNode)]),
+ p("agent info when starting test: ~n~p", [agent_info(AgentNode)]),
+
+ ?line ok = async_exec(Requests, []),
+
+ p("manager info when ending test: ~n~p", [mgr_info(MgrNode)]),
+ p("agent info when ending test: ~n~p", [agent_info(AgentNode)]),
+
+ ok.
+
+async_g_exec1(Node, Addr, Port, Oids) ->
+ mgr_user_async_get(Node, Addr, Port, Oids).
+
+sag_verify({noError, 0, _Vbs}, any) ->
+ p("verified [any]"),
+ ok;
+sag_verify({noError, 0, Vbs}, Exp) ->
+ ?DBG("verified first stage ok: "
+ "~n Vbs: ~p"
+ "~n Exp: ~p", [Vbs, Exp]),
+ sag_verify_vbs(Vbs, Exp);
+sag_verify(Error, _) ->
+ {error, {unexpected_response, Error}}.
+
+sag_verify_vbs([], []) ->
+ ?DBG("verified second stage ok", []),
+ ok;
+sag_verify_vbs(Vbs, []) ->
+ {error, {unexpected_vbs, Vbs}};
+sag_verify_vbs([], Exp) ->
+ {error, {expected_vbs, Exp}};
+sag_verify_vbs([#varbind{oid = Oid}|Vbs], [any|Exp]) ->
+ p("verified [any] oid ~w", [Oid]),
+ sag_verify_vbs(Vbs, Exp);
+sag_verify_vbs([#varbind{oid = Oid, value = Value}|Vbs], [Oid|Exp]) ->
+ p("verified oid ~w [~p]", [Oid, Value]),
+ sag_verify_vbs(Vbs, Exp);
+sag_verify_vbs([#varbind{oid = Oid, value = Value}|Vbs], [{Oid,Value}|Exp]) ->
+ p("verified oid ~w and ~p", [Oid, Value]),
+ sag_verify_vbs(Vbs, Exp);
+sag_verify_vbs([Vb|_], [E|_]) ->
+ {error, {unexpected_vb, Vb, E}}.
+
+
+%%======================================================================
+
+simple_async_get2(doc) -> ["Simple (async) get-request - "
+ "New style (TargetName)"];
+simple_async_get2(suite) -> [];
+simple_async_get2(Config) when is_list(Config) ->
+ process_flag(trap_exit, true),
+ put(tname, sag2),
+ p("starting with Config: ~p~n", [Config]),
+
+ MgrNode = ?config(manager_node, Config),
+ AgentNode = ?config(agent_node, Config),
+ TargetName = ?config(manager_agent_target_name, Config),
+
+ ?line ok = mgr_user_load_mib(MgrNode, std_mib()),
+ Test2Mib = test2_mib(Config),
+ ?line ok = mgr_user_load_mib(MgrNode, Test2Mib),
+ ?line ok = agent_load_mib(AgentNode, Test2Mib),
+
+ Exec = fun(Data) ->
+ async_g_exec2(MgrNode, TargetName, Data)
+ end,
+
+ Requests = [
+ { 1,
+ [?sysObjectID_instance],
+ Exec,
+ fun(X) -> sag_verify(X, [?sysObjectID_instance]) end},
+ { 2,
+ [?sysDescr_instance, ?sysUpTime_instance],
+ Exec,
+ fun(X) ->
+ sag_verify(X, [?sysObjectID_instance,
+ ?sysUpTime_instance])
+ end},
+ { 3,
+ [[sysObjectID, 0], [sysDescr, 0], [sysUpTime, 0]],
+ Exec,
+ fun(X) ->
+ sag_verify(X, [?sysObjectID_instance,
+ ?sysDescr_instance,
+ ?sysUpTime_instance])
+ end},
+ { 4,
+ [?sysObjectID_instance,
+ ?sysDescr_instance,
+ ?sysUpTime_instance],
+ Exec,
+ fun(X) ->
+ sag_verify(X, [?sysObjectID_instance,
+ ?sysDescr_instance,
+ ?sysUpTime_instance])
+ end}
+ ],
+
+ p("manager info when starting test: ~n~p", [mgr_info(MgrNode)]),
+ p("agent info when starting test: ~n~p", [agent_info(AgentNode)]),
+
+ ?line ok = async_exec(Requests, []),
+
+ p("manager info when ending test: ~n~p", [mgr_info(MgrNode)]),
+ p("agent info when ending test: ~n~p", [agent_info(AgentNode)]),
+
+ ok.
+
+async_g_exec2(Node, TargetName, Oids) ->
+ mgr_user_async_get(Node, TargetName, Oids).
+
+
+%%======================================================================
+
+simple_sync_get_next1(doc) -> ["Simple (sync) get_next-request - "
+ "Old style (Addr & Port)"];
+simple_sync_get_next1(suite) -> [];
+simple_sync_get_next1(Config) when is_list(Config) ->
+ process_flag(trap_exit, true),
+ put(tname, ssgn1),
+ p("starting with Config: ~p~n", [Config]),
+
+ MgrNode = ?config(manager_node, Config),
+ AgentNode = ?config(agent_node, Config),
+ Addr = ?config(ip, Config),
+ Port = ?AGENT_PORT,
+
+ %% -- 1 --
+ Oids01 = [[1,3,7,1]],
+ VF01 = fun(X) -> verify_ssgn_reply1(X, [{[1,3,7,1],endOfMibView}]) end,
+ ?line ok = do_simple_get_next(1,
+ MgrNode, Addr, Port, Oids01, VF01),
+
+ ?line ok = mgr_user_load_mib(MgrNode, std_mib()),
+
+ %% -- 2 --
+ Oids02 = [[sysDescr], [1,3,7,1]],
+ VF02 = fun(X) ->
+ verify_ssgn_reply1(X, [?sysDescr_instance, endOfMibView])
+ end,
+ ?line ok = do_simple_get_next(2,
+ MgrNode, Addr, Port, Oids02, VF02),
+
+ Test2Mib = test2_mib(Config),
+ ?line ok = mgr_user_load_mib(MgrNode, Test2Mib),
+ ?line ok = agent_load_mib(AgentNode, Test2Mib),
+
+ %% -- 3 --
+ ?line {ok, [TCnt2|_]} = mgr_user_name_to_oid(MgrNode, tCnt2),
+ Oids03 = [[TCnt2, 1]],
+ VF03 = fun(X) ->
+ verify_ssgn_reply1(X, [{fl([TCnt2,2]), 100}])
+ end,
+ ?line ok = do_simple_get_next(3,
+ MgrNode, Addr, Port, Oids03, VF03),
+
+ %% -- 4 --
+ Oids04 = [[TCnt2, 2]],
+ VF04 = fun(X) ->
+ verify_ssgn_reply1(X, [{fl([TCnt2,2]), endOfMibView}])
+ end,
+ ?line ok = do_simple_get_next(4,
+ MgrNode, Addr, Port, Oids04, VF04),
+
+ %% -- 5 --
+ ?line {ok, [TGenErr1|_]} = mgr_user_name_to_oid(MgrNode, tGenErr1),
+ Oids05 = [TGenErr1],
+ VF05 = fun(X) ->
+ verify_ssgn_reply2(X, {genErr, 1, [TGenErr1]})
+ end,
+ ?line ok = do_simple_get_next(5,
+ MgrNode, Addr, Port, Oids05, VF05),
+
+ %% -- 6 --
+ ?line {ok, [TGenErr2|_]} = mgr_user_name_to_oid(MgrNode, tGenErr2),
+ Oids06 = [TGenErr2],
+ VF06 = fun(X) ->
+ verify_ssgn_reply2(X, {genErr, 1, [TGenErr2]})
+ end,
+ ?line ok = do_simple_get_next(6,
+ MgrNode, Addr, Port, Oids06, VF06),
+
+ %% -- 7 --
+ ?line {ok, [TGenErr3|_]} = mgr_user_name_to_oid(MgrNode, tGenErr3),
+ Oids07 = [[sysDescr], TGenErr3],
+ VF07 = fun(X) ->
+ verify_ssgn_reply2(X, {genErr, 2,
+ [?sysDescr, TGenErr3]})
+ end,
+ ?line ok = do_simple_get_next(7,
+ MgrNode, Addr, Port, Oids07, VF07),
+
+ %% -- 8 --
+ ?line {ok, [TTooBig|_]} = mgr_user_name_to_oid(MgrNode, tTooBig),
+ Oids08 = [TTooBig],
+ VF08 = fun(X) ->
+ verify_ssgn_reply2(X, {tooBig, 0, []})
+ end,
+ ?line ok = do_simple_get_next(8,
+ MgrNode, Addr, Port, Oids08, VF08),
+ ok.
+
+
+do_simple_get_next(N, Node, Addr, Port, Oids, Verify) ->
+ p("issue get-next command ~w", [N]),
+ case mgr_user_sync_get_next(Node, Addr, Port, Oids) of
+ {ok, Reply, Rem} ->
+ ?DBG("get-next ok:"
+ "~n Reply: ~p"
+ "~n Rem: ~w", [Reply, Rem]),
+ Verify(Reply);
+
+ Error ->
+ {error, {unexpected_reply, Error}}
+ end.
+
+
+verify_ssgn_reply1({noError, 0, _Vbs}, any) ->
+ ok;
+verify_ssgn_reply1({noError, 0, Vbs}, Expected) ->
+ check_ssgn_vbs(Vbs, Expected);
+verify_ssgn_reply1(R, _) ->
+ {error, {unexpected_reply, R}}.
+
+verify_ssgn_reply2({ErrStatus, ErrIdx, _Vbs}, {ErrStatus, ErrIdx, any}) ->
+ ok;
+verify_ssgn_reply2({ErrStatus, ErrIdx, Vbs}, {ErrStatus, ErrIdx, Expected}) ->
+ check_ssgn_vbs(Vbs, Expected);
+verify_ssgn_reply2(R, _) ->
+ {error, {unexpected_reply, R}}.
+
+check_ssgn_vbs([], []) ->
+ ok;
+check_ssgn_vbs(Unexpected, []) ->
+ {error, {unexpected_vbs, Unexpected}};
+check_ssgn_vbs([], Expected) ->
+ {error, {expected_vbs, Expected}};
+check_ssgn_vbs([#varbind{value = endOfMibView}|R],
+ [endOfMibView|Expected]) ->
+ check_ssgn_vbs(R, Expected);
+check_ssgn_vbs([#varbind{oid = Oid}|R], [Oid|Expected]) ->
+ check_ssgn_vbs(R, Expected);
+check_ssgn_vbs([#varbind{oid = Oid, value = Value}|R],
+ [{Oid, Value}|Expected]) ->
+ check_ssgn_vbs(R, Expected);
+check_ssgn_vbs([Vb|_], [E|_]) ->
+ {error, {unexpected_vb, Vb, E}}.
+
+
+%%======================================================================
+
+simple_sync_get_next2(doc) -> ["Simple (sync) get_next-request - "
+ "New style (TargetName)"];
+simple_sync_get_next2(suite) -> [];
+simple_sync_get_next2(Config) when is_list(Config) ->
+ process_flag(trap_exit, true),
+ put(tname, ssgn),
+ p("starting with Config: ~p~n", [Config]),
+
+ MgrNode = ?config(manager_node, Config),
+ AgentNode = ?config(agent_node, Config),
+ TargetName = ?config(manager_agent_target_name, Config),
+
+ %% -- 1 --
+ Oids01 = [[1,3,7,1]],
+ VF01 = fun(X) -> verify_ssgn_reply1(X, [{[1,3,7,1],endOfMibView}]) end,
+ ?line ok = do_simple_get_next(1,
+ MgrNode, TargetName, Oids01, VF01),
+
+ ?line ok = mgr_user_load_mib(MgrNode, std_mib()),
+
+ %% -- 2 --
+ Oids02 = [[sysDescr], [1,3,7,1]],
+ VF02 = fun(X) ->
+ verify_ssgn_reply1(X, [?sysDescr_instance, endOfMibView])
+ end,
+ ?line ok = do_simple_get_next(2,
+ MgrNode, TargetName, Oids02, VF02),
+
+ Test2Mib = test2_mib(Config),
+ ?line ok = mgr_user_load_mib(MgrNode, Test2Mib),
+ ?line ok = agent_load_mib(AgentNode, Test2Mib),
+
+ %% -- 3 --
+ ?line {ok, [TCnt2|_]} = mgr_user_name_to_oid(MgrNode, tCnt2),
+ Oids03 = [[TCnt2, 1]],
+ VF03 = fun(X) ->
+ verify_ssgn_reply1(X, [{fl([TCnt2,2]), 100}])
+ end,
+ ?line ok = do_simple_get_next(3,
+ MgrNode, TargetName, Oids03, VF03),
+
+ %% -- 4 --
+ Oids04 = [[TCnt2, 2]],
+ VF04 = fun(X) ->
+ verify_ssgn_reply1(X, [{fl([TCnt2,2]), endOfMibView}])
+ end,
+ ?line ok = do_simple_get_next(4,
+ MgrNode, TargetName, Oids04, VF04),
+
+ %% -- 5 --
+ ?line {ok, [TGenErr1|_]} = mgr_user_name_to_oid(MgrNode, tGenErr1),
+ Oids05 = [TGenErr1],
+ VF05 = fun(X) ->
+ verify_ssgn_reply2(X, {genErr, 1, [TGenErr1]})
+ end,
+ ?line ok = do_simple_get_next(5,
+ MgrNode, TargetName, Oids05, VF05),
+
+ %% -- 6 --
+ ?line {ok, [TGenErr2|_]} = mgr_user_name_to_oid(MgrNode, tGenErr2),
+ Oids06 = [TGenErr2],
+ VF06 = fun(X) ->
+ verify_ssgn_reply2(X, {genErr, 1, [TGenErr2]})
+ end,
+ ?line ok = do_simple_get_next(6,
+ MgrNode, TargetName, Oids06, VF06),
+
+ %% -- 7 --
+ ?line {ok, [TGenErr3|_]} = mgr_user_name_to_oid(MgrNode, tGenErr3),
+ Oids07 = [[sysDescr], TGenErr3],
+ VF07 = fun(X) ->
+ verify_ssgn_reply2(X, {genErr, 2,
+ [?sysDescr, TGenErr3]})
+ end,
+ ?line ok = do_simple_get_next(7,
+ MgrNode, TargetName, Oids07, VF07),
+
+ %% -- 8 --
+ ?line {ok, [TTooBig|_]} = mgr_user_name_to_oid(MgrNode, tTooBig),
+ Oids08 = [TTooBig],
+ VF08 = fun(X) ->
+ verify_ssgn_reply2(X, {tooBig, 0, []})
+ end,
+ ?line ok = do_simple_get_next(8,
+ MgrNode, TargetName, Oids08, VF08),
+ ok.
+
+
+do_simple_get_next(N, Node, TargetName, Oids, Verify) ->
+ p("issue get-next command ~w", [N]),
+ case mgr_user_sync_get_next(Node, TargetName, Oids) of
+ {ok, Reply, Rem} ->
+ ?DBG("get-next ok:"
+ "~n Reply: ~p"
+ "~n Rem: ~w", [Reply, Rem]),
+ Verify(Reply);
+
+ Error ->
+ {error, {unexpected_reply, Error}}
+ end.
+
+
+%%======================================================================
+
+simple_async_get_next1(doc) -> ["Simple (async) get_next-request - "
+ "Old style (Addr & Port)"];
+simple_async_get_next1(suite) -> [];
+simple_async_get_next1(Config) when is_list(Config) ->
+ process_flag(trap_exit, true),
+ put(tname, ssgn1),
+ p("starting with Config: ~p~n", [Config]),
+
+ MgrNode = ?config(manager_node, Config),
+ AgentNode = ?config(agent_node, Config),
+ Addr = ?config(ip, Config),
+ Port = ?AGENT_PORT,
+
+ ?line ok = mgr_user_load_mib(MgrNode, std_mib()),
+ Test2Mib = test2_mib(Config),
+ ?line ok = mgr_user_load_mib(MgrNode, Test2Mib),
+ ?line ok = agent_load_mib(AgentNode, Test2Mib),
+
+ Exec = fun(X) ->
+ async_gn_exec1(MgrNode, Addr, Port, X)
+ end,
+
+ ?line {ok, [TCnt2|_]} = mgr_user_name_to_oid(MgrNode, tCnt2),
+ ?line {ok, [TGenErr1|_]} = mgr_user_name_to_oid(MgrNode, tGenErr1),
+ ?line {ok, [TGenErr2|_]} = mgr_user_name_to_oid(MgrNode, tGenErr2),
+ ?line {ok, [TGenErr3|_]} = mgr_user_name_to_oid(MgrNode, tGenErr3),
+ ?line {ok, [TTooBig|_]} = mgr_user_name_to_oid(MgrNode, tTooBig),
+
+ Requests =
+ [
+ {1,
+ [[1,3,7,1]],
+ Exec,
+ fun(X) ->
+ verify_ssgn_reply1(X, [{[1,3,7,1], endOfMibView}])
+ end},
+ {2,
+ [[sysDescr], [1,3,7,1]],
+ Exec,
+ fun(X) ->
+ verify_ssgn_reply1(X, [?sysDescr_instance, endOfMibView])
+ end},
+ {3,
+ [[TCnt2, 1]],
+ Exec,
+ fun(X) ->
+ verify_ssgn_reply1(X, [{fl([TCnt2,2]), 100}])
+ end},
+ {4,
+ [[TCnt2, 2]],
+ Exec,
+ fun(X) ->
+ verify_ssgn_reply1(X, [{fl([TCnt2,2]), endOfMibView}])
+ end},
+ {5,
+ [TGenErr1],
+ Exec,
+ fun(X) ->
+ verify_ssgn_reply2(X, {genErr, 1, [TGenErr1]})
+ end},
+ {6,
+ [TGenErr2],
+ Exec,
+ fun(X) ->
+ verify_ssgn_reply2(X, {genErr, 1, [TGenErr2]})
+ end},
+ {7,
+ [[sysDescr], TGenErr3],
+ Exec,
+ fun(X) ->
+ verify_ssgn_reply2(X, {genErr, 2, [TGenErr3]})
+ end},
+ {8,
+ [TTooBig],
+ Exec,
+ fun(X) ->
+ verify_ssgn_reply2(X, {tooBig, 0, []})
+ end}
+ ],
+
+ p("manager info when starting test: ~n~p", [mgr_info(MgrNode)]),
+ p("agent info when starting test: ~n~p", [agent_info(AgentNode)]),
+
+ ?line ok = async_exec(Requests, []),
+
+ p("manager info when ending test: ~n~p", [mgr_info(MgrNode)]),
+ p("agent info when ending test: ~n~p", [agent_info(AgentNode)]),
+
+ ok.
+
+
+async_gn_exec1(Node, Addr, Port, Oids) ->
+ mgr_user_async_get_next(Node, Addr, Port, Oids).
+
+
+%%======================================================================
+
+simple_async_get_next2(doc) -> ["Simple (async) get_next-request - "
+ "New style (TargetName)"];
+simple_async_get_next2(suite) -> [];
+simple_async_get_next2(Config) when is_list(Config) ->
+ process_flag(trap_exit, true),
+ put(tname, ssgn2),
+ p("starting with Config: ~p~n", [Config]),
+
+ MgrNode = ?config(manager_node, Config),
+ AgentNode = ?config(agent_node, Config),
+ TargetName = ?config(manager_agent_target_name, Config),
+
+ ?line ok = mgr_user_load_mib(MgrNode, std_mib()),
+ Test2Mib = test2_mib(Config),
+ ?line ok = mgr_user_load_mib(MgrNode, Test2Mib),
+ ?line ok = agent_load_mib(AgentNode, Test2Mib),
+
+ Exec = fun(X) ->
+ async_gn_exec2(MgrNode, TargetName, X)
+ end,
+
+ ?line {ok, [TCnt2|_]} = mgr_user_name_to_oid(MgrNode, tCnt2),
+ ?line {ok, [TGenErr1|_]} = mgr_user_name_to_oid(MgrNode, tGenErr1),
+ ?line {ok, [TGenErr2|_]} = mgr_user_name_to_oid(MgrNode, tGenErr2),
+ ?line {ok, [TGenErr3|_]} = mgr_user_name_to_oid(MgrNode, tGenErr3),
+ ?line {ok, [TTooBig|_]} = mgr_user_name_to_oid(MgrNode, tTooBig),
+
+ Requests =
+ [
+ {1,
+ [[1,3,7,1]],
+ Exec,
+ fun(X) ->
+ verify_ssgn_reply1(X, [{[1,3,7,1], endOfMibView}])
+ end},
+ {2,
+ [[sysDescr], [1,3,7,1]],
+ Exec,
+ fun(X) ->
+ verify_ssgn_reply1(X, [?sysDescr_instance, endOfMibView])
+ end},
+ {3,
+ [[TCnt2, 1]],
+ Exec,
+ fun(X) ->
+ verify_ssgn_reply1(X, [{fl([TCnt2,2]), 100}])
+ end},
+ {4,
+ [[TCnt2, 2]],
+ Exec,
+ fun(X) ->
+ verify_ssgn_reply1(X, [{fl([TCnt2,2]), endOfMibView}])
+ end},
+ {5,
+ [TGenErr1],
+ Exec,
+ fun(X) ->
+ verify_ssgn_reply2(X, {genErr, 1, [TGenErr1]})
+ end},
+ {6,
+ [TGenErr2],
+ Exec,
+ fun(X) ->
+ verify_ssgn_reply2(X, {genErr, 1, [TGenErr2]})
+ end},
+ {7,
+ [[sysDescr], TGenErr3],
+ Exec,
+ fun(X) ->
+ verify_ssgn_reply2(X, {genErr, 2, [TGenErr3]})
+ end},
+ {8,
+ [TTooBig],
+ Exec,
+ fun(X) ->
+ verify_ssgn_reply2(X, {tooBig, 0, []})
+ end}
+ ],
+
+ p("manager info when starting test: ~n~p", [mgr_info(MgrNode)]),
+ p("agent info when starting test: ~n~p", [agent_info(AgentNode)]),
+
+ ?line ok = async_exec(Requests, []),
+
+ p("manager info when ending test: ~n~p", [mgr_info(MgrNode)]),
+ p("agent info when ending test: ~n~p", [agent_info(AgentNode)]),
+
+ ok.
+
+
+async_gn_exec2(Node, TargetName, Oids) ->
+ mgr_user_async_get_next(Node, TargetName, Oids).
+
+
+%%======================================================================
+
+simple_sync_set1(doc) -> ["Simple (sync) set-request - "
+ "Old style (Addr & Port)"];
+simple_sync_set1(suite) -> [];
+simple_sync_set1(Config) when is_list(Config) ->
+ process_flag(trap_exit, true),
+ put(tname, sss1),
+ p("starting with Config: ~p~n", [Config]),
+
+ Node = ?config(manager_node, Config),
+ Addr = ?config(ip, Config),
+ Port = ?AGENT_PORT,
+
+ p("issue set-request without loading the mib"),
+ Val11 = "Arne Anka",
+ Val12 = "Stockholm",
+ VAVs1 = [
+ {?sysName_instance, s, Val11},
+ {?sysLocation_instance, s, Val12}
+ ],
+ ?line ok = do_simple_set1(Node, Addr, Port, VAVs1),
+
+ p("issue set-request after first loading the mibs"),
+ ?line ok = mgr_user_load_mib(Node, std_mib()),
+ Val21 = "Sune Anka",
+ Val22 = "Gothenburg",
+ VAVs2 = [
+ {[sysName, 0], Val21},
+ {[sysLocation, 0], Val22}
+ ],
+ ?line ok = do_simple_set1(Node, Addr, Port, VAVs2),
+ ok.
+
+do_simple_set1(Node, Addr, Port, VAVs) ->
+ [SysName, SysLoc] = value_of_vavs(VAVs),
+ ?line {ok, Reply, Rem} = mgr_user_sync_set(Node, Addr, Port, VAVs),
+
+ ?DBG("~n Reply: ~p"
+ "~n Rem: ~w", [Reply, Rem]),
+
+ %% verify that the operation actually worked:
+ %% The order should be the same, so no need to seach
+ %% The value we get should be exactly the same as we sent
+ ?line ok = case Reply of
+ {noError, 0, [#varbind{oid = ?sysName_instance,
+ value = SysName},
+ #varbind{oid = ?sysLocation_instance,
+ value = SysLoc}]} ->
+ ok;
+ {noError, 0, Vbs} ->
+ {error, {unexpected_vbs, Vbs}};
+ Else ->
+ p("unexpected reply: ~n~p", [Else]),
+ {error, {unexpected_response, Else}}
+ end,
+ ok.
+
+value_of_vavs(VAVs) ->
+ value_of_vavs(VAVs, []).
+
+value_of_vavs([], Acc) ->
+ lists:reverse(Acc);
+value_of_vavs([{_Oid, _Type, Val}|VAVs], Acc) ->
+ value_of_vavs(VAVs, [Val|Acc]);
+value_of_vavs([{_Oid, Val}|VAVs], Acc) ->
+ value_of_vavs(VAVs, [Val|Acc]).
+
+
+%%======================================================================
+
+simple_sync_set2(doc) -> ["Simple (sync) set-request - New style (TargetName)"];
+simple_sync_set2(suite) -> [];
+simple_sync_set2(Config) when is_list(Config) ->
+ process_flag(trap_exit, true),
+ put(tname, sss2),
+ p("starting with Config: ~p~n", [Config]),
+
+ Node = ?config(manager_node, Config),
+ TargetName = ?config(manager_agent_target_name, Config),
+
+ p("issue set-request without loading the mib"),
+ Val11 = "Arne Anka",
+ Val12 = "Stockholm",
+ VAVs1 = [
+ {?sysName_instance, s, Val11},
+ {?sysLocation_instance, s, Val12}
+ ],
+ ?line ok = do_simple_set2(Node, TargetName, VAVs1),
+
+ p("issue set-request after first loading the mibs"),
+ ?line ok = mgr_user_load_mib(Node, std_mib()),
+ Val21 = "Sune Anka",
+ Val22 = "Gothenburg",
+ VAVs2 = [
+ {[sysName, 0], Val21},
+ {[sysLocation, 0], Val22}
+ ],
+ ?line ok = do_simple_set2(Node, TargetName, VAVs2),
+ ok.
+
+do_simple_set2(Node, TargetName, VAVs) ->
+ [SysName, SysLoc] = value_of_vavs(VAVs),
+ ?line {ok, Reply, Rem} = mgr_user_sync_set(Node, TargetName, VAVs),
+
+ ?DBG("~n Reply: ~p"
+ "~n Rem: ~w", [Reply, Rem]),
+
+ %% verify that the operation actually worked:
+ %% The order should be the same, so no need to seach
+ %% The value we get should be exactly the same as we sent
+ ?line ok = case Reply of
+ {noError, 0, [#varbind{oid = ?sysName_instance,
+ value = SysName},
+ #varbind{oid = ?sysLocation_instance,
+ value = SysLoc}]} ->
+ ok;
+ {noError, 0, Vbs} ->
+ {error, {unexpected_vbs, Vbs}};
+ Else ->
+ p("unexpected reply: ~n~p", [Else]),
+ {error, {unexpected_response, Else}}
+ end,
+ ok.
+
+
+%%======================================================================
+
+simple_async_set1(doc) -> ["Simple (async) set-request - "
+ "Old style (Addr & Port)"];
+simple_async_set1(suite) -> [];
+simple_async_set1(Config) when is_list(Config) ->
+ process_flag(trap_exit, true),
+ put(tname, sas1),
+ p("starting with Config: ~p~n", [Config]),
+
+ MgrNode = ?config(manager_node, Config),
+ AgentNode = ?config(agent_node, Config),
+ Addr = ?config(ip, Config),
+ Port = ?AGENT_PORT,
+
+ ?line ok = mgr_user_load_mib(MgrNode, std_mib()),
+ Test2Mib = test2_mib(Config),
+ ?line ok = mgr_user_load_mib(MgrNode, Test2Mib),
+ ?line ok = agent_load_mib(AgentNode, Test2Mib),
+
+ Exec = fun(X) ->
+ async_s_exec1(MgrNode, Addr, Port, X)
+ end,
+
+ Requests =
+ [
+ {1,
+ [{?sysName_instance, s, "Arne Anka"}],
+ Exec,
+ fun(X) ->
+ sas_verify(X, [?sysName_instance])
+ end},
+ {2,
+ [{?sysLocation_instance, s, "Stockholm"},
+ {?sysName_instance, s, "Arne Anka"}],
+ Exec,
+ fun(X) ->
+ sas_verify(X, [?sysLocation_instance, ?sysName_instance])
+ end},
+ {3,
+ [{[sysName, 0], "Gothenburg"},
+ {[sysLocation, 0], "Sune Anka"}],
+ Exec,
+ fun(X) ->
+ sas_verify(X, [?sysName_instance, ?sysLocation_instance])
+ end}
+ ],
+
+ p("manager info when starting test: ~n~p", [mgr_info(MgrNode)]),
+ p("agent info when starting test: ~n~p", [agent_info(AgentNode)]),
+
+ ?line ok = async_exec(Requests, []),
+
+ p("manager info when ending test: ~n~p", [mgr_info(MgrNode)]),
+ p("agent info when ending test: ~n~p", [agent_info(AgentNode)]),
+
+ ok.
+
+
+async_s_exec1(Node, Addr, Port, VAVs) ->
+ mgr_user_async_set(Node, Addr, Port, VAVs).
+
+sas_verify({noError, 0, _Vbs}, any) ->
+ p("verified [any]"),
+ ok;
+sas_verify({noError, 0, Vbs}, Expected) ->
+ ?DBG("verified stage 1: "
+ "~n Vbs: ~p"
+ "~n Exp: ~p", [Vbs, Expected]),
+ sas_verify_vbs(Vbs, Expected);
+sas_verify(Error, _) ->
+ {error, {unexpected_reply, Error}}.
+
+sas_verify_vbs([], []) ->
+ ok;
+sas_verify_vbs(Vbs, []) ->
+ {error, {unexpected_vbs, Vbs}};
+sas_verify_vbs([], Exp) ->
+ {error, {expected_vbs, Exp}};
+sas_verify_vbs([#varbind{oid = Oid}|Vbs], [any|Exp]) ->
+ p("verified [any] oid ~w", [Oid]),
+ sas_verify_vbs(Vbs, Exp);
+sas_verify_vbs([#varbind{oid = Oid, value = Value}|Vbs], [Oid|Exp]) ->
+ p("verified oid ~w [~p]", [Oid, Value]),
+ sas_verify_vbs(Vbs, Exp);
+sas_verify_vbs([#varbind{oid = Oid, value = Value}|Vbs], [{Oid,Value}|Exp]) ->
+ p("verified oid ~w and ~p", [Oid, Value]),
+ sas_verify_vbs(Vbs, Exp);
+sas_verify_vbs([Vb|_], [E|_]) ->
+ {error, {unexpected_vb, Vb, E}}.
+
+
+%%======================================================================
+
+simple_async_set2(doc) -> ["Simple (async) set-request - "
+ "New style (TargetName)"];
+simple_async_set2(suite) -> [];
+simple_async_set2(Config) when is_list(Config) ->
+ process_flag(trap_exit, true),
+ put(tname, sas2),
+ p("starting with Config: ~p~n", [Config]),
+
+ MgrNode = ?config(manager_node, Config),
+ AgentNode = ?config(agent_node, Config),
+ TargetName = ?config(manager_agent_target_name, Config),
+
+ ?line ok = mgr_user_load_mib(MgrNode, std_mib()),
+ Test2Mib = test2_mib(Config),
+ ?line ok = mgr_user_load_mib(MgrNode, Test2Mib),
+ ?line ok = agent_load_mib(AgentNode, Test2Mib),
+
+ Exec = fun(X) ->
+ async_s_exec2(MgrNode, TargetName, X)
+ end,
+
+ Requests =
+ [
+ {1,
+ [{?sysName_instance, s, "Arne Anka"}],
+ Exec,
+ fun(X) ->
+ sas_verify(X, [?sysName_instance])
+ end},
+ {2,
+ [{?sysLocation_instance, s, "Stockholm"},
+ {?sysName_instance, s, "Arne Anka"}],
+ Exec,
+ fun(X) ->
+ sas_verify(X, [?sysLocation_instance, ?sysName_instance])
+ end},
+ {3,
+ [{[sysName, 0], "Gothenburg"},
+ {[sysLocation, 0], "Sune Anka"}],
+ Exec,
+ fun(X) ->
+ sas_verify(X, [?sysName_instance, ?sysLocation_instance])
+ end}
+ ],
+
+ p("manager info when starting test: ~n~p", [mgr_info(MgrNode)]),
+ p("agent info when starting test: ~n~p", [agent_info(AgentNode)]),
+
+ ?line ok = async_exec(Requests, []),
+
+ p("manager info when ending test: ~n~p", [mgr_info(MgrNode)]),
+ p("agent info when ending test: ~n~p", [agent_info(AgentNode)]),
+
+ ok.
+
+
+async_s_exec2(Node, TargetName, VAVs) ->
+ mgr_user_async_set(Node, TargetName, VAVs).
+
+
+%%======================================================================
+
+simple_sync_get_bulk1(doc) -> ["Simple (sync) get_bulk-request - "
+ "Old style (Addr & Port)"];
+simple_sync_get_bulk1(suite) -> [];
+simple_sync_get_bulk1(Config) when is_list(Config) ->
+ process_flag(trap_exit, true),
+ put(tname, ssgb1),
+ p("starting with Config: ~p~n", [Config]),
+
+ MgrNode = ?config(manager_node, Config),
+ AgentNode = ?config(agent_node, Config),
+ Addr = ?config(ip, Config),
+ Port = ?AGENT_PORT,
+
+ %% -- 1 --
+ ?line ok = do_simple_get_bulk1(1,
+ MgrNode, Addr, Port, 1, 1, [],
+ fun verify_ssgb_reply1/1),
+
+ %% -- 2 --
+ ?line ok = do_simple_get_bulk1(2,
+ MgrNode, Addr, Port, -1, 1, [],
+ fun verify_ssgb_reply1/1),
+
+ %% -- 3 --
+ ?line ok = do_simple_get_bulk1(3,
+ MgrNode, Addr, Port, -1, -1, [],
+ fun verify_ssgb_reply1/1),
+
+ ?line ok = mgr_user_load_mib(MgrNode, std_mib()),
+ %% -- 4 --
+ VF04 = fun(X) ->
+ verify_ssgb_reply2(X, [?sysDescr_instance, endOfMibView])
+ end,
+ ?line ok = do_simple_get_bulk1(4,
+ MgrNode, Addr, Port,
+ 2, 0, [[sysDescr],[1,3,7,1]], VF04),
+
+ %% -- 5 --
+ ?line ok = do_simple_get_bulk1(5,
+ MgrNode, Addr, Port,
+ 1, 2, [[sysDescr],[1,3,7,1]], VF04),
+
+ %% -- 6 --
+ VF06 = fun(X) ->
+ verify_ssgb_reply2(X,
+ [?sysDescr_instance, endOfMibView,
+ ?sysObjectID_instance, endOfMibView])
+ end,
+ ?line ok = do_simple_get_bulk1(6,
+ MgrNode, Addr, Port,
+ 0, 2, [[sysDescr],[1,3,7,1]], VF06),
+
+ %% -- 7 --
+ VF07 = fun(X) ->
+ verify_ssgb_reply2(X,
+ [?sysDescr_instance, endOfMibView,
+ ?sysDescr_instance, endOfMibView,
+ ?sysObjectID_instance, endOfMibView])
+ end,
+ ?line ok = do_simple_get_bulk1(7,
+ MgrNode, Addr, Port,
+ 2, 2,
+ [[sysDescr],[1,3,7,1],[sysDescr],[1,3,7,1]],
+ VF07),
+
+ Test2Mib = test2_mib(Config),
+ ?line ok = mgr_user_load_mib(MgrNode, Test2Mib),
+ ?line ok = agent_load_mib(AgentNode, Test2Mib),
+
+ %% -- 8 --
+ VF08 = fun(X) ->
+ verify_ssgb_reply2(X,
+ [?sysDescr_instance,
+ ?sysDescr_instance])
+ end,
+ ?line ok = do_simple_get_bulk1(8,
+ MgrNode, Addr, Port,
+ 1, 2,
+ [[sysDescr],[sysDescr],[tTooBig]],
+ VF08),
+
+ %% -- 9 --
+ ?line ok = do_simple_get_bulk1(9,
+ MgrNode, Addr, Port,
+ 1, 12,
+ [[tDescr2], [sysDescr]],
+ fun verify_ssgb_reply1/1),
+
+ %% -- 10 --
+ VF10 = fun(X) ->
+ verify_ssgb_reply3(X,
+ [{?sysDescr, 'NULL'},
+ {?sysObjectID, 'NULL'},
+ {?tGenErr1, 'NULL'},
+ {?sysDescr, 'NULL'}])
+ end,
+ ?line ok = do_simple_get_bulk1(10,
+ MgrNode, Addr, Port,
+ 2, 2,
+ [[sysDescr],
+ [sysObjectID],
+ [tGenErr1],
+ [sysDescr]],
+ VF10),
+
+ %% -- 11 --
+ ?line {ok, [TCnt2|_]} = mgr_user_name_to_oid(MgrNode, tCnt2),
+ p("TCnt2: ~p", [TCnt2]),
+ VF11 = fun(X) ->
+ verify_ssgb_reply2(X,
+ [{fl([TCnt2,2]), 100},
+ {fl([TCnt2,2]), endOfMibView}])
+ end,
+ ?line ok = do_simple_get_bulk1(11,
+ MgrNode, Addr, Port,
+ 0, 2,
+ [[TCnt2, 1]], VF11),
+
+ ok.
+
+fl(L) ->
+ lists:flatten(L).
+
+do_simple_get_bulk1(N, Node, Addr, Port, NonRep, MaxRep, Oids, Verify) ->
+ p("issue get-bulk command ~w", [N]),
+ case mgr_user_sync_get_bulk(Node, Addr, Port, NonRep, MaxRep, Oids) of
+ {ok, Reply, Rem} ->
+ ?DBG("get-bulk ok:"
+ "~n Reply: ~p"
+ "~n Rem: ~w", [Reply, Rem]),
+ Verify(Reply);
+
+ Error ->
+ {error, {unexpected_reply, Error}}
+ end.
+
+verify_ssgb_reply1({noError, 0, []}) ->
+ ok;
+verify_ssgb_reply1(X) ->
+ {error, {unexpected_reply, X}}.
+
+verify_ssgb_reply2({noError, 0, Vbs}, ExpectedVbs) ->
+ check_ssgb_vbs(Vbs, ExpectedVbs);
+verify_ssgb_reply2(Error, _) ->
+ {error, {unexpected_reply, Error}}.
+
+verify_ssgb_reply3({genErr, 3, Vbs}, ExpectedVbs) ->
+ check_ssgb_vbs(Vbs, ExpectedVbs);
+verify_ssgb_reply3(Unexpected, _) ->
+ {error, {unexpected_reply, Unexpected}}.
+
+check_ssgb_vbs([], []) ->
+ ok;
+check_ssgb_vbs(Unexpected, []) ->
+ {error, {unexpected_vbs, Unexpected}};
+check_ssgb_vbs([], Expected) ->
+ {error, {expected_vbs, Expected}};
+check_ssgb_vbs([#varbind{value = endOfMibView}|R],
+ [endOfMibView|Expected]) ->
+ check_ssgb_vbs(R, Expected);
+check_ssgb_vbs([#varbind{oid = Oid}|R], [Oid|Expected]) ->
+ check_ssgb_vbs(R, Expected);
+check_ssgb_vbs([#varbind{oid = Oid, value = Value}|R],
+ [{Oid, Value}|Expected]) ->
+ check_ssgb_vbs(R, Expected);
+check_ssgb_vbs([R|_], [E|_]) ->
+ {error, {unexpected_vb, R, E}}.
+
+
+%%======================================================================
+
+simple_sync_get_bulk2(doc) -> ["Simple (sync) get_bulk-request - "
+ "New style (TargetName)"];
+simple_sync_get_bulk2(suite) -> [];
+simple_sync_get_bulk2(Config) when is_list(Config) ->
+ process_flag(trap_exit, true),
+ put(tname, ssgb2),
+ p("starting with Config: ~p~n", [Config]),
+
+ MgrNode = ?config(manager_node, Config),
+ AgentNode = ?config(agent_node, Config),
+ TargetName = ?config(manager_agent_target_name, Config),
+
+ %% -- 1 --
+ ?line ok = do_simple_get_bulk2(1,
+ MgrNode, TargetName, 1, 1, [],
+ fun verify_ssgb_reply1/1),
+
+ %% -- 2 --
+ ?line ok = do_simple_get_bulk2(2,
+ MgrNode, TargetName, -1, 1, [],
+ fun verify_ssgb_reply1/1),
+
+ %% -- 3 --
+ ?line ok = do_simple_get_bulk2(3,
+ MgrNode, TargetName, -1, -1, [],
+ fun verify_ssgb_reply1/1),
+
+ ?line ok = mgr_user_load_mib(MgrNode, std_mib()),
+ %% -- 4 --
+ VF04 = fun(X) ->
+ verify_ssgb_reply2(X, [?sysDescr_instance, endOfMibView])
+ end,
+ ?line ok = do_simple_get_bulk2(4,
+ MgrNode, TargetName,
+ 2, 0, [[sysDescr],[1,3,7,1]], VF04),
+
+ %% -- 5 --
+ ?line ok = do_simple_get_bulk2(5,
+ MgrNode, TargetName,
+ 1, 2, [[sysDescr],[1,3,7,1]], VF04),
+
+ %% -- 6 --
+ VF06 = fun(X) ->
+ verify_ssgb_reply2(X,
+ [?sysDescr_instance, endOfMibView,
+ ?sysObjectID_instance, endOfMibView])
+ end,
+ ?line ok = do_simple_get_bulk2(6,
+ MgrNode, TargetName,
+ 0, 2, [[sysDescr],[1,3,7,1]], VF06),
+
+ %% -- 7 --
+ VF07 = fun(X) ->
+ verify_ssgb_reply2(X,
+ [?sysDescr_instance, endOfMibView,
+ ?sysDescr_instance, endOfMibView,
+ ?sysObjectID_instance, endOfMibView])
+ end,
+ ?line ok = do_simple_get_bulk2(7,
+ MgrNode, TargetName,
+ 2, 2,
+ [[sysDescr],[1,3,7,1],[sysDescr],[1,3,7,1]],
+ VF07),
+
+ Test2Mib = test2_mib(Config),
+ ?line ok = mgr_user_load_mib(MgrNode, Test2Mib),
+ ?line ok = agent_load_mib(AgentNode, Test2Mib),
+
+ %% -- 8 --
+ VF08 = fun(X) ->
+ verify_ssgb_reply2(X,
+ [?sysDescr_instance,
+ ?sysDescr_instance])
+ end,
+ ?line ok = do_simple_get_bulk2(8,
+ MgrNode, TargetName,
+ 1, 2,
+ [[sysDescr],[sysDescr],[tTooBig]],
+ VF08),
+
+ %% -- 9 --
+ ?line ok = do_simple_get_bulk2(9,
+ MgrNode, TargetName,
+ 1, 12,
+ [[tDescr2], [sysDescr]],
+ fun verify_ssgb_reply1/1),
+
+ %% -- 10 --
+ VF10 = fun(X) ->
+ verify_ssgb_reply3(X,
+ [{?sysDescr, 'NULL'},
+ {?sysObjectID, 'NULL'},
+ {?tGenErr1, 'NULL'},
+ {?sysDescr, 'NULL'}])
+ end,
+ ?line ok = do_simple_get_bulk2(10,
+ MgrNode, TargetName,
+ 2, 2,
+ [[sysDescr],
+ [sysObjectID],
+ [tGenErr1],
+ [sysDescr]],
+ VF10),
+
+ %% -- 11 --
+ ?line {ok, [TCnt2|_]} = mgr_user_name_to_oid(MgrNode, tCnt2),
+ p("TCnt2: ~p", [TCnt2]),
+ VF11 = fun(X) ->
+ verify_ssgb_reply2(X,
+ [{fl([TCnt2,2]), 100},
+ {fl([TCnt2,2]), endOfMibView}])
+ end,
+ ?line ok = do_simple_get_bulk2(11,
+ MgrNode, TargetName,
+ 0, 2,
+ [[TCnt2, 1]], VF11),
+
+ ok.
+
+do_simple_get_bulk2(N, Node, TargetName, NonRep, MaxRep, Oids, Verify) ->
+ p("issue get-bulk command ~w", [N]),
+ case mgr_user_sync_get_bulk(Node, TargetName, NonRep, MaxRep, Oids) of
+ {ok, Reply, Rem} ->
+ ?DBG("get-bulk ok:"
+ "~n Reply: ~p"
+ "~n Rem: ~w", [Reply, Rem]),
+ Verify(Reply);
+
+ Error ->
+ {error, {unexpected_reply, Error}}
+ end.
+
+
+%%======================================================================
+
+simple_async_get_bulk1(doc) -> ["Simple (async) get_bulk-request - "
+ "Old style (Addr & Port)"];
+simple_async_get_bulk1(suite) -> [];
+simple_async_get_bulk1(Config) when is_list(Config) ->
+ process_flag(trap_exit, true),
+ put(tname, sagb1),
+ p("starting with Config: ~p~n", [Config]),
+
+ MgrNode = ?config(manager_node, Config),
+ AgentNode = ?config(agent_node, Config),
+ Addr = ?config(ip, Config),
+ Port = ?AGENT_PORT,
+
+ ?line ok = mgr_user_load_mib(MgrNode, std_mib()),
+ Test2Mib = test2_mib(Config),
+ ?line ok = mgr_user_load_mib(MgrNode, Test2Mib),
+ ?line ok = agent_load_mib(AgentNode, Test2Mib),
+
+ Exec = fun(Data) ->
+ async_gb_exec1(MgrNode, Addr, Port, Data)
+ end,
+
+ %% We re-use the verification functions from the ssgb test-case
+ VF04 = fun(X) ->
+ verify_ssgb_reply2(X, [?sysDescr_instance, endOfMibView])
+ end,
+ VF06 = fun(X) ->
+ verify_ssgb_reply2(X,
+ [?sysDescr_instance, endOfMibView,
+ ?sysObjectID_instance, endOfMibView])
+ end,
+ VF07 = fun(X) ->
+ verify_ssgb_reply2(X,
+ [?sysDescr_instance, endOfMibView,
+ ?sysDescr_instance, endOfMibView,
+ ?sysObjectID_instance, endOfMibView])
+ end,
+ VF08 = fun(X) ->
+ verify_ssgb_reply2(X,
+ [?sysDescr_instance,
+ ?sysDescr_instance])
+ end,
+ VF10 = fun(X) ->
+ verify_ssgb_reply3(X,
+ [{?sysDescr, 'NULL'},
+ {?sysObjectID, 'NULL'},
+ {?tGenErr1, 'NULL'},
+ {?sysDescr, 'NULL'}])
+ end,
+ ?line {ok, [TCnt2|_]} = mgr_user_name_to_oid(MgrNode, tCnt2),
+ VF11 = fun(X) ->
+ verify_ssgb_reply2(X,
+ [{fl([TCnt2,2]), 100},
+ {fl([TCnt2,2]), endOfMibView}])
+ end,
+ Requests = [
+ { 1,
+ {1, 1, []},
+ Exec,
+ fun verify_ssgb_reply1/1},
+ { 2,
+ {-1, 1, []},
+ Exec,
+ fun verify_ssgb_reply1/1},
+ { 3,
+ {-1, -1, []},
+ Exec,
+ fun verify_ssgb_reply1/1},
+ { 4,
+ {2, 0, [[sysDescr],[1,3,7,1]]},
+ Exec,
+ VF04},
+ { 5,
+ {1, 2, [[sysDescr],[1,3,7,1]]},
+ Exec,
+ VF04},
+ { 6,
+ {0, 2, [[sysDescr],[1,3,7,1]]},
+ Exec,
+ VF06},
+ { 7,
+ {2, 2, [[sysDescr],[1,3,7,1],[sysDescr],[1,3,7,1]]},
+ Exec,
+ VF07},
+ { 8,
+ {1, 2, [[sysDescr],[sysDescr],[tTooBig]]},
+ Exec,
+ VF08},
+ { 9,
+ {1, 12, [[tDescr2], [sysDescr]]},
+ Exec,
+ fun verify_ssgb_reply1/1},
+ {10,
+ {2, 2, [[sysDescr],[sysObjectID], [tGenErr1],[sysDescr]]},
+ Exec,
+ VF10},
+ {11,
+ {0, 2, [[TCnt2, 1]]},
+ Exec,
+ VF11},
+ {12,
+ {2, 0, [[sysDescr],[1,3,7,1]]},
+ Exec,
+ VF04},
+ {13,
+ {1, 12, [[tDescr2], [sysDescr]]},
+ Exec,
+ fun verify_ssgb_reply1/1},
+ {14,
+ {2, 2, [[sysDescr],[sysObjectID],[tGenErr1],[sysDescr]]},
+ Exec,
+ VF10},
+ {15,
+ {0, 2, [[TCnt2, 1]]},
+ Exec,
+ VF11},
+ {16,
+ {2, 2, [[sysDescr],[1,3,7,1],[sysDescr],[1,3,7,1]]},
+ Exec,
+ VF07},
+ {17,
+ {2, 2, [[sysDescr],[sysObjectID], [tGenErr1],[sysDescr]]},
+ Exec,
+ VF10}
+ ],
+
+ p("manager info when starting test: ~n~p", [mgr_info(MgrNode)]),
+ p("agent info when starting test: ~n~p", [agent_info(AgentNode)]),
+
+ ?line ok = async_exec(Requests, []),
+
+ p("manager info when ending test: ~n~p", [mgr_info(MgrNode)]),
+ p("agent info when ending test: ~n~p", [agent_info(AgentNode)]),
+
+ ok.
+
+
+async_gb_exec1(Node, Addr, Port, {NR, MR, Oids}) ->
+ mgr_user_async_get_bulk(Node, Addr, Port, NR, MR, Oids).
+
+
+%%======================================================================
+
+simple_async_get_bulk2(doc) -> ["Simple (async) get_bulk-request - "
+ "New style (TargetName)"];
+simple_async_get_bulk2(suite) -> [];
+simple_async_get_bulk2(Config) when is_list(Config) ->
+ process_flag(trap_exit, true),
+ put(tname, sagb2),
+ p("starting with Config: ~p~n", [Config]),
+
+ MgrNode = ?config(manager_node, Config),
+ AgentNode = ?config(agent_node, Config),
+ TargetName = ?config(manager_agent_target_name, Config),
+
+ ?line ok = mgr_user_load_mib(MgrNode, std_mib()),
+ Test2Mib = test2_mib(Config),
+ ?line ok = mgr_user_load_mib(MgrNode, Test2Mib),
+ ?line ok = agent_load_mib(AgentNode, Test2Mib),
+
+ Exec = fun(Data) ->
+ async_gb_exec2(MgrNode, TargetName, Data)
+ end,
+
+ %% We re-use the verification functions from the ssgb test-case
+ VF04 = fun(X) ->
+ verify_ssgb_reply2(X, [?sysDescr_instance, endOfMibView])
+ end,
+ VF06 = fun(X) ->
+ verify_ssgb_reply2(X,
+ [?sysDescr_instance, endOfMibView,
+ ?sysObjectID_instance, endOfMibView])
+ end,
+ VF07 = fun(X) ->
+ verify_ssgb_reply2(X,
+ [?sysDescr_instance, endOfMibView,
+ ?sysDescr_instance, endOfMibView,
+ ?sysObjectID_instance, endOfMibView])
+ end,
+ VF08 = fun(X) ->
+ verify_ssgb_reply2(X,
+ [?sysDescr_instance,
+ ?sysDescr_instance])
+ end,
+ VF10 = fun(X) ->
+ verify_ssgb_reply3(X,
+ [{?sysDescr, 'NULL'},
+ {?sysObjectID, 'NULL'},
+ {?tGenErr1, 'NULL'},
+ {?sysDescr, 'NULL'}])
+ end,
+ ?line {ok, [TCnt2|_]} = mgr_user_name_to_oid(MgrNode, tCnt2),
+ VF11 = fun(X) ->
+ verify_ssgb_reply2(X,
+ [{fl([TCnt2,2]), 100},
+ {fl([TCnt2,2]), endOfMibView}])
+ end,
+ Requests = [
+ { 1,
+ {1, 1, []},
+ Exec,
+ fun verify_ssgb_reply1/1},
+ { 2,
+ {-1, 1, []},
+ Exec,
+ fun verify_ssgb_reply1/1},
+ { 3,
+ {-1, -1, []},
+ Exec,
+ fun verify_ssgb_reply1/1},
+ { 4,
+ {2, 0, [[sysDescr],[1,3,7,1]]},
+ Exec,
+ VF04},
+ { 5,
+ {1, 2, [[sysDescr],[1,3,7,1]]},
+ Exec,
+ VF04},
+ { 6,
+ {0, 2, [[sysDescr],[1,3,7,1]]},
+ Exec,
+ VF06},
+ { 7,
+ {2, 2, [[sysDescr],[1,3,7,1],[sysDescr],[1,3,7,1]]},
+ Exec,
+ VF07},
+ { 8,
+ {1, 2, [[sysDescr],[sysDescr],[tTooBig]]},
+ Exec,
+ VF08},
+ { 9,
+ {1, 12, [[tDescr2], [sysDescr]]},
+ Exec,
+ fun verify_ssgb_reply1/1},
+ {10,
+ {2, 2, [[sysDescr],[sysObjectID], [tGenErr1],[sysDescr]]},
+ Exec,
+ VF10},
+ {11,
+ {0, 2, [[TCnt2, 1]]},
+ Exec,
+ VF11},
+ {12,
+ {2, 0, [[sysDescr],[1,3,7,1]]},
+ Exec,
+ VF04},
+ {13,
+ {1, 12, [[tDescr2], [sysDescr]]},
+ Exec,
+ fun verify_ssgb_reply1/1},
+ {14,
+ {2, 2, [[sysDescr],[sysObjectID],[tGenErr1],[sysDescr]]},
+ Exec,
+ VF10},
+ {15,
+ {0, 2, [[TCnt2, 1]]},
+ Exec,
+ VF11},
+ {16,
+ {2, 2, [[sysDescr],[1,3,7,1],[sysDescr],[1,3,7,1]]},
+ Exec,
+ VF07},
+ {17,
+ {2, 2, [[sysDescr],[sysObjectID], [tGenErr1],[sysDescr]]},
+ Exec,
+ VF10}
+ ],
+
+ p("manager info when starting test: ~n~p", [mgr_info(MgrNode)]),
+ p("agent info when starting test: ~n~p", [agent_info(AgentNode)]),
+
+ ?line ok = async_exec(Requests, []),
+
+ p("manager info when ending test: ~n~p", [mgr_info(MgrNode)]),
+ p("agent info when ending test: ~n~p", [agent_info(AgentNode)]),
+
+ ok.
+
+
+async_gb_exec2(Node, TargetName, {NR, MR, Oids}) ->
+ mgr_user_async_get_bulk(Node, TargetName, NR, MR, Oids).
+
+
+%%======================================================================
+
+misc_async1(doc) -> ["Misc (async) request(s) - "
+ "Old style (Addr & Port)"];
+misc_async1(suite) -> [];
+misc_async1(Config) when is_list(Config) ->
+ process_flag(trap_exit, true),
+ put(tname, ms1),
+ p("starting with Config: ~p~n", [Config]),
+
+ MgrNode = ?config(manager_node, Config),
+ AgentNode = ?config(agent_node, Config),
+ Addr = ?config(ip, Config),
+ Port = ?AGENT_PORT,
+
+ ?line ok = mgr_user_load_mib(MgrNode, std_mib()),
+ Test2Mib = test2_mib(Config),
+ ?line ok = mgr_user_load_mib(MgrNode, Test2Mib),
+ ?line ok = agent_load_mib(AgentNode, Test2Mib),
+
+ ExecG = fun(Data) ->
+ async_g_exec1(MgrNode, Addr, Port, Data)
+ end,
+
+ ExecGN = fun(Data) ->
+ async_gn_exec1(MgrNode, Addr, Port, Data)
+ end,
+
+ ExecS = fun(Data) ->
+ async_s_exec1(MgrNode, Addr, Port, Data)
+ end,
+
+ ExecGB = fun(Data) ->
+ async_gb_exec1(MgrNode, Addr, Port, Data)
+ end,
+
+ ?line {ok, [TCnt2|_]} = mgr_user_name_to_oid(MgrNode, tCnt2),
+ ?line {ok, [TGenErr1|_]} = mgr_user_name_to_oid(MgrNode, tGenErr1),
+ ?line {ok, [TGenErr2|_]} = mgr_user_name_to_oid(MgrNode, tGenErr2),
+ ?line {ok, [TGenErr3|_]} = mgr_user_name_to_oid(MgrNode, tGenErr3),
+ ?line {ok, [TTooBig|_]} = mgr_user_name_to_oid(MgrNode, tTooBig),
+
+ Requests =
+ [
+ { 1,
+ [?sysObjectID_instance],
+ ExecG,
+ fun(X) ->
+ sag_verify(X, [?sysObjectID_instance])
+ end
+ },
+ { 2,
+ {1, 1, []},
+ ExecGB,
+ fun verify_ssgb_reply1/1},
+ { 3,
+ {-1, 1, []},
+ ExecGB,
+ fun verify_ssgb_reply1/1},
+ { 4,
+ [{?sysLocation_instance, s, "Stockholm"},
+ {?sysName_instance, s, "Arne Anka"}],
+ ExecS,
+ fun(X) ->
+ sas_verify(X, [?sysLocation_instance, ?sysName_instance])
+ end},
+ { 5,
+ [[sysDescr], [1,3,7,1]],
+ ExecGN,
+ fun(X) ->
+ verify_ssgn_reply1(X, [?sysDescr_instance, endOfMibView])
+ end},
+ { 6,
+ [[sysObjectID, 0], [sysDescr, 0], [sysUpTime, 0]],
+ ExecG,
+ fun(X) ->
+ sag_verify(X, [?sysObjectID_instance,
+ ?sysDescr_instance,
+ ?sysUpTime_instance])
+ end},
+ { 7,
+ [TGenErr2],
+ ExecGN,
+ fun(X) ->
+ verify_ssgn_reply2(X, {genErr, 1, [TGenErr2]})
+ end},
+ { 8,
+ {2, 0, [[sysDescr],[1,3,7,1]]},
+ ExecGB,
+ fun(X) ->
+ verify_ssgb_reply2(X, [?sysDescr_instance, endOfMibView])
+ end},
+ { 9,
+ {1, 2, [[sysDescr],[1,3,7,1]]},
+ ExecGB,
+ fun(X) ->
+ verify_ssgb_reply2(X, [?sysDescr_instance, endOfMibView])
+ end},
+ {10,
+ [TGenErr1],
+ ExecGN,
+ fun(X) ->
+ verify_ssgn_reply2(X, {genErr, 1, [TGenErr1]})
+ end},
+ {11,
+ {0, 2, [[sysDescr],[1,3,7,1]]},
+ ExecGB,
+ fun(X) ->
+ verify_ssgb_reply2(X,
+ [?sysDescr_instance, endOfMibView,
+ ?sysObjectID_instance, endOfMibView])
+ end},
+ {12,
+ [{[sysName, 0], "Gothenburg"},
+ {[sysLocation, 0], "Sune Anka"}],
+ ExecS,
+ fun(X) ->
+ sas_verify(X, [?sysName_instance, ?sysLocation_instance])
+ end},
+ {13,
+ {2, 2, [[sysDescr],[1,3,7,1],[sysDescr],[1,3,7,1]]},
+ ExecGB,
+ fun(X) ->
+ verify_ssgb_reply2(X,
+ [?sysDescr_instance, endOfMibView,
+ ?sysDescr_instance, endOfMibView,
+ ?sysObjectID_instance, endOfMibView])
+ end},
+ {14,
+ {1, 2, [[sysDescr],[sysDescr],[tTooBig]]},
+ ExecGB,
+ fun(X) ->
+ verify_ssgb_reply2(X,
+ [?sysDescr_instance,
+ ?sysDescr_instance])
+ end},
+ {15,
+ {1, 12, [[tDescr2], [sysDescr]]},
+ ExecGB,
+ fun verify_ssgb_reply1/1},
+ {16,
+ {2, 2, [[sysDescr],[sysObjectID], [tGenErr1],[sysDescr]]},
+ ExecGB,
+ fun(X) ->
+ verify_ssgb_reply3(X,
+ [{?sysDescr, 'NULL'},
+ {?sysObjectID, 'NULL'},
+ {?tGenErr1, 'NULL'},
+ {?sysDescr, 'NULL'}])
+ end},
+ {17,
+ [[sysDescr], TGenErr3],
+ ExecGN,
+ fun(X) ->
+ verify_ssgn_reply2(X, {genErr, 2, [TGenErr3]})
+ end},
+ {18,
+ {0, 2, [[TCnt2, 1]]},
+ ExecGB,
+ fun(X) ->
+ verify_ssgb_reply2(X,
+ [{fl([TCnt2,2]), 100},
+ {fl([TCnt2,2]), endOfMibView}])
+ end},
+ {19,
+ [TTooBig],
+ ExecGN,
+ fun(X) ->
+ verify_ssgn_reply2(X, {tooBig, 0, []})
+ end},
+ {20,
+ [TTooBig],
+ ExecGN,
+ fun(X) ->
+ verify_ssgn_reply2(X, {tooBig, 0, []})
+ end}
+ ],
+
+ p("manager info when starting test: ~n~p", [mgr_info(MgrNode)]),
+ p("agent info when starting test: ~n~p", [agent_info(AgentNode)]),
+
+ ?line ok = async_exec(Requests, []),
+
+ p("manager info when ending test: ~n~p", [mgr_info(MgrNode)]),
+ p("agent info when ending test: ~n~p", [agent_info(AgentNode)]),
+
+ ok.
+
+
+%%======================================================================
+
+misc_async2(doc) -> ["Misc (async) request(s) - "
+ "New style (TargetName)"];
+misc_async2(suite) -> [];
+misc_async2(Config) when is_list(Config) ->
+ process_flag(trap_exit, true),
+ put(tname, ms2),
+ p("starting with Config: ~p~n", [Config]),
+
+ MgrNode = ?config(manager_node, Config),
+ AgentNode = ?config(agent_node, Config),
+ TargetName = ?config(manager_agent_target_name, Config),
+
+ ?line ok = mgr_user_load_mib(MgrNode, std_mib()),
+ Test2Mib = test2_mib(Config),
+ ?line ok = mgr_user_load_mib(MgrNode, Test2Mib),
+ ?line ok = agent_load_mib(AgentNode, Test2Mib),
+
+ ExecG = fun(Data) ->
+ async_g_exec2(MgrNode, TargetName, Data)
+ end,
+
+ ExecGN = fun(Data) ->
+ async_gn_exec2(MgrNode, TargetName, Data)
+ end,
+
+ ExecS = fun(Data) ->
+ async_s_exec2(MgrNode, TargetName, Data)
+ end,
+
+ ExecGB = fun(Data) ->
+ async_gb_exec2(MgrNode, TargetName, Data)
+ end,
+
+ ?line {ok, [TCnt2|_]} = mgr_user_name_to_oid(MgrNode, tCnt2),
+ ?line {ok, [TGenErr1|_]} = mgr_user_name_to_oid(MgrNode, tGenErr1),
+ ?line {ok, [TGenErr2|_]} = mgr_user_name_to_oid(MgrNode, tGenErr2),
+ ?line {ok, [TGenErr3|_]} = mgr_user_name_to_oid(MgrNode, tGenErr3),
+ ?line {ok, [TTooBig|_]} = mgr_user_name_to_oid(MgrNode, tTooBig),
+
+ Requests =
+ [
+ { 1,
+ [?sysObjectID_instance],
+ ExecG,
+ fun(X) ->
+ sag_verify(X, [?sysObjectID_instance])
+ end
+ },
+ { 2,
+ {1, 1, []},
+ ExecGB,
+ fun verify_ssgb_reply1/1},
+ { 3,
+ {-1, 1, []},
+ ExecGB,
+ fun verify_ssgb_reply1/1},
+ { 4,
+ [{?sysLocation_instance, s, "Stockholm"},
+ {?sysName_instance, s, "Arne Anka"}],
+ ExecS,
+ fun(X) ->
+ sas_verify(X, [?sysLocation_instance, ?sysName_instance])
+ end},
+ { 5,
+ [[sysDescr], [1,3,7,1]],
+ ExecGN,
+ fun(X) ->
+ verify_ssgn_reply1(X, [?sysDescr_instance, endOfMibView])
+ end},
+ { 6,
+ [[sysObjectID, 0], [sysDescr, 0], [sysUpTime, 0]],
+ ExecG,
+ fun(X) ->
+ sag_verify(X, [?sysObjectID_instance,
+ ?sysDescr_instance,
+ ?sysUpTime_instance])
+ end},
+ { 7,
+ [TGenErr2],
+ ExecGN,
+ fun(X) ->
+ verify_ssgn_reply2(X, {genErr, 1, [TGenErr2]})
+ end},
+ { 8,
+ {2, 0, [[sysDescr],[1,3,7,1]]},
+ ExecGB,
+ fun(X) ->
+ verify_ssgb_reply2(X, [?sysDescr_instance, endOfMibView])
+ end},
+ { 9,
+ {1, 2, [[sysDescr],[1,3,7,1]]},
+ ExecGB,
+ fun(X) ->
+ verify_ssgb_reply2(X, [?sysDescr_instance, endOfMibView])
+ end},
+ {10,
+ [TGenErr1],
+ ExecGN,
+ fun(X) ->
+ verify_ssgn_reply2(X, {genErr, 1, [TGenErr1]})
+ end},
+ {11,
+ {0, 2, [[sysDescr],[1,3,7,1]]},
+ ExecGB,
+ fun(X) ->
+ verify_ssgb_reply2(X,
+ [?sysDescr_instance, endOfMibView,
+ ?sysObjectID_instance, endOfMibView])
+ end},
+ {12,
+ [{[sysName, 0], "Gothenburg"},
+ {[sysLocation, 0], "Sune Anka"}],
+ ExecS,
+ fun(X) ->
+ sas_verify(X, [?sysName_instance, ?sysLocation_instance])
+ end},
+ {13,
+ {2, 2, [[sysDescr],[1,3,7,1],[sysDescr],[1,3,7,1]]},
+ ExecGB,
+ fun(X) ->
+ verify_ssgb_reply2(X,
+ [?sysDescr_instance, endOfMibView,
+ ?sysDescr_instance, endOfMibView,
+ ?sysObjectID_instance, endOfMibView])
+ end},
+ {14,
+ {1, 2, [[sysDescr],[sysDescr],[tTooBig]]},
+ ExecGB,
+ fun(X) ->
+ verify_ssgb_reply2(X,
+ [?sysDescr_instance,
+ ?sysDescr_instance])
+ end},
+ {15,
+ {1, 12, [[tDescr2], [sysDescr]]},
+ ExecGB,
+ fun verify_ssgb_reply1/1},
+ {16,
+ {2, 2, [[sysDescr],[sysObjectID], [tGenErr1],[sysDescr]]},
+ ExecGB,
+ fun(X) ->
+ verify_ssgb_reply3(X,
+ [{?sysDescr, 'NULL'},
+ {?sysObjectID, 'NULL'},
+ {?tGenErr1, 'NULL'},
+ {?sysDescr, 'NULL'}])
+ end},
+ {17,
+ [[sysDescr], TGenErr3],
+ ExecGN,
+ fun(X) ->
+ verify_ssgn_reply2(X, {genErr, 2, [TGenErr3]})
+ end},
+ {18,
+ {0, 2, [[TCnt2, 1]]},
+ ExecGB,
+ fun(X) ->
+ verify_ssgb_reply2(X,
+ [{fl([TCnt2,2]), 100},
+ {fl([TCnt2,2]), endOfMibView}])
+ end},
+ {19,
+ [TTooBig],
+ ExecGN,
+ fun(X) ->
+ verify_ssgn_reply2(X, {tooBig, 0, []})
+ end},
+ {20,
+ [TTooBig],
+ ExecGN,
+ fun(X) ->
+ verify_ssgn_reply2(X, {tooBig, 0, []})
+ end}
+ ],
+
+ p("manager info when starting test: ~n~p", [mgr_info(MgrNode)]),
+ p("agent info when starting test: ~n~p", [agent_info(AgentNode)]),
+
+ ?line ok = async_exec(Requests, []),
+
+ p("manager info when ending test: ~n~p", [mgr_info(MgrNode)]),
+ p("agent info when ending test: ~n~p", [agent_info(AgentNode)]),
+
+ ok.
+
+
+%%======================================================================
+
+discovery(suite) -> [];
+discovery(Config) when is_list(Config) ->
+ ?SKIP(not_yet_implemented).
+
+
+%%======================================================================
+%%
+%% Utility functions for cases trap1 and trap2
+%%
+
+collect_traps(N) ->
+ collect_traps(N, []).
+
+collect_traps(0, TrapInfo) ->
+ TrapInfo;
+collect_traps(N, Acc) ->
+ receive
+ {async_event, _From, {trap, TrapInfo}} ->
+ p("collect_traps -> received trap: ~n ~p", [TrapInfo]),
+ collect_traps(N-1, [TrapInfo|Acc])
+ after 10000 ->
+ p("collect_traps -> still awaiting ~w trap(s) - giving up", [N]),
+ Acc
+ end.
+
+verify_traps([], []) ->
+ p("verify_traps -> done"),
+ ok;
+verify_traps([], Verifiers) ->
+ p("verify_traps -> done when ~w verifiers remain", [length(Verifiers)]),
+ {error, {failed_verify, [Id || {Id, _} <- Verifiers]}};
+verify_traps([Trap|Traps], Verifiers0) ->
+ p("verify_traps -> entry"),
+ case verify_trap(Trap, Verifiers0) of
+ {ok, Id} ->
+ p("verify_traps -> trap verified: ~p", [Id]),
+ Verifiers = lists:keydelete(Id, 1, Verifiers0),
+ verify_traps(Traps, Verifiers);
+ error ->
+ p("verify_traps -> failed verifying trap: ~n ~p", [Trap]),
+ {error, {failed_verifying_trap, Trap}}
+ end.
+
+verify_trap(Trap, []) ->
+ p("verify_trap -> could not verify trap:"
+ "~n Trap: ~p", [Trap]),
+ error;
+verify_trap(Trap, [{Id, Verifier}|Verifiers]) ->
+ p("verify_trap -> entry with"
+ "~n Id: ~p"
+ "~n Trap: ~p", [Id, Trap]),
+ case Verifier(Trap) of
+ ok ->
+ p("verify_trap -> verified"),
+ {ok, Id};
+ {error, _} ->
+ p("verify_trap -> not verified"),
+ verify_trap(Trap, Verifiers)
+ end.
+
+
+%%======================================================================
+
+trap1(suite) -> [];
+trap1(Config) when is_list(Config) ->
+ process_flag(trap_exit, true),
+ put(tname,t1),
+ p("starting with Config: ~p~n", [Config]),
+
+ MgrNode = ?config(manager_node, Config),
+ AgentNode = ?config(agent_node, Config),
+
+ ?line ok = mgr_user_load_mib(MgrNode, snmpv2_mib()),
+ Test2Mib = test2_mib(Config),
+ TestTrapMib = test_trap_mib(Config),
+ TestTrapv2Mib = test_trap_v2_mib(Config),
+ ?line ok = mgr_user_load_mib(MgrNode, Test2Mib),
+ ?line ok = mgr_user_load_mib(MgrNode, TestTrapMib),
+ ?line ok = mgr_user_load_mib(MgrNode, TestTrapv2Mib),
+ ?line ok = agent_load_mib(AgentNode, Test2Mib),
+ ?line ok = agent_load_mib(AgentNode, TestTrapMib),
+ ?line ok = agent_load_mib(AgentNode, TestTrapv2Mib),
+
+ %% Version 1 trap verification function:
+ VerifyTrap_v1 =
+ fun(Ent, Gen, Spec, ExpVBs, Trap) ->
+ case Trap of
+ {Ent, Gen, Spec, _Timestamp, VBs} ->
+ p("trap info as expected"),
+ case (catch validate_vbs(MgrNode,
+ ExpVBs, VBs)) of
+ ok ->
+ p("valid trap"),
+ ok;
+ Error ->
+ p("invalid trap: ~n Error: ~p", [Error]),
+ Error
+ end;
+ {Enteprise, Generic, Spec, Timestamp, VBs} ->
+ p("unepxected v1 trap info:"
+ "~n Enteprise: ~p"
+ "~n Generic: ~p"
+ "~n Spec: ~p"
+ "~n Timestamp: ~p"
+ "~n VBs: ~p",
+ [Enteprise, Generic, Spec, Timestamp, VBs]),
+ ExpTrap = {Ent, Gen, Spec, ignore, ExpVBs},
+ Reason = {unexpected_trap, {ExpTrap, Trap}},
+ {error, Reason};
+ {Err, Idx, VBs} ->
+ p("unexpected trap info: "
+ "~n Err: ~p"
+ "~n Idx: ~p"
+ "~n VBs: ~p", [Err, Idx, VBs]),
+ Reason = {unexpected_status, {Err, Idx, VBs}},
+ {error, Reason}
+ end
+ end,
+
+ %% Version 2 trap verification function:
+ VerifyTrap_v2 =
+ fun(ExpVBs, Trap) ->
+ case Trap of
+ {noError, 0, VBs0} ->
+ p("trap info as expected: ~n~p", [VBs0]),
+ %% The first two are a timestamp and oid
+ [_,_|VBs] = VBs0,
+ case (catch validate_vbs(MgrNode,
+ ExpVBs, VBs)) of
+ ok ->
+ p("valid trap"),
+ ok;
+ Error ->
+ p("invalid trap: ~n Error: ~p",
+ [Error]),
+ Error
+ end;
+ {Err, Idx, VBs} ->
+ p("unexpected error status: "
+ "~n Err: ~p"
+ "~n Idx: ~p"
+ "~n VBs: ~p", [Err, Idx, VBs]),
+ Reason = {unexpected_status, {Err, Idx, VBs}},
+ {error, Reason}
+ end
+ end,
+
+
+ %% -- command 1 --
+ %% Collect various info about the manager and the agent
+ Cmd1 =
+ fun() ->
+ p("manager info: ~n~p", [mgr_info(MgrNode)]),
+ p("agent info: ~n~p", [agent_info(AgentNode)]),
+ ok
+ end,
+
+ %% -- command 2 --
+ %% Make the agent send trap(s) (both a v1 and a v2 trap)
+ Cmd2 =
+ fun() ->
+ VBs = [{ifIndex, [1], 1},
+ {ifAdminStatus, [1], 1},
+ {ifOperStatus, [1], 2}],
+ agent_send_trap(AgentNode, linkUp, "standard trap", VBs),
+ ok
+ end,
+
+ %% -- command 3 --
+ %% Version 1 trap verify function
+ Cmd3_VerifyTrap_v1 =
+ fun(Trap) ->
+ Ent = [1,2,3],
+ Gen = 3,
+ Spec = 0,
+ ExpVBs = [{[ifIndex, 1], 1},
+ {[ifAdminStatus, 1], 1},
+ {[ifOperStatus, 1], 2}],
+ VerifyTrap_v1(Ent, Gen, Spec, ExpVBs, Trap)
+ end,
+
+ %% Version 2 trap verify function
+ Cmd3_VerifyTrap_v2 =
+ fun(Trap) ->
+ ExpVBs = [{[ifIndex, 1], 1},
+ {[ifAdminStatus, 1], 1},
+ {[ifOperStatus, 1], 2}],
+ VerifyTrap_v2(ExpVBs, Trap)
+ end,
+
+ %% Verify the two traps. The order of them is unknown
+ Cmd3 =
+ fun() ->
+ Verifiers = [{"v1 trap verifier", Cmd3_VerifyTrap_v1},
+ {"v2 trap verifier", Cmd3_VerifyTrap_v2}],
+ verify_traps(collect_traps(2), Verifiers)
+ end,
+
+ Cmd4 = fun() -> ?SLEEP(1000), ok end,
+
+ Commands =
+ [
+ {1, "Manager and agent info at start of test", Cmd1},
+ {2, "Send trap from agent", Cmd2},
+ {3, "Await trap(s) to manager", Cmd3},
+ {4, "Sleep some time (1 sec)", Cmd4},
+ {5, "Manager and agent info after test completion", Cmd1}
+ ],
+
+ command_handler(Commands).
+
+
+%%======================================================================
+
+trap2(suite) -> [];
+trap2(Config) when is_list(Config) ->
+ process_flag(trap_exit, true),
+ put(tname,t2),
+ p("starting with Config: ~p~n", [Config]),
+
+ MgrNode = ?config(manager_node, Config),
+ AgentNode = ?config(agent_node, Config),
+
+ ?line ok = mgr_user_load_mib(MgrNode, snmpv2_mib()),
+ Test2Mib = test2_mib(Config),
+ TestTrapMib = test_trap_mib(Config),
+ TestTrapv2Mib = test_trap_v2_mib(Config),
+ ?line ok = mgr_user_load_mib(MgrNode, Test2Mib),
+ ?line ok = mgr_user_load_mib(MgrNode, TestTrapMib),
+ ?line ok = mgr_user_load_mib(MgrNode, TestTrapv2Mib),
+ ?line ok = agent_load_mib(AgentNode, Test2Mib),
+ ?line ok = agent_load_mib(AgentNode, TestTrapMib),
+ ?line ok = agent_load_mib(AgentNode, TestTrapv2Mib),
+
+ %% Version 1 trap verification function:
+ VerifyTrap_v1 =
+ fun(Ent, Gen, Spec, ExpVBs, Trap) ->
+ case Trap of
+ {Ent, Gen, Spec, _Timestamp, VBs} ->
+ p("trap info as expected"),
+ case (catch validate_vbs(MgrNode,
+ ExpVBs, VBs)) of
+ ok ->
+ p("valid trap"),
+ ok;
+ Error ->
+ p("invalid trap: ~n Error: ~p", [Error]),
+ Error
+ end;
+ {Enteprise, Generic, Spec, Timestamp, VBs} ->
+ p("unepxected v1 trap info:"
+ "~n Enteprise: ~p"
+ "~n Generic: ~p"
+ "~n Spec: ~p"
+ "~n Timestamp: ~p"
+ "~n VBs: ~p",
+ [Enteprise, Generic, Spec, Timestamp, VBs]),
+ ExpTrap = {Ent, Gen, Spec, ignore, ExpVBs},
+ Reason = {unexpected_trap, {ExpTrap, Trap}},
+ {error, Reason};
+ {Err, Idx, VBs} ->
+ p("unexpected trap info: "
+ "~n Err: ~p"
+ "~n Idx: ~p"
+ "~n VBs: ~p", [Err, Idx, VBs]),
+ Reason = {unexpected_status, {Err, Idx, VBs}},
+ {error, Reason}
+ end
+ end,
+
+ %% Version 2 trap verification function:
+ VerifyTrap_v2 =
+ fun(ExpVBs, Trap) ->
+ case Trap of
+ {noError, 0, VBs0} ->
+ p("trap info as expected: ~n~p", [VBs0]),
+ %% The first two are a timestamp and oid
+ [_,_|VBs] = VBs0,
+ case (catch validate_vbs(MgrNode,
+ ExpVBs, VBs)) of
+ ok ->
+ p("valid trap"),
+ ok;
+ Error ->
+ p("invalid trap: ~n Error: ~p",
+ [Error]),
+ Error
+ end;
+ {Err, Idx, VBs} ->
+ p("unexpected error status: "
+ "~n Err: ~p"
+ "~n Idx: ~p"
+ "~n VBs: ~p", [Err, Idx, VBs]),
+ Reason = {unexpected_status, {Err, Idx, VBs}},
+ {error, Reason}
+ end
+ end,
+
+ %% -- command 1 --
+ %% Collect various info about the manager and the agent
+ Cmd1 =
+ fun() ->
+ p("manager info: ~n~p", [mgr_info(MgrNode)]),
+ p("agent info: ~n~p", [agent_info(AgentNode)]),
+ ok
+ end,
+
+ %% -- command 2 --
+ %% Make the agent send trap(s) (both a v1 and a v2 trap)
+ Cmd2 =
+ fun() ->
+ VBs = [{sysContact, "pelle"}],
+ agent_send_trap(AgentNode, testTrap1, "standard trap", VBs),
+ ok
+ end,
+
+ %% -- command 3 --
+ %% Version 1 trap verify function
+ Cmd3_VerifyTrap_v1 =
+ fun(Trap) ->
+ Ent = [1,2,3],
+ Gen = 1,
+ Spec = 0,
+ ExpVBs = [{[system, [4,0]], "pelle"}],
+ VerifyTrap_v1(Ent, Gen, Spec, ExpVBs, Trap)
+ end,
+
+ %% Version 2 trap verify function
+ Cmd3_VerifyTrap_v2 =
+ fun(Trap) ->
+ ExpVBs = [{[system, [4,0]], "pelle"},
+ {[snmpTrapEnterprise,0], any}],
+ VerifyTrap_v2(ExpVBs, Trap)
+ end,
+
+ %% Verify the two traps. The order of them is unknown
+ Cmd3 =
+ fun() ->
+ Verifiers = [{"v1 trap verifier", Cmd3_VerifyTrap_v1},
+ {"v2 trap verifier", Cmd3_VerifyTrap_v2}],
+ verify_traps(collect_traps(2), Verifiers)
+ end,
+
+ %% -- command 4 --
+ %% Make the agent send another set of trap(s) (both a v1 and a v2 trap)
+ Cmd4 =
+ fun() ->
+ VBs = [{ifIndex, [1], 1},
+ {ifAdminStatus, [1], 1},
+ {ifOperStatus, [1], 2}],
+ agent_send_trap(AgentNode, linkUp, "standard trap", VBs),
+ ok
+ end,
+
+
+ %% -- command 5 --
+ %% Expected varbinds
+ ExpVBs5 = [{[ifIndex, 1], 1},
+ {[ifAdminStatus, 1], 1},
+ {[ifOperStatus, 1], 2}],
+
+
+ %% Version 1 trap verify function
+ Cmd5_VerifyTrap_v1 =
+ fun(Trap) ->
+ Ent = [1,2,3],
+ Gen = 3,
+ Spec = 0,
+ VerifyTrap_v1(Ent, Gen, Spec, ExpVBs5, Trap)
+ end,
+
+ %% Version 2 trap verify function
+ Cmd5_VerifyTrap_v2 =
+ fun(Trap) ->
+ VerifyTrap_v2(ExpVBs5, Trap)
+ end,
+
+ %% Verify the two traps. The order of them is unknown
+ Cmd5 =
+ fun() ->
+ Verifiers = [{"v1 trap verifier", Cmd5_VerifyTrap_v1},
+ {"v2 trap verifier", Cmd5_VerifyTrap_v2}],
+ verify_traps(collect_traps(2), Verifiers)
+ end,
+
+ %% -- command 6 --
+ %% Some sleep before we are done
+ Cmd6 = fun() -> ?SLEEP(1000), ok end,
+
+ Commands =
+ [
+ {1, "Manager and agent info at start of test", Cmd1},
+ {2, "Send first trap(s) from agent", Cmd2},
+ {3, "Await the trap(s) from agent", Cmd3},
+ {4, "Send second trap(s) from agent", Cmd4},
+ {5, "Await the trap(s) from the agent", Cmd5},
+ {6, "Sleep some time (1 sec)", Cmd6},
+ {7, "Manager and agent info after test completion", Cmd1}
+ ],
+
+ command_handler(Commands).
+
+
+%%======================================================================
+
+inform1(suite) -> [];
+inform1(Config) when is_list(Config) ->
+ process_flag(trap_exit, true),
+ put(tname,i1),
+ p("starting with Config: ~p~n", [Config]),
+
+ MgrNode = ?config(manager_node, Config),
+ AgentNode = ?config(agent_node, Config),
+
+ ?line ok = mgr_user_load_mib(MgrNode, snmpv2_mib()),
+ Test2Mib = test2_mib(Config),
+ TestTrapMib = test_trap_mib(Config),
+ TestTrapv2Mib = test_trap_v2_mib(Config),
+ ?line ok = mgr_user_load_mib(MgrNode, Test2Mib),
+ ?line ok = mgr_user_load_mib(MgrNode, TestTrapMib),
+ ?line ok = mgr_user_load_mib(MgrNode, TestTrapv2Mib),
+ ?line ok = agent_load_mib(AgentNode, Test2Mib),
+ ?line ok = agent_load_mib(AgentNode, TestTrapMib),
+ ?line ok = agent_load_mib(AgentNode, TestTrapv2Mib),
+
+
+ Cmd1 =
+ fun() ->
+ p("manager info: ~n~p", [mgr_info(MgrNode)]),
+ p("manager system info: ~n~p", [mgr_sys_info(MgrNode)]),
+ p("agent info: ~n~p", [agent_info(AgentNode)]),
+ ok
+ end,
+
+ Cmd2 =
+ fun() ->
+ agent_send_notif(AgentNode, testTrapv22, "standard inform"),
+ ok
+ end,
+
+ Cmd3 =
+ fun() ->
+ receive
+ {async_event, From, {inform, Pid, Inform}} ->
+ p("received inform"),
+ case Inform of
+ {noError, 0, VBs} when is_list(VBs) ->
+ case (catch validate_testTrapv22_vbs(MgrNode,
+ VBs)) of
+ ok ->
+ p("valid inform"),
+ Pid ! {handle_inform_no_response,
+ From},
+ ok;
+ Error ->
+ p("invalid inform: ~n Error: ~p",
+ [Error]),
+ Error
+ end;
+ {Err, Idx, VBs} ->
+ p("unexpected error status: "
+ "~n Err: ~p"
+ "~n Idx: ~p"
+ "~n VBs: ~p", [Err, Idx, VBs]),
+ Reason = {unexpected_status, {Err, Idx, VBs}},
+ {error, Reason}
+ end
+ after 10000 ->
+ receive
+ Any ->
+ {error, {timeout_crap, Any}}
+ after 1000 ->
+ {error, timeout}
+ end
+ end
+ end,
+
+ Cmd4 =
+ fun() ->
+ receive
+ {async_event, From, {inform, Pid, Inform}} ->
+ p("received inform"),
+ case Inform of
+ {noError, 0, VBs} when is_list(VBs) ->
+ case (catch validate_testTrapv22_vbs(MgrNode,
+ VBs)) of
+ ok ->
+ p("valid inform"),
+ Pid ! {handle_inform_response, From},
+ ok;
+ Error ->
+ p("invalid inform: ~n Error: ~p",
+ [Error]),
+ Error
+ end;
+ {Err, Idx, VBs} ->
+ p("unexpected error status: "
+ "~n Err: ~p"
+ "~n Idx: ~p"
+ "~n VBs: ~p", [Err, Idx, VBs]),
+ Reason = {unexpected_status, {Err, Idx, VBs}},
+ {error, Reason}
+ end
+ after 20000 ->
+ receive
+ Any ->
+ {error, {timeout_crap, Any}}
+ after 1000 ->
+ {error, timeout}
+ end
+ end
+ end,
+
+ Cmd5 = fun() -> ?SLEEP(5000), ok end,
+
+ Commands =
+ [
+ {1, "Manager and agent info at start of test", Cmd1},
+ {2, "Send notifcation [no receiver] from agent", Cmd2},
+ {3, "Await first inform to manager - do not reply", Cmd3},
+ {4, "Await second inform to manager - reply", Cmd4},
+ {5, "Sleep some time (5 sec)", Cmd5},
+ {6, "Manager and agent info after test completion", Cmd1}
+ ],
+
+ command_handler(Commands).
+
+
+%%======================================================================
+
+inform2(suite) -> [];
+inform2(Config) when is_list(Config) ->
+ process_flag(trap_exit, true),
+ put(tname,i2),
+ p("starting with Config: ~p~n", [Config]),
+
+ MgrNode = ?config(manager_node, Config),
+ AgentNode = ?config(agent_node, Config),
+ %% Addr = ?config(ip, Config),
+ %% Port = ?AGENT_PORT,
+
+ ?line ok = mgr_user_load_mib(MgrNode, snmpv2_mib()),
+ Test2Mib = test2_mib(Config),
+ TestTrapMib = test_trap_mib(Config),
+ TestTrapv2Mib = test_trap_v2_mib(Config),
+ ?line ok = mgr_user_load_mib(MgrNode, Test2Mib),
+ ?line ok = mgr_user_load_mib(MgrNode, TestTrapMib),
+ ?line ok = mgr_user_load_mib(MgrNode, TestTrapv2Mib),
+ ?line ok = agent_load_mib(AgentNode, Test2Mib),
+ ?line ok = agent_load_mib(AgentNode, TestTrapMib),
+ ?line ok = agent_load_mib(AgentNode, TestTrapv2Mib),
+
+ Cmd1 =
+ fun() ->
+ p("manager info: ~n~p", [mgr_info(MgrNode)]),
+ p("agent info: ~n~p", [agent_info(AgentNode)]),
+ ok
+ end,
+
+ Cmd2 =
+ fun() ->
+ agent_send_notif(AgentNode,
+ testTrapv22,
+ {inform2_tag1, self()},
+ "standard inform",
+ []),
+ ok
+ end,
+
+ Cmd3 =
+ fun() ->
+ receive
+ {snmp_targets, inform2_tag1, Addrs} ->
+ p("sent inform to ~p", [Addrs]),
+ ok
+ after 10000 ->
+ receive
+ Any ->
+ {error, {timeout_crap, Any}}
+ after 1000 ->
+ {error, timeout}
+ end
+ end
+ end,
+
+ Cmd4 =
+ fun() ->
+ receive
+ {async_event, From, {inform, Pid, Inform}} ->
+ p("received inform"),
+ case Inform of
+ {noError, 0, VBs} when is_list(VBs) ->
+ case (catch validate_testTrapv22_vbs(MgrNode,
+ VBs)) of
+ ok ->
+ p("valid inform"),
+ Pid ! {handle_inform_no_response,
+ From},
+ ok;
+ Error ->
+ p("invalid inform: ~n Error: ~p",
+ [Error]),
+ Error
+ end;
+ {Err, Idx, VBs} ->
+ p("unexpected error status: "
+ "~n Err: ~p"
+ "~n Idx: ~p"
+ "~n VBs: ~p", [Err, Idx, VBs]),
+ Reason = {unexpected_status, {Err, Idx, VBs}},
+ {error, Reason}
+ end
+ after 10000 ->
+ receive
+ Any ->
+ {error, {timeout_crap, Any}}
+ after 1000 ->
+ {error, timeout}
+ end
+ end
+ end,
+
+ Cmd5 =
+ fun() ->
+ receive
+ {async_event, From, {inform, Pid, Inform}} ->
+ p("received inform"),
+ case Inform of
+ {noError, 0, VBs} when is_list(VBs) ->
+ case (catch validate_testTrapv22_vbs(MgrNode,
+ VBs)) of
+ ok ->
+ p("valid inform"),
+ Pid ! {handle_inform_response, From},
+ ok;
+ Error ->
+ p("invalid inform: ~n Error: ~p",
+ [Error]),
+ Error
+ end;
+ {Err, Idx, VBs} ->
+ p("unexpected error status: "
+ "~n Err: ~p"
+ "~n Idx: ~p"
+ "~n VBs: ~p", [Err, Idx, VBs]),
+ Reason = {unexpected_status, {Err, Idx, VBs}},
+ {error, Reason}
+ end
+ after 20000 ->
+ receive
+ Any ->
+ {error, {timeout_crap, Any}}
+ after 1000 ->
+ {error, timeout}
+ end
+ end
+ end,
+
+ Cmd6 =
+ fun() ->
+ receive
+ {snmp_notification, inform2_tag1, {got_response, Addr}} ->
+ p("received expected \"got response\" notification "
+ "from: "
+ "~n ~p", [Addr]),
+ ok;
+ {snmp_notification, inform2_tag1, {no_response, Addr}} ->
+ p("<ERROR> received expected \"no response\" "
+ "notification from: "
+ "~n ~p", [Addr]),
+ {error, no_response}
+ after 10000 ->
+ receive
+ Any ->
+ {error, {timeout_crap, Any}}
+ after 1000 ->
+ {error, timeout}
+ end
+ end
+ end,
+
+ Cmd7 = fun() -> ?SLEEP(5000), ok end,
+
+ Commands =
+ [
+ {1, "Manager and agent info at start of test", Cmd1},
+ {2, "Send notifcation [no receiver] from agent", Cmd2},
+ {3, "await inform-sent acknowledge from agent", Cmd3},
+ {4, "Await first inform to manager - do not reply", Cmd4},
+ {5, "Await second inform to manager - reply", Cmd5},
+ {6, "await inform-acknowledge from agent", Cmd6},
+ {7, "Sleep some time (5 sec)", Cmd7},
+ {8, "Manager and agent info after test completion", Cmd1}
+ ],
+
+ command_handler(Commands).
+
+
+%%======================================================================
+
+inform3(suite) -> [];
+inform3(Config) when is_list(Config) ->
+ process_flag(trap_exit, true),
+ put(tname,i3),
+ p("starting with Config: ~p~n", [Config]),
+
+ MgrNode = ?config(manager_node, Config),
+ AgentNode = ?config(agent_node, Config),
+
+ ?line ok = mgr_user_load_mib(MgrNode, snmpv2_mib()),
+ Test2Mib = test2_mib(Config),
+ TestTrapMib = test_trap_mib(Config),
+ TestTrapv2Mib = test_trap_v2_mib(Config),
+ ?line ok = mgr_user_load_mib(MgrNode, Test2Mib),
+ ?line ok = mgr_user_load_mib(MgrNode, TestTrapMib),
+ ?line ok = mgr_user_load_mib(MgrNode, TestTrapv2Mib),
+ ?line ok = agent_load_mib(AgentNode, Test2Mib),
+ ?line ok = agent_load_mib(AgentNode, TestTrapMib),
+ ?line ok = agent_load_mib(AgentNode, TestTrapv2Mib),
+
+ Cmd1 =
+ fun() ->
+ p("manager info: ~n~p", [mgr_info(MgrNode)]),
+ p("agent info: ~n~p", [agent_info(AgentNode)]),
+ ok
+ end,
+
+ Cmd2 =
+ fun() ->
+ agent_send_notif(AgentNode,
+ testTrapv22,
+ {inform3_tag1, self()},
+ "standard inform",
+ []),
+ ok
+ end,
+
+ Cmd3 =
+ fun() ->
+ receive
+ {snmp_targets, inform3_tag1, [_Addr]} ->
+ p("received inform-sent acknowledgement", []),
+ ok
+ after 10000 ->
+ receive
+ Crap ->
+ {error, {timeout_crap, Crap}}
+ after 0 ->
+ {error, timeout}
+ end
+ end
+ end,
+
+ Cmd4 =
+ fun() ->
+ receive
+ {async_event, From, {inform, Pid, Inform}} ->
+ p("received inform"),
+ case Inform of
+ {noError, 0, VBs} when is_list(VBs) ->
+ case (catch validate_testTrapv22_vbs(MgrNode,
+ VBs)) of
+ ok ->
+ p("valid inform"),
+ Pid ! {handle_inform_no_response,
+ From},
+ ok;
+ Error ->
+ p("invalid inform: ~n Error: ~p",
+ [Error]),
+ Error
+ end;
+ {Err, Idx, VBs} ->
+ p("unexpected error status: "
+ "~n Err: ~p"
+ "~n Idx: ~p"
+ "~n VBs: ~p", [Err, Idx, VBs]),
+ Reason = {unexpected_status, {Err, Idx, VBs}},
+ {error, Reason}
+ end
+ after 50000 ->
+ receive
+ Any ->
+ {error, {timeout_crap, Any}}
+ after 0 ->
+ {error, timeout}
+ end
+ end
+ end,
+
+ Cmd7 =
+ fun() ->
+ receive
+ {snmp_notification, inform3_tag1, {no_response, Addr}} ->
+ p("received expected \"no response\" notification "
+ "from: "
+ "~n ~p", [Addr]),
+ ok;
+ {snmp_notification, inform3_tag1, {got_response, Addr}} ->
+ p("<ERROR> received unexpected \"got response\" "
+ "notification from: "
+ "~n ~p",
+ [Addr]),
+ {error, {got_response, Addr}}
+ after 120000 ->
+ receive
+ Crap ->
+ {error, {timeout_crap, Crap}}
+ after 0 ->
+ {error, timeout}
+ end
+ end
+ end,
+
+ Cmd8 = fun() -> ?SLEEP(1000), ok end,
+
+ Commands =
+ [
+ {1, "Manager and agent info at start of test", Cmd1},
+ {2, "Send notifcation from agent", Cmd2},
+ {3, "await inform-sent acknowledge from agent", Cmd3},
+ {4, "Await first inform to manager - do not reply", Cmd4},
+ {5, "Await first inform to manager - do not reply", Cmd4},
+ {6, "Await first inform to manager - do not reply", Cmd4},
+ {7, "await inform-acknowledge from agent", Cmd7},
+ {8, "Sleep some time (1 sec)", Cmd8},
+ {9, "Manager and agent info after test completion", Cmd1}
+ ],
+
+ command_handler(Commands).
+
+
+%%======================================================================
+
+inform4(suite) -> [];
+inform4(Config) when is_list(Config) ->
+ process_flag(trap_exit, true),
+ put(tname,i4),
+ p("starting with Config: ~p~n", [Config]),
+
+ MgrNode = ?config(manager_node, Config),
+ AgentNode = ?config(agent_node, Config),
+
+ ?line ok = mgr_user_load_mib(MgrNode, snmpv2_mib()),
+ Test2Mib = test2_mib(Config),
+ TestTrapMib = test_trap_mib(Config),
+ TestTrapv2Mib = test_trap_v2_mib(Config),
+ ?line ok = mgr_user_load_mib(MgrNode, Test2Mib),
+ ?line ok = mgr_user_load_mib(MgrNode, TestTrapMib),
+ ?line ok = mgr_user_load_mib(MgrNode, TestTrapv2Mib),
+ ?line ok = agent_load_mib(AgentNode, Test2Mib),
+ ?line ok = agent_load_mib(AgentNode, TestTrapMib),
+ ?line ok = agent_load_mib(AgentNode, TestTrapv2Mib),
+
+ Cmd1 =
+ fun() ->
+ p("manager info: ~n~p", [mgr_info(MgrNode)]),
+ p("agent info: ~n~p", [agent_info(AgentNode)]),
+ ok
+ end,
+
+ Cmd2 =
+ fun() ->
+ agent_send_notif(AgentNode, testTrapv22, "standard inform"),
+ ok
+ end,
+
+ Cmd3 =
+ fun() ->
+ receive
+ {async_event, From, {inform, Pid, Inform}} ->
+ p("received inform"),
+ case Inform of
+ {noError, 0, VBs} when is_list(VBs) ->
+ case (catch validate_testTrapv22_vbs(MgrNode,
+ VBs)) of
+ ok ->
+ p("valid inform"),
+ %% Actually, as we have
+ %% configured the manager in
+ %% this test case (irb = auto)
+ %% it has already responded
+ Pid ! {handle_inform_response, From},
+ ok;
+ Error ->
+ p("invalid inform: ~n Error: ~p",
+ [Error]),
+ Error
+ end;
+ {Err, Idx, VBs} ->
+ p("unexpected error status: "
+ "~n Err: ~p"
+ "~n Idx: ~p"
+ "~n VBs: ~p", [Err, Idx, VBs]),
+ Reason = {unexpected_status, {Err, Idx, VBs}},
+ {error, Reason}
+ end
+ after 20000 ->
+ receive
+ Any ->
+ {error, {crap, Any}}
+ after 1000 ->
+ {error, timeout}
+ end
+ end
+ end,
+
+ %% This is the a result of erroneous configuration.
+%% Cmd4 =
+%% fun() ->
+%% receive
+%% {async_event, _ReqId, {error, Reason}} ->
+%% p("received error"),
+%% case Reason of
+%% {failed_processing_message,
+%% {securityError, usmStatsUnknownEngineIDs}} ->
+%% p("expected error"),
+%% ok;
+%% _ ->
+%% p("unexpected error: "
+%% "~n Reason: ~p", [Reason]),
+%% {error, {unexpected_error, Reason}}
+%% end
+%% after 20000 ->
+%% receive
+%% Any ->
+%% {error, {crap, Any}}
+%% after 1000 ->
+%% {error, timeout}
+%% end
+%% end
+%% end,
+
+ Cmd5 = fun() -> ?SLEEP(1000), ok end,
+
+ Commands =
+ [
+ {1, "Manager and agent info at start of test", Cmd1},
+ {2, "Send notifcation [no receiver] from agent", Cmd2},
+ {3, "Await inform to manager", Cmd3},
+%% {4, "Await error info (because of erroneous config)", Cmd4},
+ {5, "Sleep some time (1 sec)", Cmd5},
+ {6, "Manager and agent info after test completion", Cmd1}
+ ],
+
+ command_handler(Commands).
+
+
+%%======================================================================
+%%
+%% Test: ts:run(snmp, snmp_manager_test, inform_swarm, [batch]).
+
+inform_swarm(suite) -> [];
+inform_swarm(Config) when is_list(Config) ->
+ process_flag(trap_exit, true),
+ put(tname, is),
+ p("starting with Config: ~p~n", [Config]),
+
+ MgrNode = ?config(manager_node, Config),
+ AgentNode = ?config(agent_node, Config),
+
+ ?line ok = mgr_user_load_mib(MgrNode, snmpv2_mib()),
+ Test2Mib = test2_mib(Config),
+ TestTrapMib = test_trap_mib(Config),
+ TestTrapv2Mib = test_trap_v2_mib(Config),
+ ?line ok = mgr_user_load_mib(MgrNode, Test2Mib),
+ ?line ok = mgr_user_load_mib(MgrNode, TestTrapMib),
+ ?line ok = mgr_user_load_mib(MgrNode, TestTrapv2Mib),
+ ?line ok = agent_load_mib(AgentNode, Test2Mib),
+ ?line ok = agent_load_mib(AgentNode, TestTrapMib),
+ ?line ok = agent_load_mib(AgentNode, TestTrapv2Mib),
+ NumInforms = 100,
+
+ Collector = self(),
+
+ Generator =
+ erlang:spawn(
+ fun() ->
+ receive
+ {Collector, start} ->
+ ok
+ end,
+ Seqs = lists:seq(1, NumInforms),
+ lists:foreach(
+ fun(N) ->
+ p("send notification ~w", [N]),
+ agent_send_notif(AgentNode,
+ testTrapv22,
+ {{inform2_tag1, N}, Collector},
+ "standard inform",
+ []),
+ %% Sleep some [(N div 10)*100 ms]
+ %% every tenth notification
+ if
+ N rem 10 == 0 ->
+ %% Time to sleep some
+ Sleep = (N div 10) * 50,
+ p("sleep ~w [~w]", [Sleep, N]),
+ ?SLEEP(Sleep);
+ true ->
+ ok
+ end
+ end,
+ Seqs),
+ ok
+ end),
+
+ Cmd1 =
+ fun() ->
+ p("manager info: ~n~p", [mgr_info(MgrNode)]),
+ p("agent info: ~n~p", [agent_info(AgentNode)]),
+ ok
+ end,
+
+ Cmd2 = fun() -> Generator ! {Collector, start}, ok end,
+
+ Cmd3 =
+ fun() ->
+ inform_swarm_collector(NumInforms)
+ end,
+
+
+ Cmd4 = fun() -> ?SLEEP(1000), ok end,
+
+ Commands =
+ [
+ {1, "Manager and agent info at start of test", Cmd1},
+ {2, "Send notifcation(s) from agent", Cmd2},
+ {3, "Await send-ack(s)/inform(s)/response(s)", Cmd3},
+ {4, "Sleep some time (1 sec)", Cmd4},
+ {5, "Manager and agent info after test completion", Cmd1}
+ ],
+
+ command_handler(Commands).
+
+inform_swarm_collector(N) ->
+ inform_swarm_collector(N, 0, 0, 0, 10000).
+
+%% Note that we need to deal with re-transmissions!
+%% That is, the agent did not receive the ack in time,
+%% and therefor did a re-transmit. This means that we
+%% expect to receive more inform's then we actually
+%% sent. So for sucess we assume:
+%%
+%% SentAckCnt = N
+%% RespCnt = N
+%% RecvCnt >= N
+%%
+inform_swarm_collector(N, SentAckCnt, RecvCnt, RespCnt, _)
+ when ((N == SentAckCnt) and
+ (N == RespCnt) and
+ (N >= RecvCnt)) ->
+ p("inform_swarm_collector -> done when"
+ "~n N: ~w"
+ "~n SentAckCnt: ~w"
+ "~n RecvCnt: ~w"
+ "~n RespCnt: ~w", [N, SentAckCnt, RecvCnt, RespCnt]),
+ ok;
+inform_swarm_collector(N, SentAckCnt, RecvCnt, RespCnt, Timeout) ->
+ p("inform_swarm_collector -> entry with"
+ "~n N: ~w"
+ "~n SentAckCnt: ~w"
+ "~n RecvCnt: ~w"
+ "~n RespCnt: ~w", [N, SentAckCnt, RecvCnt, RespCnt]),
+ receive
+ {snmp_targets, {inform2_tag1, Id}, [_Addr]} ->
+ p("received inform-sent acknowledgement for ~w", [Id]),
+ inform_swarm_collector(N, SentAckCnt+1, RecvCnt, RespCnt,
+ Timeout);
+
+ %% The manager has received the actual inform
+ {async_event, From, {inform, Pid, Inform}} ->
+ p("received inform"),
+ case Inform of
+ {noError, 0, VBs} when is_list(VBs) ->
+ Pid ! {handle_inform_response, From},
+ inform_swarm_collector(N, SentAckCnt, RecvCnt+1, RespCnt,
+ Timeout);
+ {Err, Idx, VBs} ->
+ p("<ERROR> unexpected error status: "
+ "~n Err: ~p"
+ "~n Idx: ~p"
+ "~n VBs: ~p", [Err, Idx, VBs]),
+ Reason = {unexpected_status, {Err, Idx, VBs}},
+ {error, Reason}
+ end;
+
+ %% The agent has received ack from the manager
+ {snmp_notification, {inform2_tag1, Id}, {got_response, Addr}} ->
+ p("received expected \"got response\" for ~w"
+ "notification from: "
+ "~n ~p",
+ [Id, Addr]),
+ inform_swarm_collector(N, SentAckCnt, RecvCnt, RespCnt+1,
+ Timeout);
+
+ %% The agent did not received ack from the manager in time
+ {snmp_notification, inform2_tag1, {no_response, Addr}} ->
+ p("<ERROR> received expected \"no response\" notification "
+ "from: "
+ "~n ~p", [Addr]),
+ Reason = {no_response, Addr, {N, SentAckCnt, RecvCnt, RespCnt}},
+ {error, Reason}
+
+ after Timeout ->
+ %% Give up when we have been dead in the water for Timeout ms
+ {error, {timeout, N, SentAckCnt, RecvCnt, RespCnt}}
+ end.
+
+
+%%======================================================================
+
+report(suite) -> [];
+report(Config) when is_list(Config) ->
+ ?SKIP(not_yet_implemented).
+
+
+
+%%======================================================================
+
+otp8015_1(doc) -> ["OTP-8015:1 - testing the new api-function."];
+otp8015_1(suite) -> [];
+otp8015_1(Config) when is_list(Config) ->
+ process_flag(trap_exit, true),
+ put(tname, otp8015_1),
+ p("starting with Config: ~p~n", [Config]),
+
+ ConfDir = ?config(manager_conf_dir, Config),
+ DbDir = ?config(manager_db_dir, Config),
+
+ write_manager_conf(ConfDir),
+
+ Opts = [{server, [{verbosity, trace}]},
+ {net_if, [{verbosity, trace}]},
+ {note_store, [{verbosity, trace}]},
+ {config, [{verbosity, trace}, {dir, ConfDir}, {db_dir, DbDir}]}],
+
+ p("starting manager"),
+ ok = snmpm:start_link(Opts),
+
+ ?SLEEP(1000),
+
+ snmpm:load_mib(std_mib()),
+ snmpm:load_mib(test_trap_mib(Config)),
+
+ p("manager started, now sleep some"),
+
+ ?SLEEP(1000),
+
+ p("loaded mibs: ~p", [snmpm:which_mibs()]),
+
+ p("get some type(s) from the mibs"),
+ {ok, 'Counter32'} = snmpm:oid_to_type(?snmpOutTraps),
+ {ok, [IfIndex]} = snmpm:name_to_oid(ifIndex),
+ {ok, 'INTEGER'} = snmpm:oid_to_type(IfIndex),
+
+
+ p("stop manager"),
+ ok = snmpm:stop(),
+
+ ?SLEEP(1000),
+
+ p("end"),
+ ok.
+
+
+%%======================================================================
+%% async snmp utility functions
+%%======================================================================
+
+async_exec([], Acc) ->
+ p("all async request's sent => now await reponses"),
+ async_verify(async_collector(Acc, []));
+async_exec([{Id, Data, Exec, Ver}|Reqs], Acc) ->
+ p("issue async request ~w", [Id]),
+ ?line {ok, ReqId} = Exec(Data),
+ async_exec(Reqs, [{ReqId, Id, Ver}|Acc]).
+
+async_collector([], Acc) ->
+ p("received replies for all requests - now sort"),
+ lists:keysort(1, Acc);
+async_collector(Expected, Acc) ->
+ receive
+ {async_event, ReqId, Reply} ->
+ p("received async event with request-id ~w", [ReqId]),
+ case lists:keysearch(ReqId, 1, Expected) of
+ {value, {_, Id, Ver}} ->
+ p("event was for request ~w", [Id]),
+ Expected2 = lists:keydelete(ReqId, 1, Expected),
+ async_collector(Expected2, [{Id, Ver, Reply}|Acc]);
+ false ->
+ % Duplicate reply?
+ ?FAIL({unexpected_async_event, ReqId, Reply})
+ end
+ after 10000 ->
+ ?FAIL({timeout, {Expected, Acc}})
+ end.
+
+async_verify([]) ->
+ ok;
+async_verify([{Id, Verify, Reply}|Replies]) ->
+ p("verify reply ~w", [Id]),
+ Verify(Reply),
+ async_verify(Replies).
+
+
+
+%%======================================================================
+%% Internal functions
+%%======================================================================
+
+
+%% -- Verify varbinds --
+
+validate_vbs(Node, ExpVBs, VBs) ->
+ validate_vbs(purify_oids(Node, ExpVBs), VBs).
+
+validate_testTrapv22_vbs(Node, VBs) ->
+ ExpVBs = [{[sysUpTime, 0], any},
+ {[snmpTrapOID, 0], ?system ++ [0,1]}],
+ validate_vbs(purify_oids(Node, ExpVBs), VBs).
+
+validate_vbs([], []) ->
+ ok;
+validate_vbs(Exp, []) ->
+ {error, {expected_vbs, Exp}};
+validate_vbs([], VBs) ->
+ {error, {unexpected_vbs, VBs}};
+validate_vbs([any|Exp], [_|VBs]) ->
+ validate_vbs(Exp, VBs);
+validate_vbs([{_, any}|Exp], [#varbind{}|VBs]) ->
+ validate_vbs(Exp, VBs);
+validate_vbs([{Oid, Val}|Exp], [#varbind{oid = Oid, value = Val}|VBs]) ->
+ validate_vbs(Exp, VBs);
+validate_vbs([{Oid, Val1}|_], [#varbind{oid = Oid, value = Val2}|_]) ->
+ {error, {unexpected_vb_value, Oid, Val1, Val2}};
+validate_vbs([{Oid1, _}|_], [#varbind{oid = Oid2}|_]) ->
+ {error, {unexpected_vb_oid, Oid1, Oid2}}.
+
+purify_oids(_, []) ->
+ [];
+purify_oids(Node, [{Oid, Val}|Oids]) ->
+ [{purify_oid(Node, Oid), Val}| purify_oids(Node, Oids)].
+
+purify_oid(Node, Oid) ->
+ case mgr_user_purify_oid(Node, Oid) of
+ Oid2 when is_list(Oid2) ->
+ Oid2;
+ {error, _} = Error ->
+ throw(Error)
+ end.
+
+
+%% -- Test case command handler (executor) ---
+
+command_handler([]) ->
+ ok;
+command_handler([{No, Desc, Cmd}|Cmds]) ->
+ p("command_handler -> command ~w: "
+ "~n ~s", [No, Desc]),
+ case (catch Cmd()) of
+ ok ->
+ p("command_handler -> ~w: ok",[No]),
+ command_handler(Cmds);
+ {error, Reason} ->
+ p("<ERROR> command_handler -> ~w error: ~n~p",[No, Reason]),
+ ?line ?FAIL({command_failed, No, Reason});
+ Error ->
+ p("<ERROR> command_handler -> ~w unexpected: ~n~p",[No, Error]),
+ ?line ?FAIL({unexpected_command_result, No, Error})
+ end.
+
+
+%% -- Misc manager functions --
+
+init_manager(AutoInform, Config) ->
+ ?LOG("init_manager -> entry with"
+ "~n AutoInform: ~p"
+ "~n Config: ~p", [AutoInform, Config]),
+
+
+ %% --
+ %% Start node
+ %%
+
+ ?line Node = start_manager_node(),
+
+
+ %% --
+ %% Start and initiate crypto on manager node
+ %%
+
+ ?line ok = init_crypto(Node),
+
+ %%
+ %% Write manager config
+ %%
+
+ ?line ok = write_manager_config(Config),
+
+ IRB = case AutoInform of
+ true ->
+ auto;
+ _ ->
+ user
+ end,
+ Conf = [{manager_node, Node}, {irb, IRB} | Config],
+ Vsns = [v1,v2,v3],
+ start_manager(Node, Vsns, Conf).
+
+fin_manager(Config) ->
+ Node = ?config(manager_node, Config),
+ stop_manager(Node, Config),
+ fin_crypto(Node),
+ stop_node(Node),
+ Config.
+
+
+%% -- Misc agent functions --
+
+init_agent(Config) ->
+ ?LOG("init_agent -> entry with"
+ "~n Config: ~p", [Config]),
+
+ %% --
+ %% Retrieve some dir's
+ %%
+ Dir = ?config(top_dir, Config),
+ DataDir = ?config(data_dir, Config),
+
+ %% --
+ %% Start node
+ %%
+
+ ?line Node = start_agent_node(),
+
+
+ %% --
+ %% Start and initiate mnesia on agent node
+ %%
+
+ ?line ok = init_mnesia(Node, Dir),
+
+
+ %% --
+ %% Start and initiate crypto on agent node
+ %%
+
+ ?line ok = init_crypto(Node),
+
+
+ %%
+ %% Write agent config
+ %%
+
+ Vsns = [v1,v2],
+ ?line ok = write_agent_config(Vsns, Config),
+
+ Conf = [{agent_node, Node},
+ {mib_dir, DataDir} | Config],
+
+ %%
+ %% Start the agent
+ %%
+
+ start_agent(Node, Vsns, Conf).
+
+fin_agent(Config) ->
+ Node = ?config(agent_node, Config),
+ stop_agent(Node, Config),
+ fin_crypto(Node),
+ fin_mnesia(Node),
+ stop_node(Node),
+ Config.
+
+init_mnesia(Node, Dir) ->
+ ?DBG("init_mnesia -> load application mnesia", []),
+ ?line ok = load_mnesia(Node),
+
+ ?DBG("init_mnesia -> application mnesia: set_env dir: ~n~p",[Dir]),
+ ?line ok = set_mnesia_env(Node, dir, filename:join(Dir, "mnesia")),
+
+ ?DBG("init_mnesia -> create mnesia schema",[]),
+ ?line case create_schema(Node) of
+ ok ->
+ ok;
+ {error, {Node, {already_exists, Node}}} ->
+ ?line ok = delete_schema(Node),
+ ?line ok = create_schema(Node);
+ Error ->
+ ?FAIL({failed_creating_mnesia_schema, Error})
+ end,
+
+ ?DBG("init_mnesia -> start application mnesia",[]),
+ ?line ok = start_mnesia(Node),
+
+ ?DBG("init_mnesia -> create tables",[]),
+ ?line ok = create_tables(Node),
+ ok.
+
+fin_mnesia(Node) ->
+ ?line ok = delete_tables(Node),
+ ?line ok = stop_mnesia(Node),
+ ok.
+
+
+init_crypto(Node) ->
+ ?line ok = load_crypto(Node),
+ ?line ok = start_crypto(Node),
+ ok.
+
+fin_crypto(Node) ->
+ ?line ok = stop_crypto(Node),
+ ok.
+
+
+%% -- Misc application wrapper functions --
+
+load_app(Node, App) when (Node =:= node()) andalso is_atom(App) ->
+ application:load(App);
+load_app(Node, App) when is_atom(App) ->
+ rcall(Node, application, load, [App]).
+
+start_app(Node, App) when (Node =:= node()) andalso is_atom(App) ->
+ application:start(App);
+start_app(Node, App) ->
+ rcall(Node, application, start, [App]).
+
+stop_app(Node, App) when (Node =:= node()) andalso is_atom(App) ->
+ application:stop(App);
+stop_app(Node, App) when is_atom(App) ->
+ rcall(Node, application, stop, [App]).
+
+set_app_env(Node, App, Key, Val) when (Node =:= node()) andalso is_atom(App) ->
+ application:set_env(App, Key, Val);
+set_app_env(Node, App, Key, Val) when is_atom(App) ->
+ rcall(Node, application, set_env, [App, Key, Val]).
+
+
+%% -- Misc snmp wrapper functions --
+
+load_snmp(Node) -> load_app(Node, snmp).
+start_snmp(Node) -> start_app(Node, snmp).
+stop_snmp(Node) -> stop_app(Node, snmp).
+set_agent_env(Node, Env) -> set_snmp_env(Node, agent, Env).
+set_mgr_env(Node, Env) -> set_snmp_env(Node, manager, Env).
+set_snmp_env(Node, Entity, Env) -> set_app_env(Node, snmp, Entity, Env).
+
+mgr_info(Node) ->
+ rcall(Node, snmpm, info, []).
+
+mgr_sys_info(Node) ->
+ rcall(Node, snmpm_config, system_info, []).
+
+%% mgr_register_user(Node, Id, Data) ->
+%% mgr_register_user(Node, Id, ?MODULE, Data).
+
+mgr_register_user(Node, Id, Mod, Data) when is_atom(Mod) ->
+ rcall(Node, snmpm, register_user, [Id, Mod, Data]).
+
+mgr_unregister_user(Node, Id) ->
+ rcall(Node, snmpm, unregister_user, [Id]).
+
+mgr_which_users(Node) ->
+ rcall(Node, snmpm, which_users, []).
+
+%% mgr_register_agent(Node, Id) ->
+%% mgr_register_agent(Node, Id, []).
+
+%% mgr_register_agent(Node, Id, Conf) when is_list(Conf) ->
+%% mgr_register_agent(Node, Id, 5000, Conf).
+
+mgr_register_agent(Node, Id, Port, Conf)
+ when is_integer(Port) andalso is_list(Conf) ->
+ Localhost = snmp_test_lib:localhost(),
+ mgr_register_agent(Node, Id, Localhost, Port, Conf);
+mgr_register_agent(Node, Id, TargetName, Config)
+ when is_list(TargetName) andalso is_list(Config) ->
+ rcall(Node, snmpm, register_agent, [Id, TargetName, Config]).
+
+mgr_register_agent(Node, Id, Addr, Port, Conf)
+ when is_integer(Port) andalso is_list(Conf) ->
+ rcall(Node, snmpm, register_agent, [Id, Addr, Port, Conf]).
+
+%% mgr_unregister_agent(Node, Id) ->
+%% mgr_unregister_agent(Node, Id, 4000).
+
+mgr_unregister_agent(Node, Id, Port) when is_integer(Port) ->
+ Localhost = snmp_test_lib:localhost(),
+ rcall(Node, snmpm, unregister_agent, [Id, Localhost, Port]);
+mgr_unregister_agent(Node, Id, TargetName) when is_list(TargetName) ->
+ rcall(Node, snmpm, unregister_agent, [Id, TargetName]).
+
+mgr_which_agents(Node) ->
+ rcall(Node, snmpm, which_agents, []).
+
+mgr_which_agents(Node, Id) ->
+ rcall(Node, snmpm, which_agents, [Id]).
+
+
+%% -- Misc crypto wrapper functions --
+
+load_crypto(Node) -> load_app(Node, crypto).
+start_crypto(Node) -> start_app(Node, crypto).
+stop_crypto(Node) -> stop_app(Node, crypto).
+
+
+%% -- Misc mnesia wrapper functions --
+
+load_mnesia(Node) -> load_app(Node, mnesia).
+start_mnesia(Node) -> start_app(Node, mnesia).
+stop_mnesia(Node) -> stop_app(Node, mnesia).
+set_mnesia_env(Node, Key, Val) -> set_app_env(Node, mnesia, Key, Val).
+
+create_schema(Node) ->
+ rcall(Node, mnesia, create_schema, [[Node]]).
+
+delete_schema(Node) ->
+ rcall(Node, mnesia, delete_schema, [[Node]]).
+
+create_table(Node, Table) ->
+ rcall(Node, mnesia, create_table, [Table]).
+
+delete_table(Node, Table) ->
+ rcall(Node, mnesia, delete_table, [Table]).
+
+create_tables(Node) ->
+ Tab1 = [{name, friendsTable2},
+ {ram_copies, [Node]},
+ {snmp, [{key, integer}]},
+ {attributes, [a1,a2,a3]}],
+ Tab2 = [{name, kompissTable2},
+ {ram_copies, [Node]},
+ {snmp, [{key, integer}]},
+ {attributes, [a1,a2,a3]}],
+ Tab3 = [{name, snmp_variables},
+ {attributes, [a1,a2]}],
+ Tabs = [Tab1, Tab2, Tab3],
+ create_tables(Node, Tabs).
+
+create_tables(_Node, []) ->
+ ok;
+create_tables(Node, [Tab|Tabs]) ->
+ case create_table(Node, Tab) of
+ {atomic, ok} ->
+ create_tables(Node, Tabs);
+ Error ->
+ ?FAIL({failed_creating_table, Node, Tab, Error})
+ end.
+
+delete_tables(Node) ->
+ Tabs = [friendsTable2, kompissTable2, snmp_variables],
+ delete_tables(Node, Tabs).
+
+%% delete_mib_storage_tables(Node) ->
+%% Tabs = [snmpa_mib_data, snmpa_mib_tree, snmpa_symbolic_store],
+%% delete_tables(Node, Tabs).
+
+delete_tables(Node, Tabs) ->
+ lists:foreach(fun(Tab) -> delete_table(Node, Tab) end, Tabs).
+
+
+%% -- Misc manager user wrapper functions --
+
+init_mgr_user(Conf) ->
+ ?DBG("init_mgr_user -> entry with"
+ "~n Conf: ~p", [Conf]),
+
+ Node = ?config(manager_node, Conf),
+ %% UserId = ?config(user_id, Conf),
+
+ ?line {ok, User} = mgr_user_start(Node),
+ ?DBG("start_mgr_user -> User: ~p", [User]),
+ link(User),
+
+ [{user_pid, User} | Conf].
+
+fin_mgr_user(Conf) ->
+ User = ?config(user_pid, Conf),
+ unlink(User),
+ Node = ?config(manager_node, Conf),
+ ?line ok = mgr_user_stop(Node),
+ Conf.
+
+init_mgr_user_data1(Conf) ->
+ Node = ?config(manager_node, Conf),
+ Addr = ?config(ip, Conf),
+ Port = ?AGENT_PORT,
+ ?line ok = mgr_user_register_agent(Node, Addr, Port),
+ Agents = mgr_user_which_own_agents(Node),
+ ?DBG("Own agents: ~p", [Agents]),
+
+ ?line {ok, DefAgentConf} = mgr_user_agent_info(Node, Addr, Port, all),
+ ?DBG("Default agent config: ~n~p", [DefAgentConf]),
+
+ ?line ok = mgr_user_update_agent_info(Node, Addr, Port,
+ community, "all-rights"),
+ ?line ok = mgr_user_update_agent_info(Node, Addr, Port,
+ sec_name, "all-rights"),
+ ?line ok = mgr_user_update_agent_info(Node, Addr, Port,
+ engine_id, "agentEngine"),
+ ?line ok = mgr_user_update_agent_info(Node, Addr, Port,
+ max_message_size, 1024),
+
+ ?line {ok, AgentConf} = mgr_user_agent_info(Node, Addr, Port, all),
+ ?DBG("Updated agent config: ~n~p", [AgentConf]),
+ Conf.
+
+init_mgr_user_data2(Conf) ->
+ Node = ?config(manager_node, Conf),
+ TargetName = ?config(manager_agent_target_name, Conf),
+ Addr = ?config(ip, Conf),
+ Port = ?AGENT_PORT,
+ ?line ok = mgr_user_register_agent(Node, TargetName,
+ [{address, Addr},
+ {port, Port},
+ {engine_id, "agentEngine"}]),
+ Agents = mgr_user_which_own_agents(Node),
+ ?DBG("Own agents: ~p", [Agents]),
+
+ ?line {ok, DefAgentConf} = mgr_user_agent_info(Node, TargetName, all),
+ ?DBG("Default agent config: ~n~p", [DefAgentConf]),
+
+ ?line ok = mgr_user_update_agent_info(Node, TargetName,
+ community, "all-rights"),
+ ?line ok = mgr_user_update_agent_info(Node, TargetName,
+ sec_name, "all-rights"),
+ ?line ok = mgr_user_update_agent_info(Node, TargetName,
+ max_message_size, 1024),
+
+ ?line {ok, AgentConf} = mgr_user_agent_info(Node, TargetName, all),
+ ?DBG("Updated agent config: ~n~p", [AgentConf]),
+ Conf.
+
+fin_mgr_user_data1(Conf) ->
+ Node = ?config(manager_node, Conf),
+ Addr = ?config(ip, Conf),
+ Port = ?AGENT_PORT,
+ mgr_user_unregister_agent(Node, Addr, Port),
+ mgr_user_which_own_agents(Node),
+ Conf.
+
+fin_mgr_user_data2(Conf) ->
+ Node = ?config(manager_node, Conf),
+ TargetName = ?config(manager_agent_target_name, Conf),
+ mgr_user_unregister_agent(Node, TargetName),
+ mgr_user_which_own_agents(Node),
+ Conf.
+
+mgr_user_start(Node) ->
+ mgr_user_start(Node, snmp_manager_test_user).
+mgr_user_start(Node, Id) ->
+ rcall(Node, snmp_manager_user, start, [self(), Id]).
+
+mgr_user_stop(Node) ->
+ rcall(Node, snmp_manager_user, stop, []).
+
+%% mgr_user_register_agent(Node) ->
+%% mgr_user_register_agent(Node, ?LOCALHOST(), ?AGENT_PORT, []).
+%% mgr_user_register_agent(Node, TargetName) when is_list(TargetName) ->
+%% mgr_user_register_agent(Node, TargetName, []);
+%% mgr_user_register_agent(Node, Addr) ->
+%% mgr_user_register_agent(Node, Addr, ?AGENT_PORT, []).
+mgr_user_register_agent(Node, TargetName, Conf)
+ when is_list(TargetName) andalso is_list(Conf) ->
+ rcall(Node, snmp_manager_user, register_agent, [TargetName, Conf]);
+mgr_user_register_agent(Node, Addr, Port) ->
+ mgr_user_register_agent(Node, Addr, Port, []).
+mgr_user_register_agent(Node, Addr, Port, Conf) ->
+ rcall(Node, snmp_manager_user, register_agent, [Addr, Port, Conf]).
+
+%% mgr_user_unregister_agent(Node) ->
+%% mgr_user_unregister_agent(Node, ?LOCALHOST(), ?AGENT_PORT).
+mgr_user_unregister_agent(Node, Addr_or_TargetName) ->
+ rcall(Node, snmp_manager_user, unregister_agent, [Addr_or_TargetName]).
+mgr_user_unregister_agent(Node, Addr, Port) ->
+ rcall(Node, snmp_manager_user, unregister_agent, [Addr, Port]).
+
+mgr_user_agent_info(Node, Addr_or_TargetName, Item) when is_atom(Item) ->
+ rcall(Node, snmp_manager_user, agent_info, [Addr_or_TargetName, Item]).
+mgr_user_agent_info(Node, Addr, Port, Item) when is_atom(Item) ->
+ rcall(Node, snmp_manager_user, agent_info, [Addr, Port, Item]).
+
+%% mgr_user_update_agent_info(Node, Item, Val) when atom(Item) ->
+%% mgr_user_update_agent_info(Node, ?LOCALHOST(), ?AGENT_PORT, Item, Val).
+mgr_user_update_agent_info(Node, Addr_or_TargetName, Item, Val)
+ when is_atom(Item) ->
+ rcall(Node, snmp_manager_user, update_agent_info,
+ [Addr_or_TargetName, Item, Val]).
+mgr_user_update_agent_info(Node, Addr, Port, Item, Val) when is_atom(Item) ->
+ rcall(Node, snmp_manager_user, update_agent_info,
+ [Addr, Port, Item, Val]).
+
+%% mgr_user_which_all_agents(Node) ->
+%% rcall(Node, snmp_manager_user, which_all_agents, []).
+
+mgr_user_which_own_agents(Node) ->
+ rcall(Node, snmp_manager_user, which_own_agents, []).
+
+mgr_user_load_mib(Node, Mib) ->
+ rcall(Node, snmp_manager_user, load_mib, [Mib]).
+
+%% mgr_user_sync_get(Node, Oids) ->
+%% mgr_user_sync_get(Node, ?LOCALHOST(), ?AGENT_PORT, Oids).
+mgr_user_sync_get(Node, Addr_or_TargetName, Oids) ->
+ rcall(Node, snmp_manager_user, sync_get, [Addr_or_TargetName, Oids]).
+mgr_user_sync_get(Node, Addr, Port, Oids) ->
+ rcall(Node, snmp_manager_user, sync_get, [Addr, Port, Oids]).
+
+%% mgr_user_async_get(Node, Oids) ->
+%% mgr_user_async_get(Node, ?LOCALHOST(), ?AGENT_PORT, Oids).
+mgr_user_async_get(Node, Addr_or_TargetName, Oids) ->
+ rcall(Node, snmp_manager_user, async_get, [Addr_or_TargetName, Oids]).
+mgr_user_async_get(Node, Addr, Port, Oids) ->
+ rcall(Node, snmp_manager_user, async_get, [Addr, Port, Oids]).
+
+%% mgr_user_sync_get_next(Node, Oids) ->
+%% mgr_user_sync_get_next(Node, ?LOCALHOST(), ?AGENT_PORT, Oids).
+mgr_user_sync_get_next(Node, Addr_or_TargetName, Oids) ->
+ rcall(Node, snmp_manager_user, sync_get_next, [Addr_or_TargetName, Oids]).
+mgr_user_sync_get_next(Node, Addr, Port, Oids) ->
+ rcall(Node, snmp_manager_user, sync_get_next, [Addr, Port, Oids]).
+
+%% mgr_user_async_get_next(Node, Oids) ->
+%% mgr_user_async_get_next(Node, ?LOCALHOST(), ?AGENT_PORT, Oids).
+mgr_user_async_get_next(Node, Addr_or_TargetName, Oids) ->
+ rcall(Node, snmp_manager_user, async_get_next, [Addr_or_TargetName, Oids]).
+mgr_user_async_get_next(Node, Addr, Port, Oids) ->
+ rcall(Node, snmp_manager_user, async_get_next, [Addr, Port, Oids]).
+
+%% mgr_user_sync_set(Node, VAV) ->
+%% mgr_user_sync_set(Node, ?LOCALHOST(), ?AGENT_PORT, VAV).
+mgr_user_sync_set(Node, Addr_or_TargetName, VAV) ->
+ rcall(Node, snmp_manager_user, sync_set, [Addr_or_TargetName, VAV]).
+mgr_user_sync_set(Node, Addr, Port, VAV) ->
+ rcall(Node, snmp_manager_user, sync_set, [Addr, Port, VAV]).
+
+%% mgr_user_async_set(Node, VAV) ->
+%% mgr_user_async_set(Node, ?LOCALHOST(), ?AGENT_PORT, VAV).
+mgr_user_async_set(Node, Addr_or_TargetName, VAV) ->
+ rcall(Node, snmp_manager_user, async_set, [Addr_or_TargetName, VAV]).
+mgr_user_async_set(Node, Addr, Port, VAV) ->
+ rcall(Node, snmp_manager_user, async_set, [Addr, Port, VAV]).
+
+%% mgr_user_sync_get_bulk(Node, NonRep, MaxRep, Oids) ->
+%% mgr_user_sync_get_bulk(Node, ?LOCALHOST(), ?AGENT_PORT,
+%% NonRep, MaxRep, Oids).
+mgr_user_sync_get_bulk(Node, Addr_or_TargetName, NonRep, MaxRep, Oids) ->
+ rcall(Node, snmp_manager_user, sync_get_bulk,
+ [Addr_or_TargetName, NonRep, MaxRep, Oids]).
+mgr_user_sync_get_bulk(Node, Addr, Port, NonRep, MaxRep, Oids) ->
+ rcall(Node, snmp_manager_user, sync_get_bulk,
+ [Addr, Port, NonRep, MaxRep, Oids]).
+
+%% mgr_user_async_get_bulk(Node, NonRep, MaxRep, Oids) ->
+%% mgr_user_async_get_bulk(Node, ?LOCALHOST(), ?AGENT_PORT,
+%% NonRep, MaxRep, Oids).
+mgr_user_async_get_bulk(Node, Addr_or_TargetName, NonRep, MaxRep, Oids) ->
+ rcall(Node, snmp_manager_user, async_get_bulk,
+ [Addr_or_TargetName, NonRep, MaxRep, Oids]).
+mgr_user_async_get_bulk(Node, Addr, Port, NonRep, MaxRep, Oids) ->
+ rcall(Node, snmp_manager_user, async_get_bulk,
+ [Addr, Port, NonRep, MaxRep, Oids]).
+
+mgr_user_purify_oid(Node, Oid) ->
+ rcall(Node, snmp_manager_user, purify_oid, [Oid]).
+
+mgr_user_name_to_oid(Node, Name) ->
+ rcall(Node, snmp_manager_user, name_to_oid, [Name]).
+
+
+%% -- Misc manager wrapper functions --
+
+start_manager(Node, Vsns, Config) ->
+ start_manager(Node, Vsns, Config, []).
+start_manager(Node, Vsns, Conf0, Opts) ->
+ ?DBG("start_manager -> entry with"
+ "~n Node: ~p"
+ "~n Vsns: ~p"
+ "~n Conf0: ~p"
+ "~n Opts: ~p", [Node, Vsns, Conf0, Opts]),
+
+ AtlDir = ?config(manager_log_dir, Conf0),
+ ConfDir = ?config(manager_conf_dir, Conf0),
+ DbDir = ?config(manager_db_dir, Conf0),
+ IRB = ?config(irb, Conf0),
+
+ ConfigVerbosity = get_opt(manager_config_verbosity, Conf0, trace),
+ NoteStoreVerbosity = get_opt(manager_note_store_verbosity, Conf0, log),
+ ServerVerbosity = get_opt(manager_server_verbosity, Conf0, trace),
+ NetIfVerbosity = get_opt(manager_net_if_verbosity, Conf0, trace),
+
+ Env = [{versions, Vsns},
+ {inform_request_behaviour, IRB},
+ {audit_trail_log, [{type, read_write},
+ {dir, AtlDir},
+ {size, {10240, 10}},
+ {repair, true}]},
+ {config, [{dir, ConfDir},
+ {db_dir, DbDir},
+ {verbosity, ConfigVerbosity}]},
+ {note_store, [{verbosity, NoteStoreVerbosity}]},
+ {server, [{verbosity, ServerVerbosity}]},
+ {net_if, [{verbosity, NetIfVerbosity}]}],
+ ?line ok = set_mgr_env(Node, Env),
+
+ ?line ok = start_snmp(Node),
+
+ Conf0.
+
+stop_manager(Node, Conf) ->
+ stop_snmp(Node),
+ Conf.
+
+%% -- Misc agent wrapper functions --
+
+start_agent(Node, Vsns, Config) ->
+ start_agent(Node, Vsns, Config, []).
+start_agent(Node, Vsns, Conf0, Opts) ->
+ ?DBG("start_agent -> entry with"
+ "~n Node: ~p"
+ "~n Vsns: ~p"
+ "~n Conf0: ~p"
+ "~n Opts: ~p", [Node, Vsns, Conf0, Opts]),
+
+ AtlDir = ?config(agent_log_dir, Conf0),
+ ConfDir = ?config(agent_conf_dir, Conf0),
+ DbDir = ?config(agent_db_dir, Conf0),
+
+ MAV = get_opt(agent_verbosity, Conf0, trace),
+ CV = get_opt(agent_config_verbosity, Conf0, info),
+ LDBV = get_opt(agent_local_db_verbosity, Conf0, info),
+ MSV = get_opt(agent_mib_server_verbosity, Conf0, info),
+ NSV = get_opt(agent_note_store_verbosity, Conf0, info),
+ SSV = get_opt(agent_symbolic_store_verbosity, Conf0, info),
+ NIV = get_opt(agent_net_if_verbosity, Conf0, log),
+
+ Env = [{versions, Vsns},
+ {type, master},
+ {agent_verbosity, MAV},
+ {audit_trail_log, [{type, read_write},
+ {dir, AtlDir},
+ {size, {10240, 10}},
+ {repair, true}]},
+ {config, [{dir, ConfDir},
+ {force_load, false},
+ {verbosity, CV}]},
+ {db_dir, DbDir},
+ {local_db, [{repair, true},
+ {auto_save, 10000},
+ {verbosity, LDBV}]},
+ {mib_server, [{verbosity, MSV}]},
+ {note_store, [{verbosity, NSV}]},
+ {stymbolic_store, [{verbosity, SSV}]},
+ {net_if, [{verbosity, NIV}]},
+ {multi_threaded, true}],
+ ?line ok = set_agent_env(Node, Env),
+
+ ?line ok = start_snmp(Node),
+ Conf0.
+
+stop_agent(Node, Conf) ->
+ stop_snmp(Node),
+ Conf.
+
+agent_load_mib(Node, Mib) ->
+ rcall(Node, snmpa, load_mibs, [[Mib]]).
+%% agent_unload_mib(Node, Mib) ->
+%% rcall(Node, snmpa, unload_mibs, [[Mib]]).
+
+%% agent_send_trap(Node, Trap, Community) ->
+%% Args = [snmp_master_agent, Trap, Community],
+%% rcall(Node, snmpa, send_trap, Args).
+
+agent_send_trap(Node, Trap, Community, VBs) ->
+ Args = [snmp_master_agent, Trap, Community, VBs],
+ rcall(Node, snmpa, send_trap, Args).
+
+agent_send_notif(Node, Trap, Name) ->
+ agent_send_notif(Node, Trap, Name, []).
+
+agent_send_notif(Node, Trap, Name, VBs) ->
+ agent_send_notif(Node, Trap, no_receiver, Name, VBs).
+
+agent_send_notif(Node, Trap, Recv, Name, VBs) ->
+ Args = [snmp_master_agent, Trap, Recv, Name, VBs],
+ rcall(Node, snmpa, send_notification, Args).
+
+agent_info(Node) ->
+ rcall(Node, snmpa, info, []).
+
+%% agent_which_mibs(Node) ->
+%% rcall(Node, snmpa, which_mibs, []).
+
+
+%% -- Misc node operation wrapper functions --
+
+start_agent_node() ->
+ start_node(snmp_agent).
+
+start_manager_node() ->
+ start_node(snmp_manager).
+
+start_node(Name) ->
+ Pa = filename:dirname(code:which(?MODULE)),
+ Args = case init:get_argument('CC_TEST') of
+ {ok, [[]]} ->
+ " -pa /clearcase/otp/libraries/snmp/ebin ";
+ {ok, [[Path]]} ->
+ " -pa " ++ Path;
+ error ->
+ ""
+ end,
+ A = Args ++ " -pa " ++ Pa,
+ case (catch ?START_NODE(Name, A)) of
+ {ok, Node} ->
+ Node;
+ Else ->
+ ?line ?FAIL(Else)
+ end.
+
+stop_node(Node) ->
+ rpc:cast(Node, erlang, halt, []),
+ await_stopped(Node, 5).
+
+await_stopped(_, 0) ->
+ ok;
+await_stopped(Node, N) ->
+ Nodes = erlang:nodes(),
+ case lists:member(Node, Nodes) of
+ true ->
+ ?DBG("[~w] ~p still exist", [N, Node]),
+ ?SLEEP(1000),
+ await_stopped(Node, N-1);
+ false ->
+ ?DBG("[~w] ~p gone", [N, Node]),
+ ok
+ end.
+
+
+
+%% -- Misc config wrapper functions --
+
+write_manager_config(Config) ->
+ Dir = ?config(manager_conf_dir, Config),
+ Ip = ?config(ip, Config),
+ Addr = tuple_to_list(Ip),
+ snmp_config:write_manager_snmp_files(Dir, Addr, ?MGR_PORT,
+ ?MGR_MMS, ?MGR_ENGINE_ID, [], [], []).
+
+write_manager_conf(Dir) ->
+ Port = "5000",
+ MMS = "484",
+ EngineID = "\"mgrEngine\"",
+ Str = lists:flatten(
+ io_lib:format("%% Minimum manager config file\n"
+ "{port, ~s}.\n"
+ "{max_message_size, ~s}.\n"
+ "{engine_id, ~s}.\n",
+ [Port, MMS, EngineID])),
+ write_manager_conf(Dir, Str).
+
+%% write_manager_conf(Dir, IP, Port, MMS, EngineID) ->
+%% Str = lists:flatten(
+%% io_lib:format("{address, ~s}.\n"
+%% "{port, ~s}.\n"
+%% "{max_message_size, ~s}.\n"
+%% "{engine_id, ~s}.\n",
+%% [IP, Port, MMS, EngineID])),
+%% write_manager_conf(Dir, Str).
+
+write_manager_conf(Dir, Str) ->
+ write_conf_file(Dir, "manager.conf", Str).
+
+
+write_agent_config(Vsns, Conf) ->
+ Dir = ?config(agent_conf_dir, Conf),
+ Ip = ?config(ip, Conf),
+ ?line Addr = tuple_to_list(Ip),
+ ?line ok = write_agent_config_files(Dir, Vsns, Addr),
+ ?line ok = update_agent_usm(Vsns, Dir),
+ ?line ok = update_agent_community(Vsns, Dir),
+ ?line ok = update_agent_vacm(Vsns, Dir),
+ ?line ok = write_agent_target_addr_conf(Dir, Addr, Vsns),
+ ?line ok = write_agent_target_params_conf(Dir, Vsns),
+ ?line ok = write_agent_notify_conf(Dir),
+ ok.
+
+write_agent_config_files(Dir, Vsns, Addr) ->
+ snmp_config:write_agent_snmp_files(Dir, Vsns,
+ Addr, ?MGR_PORT,
+ Addr, ?AGENT_PORT,
+ "mgr-test", "trap",
+ none, "",
+ ?AGENT_ENGINE_ID,
+ ?AGENT_MMS).
+
+update_agent_usm(Vsns, Dir) ->
+ case lists:member(v3, Vsns) of
+ true ->
+ Conf = [{"agentEngine", "all-rights", "all-rights", zeroDotZero,
+ usmNoAuthProtocol, "", "",
+ usmNoPrivProtocol, "", "", "", "", ""},
+
+ {"agentEngine", "no-rights", "no-rights", zeroDotZero,
+ usmNoAuthProtocol, "", "",
+ usmNoPrivProtocol, "", "", "", "", ""},
+
+ {"agentEngine", "authMD5", "authMD5", zeroDotZero,
+ usmHMACMD5AuthProtocol, "", "",
+ usmNoPrivProtocol, "", "", "", "passwd_md5xxxxxx", ""},
+
+ {"agentEngine", "authSHA", "authSHA", zeroDotZero,
+ usmHMACSHAAuthProtocol, "", "",
+ usmNoPrivProtocol, "", "", "",
+ "passwd_shaxxxxxxxxxx", ""},
+
+ {"agentEngine", "privDES", "privDES", zeroDotZero,
+ usmHMACSHAAuthProtocol, "", "",
+ usmDESPrivProtocol, "", "", "",
+ "passwd_shaxxxxxxxxxx", "passwd_desxxxxxx"},
+
+ {"mgrEngine", "all-rights", "all-rights", zeroDotZero,
+ usmNoAuthProtocol, "", "",
+ usmNoPrivProtocol, "", "", "", "", ""},
+
+ {"mgrEngine", "no-rights", "no-rights", zeroDotZero,
+ usmNoAuthProtocol, "", "",
+ usmNoPrivProtocol, "", "", "", "", ""},
+
+ {"mgrEngine", "authMD5", "authMD5", zeroDotZero,
+ usmHMACMD5AuthProtocol, "", "",
+ usmNoPrivProtocol, "", "", "", "passwd_md5xxxxxx", ""},
+
+ {"mgrEngine", "authSHA", "authSHA", zeroDotZero,
+ usmHMACSHAAuthProtocol, "", "",
+ usmNoPrivProtocol, "", "", "",
+ "passwd_shaxxxxxxxxxx", ""},
+
+ {"mgrEngine", "privDES", "privDES", zeroDotZero,
+ usmHMACSHAAuthProtocol, "", "",
+ usmDESPrivProtocol, "", "", "",
+ "passwd_shaxxxxxxxxxx", "passwd_desxxxxxx"}],
+ snmp_config:update_agent_usm_config(Dir, Conf);
+ false ->
+ ok
+ end.
+
+update_agent_community([v3], _Dir) ->
+ ok;
+update_agent_community(_, Dir) ->
+ Conf = [{"no-rights", "no-rights", "no-rights", "", ""}],
+ snmp_config:update_agent_community_config(Dir, Conf).
+
+update_agent_vacm(_Vsns, Dir) ->
+ Conf = [{vacmSecurityToGroup, usm, "authMD5", "initial"},
+ {vacmSecurityToGroup, usm, "authSHA", "initial"},
+ {vacmSecurityToGroup, usm, "privDES", "initial"},
+ {vacmSecurityToGroup, usm, "newUser", "initial"},
+ {vacmViewTreeFamily, "internet", ?tDescr_instance,
+ excluded, null}],
+ snmp_config:update_agent_vacm_config(Dir, Conf).
+
+write_agent_target_addr_conf(Dir, Addr, Vsns) ->
+ snmp_config:write_agent_snmp_target_addr_conf(Dir, Addr, ?MGR_PORT,
+ 300, 3, Vsns).
+
+write_agent_target_params_conf(Dir, Vsns) ->
+ F = fun(v1) -> {"target_v1", v1, v1, "all-rights", noAuthNoPriv};
+ (v2) -> {"target_v2", v2c, v2c, "all-rights", noAuthNoPriv};
+ (v3) -> {"target_v3", v3, usm, "all-rights", noAuthNoPriv}
+ end,
+ Conf = [F(Vsn) || Vsn <- Vsns],
+ snmp_config:write_agent_target_params_config(Dir, "", Conf).
+
+write_agent_notify_conf(Dir) ->
+ Conf = [{"standard trap", "std_trap", trap},
+ {"standard inform", "std_inform", inform}],
+ snmp_config:write_agent_notify_config(Dir, "", Conf).
+
+
+write_conf_file(Dir, File, Str) ->
+ ?line {ok, Fd} = file:open(filename:join(Dir, File), write),
+ ?line ok = io:format(Fd, "~s", [Str]),
+ file:close(Fd).
+
+
+%% ------
+
+test2_mib(Config) ->
+ j(test_mib_dir(Config), "Test2.bin").
+
+test_trap_mib(Config) ->
+ j(test_mib_dir(Config), "TestTrap.bin").
+
+test_trap_v2_mib(Config) ->
+ j(test_mib_dir(Config), "TestTrapv2.bin").
+
+std_mib() ->
+ j(mib_dir(), "STANDARD-MIB.bin").
+
+snmpv2_mib() ->
+ j(mib_dir(), "SNMPv2-MIB.bin").
+
+test_mib_dir(Config) ->
+ ?config(snmp_data_dir, Config).
+
+mib_dir() ->
+ j(code:priv_dir(snmp), "mibs").
+
+j(A, B) ->
+ filename:join(A, B).
+
+
+%% ------
+
+get_opt(Key, Opts, Def) ->
+ snmp_misc:get_option(Key, Opts, Def).
+
+
+%% ------
+
+rcall(Node, Mod, Func, Args) ->
+ case rpc:call(Node, Mod, Func, Args) of
+ {badrpc, nodedown} ->
+ ?FAIL({rpc_failure, Node});
+ Else ->
+ Else
+ end.
+
+
+%% ------
+
+%% Time in milli sec
+%% t() ->
+%% {A,B,C} = erlang:now(),
+%% A*1000000000+B*1000+(C div 1000).
+
+
+%% ------
+
+p(F) ->
+ p(F, []).
+
+p(F, A) ->
+ p(get(tname), F, A).
+
+p(TName, F, A) ->
+ io:format("*** [~w][~s] ***"
+ "~n" ++ F ++ "~n", [TName,format_timestamp(now())|A]).
+
+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).
+
+%% p(TName, F, A) ->
+%% io:format("~w -> " ++ F ++ "~n", [TName|A]).
+
diff --git a/lib/snmp/test/snmp_manager_user.erl b/lib/snmp/test/snmp_manager_user.erl
new file mode 100644
index 0000000000..07b56bde39
--- /dev/null
+++ b/lib/snmp/test/snmp_manager_user.erl
@@ -0,0 +1,935 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2005-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%
+%%
+
+%%----------------------------------------------------------------------
+%% Purpose: Utility functions for the (snmp manager) user test(s).
+%%----------------------------------------------------------------------
+
+-module(snmp_manager_user).
+
+-behaviour(snmpm_user).
+%% -behaviour(snmpm_user_old).
+
+
+%%----------------------------------------------------------------------
+%% Include files
+%%----------------------------------------------------------------------
+-include("test_server.hrl").
+-include("snmp_test_lib.hrl").
+
+
+%%----------------------------------------------------------------------
+%% External exports
+%%----------------------------------------------------------------------
+-export([
+ start_link/0, start_link/1, start_link/2,
+ start/0, start/1, start/2,
+ stop/0,
+ info/0,
+ system_info/0,
+ simulate_crash/1,
+ register_agent/2, register_agent/3,
+ unregister_agent/1, unregister_agent/2,
+ agent_info/2, agent_info/3,
+ update_agent_info/3, update_agent_info/4,
+ which_all_agents/0, which_own_agents/0,
+ load_mib/1, unload_mib/1,
+ sync_get/1, sync_get/2, sync_get/3,
+ async_get/1, async_get/2, async_get/3,
+ sync_get_next/1, sync_get_next/2, sync_get_next/3,
+ async_get_next/1, async_get_next/2, async_get_next/3,
+ sync_set/1, sync_set/2, sync_set/3,
+ async_set/1, async_set/2, async_set/3,
+ sync_get_bulk/3, sync_get_bulk/4, sync_get_bulk/5,
+ async_get_bulk/3, async_get_bulk/4, async_get_bulk/5,
+ name_to_oid/1, oid_to_name/1,
+ purify_oid/1
+ ]).
+
+
+%%----------------------------------------------------------------------
+%% Internal exports
+%%----------------------------------------------------------------------
+
+-export([
+ main/4
+ ]).
+
+-export([
+ handle_error/3,
+ handle_agent/4,
+ handle_pdu/4,
+ handle_trap/3,
+ handle_inform/3,
+ handle_report/3,
+ handle_pdu/5, % For backwards compatibillity
+ handle_trap/4, % For backwards compatibillity
+ handle_inform/4, % For backwards compatibillity
+ handle_report/4 % For backwards compatibillity
+ ]).
+
+
+-define(SERVER, ?MODULE).
+
+-record(state, {parent, id, reqs = []}).
+%% -record(request, {from, ref, tmr, req_id, type}).
+
+
+%%----------------------------------------------------------------------
+%% The user API
+%%----------------------------------------------------------------------
+
+start() ->
+ start(self()).
+
+start(Parent) ->
+ start(Parent, test_user).
+
+start(Parent, Id) ->
+ proc_lib:start(?MODULE, main, [true, Parent, self(), Id]).
+
+start_link() ->
+ start_link(self()).
+start_link(Parent) ->
+ start_link(Parent, test_user).
+
+start_link(Parent, Id) ->
+ proc_lib:start_link(?MODULE, main, [true, Parent, self(), Id]).
+
+stop() ->
+ cast(stop).
+
+info() ->
+ call(info).
+
+system_info() ->
+ call(system_info).
+
+simulate_crash(Reason) ->
+ call({simulate_crash, Reason}).
+
+register_agent(TargetName, Config)
+ when is_list(TargetName) andalso is_list(Config) ->
+ call({register_agent, TargetName, Config});
+register_agent(Addr, Port) ->
+ register_agent(Addr, Port, []).
+
+register_agent(Addr, Port, Conf) ->
+ call({register_agent, Addr, Port, Conf}).
+
+unregister_agent(TargetName) ->
+ call({unregister_agent, TargetName}).
+unregister_agent(Addr, Port) ->
+ call({unregister_agent, Addr, Port}).
+
+agent_info(TargetName, Item) ->
+ call({agent_info, TargetName, Item}).
+agent_info(Addr, Port, Item) ->
+ call({agent_info, Addr, Port, Item}).
+
+update_agent_info(TargetName, Item, Val) ->
+ call({update_agent_info, TargetName, Item, Val}).
+update_agent_info(Addr, Port, Item, Val) ->
+ call({update_agent_info, Addr, Port, Item, Val}).
+
+which_all_agents() ->
+ call(which_all_agents).
+
+which_own_agents() ->
+ call(which_own_agents).
+
+load_mib(Mib) ->
+ call({load_mib, Mib}).
+
+unload_mib(Mib) ->
+ call({unload_mib, Mib}).
+
+%% --
+
+sync_get(Oids) ->
+ call({sync_get, Oids}).
+
+sync_get(Addr_or_TargetName, Oids) ->
+ call({sync_get, Addr_or_TargetName, Oids}).
+
+sync_get(Addr, Port, Oids) ->
+ call({sync_get, Addr, Port, Oids}).
+
+%% --
+
+async_get(Oids) ->
+ call({async_get, Oids}).
+
+async_get(Addr_or_TargetName, Oids) ->
+ call({async_get, Addr_or_TargetName, Oids}).
+
+async_get(Addr, Port, Oids) ->
+ call({async_get, Addr, Port, Oids}).
+
+%% --
+
+sync_get_next(Oids) ->
+ call({sync_get_next, Oids}).
+
+sync_get_next(Addr_or_TargetName, Oids) ->
+ call({sync_get_next, Addr_or_TargetName, Oids}).
+
+sync_get_next(Addr, Port, Oids) ->
+ call({sync_get_next, Addr, Port, Oids}).
+
+%% --
+
+async_get_next(Oids) ->
+ call({async_get_next, Oids}).
+
+async_get_next(Addr_or_TargetName, Oids) ->
+ call({async_get_next, Addr_or_TargetName, Oids}).
+
+async_get_next(Addr, Port, Oids) ->
+ call({async_get_next, Addr, Port, Oids}).
+
+%% --
+
+sync_set(VAV) ->
+ call({sync_set, VAV}).
+
+sync_set(Addr_or_TargetName, VAV) ->
+ call({sync_set, Addr_or_TargetName, VAV}).
+
+sync_set(Addr, Port, VAV) ->
+ call({sync_set, Addr, Port, VAV}).
+
+%% --
+
+async_set(VAV) ->
+ call({async_set, VAV}).
+
+async_set(Addr_or_TargetName, VAV) ->
+ call({async_set, Addr_or_TargetName, VAV}).
+
+async_set(Addr, Port, VAV) ->
+ call({async_set, Addr, Port, VAV}).
+
+%% --
+
+sync_get_bulk(NonRep, MaxRep, Oids) ->
+ call({sync_get_bulk, NonRep, MaxRep, Oids}).
+
+sync_get_bulk(Addr_or_TargetName, NonRep, MaxRep, Oids) ->
+ call({sync_get_bulk, Addr_or_TargetName, NonRep, MaxRep, Oids}).
+
+sync_get_bulk(Addr, Port, NonRep, MaxRep, Oids) ->
+ call({sync_get_bulk, Addr, Port, NonRep, MaxRep, Oids}).
+
+%% --
+
+async_get_bulk(NonRep, MaxRep, Oids) ->
+ call({async_get_bulk, NonRep, MaxRep, Oids}).
+
+async_get_bulk(Addr_or_TargetName, NonRep, MaxRep, Oids) ->
+ call({async_get_bulk, Addr_or_TargetName, NonRep, MaxRep, Oids}).
+
+async_get_bulk(Addr, Port, NonRep, MaxRep, Oids) ->
+ call({async_get_bulk, Addr, Port, NonRep, MaxRep, Oids}).
+
+%% --
+
+name_to_oid(Name) ->
+ call({name_to_oid, Name}).
+
+oid_to_name(Oid) ->
+ call({oid_to_name, Oid}).
+
+purify_oid(Oid) ->
+ call({purify_oid, Oid}).
+
+
+%%----------------------------------------------------------------------
+
+main(Debug, Parent, Starter, Id) ->
+ put(debug, Debug),
+ d("main -> entry with"
+ "~n Parent: ~p"
+ "~n Starter: ~p"
+ "~n Id: ~p", [Parent, Starter, Id]),
+ case (catch do_init(Id)) of
+ ok ->
+ proc_lib:init_ack(Starter, {ok, self()}),
+ loop(#state{parent = Parent, id = Id});
+ Error ->
+ d("main -> error: "
+ "~p", [Error]),
+ proc_lib:init_ack(Starter, Error)
+ end.
+
+do_init(Id) ->
+ erlang:register(?SERVER, self()),
+ snmpm:register_user(Id, ?MODULE, self()).
+
+
+%%----------------------------------------------------------------------
+
+loop(#state{parent = Parent, id = Id} = S) ->
+ d("loop -> entry"),
+ receive
+ {stop, _From} ->
+ d("loop -> received stop request"),
+ exit(normal);
+
+ {{simulate_crash, Reason}, From, Ref} ->
+ d("loop -> received simulate_crash request"),
+ reply(From, ok, Ref),
+ exit(Reason);
+
+ {info, From, Ref} ->
+ d("loop -> received info request"),
+ Res = snmpm:info(),
+ reply(From, Res, Ref),
+ loop(S);
+
+ {system_info, From, Ref} ->
+ d("loop -> received system_info request"),
+ Res = snmpm_config:system_info(),
+ reply(From, Res, Ref),
+ loop(S);
+
+ {{register_agent, TargetName, Conf}, From, Ref} ->
+ d("loop -> received register_agent request"),
+ Res = snmpm:register_agent(Id, TargetName, Conf),
+ reply(From, Res, Ref),
+ loop(S);
+
+ {{register_agent, Addr, Port, Conf}, From, Ref} ->
+ d("loop -> received register_agent request"),
+ Res = snmpm:register_agent(Id, Addr, Port, Conf),
+ reply(From, Res, Ref),
+ loop(S);
+
+ {{unregister_agent, TargetName}, From, Ref} ->
+ d("loop -> received unregister_agent request"),
+ Res = snmpm:unregister_agent(Id, TargetName),
+ reply(From, Res, Ref),
+ loop(S);
+
+ {{unregister_agent, Addr, Port}, From, Ref} ->
+ d("loop -> received unregister_agent request"),
+ Res = snmpm:unregister_agent(Id, Addr, Port),
+ reply(From, Res, Ref),
+ loop(S);
+
+ {{agent_info, TargetName, Item}, From, Ref} ->
+ d("loop -> received agent_info request with"
+ "~n TargetName: ~p"
+ "~n Item: ~p", [TargetName, Item]),
+ Res = snmpm:agent_info(TargetName, Item),
+ d("loop -> agent_info for ~p"
+ "~n Res: ~p", [Item, Res]),
+ reply(From, Res, Ref),
+ loop(S);
+
+ {{agent_info, Addr, Port, Item}, From, Ref} ->
+ d("loop -> received agent_info request with"
+ "~n Addr: ~p"
+ "~n Port: ~p"
+ "~n Item: ~p", [Addr, Port, Item]),
+ Res = snmpm:agent_info(Addr, Port, Item),
+ reply(From, Res, Ref),
+ loop(S);
+
+ {{update_agent_info, TargetName, Item, Val}, From, Ref} ->
+ d("loop -> received update_agent_info request with"
+ "~n TargetName: ~p"
+ "~n Item: ~p"
+ "~n Val: ~p", [TargetName, Item, Val]),
+ Res = snmpm:update_agent_info(Id, TargetName, Item, Val),
+ reply(From, Res, Ref),
+ loop(S);
+
+ {{update_agent_info, Addr, Port, Item, Val}, From, Ref} ->
+ d("loop -> received update_agent_info request with"
+ "~n Addr: ~p"
+ "~n Port: ~p"
+ "~n Item: ~p"
+ "~n Val: ~p", [Addr, Port, Item, Val]),
+ Res = snmpm:update_agent_info(Id, Addr, Port, Item, Val),
+ reply(From, Res, Ref),
+ loop(S);
+
+ {which_all_agents, From, Ref} ->
+ d("loop -> received which_all_agents request"),
+ Res = snmpm:which_agents(),
+ reply(From, Res, Ref),
+ loop(S);
+
+ {which_own_agents, From, Ref} ->
+ d("loop -> received which_own_agents request"),
+ Res = snmpm:which_agents(Id),
+ reply(From, Res, Ref),
+ loop(S);
+
+ {{load_mib, Mib}, From, Ref} ->
+ d("loop -> received load_mib request"),
+ Res = snmpm:load_mib(Mib),
+ reply(From, Res, Ref),
+ loop(S);
+
+ {{unload_mib, Mib}, From, Ref} ->
+ d("loop -> received unload_mib request"),
+ Res = snmpm:unload_mib(Mib),
+ reply(From, Res, Ref),
+ loop(S);
+
+
+ %%
+ %% -- (sync) get-request --
+ %%
+
+ %% No agent specified, so send it to all of them
+ {{sync_get, Oids}, From, Ref} ->
+ d("loop -> received sync_get request "
+ "(for every agent of this user)"),
+ Res = [snmpm:sync_get(Id, TargetName, Oids) ||
+ TargetName <- snmpm:which_agents(Id)],
+ reply(From, Res, Ref),
+ loop(S);
+
+ {{sync_get, TargetName, Oids}, From, Ref} when is_list(TargetName) ->
+ d("loop -> received sync_get request with"
+ "~n TargetName: ~p"
+ "~n Oids: ~p", [TargetName, Oids]),
+ Res = snmpm:sync_get(Id, TargetName, Oids),
+ reply(From, Res, Ref),
+ loop(S);
+
+ {{sync_get, Addr, Oids}, From, Ref} ->
+ d("loop -> received sync_get request with"
+ "~n Addr: ~p"
+ "~n Oids: ~p", [Addr, Oids]),
+ Res = snmpm:g(Id, Addr, Oids),
+ reply(From, Res, Ref),
+ loop(S);
+
+ {{sync_get, Addr, Port, Oids}, From, Ref} ->
+ d("loop -> received sync_get request with"
+ "~n Addr: ~p"
+ "~n Port: ~p"
+ "~n Oids: ~p", [Addr, Port, Oids]),
+ Res = snmpm:g(Id, Addr, Port, Oids),
+ reply(From, Res, Ref),
+ loop(S);
+
+
+ %%
+ %% -- (async) get-request --
+ %%
+
+ %% No agent specified, so send it to all of them
+ {{async_get, Oids}, From, Ref} ->
+ d("loop -> received async_get request"),
+ Res = [snmpm:async_get(Id, TargetName, Oids) ||
+ TargetName <- snmpm:which_agents(Id)],
+ reply(From, Res, Ref),
+ loop(S);
+
+ {{async_get, TargetName, Oids}, From, Ref} when is_list(TargetName) ->
+ d("loop -> received async_get request with"
+ "~n TargetName: ~p"
+ "~n Oids: ~p", [TargetName, Oids]),
+ Res = snmpm:async_get(Id, TargetName, Oids),
+ reply(From, Res, Ref),
+ loop(S);
+
+ {{async_get, Addr, Oids}, From, Ref} ->
+ d("loop -> received async_get request"),
+ Res = snmpm:ag(Id, Addr, Oids),
+ reply(From, Res, Ref),
+ loop(S);
+
+ {{async_get, Addr, Port, Oids}, From, Ref} ->
+ d("loop -> received async_get request"),
+ Res = snmpm:ag(Id, Addr, Port, Oids),
+ reply(From, Res, Ref),
+ loop(S);
+
+
+ %%
+ %% -- (sync) get_next-request --
+ %%
+
+ %% No agent specified, so send it to all of them
+ {{sync_get_next, Oids}, From, Ref} ->
+ d("loop -> received sync_get_next request"),
+ Res = [snmpm:sync_get_next(Id, TargetName, Oids) ||
+ TargetName <- snmpm:which_agents(Id)],
+ reply(From, Res, Ref),
+ loop(S);
+
+ {{sync_get_next, TargetName, Oids}, From, Ref} when is_list(TargetName) ->
+ d("loop -> received sync_get_next request with"
+ "~n TargetName: ~p"
+ "~n Oids: ~p", [TargetName, Oids]),
+ Res = snmpm:sync_get_next(Id, TargetName, Oids),
+ reply(From, Res, Ref),
+ loop(S);
+
+ {{sync_get_next, Addr, Oids}, From, Ref} ->
+ d("loop -> received sync_get_next request"),
+ Res = snmpm:gn(Id, Addr, Oids),
+ reply(From, Res, Ref),
+ loop(S);
+
+ {{sync_get_next, Addr, Port, Oids}, From, Ref} ->
+ d("loop -> received sync_get_next request"),
+ Res = snmpm:gn(Id, Addr, Port, Oids),
+ reply(From, Res, Ref),
+ loop(S);
+
+
+ %%
+ %% -- (async) get_next-request --
+ %%
+
+ %% No agent specified, so send it to all of them
+ {{async_get_next, Oids}, From, Ref} ->
+ d("loop -> received async_get_next request"),
+ Res = [snmpm:async_get_next(Id, TargetName, Oids) ||
+ TargetName <- snmpm:which_agents(Id)],
+ reply(From, Res, Ref),
+ loop(S);
+
+ {{async_get_next, TargetName, Oids}, From, Ref} when is_list(TargetName) ->
+ d("loop -> received async_get_next request with"
+ "~n TargetName: ~p"
+ "~n Oids: ~p", [TargetName, Oids]),
+ Res = snmpm:async_get_next(Id, TargetName, Oids),
+ reply(From, Res, Ref),
+ loop(S);
+
+ {{async_get_next, Addr, Oids}, From, Ref} ->
+ d("loop -> received async_get_next request"),
+ Res = snmpm:agn(Id, Addr, Oids),
+ reply(From, Res, Ref),
+ loop(S);
+
+ {{async_get_next, Addr, Port, Oids}, From, Ref} ->
+ d("loop -> received async_get_next request"),
+ Res = snmpm:agn(Id, Addr, Port, Oids),
+ reply(From, Res, Ref),
+ loop(S);
+
+
+ %%
+ %% -- (sync) set-request --
+ %%
+
+ {{sync_set, VAV}, From, Ref} ->
+ d("loop -> received sync_set request"),
+ Res = [snmpm:sync_set(Id, TargetName, VAV) ||
+ TargetName <- snmpm:which_agents(Id)],
+ reply(From, Res, Ref),
+ loop(S);
+
+ {{sync_set, TargetName, VAV}, From, Ref} when is_list(TargetName) ->
+ d("loop -> received sync_set request"),
+ Res = snmpm:sync_set(Id, TargetName, VAV),
+ reply(From, Res, Ref),
+ loop(S);
+
+ {{sync_set, Addr, VAV}, From, Ref} ->
+ d("loop -> received sync_set request"),
+ Res = snmpm:s(Id, Addr, VAV),
+ reply(From, Res, Ref),
+ loop(S);
+
+ {{sync_set, Addr, Port, VAV}, From, Ref} ->
+ d("loop -> received sync_set request"),
+ Res = snmpm:s(Id, Addr, Port, VAV),
+ reply(From, Res, Ref),
+ loop(S);
+
+
+ %%
+ %% -- (async) set-request --
+ %%
+
+ {{async_set, VAV}, From, Ref} ->
+ d("loop -> received async_set request"),
+ Res = [snmpm:async_set(Id, TargetName, VAV) ||
+ TargetName <- snmpm:which_agents(Id)],
+ reply(From, Res, Ref),
+ loop(S);
+
+ {{async_set, TargetName, VAV}, From, Ref} when is_list(TargetName) ->
+ d("loop -> received async_set request"),
+ Res = snmpm:async_set(Id, TargetName, VAV),
+ reply(From, Res, Ref),
+ loop(S);
+
+ {{async_set, Addr, VAV}, From, Ref} ->
+ d("loop -> received async_set request"),
+ Res = snmpm:as(Id, Addr, VAV),
+ reply(From, Res, Ref),
+ loop(S);
+
+ {{async_set, Addr, Port, VAV}, From, Ref} ->
+ d("loop -> received async_set request"),
+ Res = snmpm:as(Id, Addr, Port, VAV),
+ reply(From, Res, Ref),
+ loop(S);
+
+
+ %%
+ %% -- (sync) get-bulk-request --
+ %%
+
+ %% No agent specified, so send it to all of them
+ {{sync_get_bulk, NonRep, MaxRep, Oids}, From, Ref} ->
+ d("loop -> received sync_get_bulk request with"
+ "~n NonRep: ~w"
+ "~n MaxRep: ~w"
+ "~n Oids: ~p", [NonRep, MaxRep, Oids]),
+ Res = [snmpm:sync_get_bulk(Id, TargetName, NonRep, MaxRep, Oids) ||
+ TargetName <- snmpm:which_agents(Id)],
+ reply(From, Res, Ref),
+ loop(S);
+
+ {{sync_get_bulk, TargetName, NonRep, MaxRep, Oids}, From, Ref} when is_list(TargetName) ->
+ d("loop -> received sync_get_bulk request with"
+ "~n TargetName: ~p"
+ "~n NonRep: ~w"
+ "~n MaxRep: ~w"
+ "~n Oids: ~p", [TargetName, NonRep, MaxRep, Oids]),
+ Res = snmpm:sync_get_bulk(Id, TargetName, NonRep, MaxRep, Oids),
+ reply(From, Res, Ref),
+ loop(S);
+
+ {{sync_get_bulk, Addr, NonRep, MaxRep, Oids}, From, Ref} ->
+ d("loop -> received sync_get_bulk request with"
+ "~n Addr: ~p"
+ "~n NonRep: ~w"
+ "~n MaxRep: ~w"
+ "~n Oids: ~p", [Addr, NonRep, MaxRep, Oids]),
+ Res = snmpm:gb(Id, Addr, NonRep, MaxRep, Oids),
+ reply(From, Res, Ref),
+ loop(S);
+
+ {{sync_get_bulk, Addr, Port, NonRep, MaxRep, Oids}, From, Ref} ->
+ d("loop -> received sync_get_bulk request with"
+ "~n Addr: ~p"
+ "~n Port: ~w"
+ "~n NonRep: ~w"
+ "~n MaxRep: ~w"
+ "~n Oids: ~p", [Addr, Port, NonRep, MaxRep, Oids]),
+ Res = snmpm:gb(Id, Addr, Port, NonRep, MaxRep, Oids),
+ reply(From, Res, Ref),
+ loop(S);
+
+
+ %%
+ %% -- (async) get-bulk-request --
+ %%
+
+ %% No agent specified, so send it to all of them
+ {{async_get_bulk, NonRep, MaxRep, Oids}, From, Ref} ->
+ d("loop -> received async_get_bulk request with"
+ "~n NonRep: ~w"
+ "~n MaxRep: ~w"
+ "~n Oids: ~p", [NonRep, MaxRep, Oids]),
+ Res = [snmpm:async_get_bulk(Id, TargetName, NonRep, MaxRep, Oids) ||
+ TargetName <- snmpm:which_agents(Id)],
+ reply(From, Res, Ref),
+ loop(S);
+
+ {{async_get_bulk, TargetName, NonRep, MaxRep, Oids}, From, Ref} when is_list(TargetName) ->
+ d("loop -> received async_get_bulk request with"
+ "~n TargetName: ~p"
+ "~n NonRep: ~w"
+ "~n MaxRep: ~w"
+ "~n Oids: ~p", [TargetName, NonRep, MaxRep, Oids]),
+ Res = snmpm:async_get_bulk(Id, TargetName, NonRep, MaxRep, Oids),
+ reply(From, Res, Ref),
+ loop(S);
+
+ {{async_get_bulk, Addr, NonRep, MaxRep, Oids}, From, Ref} ->
+ d("loop -> received async_get_bulk request with"
+ "~n Addr: ~p"
+ "~n NonRep: ~w"
+ "~n MaxRep: ~w"
+ "~n Oids: ~p", [Addr, NonRep, MaxRep, Oids]),
+ Res = snmpm:agb(Id, Addr, NonRep, MaxRep, Oids),
+ reply(From, Res, Ref),
+ loop(S);
+
+ {{async_get_bulk, Addr, Port, NonRep, MaxRep, Oids}, From, Ref} ->
+ d("loop -> received async_get_bulk request with"
+ "~n Addr: ~p"
+ "~n Port: ~w"
+ "~n NonRep: ~w"
+ "~n MaxRep: ~w"
+ "~n Oids: ~p", [Addr, Port, NonRep, MaxRep, Oids]),
+ Res = snmpm:agb(Id, Addr, Port, NonRep, MaxRep, Oids),
+ reply(From, Res, Ref),
+ loop(S);
+
+
+ %%
+ %% -- logical name translation --
+ %%
+
+ {{name_to_oid, Name}, From, Ref} ->
+ d("loop -> received name_to_oid request for"
+ "~n Name: ~p", [Name]),
+ Res = snmpm:name_to_oid(Name),
+ reply(From, Res, Ref),
+ loop(S);
+
+ {{oid_to_name, Oid}, From, Ref} ->
+ d("loop -> received oid_to_name request for"
+ "~n Oid: ~p", [Oid]),
+ Res = snmpm:oid_to_name(Oid),
+ reply(From, Res, Ref),
+ loop(S);
+
+ {{purify_oid, Oid}, From, Ref} ->
+ d("loop -> received purify_oid request for"
+ "~n Oid: ~p", [Oid]),
+ Res = do_purify_oid(Oid),
+ reply(From, Res, Ref),
+ loop(S);
+
+
+ %% SNMP manager callback messages (from our callback API):
+
+ {handle_error, _Pid, ReqId, Reason} ->
+ d("loop -> received error callback from manager for ~w:"
+ "~n ~p", [ReqId, Reason]),
+ Parent ! {async_event, ReqId, {error, Reason}},
+ loop(S);
+
+ {handle_agent, _Pid, Addr, Port, SnmpInfo} ->
+ d("loop -> received agent callback from manager for ~n ~p:~w",
+ [Addr, Port]),
+ Parent ! {async_event, {Addr, Port}, {agent, SnmpInfo}},
+ loop(S);
+
+ {handle_pdu, _Pid, _TargetName, ReqId, SnmpResponse} ->
+ d("loop -> received pdu callback from manager for ~w", [ReqId]),
+ Parent ! {async_event, ReqId, {pdu, SnmpResponse}},
+ loop(S);
+
+ %% For backwards compatibillity
+ {handle_pdu, _Pid, _Addr, _Port, ReqId, SnmpResponse} ->
+ d("loop -> received pdu callback from manager for ~w", [ReqId]),
+ Parent ! {async_event, ReqId, {pdu, SnmpResponse}},
+ loop(S);
+
+ {handle_trap, _Pid, TargetName, SnmpTrap} ->
+ d("loop -> received trap callback from manager for "
+ "~n ~p",
+ "~n ~p",
+ [TargetName, SnmpTrap]),
+ Parent ! {async_event, TargetName, {trap, SnmpTrap}},
+ loop(S);
+
+ %% For backwards compatibillity
+ {handle_trap, _Pid, Addr, Port, SnmpTrap} ->
+ d("loop -> received trap callback from manager for "
+ "~n ~p:~w",
+ "~n ~p",
+ [Addr, Port, SnmpTrap]),
+ Parent ! {async_event, {Addr, Port}, {trap, SnmpTrap}},
+ loop(S);
+
+ {handle_inform, Pid, TargetName, SnmpInform} ->
+ d("loop -> received inform callback from manager for "
+ "~n ~p",
+ "~n ~p",
+ [TargetName, SnmpInform]),
+ Parent ! {async_event, TargetName, {inform, Pid, SnmpInform}},
+ loop(S);
+
+ %% For backwards compatibillity
+ {handle_inform, Pid, Addr, Port, SnmpInform} ->
+ d("loop -> received inform callback from manager for "
+ "~n ~p:~w",
+ "~n ~p",
+ [Addr, Port, SnmpInform]),
+ Parent ! {async_event, {Addr, Port}, {inform, Pid, SnmpInform}},
+ loop(S);
+
+ {handle_report, _Pid, TargetName, SnmpReport} ->
+ d("loop -> received report callback from manager for "
+ "~n ~p",
+ "~n ~p",
+ [TargetName, SnmpReport]),
+ Parent ! {async_event, TargetName, {report, SnmpReport}},
+ loop(S);
+
+ %% For backwards compatibillity
+ {handle_report, _Pid, Addr, Port, SnmpReport} ->
+ d("loop -> received report callback from manager for "
+ "~n ~p:~w",
+ "~n ~p",
+ [Addr, Port, SnmpReport]),
+ Parent ! {async_event, {Addr, Port}, {report, SnmpReport}},
+ loop(S);
+
+ {'EXIT', Parent, Reason} ->
+ d("received exit signal from parent: ~n~p", [Reason]),
+ info("received exit signal from parent: ~n~p", [Reason]),
+ exit(Reason);
+
+ Unknown ->
+ d("received unknown message: ~n~p", [Unknown]),
+ info("received unknown message: ~n~p", [Unknown]),
+ loop(S)
+ end.
+
+
+%% -------------
+
+do_purify_oid([A|T]) when is_atom(A) ->
+ case snmpm:name_to_oid(A) of
+ {ok, [Oid|_]} ->
+ verify_pure_oid(lists:flatten([Oid|T]));
+ {error, not_found} ->
+ {error, {not_found, A}};
+ {error, _} = Error ->
+ Error
+ end;
+do_purify_oid(L) when is_list(L) ->
+ verify_pure_oid(lists:flatten(L));
+do_purify_oid(X) ->
+ {error, {unpure_oid, X}}.
+
+verify_pure_oid([]) ->
+ [];
+verify_pure_oid([H | T]) when is_integer(H) andalso (H >= 0) ->
+ [H | verify_pure_oid(T)];
+verify_pure_oid([H | _]) ->
+ throw({error, {not_pure_oid, H}}).
+
+
+%% -------------
+
+info(F, A) ->
+ error_logger:info_msg("TEST MGR USER " ++ F ++ "~n", A).
+
+
+%% -------------
+
+call(Req) ->
+ call(Req, 5000).
+
+call(Req, To) when is_integer(To) ->
+ Ref = make_ref(),
+ ?SERVER ! {Req, self(), Ref},
+ receive
+ {Reply, Ref} ->
+ Reply
+ after To ->
+ {error, timeout}
+ end.
+
+reply(Pid, Reply, Ref) ->
+ Pid ! {Reply, Ref}.
+
+cast(Msg) ->
+ ?SERVER ! {Msg, self()},
+ ok.
+
+
+%%----------------------------------------------------------------------
+%% User callback functions:
+%%----------------------------------------------------------------------
+
+handle_error(ReqId, Reason, UserPid) ->
+ UserPid ! {handle_error, self(), ReqId, Reason},
+ ignore.
+
+
+handle_agent(Addr, Port, SnmpInfo, UserPid) ->
+ UserPid ! {handle_agent, self(), Addr, Port, SnmpInfo},
+ ignore.
+
+
+handle_pdu(TargetName, ReqId, SnmpResponse, UserPid) ->
+ UserPid ! {handle_pdu, self(), TargetName, ReqId, SnmpResponse},
+ ignore.
+
+%% For backwards compatibillity
+handle_pdu(Addr, Port, ReqId, SnmpResponse, UserPid) ->
+ UserPid ! {handle_pdu, self(), Addr, Port, ReqId, SnmpResponse},
+ ignore.
+
+
+handle_trap(TargetName, SnmpTrap, UserPid) ->
+ UserPid ! {handle_trap, self(), TargetName, SnmpTrap},
+ ok.
+
+%% For backwards compatibillity
+handle_trap(Addr, Port, SnmpTrap, UserPid) ->
+ UserPid ! {handle_trap, self(), Addr, Port, SnmpTrap},
+ ok.
+
+
+handle_inform(TargetName, SnmpInform, UserPid) ->
+ UserPid ! {handle_inform, self(), TargetName, SnmpInform},
+ receive
+ {handle_inform_no_response, TargetName} ->
+ no_reply;
+ {handle_inform_response, TargetName} ->
+ ok
+ end.
+
+%% For backwards compatibillity
+handle_inform(Addr, Port, SnmpInform, UserPid) ->
+ UserPid ! {handle_inform, self(), Addr, Port, SnmpInform},
+ receive
+ {handle_inform_no_response, {Addr, Port}} ->
+ no_reply;
+ {handle_inform_response, {Addr, Port}} ->
+ ok
+ end.
+
+
+handle_report(TargetName, SnmpReport, UserPid) ->
+ UserPid ! {handle_report, self(), TargetName, SnmpReport},
+ ok.
+
+%% For backwards compatibillity
+handle_report(Addr, Port, SnmpReport, UserPid) ->
+ UserPid ! {handle_report, self(), Addr, Port, SnmpReport},
+ ok.
+
+
+%%----------------------------------------------------------------------
+%% Debug
+%%----------------------------------------------------------------------
+
+d(F) ->
+ d(F, []).
+
+d(F, A) ->
+ d(get(debug), F, A).
+
+d(true, F, A) ->
+ io:format("~w:" ++ F ++ "~n", [?SERVER|A]);
+d(_, _, _) ->
+ ok.
diff --git a/lib/snmp/test/snmp_manager_user_old.erl b/lib/snmp/test/snmp_manager_user_old.erl
new file mode 100755
index 0000000000..b53514d699
--- /dev/null
+++ b/lib/snmp/test/snmp_manager_user_old.erl
@@ -0,0 +1,264 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 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%
+%%
+
+%%----------------------------------------------------------------------
+%% Purpose: Utility functions for the (snmp manager) user test(s).
+%%----------------------------------------------------------------------
+
+-module(snmp_manager_user_old).
+
+-behaviour(snmpm_user_old).
+
+
+%%----------------------------------------------------------------------
+%% Include files
+%%----------------------------------------------------------------------
+-include("test_server.hrl").
+-include("snmp_test_lib.hrl").
+
+
+%%----------------------------------------------------------------------
+%% External exports
+%%----------------------------------------------------------------------
+-export([
+ start/0, start/1,
+ stop/0,
+ register_agent/1, register_agent/2, register_agent/3,
+ unregister_agent/1, unregister_agent/2,
+ agent_info/3,
+ update_agent_info/4,
+ which_agents/0, which_users/0,
+ load_mib/1, unload_mib/1,
+ sync_get/2, sync_get/3,
+ async_get/2, async_get/3,
+ sync_get_next/2, sync_get_next/3,
+ async_get_next/2, async_get_next/3,
+ sync_set/2, sync_set/3,
+ async_set/2, async_set/3,
+ sync_get_bulk/4, sync_get_bulk/5,
+ async_get_bulk/4, async_get_bulk/5,
+ name_to_oid/1, oid_to_name/1,
+ purify_oid/1
+ ]).
+
+-export([
+ handle_error/3,
+ handle_agent/4,
+ handle_pdu/5,
+ handle_trap/4,
+ handle_inform/4,
+ handle_report/4
+ ]).
+
+
+%%----------------------------------------------------------------------
+%% Internal exports
+%%----------------------------------------------------------------------
+
+%% -define(SERVER, ?MODULE).
+-define(USER_ID, ?MODULE).
+
+%% -record(state, {parent, id, reqs = []}).
+%% -record(request, {from, ref, tmr, req_id, type}).
+
+
+%%----------------------------------------------------------------------
+%% The user API
+%%----------------------------------------------------------------------
+
+start() ->
+ start([]).
+
+start(DefaultAgentConfig) when is_list(DefaultAgentConfig) ->
+ snmpm:register_user(?USER_ID, ?MODULE, self(), DefaultAgentConfig).
+
+stop() ->
+ snmpm:unregister_user(?USER_ID).
+
+register_agent(Addr) ->
+ snmpm:register_agent(?USER_ID, Addr).
+
+register_agent(Addr, PortOrConfig) ->
+ snmpm:register_agent(?USER_ID, Addr, PortOrConfig).
+
+register_agent(Addr, Port, Config) ->
+ snmpm:register_agent(?USER_ID, Addr, Port, Config).
+
+unregister_agent(Addr) ->
+ snmpm:unregister_agent(?USER_ID, Addr).
+
+unregister_agent(Addr, Port) ->
+ snmpm:unregister_agent(?USER_ID, Addr, Port).
+
+agent_info(Addr, Port, Item) ->
+ snmpm:agent_info(?USER_ID, Addr, Port, Item).
+
+update_agent_info(Addr, Port, Item, Val) ->
+ snmpm:update_agent_info(?USER_ID, Addr, Port, Item, Val).
+
+which_agents() ->
+ snmpm:which_agents().
+
+which_users() ->
+ snmpm:which_users().
+
+load_mib(Mib) ->
+ snmpm:load_mib(?USER_ID, Mib).
+
+unload_mib(Mib) ->
+ snmpm:unload_mib(?USER_ID, Mib).
+
+
+%% --
+
+sync_get(Addr, Oids) ->
+ snmpm:g(?USER_ID, Addr, Oids).
+
+sync_get(Addr, Port, Oids) ->
+ snmpm:g(?USER_ID, Addr, Port, Oids).
+
+
+%% --
+
+async_get(Addr, Oids) ->
+ snmpm:ag(?USER_ID, Addr, Oids).
+
+async_get(Addr, Port, Oids) ->
+ snmpm:ag(?USER_ID, Addr, Port, Oids).
+
+
+%% --
+
+sync_get_next(Addr, Oids) ->
+ snmpm:gn(?USER_ID, Addr, Oids).
+
+sync_get_next(Addr, Port, Oids) ->
+ snmpm:gn(?USER_ID, Addr, Port, Oids).
+
+
+%% --
+
+async_get_next(Addr, Oids) ->
+ snmpm:agn(?USER_ID, Addr, Oids).
+
+async_get_next(Addr, Port, Oids) ->
+ snmpm:agn(?USER_ID, Addr, Port, Oids).
+
+
+%% --
+
+sync_set(Addr, VAV) ->
+ snmpm:s(?USER_ID, Addr, VAV).
+
+sync_set(Addr, Port, VAV) ->
+ snmpm:s(?USER_ID, Addr, Port, VAV).
+
+
+%% --
+
+async_set(Addr, VAV) ->
+ snmpm:as(?USER_ID, Addr, VAV).
+
+async_set(Addr, Port, VAV) ->
+ snmpm:as(?USER_ID, Addr, Port, VAV).
+
+
+%% --
+
+sync_get_bulk(Addr, NonRep, MaxRep, Oids) ->
+ snmpm:gb(?USER_ID, Addr, NonRep, MaxRep, Oids).
+
+sync_get_bulk(Addr, Port, NonRep, MaxRep, Oids) ->
+ snmpm:gb(?USER_ID, Addr, Port, NonRep, MaxRep, Oids).
+
+
+%% --
+
+async_get_bulk(Addr, NonRep, MaxRep, Oids) ->
+ snmpm:agb(?USER_ID, Addr, NonRep, MaxRep, Oids).
+
+async_get_bulk(Addr, Port, NonRep, MaxRep, Oids) ->
+ snmpm:agb(?USER_ID, Addr, Port, NonRep, MaxRep, Oids).
+
+
+%% --
+
+name_to_oid(Name) ->
+ snmpm:name_to_oid(Name).
+
+oid_to_name(Oid) ->
+ snmpm:oid_to_name(Oid).
+
+purify_oid(Oid) ->
+ snmpm:purify_oid(Oid).
+
+
+%%----------------------------------------------------------------------
+%% User callback functions:
+%%----------------------------------------------------------------------
+
+handle_error(ReqId, Reason, UserPid) ->
+ UserPid ! {handle_error, self(), ReqId, Reason},
+ ignore.
+
+
+handle_agent(Addr, Port, SnmpInfo, UserPid) ->
+ UserPid ! {handle_agent, self(), Addr, Port, SnmpInfo},
+ ignore.
+
+
+handle_pdu(Addr, Port, ReqId, SnmpResponse, UserPid) ->
+ UserPid ! {handle_pdu, self(), Addr, Port, ReqId, SnmpResponse},
+ ignore.
+
+
+handle_trap(Addr, Port, SnmpTrap, UserPid) ->
+ UserPid ! {handle_trap, self(), Addr, Port, SnmpTrap},
+ ok.
+
+
+handle_inform(Addr, Port, SnmpInform, UserPid) ->
+ UserPid ! {handle_inform, self(), Addr, Port, SnmpInform},
+ receive
+ {handle_inform_no_response, {Addr, Port}} ->
+ no_reply;
+ {handle_inform_response, {Addr, Port}} ->
+ ok
+ end.
+
+
+handle_report(Addr, Port, SnmpReport, UserPid) ->
+ UserPid ! {handle_report, self(), Addr, Port, SnmpReport},
+ ok.
+
+
+%%----------------------------------------------------------------------
+%% Debug
+%%----------------------------------------------------------------------
+
+%% d(F) ->
+%% d(F, []).
+
+%% d(F, A) ->
+%% d(get(debug), F, A).
+
+%% d(true, F, A) ->
+%% io:format("~w:" ++ F ++ "~n", [?SERVER|A]);
+%% d(_, _, _) ->
+%% ok.
diff --git a/lib/snmp/test/snmp_manager_user_test.erl b/lib/snmp/test/snmp_manager_user_test.erl
new file mode 100644
index 0000000000..24ed3b0b73
--- /dev/null
+++ b/lib/snmp/test/snmp_manager_user_test.erl
@@ -0,0 +1,1244 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2004-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%
+%%
+
+%%----------------------------------------------------------------------
+%% Purpose: Various (snmp manager) user related tests
+%%----------------------------------------------------------------------
+-module(snmp_manager_user_test).
+
+
+%%----------------------------------------------------------------------
+%% Include files
+%%----------------------------------------------------------------------
+-include("test_server.hrl").
+-include("snmp_test_lib.hrl").
+
+
+%%----------------------------------------------------------------------
+%% External exports
+%%----------------------------------------------------------------------
+%% -compile(export_all).
+
+-export([
+ all/1,
+ init_per_testcase/2, fin_per_testcase/2,
+
+ register_user/1,
+ simple_register_and_unregister1/1,
+ simple_register_and_unregister2/1,
+ simple_register_and_unregister3/1,
+ register_and_crash1/1,
+ register_and_crash2/1,
+ register_and_crash3/1,
+ register_request_and_crash1/1,
+ register_request_and_crash2/1,
+ register_request_and_crash3/1,
+ simple_register_monitor_and_unregister1/1,
+ simple_register_monitor_and_unregister2/1,
+ simple_register_monitor_and_unregister3/1,
+ register_monitor_and_crash1/1,
+ register_monitor_and_crash2/1,
+ register_monitor_and_crash3/1,
+ register_monitor_and_crash4/1,
+ register_monitor_and_crash5/1,
+ register_monitor_request_and_crash1/1,
+ register_monitor_request_and_crash2/1,
+ register_monitor_request_and_crash3/1,
+ register_monitor_request_and_crash4/1,
+
+ tickets/1,
+ otp7902/1
+
+ ]).
+
+%%----------------------------------------------------------------------
+%% Internal exports
+%%----------------------------------------------------------------------
+-export([
+ ]).
+
+
+%%----------------------------------------------------------------------
+%% Macros
+%%----------------------------------------------------------------------
+
+
+%%----------------------------------------------------------------------
+%% Records
+%%----------------------------------------------------------------------
+
+
+%%======================================================================
+%% External functions
+%%======================================================================
+
+init_per_testcase(Case, Config) when is_list(Config) ->
+ p("init_per_testcase -> Case: ~p", [Case]),
+ SnmpPrivDir = ?config(priv_dir, Config),
+ p("init_per_testcase -> SnmpPrivDir: ~p", [SnmpPrivDir]),
+ SuiteDir = atom_to_list(?MODULE),
+ SuiteTopDir = filename:join(SnmpPrivDir, SuiteDir),
+ case file:make_dir(SuiteTopDir) of
+ ok ->
+ ok;
+ {error, eexist} ->
+ ok;
+ {error, Reason} ->
+ ?FAIL({failed_creating, SuiteTopDir, Reason})
+ end,
+ p("init_per_testcase -> SuiteTopDir: ~p", [SuiteTopDir]),
+ CaseDir = atom_to_list(Case),
+ ?line ok =
+ file:make_dir(CaseTopDir = filename:join(SuiteTopDir, CaseDir)),
+ p("init_per_testcase -> CaseTopDir: ~p", [CaseTopDir]),
+ ?line ok =
+ file:make_dir(MgrTopDir = filename:join(CaseTopDir, "manager/")),
+ ?line ok =
+ file:make_dir(MgrConfDir = filename:join(MgrTopDir, "conf/")),
+ ?line ok =
+ file:make_dir(MgrDbDir = filename:join(MgrTopDir, "db/")),
+ ?line ok =
+ file:make_dir(MgrLogDir = filename:join(MgrTopDir, "log/")),
+ [{suite_top_dir, SuiteTopDir},
+ {case_top_dir, CaseTopDir},
+ {manager_dir, MgrTopDir},
+ {manager_conf_dir, MgrConfDir},
+ {manager_db_dir, MgrDbDir},
+ {manager_log_dir, MgrLogDir} | Config].
+
+
+fin_per_testcase(Case, Config) when is_list(Config) ->
+ p("fin_per_testcase -> Case: ~p", [Case]),
+% MgrTopDir = ?config(manager_dir, Config),
+% ?DEL_DIR(MgrTopDir),
+ Config.
+
+
+%%======================================================================
+%% Test case definitions
+%%======================================================================
+
+all(suite) ->
+ [
+ register_user,
+ tickets
+ ].
+
+register_user(suite) ->
+ [
+ simple_register_and_unregister1,
+ simple_register_and_unregister2,
+ simple_register_and_unregister3,
+ register_and_crash1,
+ register_and_crash2,
+ register_and_crash3,
+ register_request_and_crash1,
+ register_request_and_crash2,
+ register_request_and_crash3,
+ simple_register_monitor_and_unregister1,
+ simple_register_monitor_and_unregister2,
+ simple_register_monitor_and_unregister3,
+ register_monitor_and_crash1,
+ register_monitor_and_crash2,
+ register_monitor_and_crash3,
+ register_monitor_and_crash4,
+ register_monitor_and_crash5,
+ register_monitor_request_and_crash1,
+ register_monitor_request_and_crash2,
+ register_monitor_request_and_crash3,
+ register_monitor_request_and_crash4
+ ].
+
+
+tickets(suite) ->
+ [
+ otp7902
+ ].
+
+
+%%======================================================================
+%% Test functions
+%%======================================================================
+
+simple_register_and_unregister1(suite) -> [];
+simple_register_and_unregister1(doc) ->
+ "Start a user, register and unregister the user.";
+simple_register_and_unregister1(Conf) when is_list(Conf) ->
+ put(tname,srar1),
+ p("start"),
+ process_flag(trap_exit, true),
+
+ ConfDir = ?config(manager_conf_dir, Conf),
+ DbDir = ?config(manager_db_dir, Conf),
+
+ write_manager_conf(ConfDir),
+
+ Opts = [{server, [{verbosity, trace}]},
+ {net_if, [{verbosity, trace}]},
+ {note_store, [{verbosity, trace}]},
+ {config, [{verbosity, trace}, {dir, ConfDir}, {db_dir, DbDir}]}],
+
+ p("try starting manager"),
+ ok = snmpm:start_link(Opts),
+
+ ?SLEEP(1000),
+
+ Id = make_ref(),
+
+ ?line Pid = start_user(),
+
+ ?line [] = Users1 = which_users(),
+ p("Users1: ~p", [Users1]),
+
+ ?line ok = register_user(Pid, Id),
+
+ ?line [Id] = Users2 = which_users(),
+ p("Users2: ~p", [Users2]),
+
+ ?line ok = unregister_user(Pid),
+
+ ?line [] = Users3 = which_users(),
+ p("Users3: ~p", [Users3]),
+
+ ?line stop_user(Pid),
+
+ ?line ok = snmpm:stop(),
+
+ p("end"),
+ ok.
+
+
+%% ------------------------------------------------------------------
+
+simple_register_and_unregister2(suite) -> [];
+simple_register_and_unregister2(doc) ->
+ "Start a single user process, "
+ "register 2 users (per that process) and unregister the 2 users.";
+simple_register_and_unregister2(Conf) when is_list(Conf) ->
+ put(tname,srar2),
+ p("start"),
+ process_flag(trap_exit, true),
+
+ ConfDir = ?config(manager_conf_dir, Conf),
+ DbDir = ?config(manager_db_dir, Conf),
+
+ write_manager_conf(ConfDir),
+
+ Opts = [{server, [{verbosity, trace}]},
+ {net_if, [{verbosity, trace}]},
+ {note_store, [{verbosity, trace}]},
+ {config, [{verbosity, trace}, {dir, ConfDir}, {db_dir, DbDir}]}],
+
+ p("try starting manager"),
+ ok = snmpm:start_link(Opts),
+
+ ?SLEEP(1000),
+
+ Id1 = make_ref(),
+ Id2 = make_ref(),
+
+ ?line Pid = start_user(),
+
+ ?line [] = Users1 = which_users(),
+ p("Users1: ~p", [Users1]),
+
+ ?line ok = register_user(Pid, Id1),
+ ?line ok = register_user(Pid, Id2),
+
+ ?line Users2 = case which_users() of
+ [Id1, Id2] = U1 ->
+ U1;
+ [Id2, Id1] = U2 ->
+ U2;
+ Else ->
+ ?FAIL({invalid_users, Else})
+ end,
+ p("Users2: ~p", [Users2]),
+
+
+ ?line ok = unregister_user(Pid, Id1),
+ ?line ok = unregister_user(Pid, Id2),
+
+ ?line [] = Users3 = which_users(),
+ p("Users3: ~p", [Users3]),
+
+ ?line stop_user(Pid),
+
+ ?line ok = snmpm:stop(),
+
+ p("end"),
+ ok.
+
+
+%% ------------------------------------------------------------------
+
+simple_register_and_unregister3(suite) -> [];
+simple_register_and_unregister3(doc) ->
+ "Start 2 user processes, "
+ "register one users per process and unregister the 2 users.";
+simple_register_and_unregister3(Conf) when is_list(Conf) ->
+ put(tname,srar2),
+ p("start"),
+ process_flag(trap_exit, true),
+
+ ConfDir = ?config(manager_conf_dir, Conf),
+ DbDir = ?config(manager_db_dir, Conf),
+
+ write_manager_conf(ConfDir),
+
+ Opts = [{server, [{verbosity, trace}]},
+ {net_if, [{verbosity, trace}]},
+ {note_store, [{verbosity, trace}]},
+ {config, [{verbosity, trace}, {dir, ConfDir}, {db_dir, DbDir}]}],
+
+ p("try starting manager"),
+ ok = snmpm:start_link(Opts),
+
+ ?SLEEP(1000),
+
+ Id1 = make_ref(),
+ Id2 = make_ref(),
+
+ ?line Pid1 = start_user(),
+ ?line Pid2 = start_user(),
+
+ ?line [] = Users1 = which_users(),
+ p("Users1: ~p", [Users1]),
+
+ ?line ok = register_user(Pid1, Id1),
+ ?line ok = register_user(Pid2, Id2),
+
+ ?line Users2 = case which_users() of
+ [Id1, Id2] = U1 ->
+ U1;
+ [Id2, Id1] = U2 ->
+ U2;
+ Else ->
+ ?FAIL({invalid_users, Else})
+ end,
+ p("Users2: ~p", [Users2]),
+
+
+ ?line ok = unregister_user(Pid1, Id1),
+ ?line ok = unregister_user(Pid2, Id2),
+
+ ?line [] = Users3 = which_users(),
+ p("Users3: ~p", [Users3]),
+
+ ?line stop_user(Pid1),
+ ?line stop_user(Pid2),
+
+ ?line ok = snmpm:stop(),
+
+ p("end"),
+ ok.
+
+
+%% ------------------------------------------------------------------
+
+register_and_crash1(suite) -> [];
+register_and_crash1(doc) ->
+ "Start a user, register and crash user.";
+register_and_crash1(Conf) when is_list(Conf) ->
+ put(tname,racau1),
+ p("start"),
+ process_flag(trap_exit, true),
+
+ ConfDir = ?config(manager_conf_dir, Conf),
+ DbDir = ?config(manager_db_dir, Conf),
+
+ write_manager_conf(ConfDir),
+
+ Opts = [{server, [{verbosity, trace}]},
+ {net_if, [{verbosity, trace}]},
+ {note_store, [{verbosity, trace}]},
+ {config, [{verbosity, trace}, {dir, ConfDir}, {db_dir, DbDir}]}],
+
+ p("try starting manager"),
+ ?line ok = snmpm:start_link(Opts),
+
+ ?SLEEP(1000),
+
+ Id = make_ref(),
+
+ ?line Pid = start_user(),
+
+ ?line [] = Users1 = which_users(),
+ p("Users1: ~p", [Users1]),
+
+ ?line ok = register_user(Pid, Id),
+
+ ?line [Id] = Users2 = which_users(),
+ p("Users2: ~p", [Users2]),
+
+ ?line ok = simulate_crash(Pid),
+
+ ?line [Id] = Users3 = which_users(),
+ p("Users3: ~p", [Users3]),
+
+ p("stop manager"),
+ ?line ok = snmpm:stop(),
+
+ p("end"),
+ ok.
+
+
+%% ------------------------------------------------------------------
+
+register_and_crash2(suite) -> [];
+register_and_crash2(doc) ->
+ "Start a single user process, "
+ "register 2 users (per that process) and crash the process.";
+register_and_crash2(Conf) when is_list(Conf) ->
+ put(tname,racau2),
+ p("start"),
+ process_flag(trap_exit, true),
+
+ ConfDir = ?config(manager_conf_dir, Conf),
+ DbDir = ?config(manager_db_dir, Conf),
+
+ write_manager_conf(ConfDir),
+
+ Opts = [{server, [{verbosity, trace}]},
+ {net_if, [{verbosity, trace}]},
+ {note_store, [{verbosity, trace}]},
+ {config, [{verbosity, trace}, {dir, ConfDir}, {db_dir, DbDir}]}],
+
+ p("try starting manager"),
+ ?line ok = snmpm:start_link(Opts),
+
+ ?SLEEP(1000),
+
+ Id1 = make_ref(),
+ Id2 = make_ref(),
+
+ ?line Pid = start_user(),
+
+ ?line [] = Users1 = which_users(),
+ p("Users1: ~p", [Users1]),
+
+ ?line ok = register_user(Pid, Id1),
+ ?line ok = register_user(Pid, Id2),
+
+ ?line Users2 = case which_users() of
+ [Id1, Id2] = U1 ->
+ U1;
+ [Id2, Id1] = U2 ->
+ U2;
+ Else1 ->
+ ?FAIL({invalid_users, Else1})
+ end,
+ p("Users2: ~p", [Users2]),
+
+ ?line ok = simulate_crash(Pid),
+
+ ?line Users3 = case which_users() of
+ [Id1, Id2] = U3 ->
+ U3;
+ [Id2, Id1] = U4 ->
+ U4;
+ Else2 ->
+ ?FAIL({invalid_users, Else2})
+ end,
+ p("Users3: ~p", [Users3]),
+
+ p("stop manager"),
+ ?line ok = snmpm:stop(),
+
+ p("end"),
+ ok.
+
+
+%% ------------------------------------------------------------------
+
+register_and_crash3(suite) -> [];
+register_and_crash3(doc) ->
+ "Start 2 user processes, "
+ "register one user per process and "
+ "crash the first user process.";
+register_and_crash3(Conf) when is_list(Conf) ->
+ %% put(tname,rac3),
+ %% p("start"),
+ %% process_flag(trap_exit, true),
+ ?SKIP(not_yet_implemented).
+
+
+%% ------------------------------------------------------------------
+
+register_request_and_crash1(suite) -> [];
+register_request_and_crash1(doc) ->
+ "Start a single user process, "
+ "register user, send request and crash user.";
+register_request_and_crash1(Conf) when is_list(Conf) ->
+ %% put(tname,rrac1),
+ %% p("start"),
+ %% process_flag(trap_exit, true),
+ ?SKIP(not_yet_implemented).
+
+
+%% ------------------------------------------------------------------
+
+register_request_and_crash2(suite) -> [];
+register_request_and_crash2(doc) ->
+ "Start a single user process, "
+ "register 2 users (per that single user process), "
+ "send a request for each user and crash the single user process.";
+register_request_and_crash2(Conf) when is_list(Conf) ->
+ %% put(tname,rrac2),
+ %% p("start"),
+ %% process_flag(trap_exit, true),
+ ?SKIP(not_yet_implemented).
+
+
+%% ------------------------------------------------------------------
+
+register_request_and_crash3(suite) -> [];
+register_request_and_crash3(doc) ->
+ "Start 2 user processes, "
+ "register one user per process, "
+ "send a request for each user and crash the first user process.";
+register_request_and_crash3(Conf) when is_list(Conf) ->
+ %% put(tname,rrac3),
+ %% p("start"),
+ %% process_flag(trap_exit, true),
+ ?SKIP(not_yet_implemented).
+
+
+%% ------------------------------------------------------------------
+
+simple_register_monitor_and_unregister1(suite) -> [];
+simple_register_monitor_and_unregister1(doc) ->
+ "Start a user, register-link and unregister the user.";
+simple_register_monitor_and_unregister1(Conf) when is_list(Conf) ->
+ put(tname,srlau1),
+ p("start"),
+ process_flag(trap_exit, true),
+
+ ConfDir = ?config(manager_conf_dir, Conf),
+ DbDir = ?config(manager_db_dir, Conf),
+
+ write_manager_conf(ConfDir),
+
+ Opts = [{server, [{verbosity, trace}]},
+ {net_if, [{verbosity, trace}]},
+ {note_store, [{verbosity, trace}]},
+ {config, [{verbosity, trace}, {dir, ConfDir}, {db_dir, DbDir}]}],
+
+ p("try starting manager"),
+ ok = snmpm:start_link(Opts),
+
+ ?SLEEP(1000),
+
+ Id = make_ref(),
+
+ p("start user"),
+ ?line Pid = start_user(),
+
+ p("get users (=0)"),
+ ?line [] = Users1 = which_users(),
+ p("Users1: ~p", [Users1]),
+
+ p("register monitored user"),
+ ?line ok = register_user_monitor(Pid, Id),
+
+ p("get users (=1)"),
+ ?line [Id] = Users2 = which_users(),
+ p("Users2: ~p", [Users2]),
+
+ p("unregister monitored user"),
+ ?line unregister_user(Pid),
+
+ p("get users (=0)"),
+ ?line [] = Users3 = which_users(),
+ p("Users3: ~p", [Users3]),
+
+ p("start user"),
+ ?line stop_user(Pid),
+
+ p("stop manager"),
+ ?line ok = snmpm:stop(),
+
+ p("end"),
+ ok.
+
+
+%% ------------------------------------------------------------------
+
+simple_register_monitor_and_unregister2(suite) -> [];
+simple_register_monitor_and_unregister2(doc) ->
+ "Start a single user process, "
+ "register-link 2 users (per that process) and "
+ "unregister the 2 users.";
+simple_register_monitor_and_unregister2(Conf) when is_list(Conf) ->
+ put(tname,srlau2),
+ p("start"),
+ process_flag(trap_exit, true),
+
+ ConfDir = ?config(manager_conf_dir, Conf),
+ DbDir = ?config(manager_db_dir, Conf),
+
+ write_manager_conf(ConfDir),
+
+ Opts = [{server, [{verbosity, trace}]},
+ {net_if, [{verbosity, trace}]},
+ {note_store, [{verbosity, trace}]},
+ {config, [{verbosity, trace}, {dir, ConfDir}, {db_dir, DbDir}]}],
+
+ p("try starting manager"),
+ ok = snmpm:start_link(Opts),
+
+ ?SLEEP(1000),
+
+ Id1 = make_ref(),
+ Id2 = make_ref(),
+
+ ?line Pid = start_user(),
+
+ ?line [] = Users1 = which_users(),
+ p("Users1: ~p", [Users1]),
+
+ ?line ok = register_user_monitor(Pid, Id1),
+ ?line ok = register_user_monitor(Pid, Id2),
+
+ ?line Users2 = case which_users() of
+ [Id1, Id2] = U1 ->
+ U1;
+ [Id2, Id1] = U2 ->
+ U2;
+ Else ->
+ ?FAIL({invalid_users, Else})
+ end,
+ p("Users2: ~p", [Users2]),
+
+ ?line ok = unregister_user(Pid, Id1),
+ ?line ok = unregister_user(Pid, Id2),
+
+ ?line [] = Users3 = which_users(),
+ p("Users3: ~p", [Users3]),
+
+ ?line stop_user(Pid),
+
+ ?line ok = snmpm:stop(),
+
+ p("end"),
+ ok.
+
+
+%% ------------------------------------------------------------------
+
+simple_register_monitor_and_unregister3(suite) -> [];
+simple_register_monitor_and_unregister3(doc) ->
+ "Start a single user process, "
+ "register one user and register-monitor one user "
+ "(per that process) and "
+ "unregister the 2 users.";
+simple_register_monitor_and_unregister3(Conf) when is_list(Conf) ->
+ put(tname,srlau3),
+ p("start"),
+ process_flag(trap_exit, true),
+
+ ConfDir = ?config(manager_conf_dir, Conf),
+ DbDir = ?config(manager_db_dir, Conf),
+
+ write_manager_conf(ConfDir),
+
+ Opts = [{server, [{verbosity, trace}]},
+ {net_if, [{verbosity, trace}]},
+ {note_store, [{verbosity, trace}]},
+ {config, [{verbosity, trace}, {dir, ConfDir}, {db_dir, DbDir}]}],
+
+ p("try starting manager"),
+ ok = snmpm:start_link(Opts),
+
+ ?SLEEP(1000),
+
+ Id1 = make_ref(),
+ Id2 = make_ref(),
+
+ ?line Pid = start_user(),
+
+ ?line [] = Users1 = which_users(),
+ p("Users1: ~p", [Users1]),
+
+ ?line ok = register_user(Pid, Id1),
+ ?line ok = register_user_monitor(Pid, Id2),
+
+ ?line Users2 = case which_users() of
+ [Id1, Id2] = U1 ->
+ U1;
+ [Id2, Id1] = U2 ->
+ U2;
+ Else ->
+ ?FAIL({invalid_users, Else})
+ end,
+ p("Users2: ~p", [Users2]),
+
+ ?line unregister_user(Pid),
+
+ ?line [] = Users3 = which_users(),
+ p("Users3: ~p", [Users3]),
+
+ ?line stop_user(Pid),
+
+ ?line ok = snmpm:stop(),
+
+ p("end"),
+ ok.
+
+
+%% ------------------------------------------------------------------
+
+register_monitor_and_crash1(suite) -> [];
+register_monitor_and_crash1(doc) ->
+ "Start a user, register-monitor and crash the user.";
+register_monitor_and_crash1(Conf) when is_list(Conf) ->
+ put(tname,rlac1),
+ p("start"),
+ process_flag(trap_exit, true),
+
+ ConfDir = ?config(manager_conf_dir, Conf),
+ DbDir = ?config(manager_db_dir, Conf),
+
+ write_manager_conf(ConfDir),
+
+ Opts = [{server, [{verbosity, trace}]},
+ {net_if, [{verbosity, trace}]},
+ {note_store, [{verbosity, trace}]},
+ {config, [{verbosity, trace}, {dir, ConfDir}, {db_dir, DbDir}]}],
+
+ p("try starting manager"),
+ ?line ok = snmpm:start_link(Opts),
+
+ ?SLEEP(1000),
+
+ Id = make_ref(),
+
+ ?line Pid = start_user(),
+
+ ?line [] = Users1 = which_users(),
+ p("Users1: ~p", [Users1]),
+
+ ?line ok = register_user_monitor(Pid, Id),
+
+ ?line [Id] = Users2 = which_users(),
+ p("Users2: ~p", [Users2]),
+
+ ?line ok = simulate_crash(Pid),
+
+ ?SLEEP(1000),
+
+ ?line [] = Users3 = which_users(),
+ p("Users3: ~p", [Users3]),
+
+ p("stop manager"),
+ ?line ok = snmpm:stop(),
+
+ p("end"),
+ ok.
+
+
+%% ------------------------------------------------------------------
+
+register_monitor_and_crash2(suite) -> [];
+register_monitor_and_crash2(doc) ->
+ "Start a single user process, "
+ "register-monitor 2 users (per that process) "
+ "and crash the single user process.";
+register_monitor_and_crash2(Conf) when is_list(Conf) ->
+ put(tname,rlac2),
+ p("start"),
+ process_flag(trap_exit, true),
+
+ ConfDir = ?config(manager_conf_dir, Conf),
+ DbDir = ?config(manager_db_dir, Conf),
+
+ write_manager_conf(ConfDir),
+
+ Opts = [{server, [{verbosity, trace}]},
+ {net_if, [{verbosity, trace}]},
+ {note_store, [{verbosity, trace}]},
+ {config, [{verbosity, trace}, {dir, ConfDir}, {db_dir, DbDir}]}],
+
+ p("try starting manager"),
+ ?line ok = snmpm:start_link(Opts),
+
+ ?SLEEP(1000),
+
+ Id1 = make_ref(),
+ Id2 = make_ref(),
+
+ ?line Pid = start_user(),
+
+ ?line [] = Users1 = which_users(),
+ p("Users1: ~p", [Users1]),
+
+ ?line ok = register_user_monitor(Pid, Id1),
+ ?line ok = register_user_monitor(Pid, Id2),
+
+ ?line Users2 = case which_users() of
+ [Id1, Id2] = U1 ->
+ U1;
+ [Id2, Id1] = U2 ->
+ U2;
+ Else ->
+ ?FAIL({invalid_users, Else})
+ end,
+ p("Users2: ~p", [Users2]),
+
+ ?line ok = simulate_crash(Pid),
+
+ ?SLEEP(1000),
+
+ ?line [] = Users3 = which_users(),
+ p("Users3: ~p", [Users3]),
+
+ p("stop manager"),
+ ?line ok = snmpm:stop(),
+
+ p("end"),
+ ok.
+
+
+%% ------------------------------------------------------------------
+
+register_monitor_and_crash3(suite) -> [];
+register_monitor_and_crash3(doc) ->
+ "Start a single user process, "
+ "register-monitor one user and register one user, "
+ "crash the single user process.";
+register_monitor_and_crash3(Conf) when is_list(Conf) ->
+ put(tname,rlac3),
+ p("start"),
+ process_flag(trap_exit, true),
+
+ ConfDir = ?config(manager_conf_dir, Conf),
+ DbDir = ?config(manager_db_dir, Conf),
+
+ write_manager_conf(ConfDir),
+
+ Opts = [{server, [{verbosity, trace}]},
+ {net_if, [{verbosity, trace}]},
+ {note_store, [{verbosity, trace}]},
+ {config, [{verbosity, trace}, {dir, ConfDir}, {db_dir, DbDir}]}],
+
+ p("try starting manager"),
+ ?line ok = snmpm:start_link(Opts),
+
+ ?SLEEP(1000),
+
+ Id1 = make_ref(),
+ Id2 = make_ref(),
+
+ ?line Pid = start_user(),
+
+ ?line [] = Users1 = which_users(),
+ p("Users1: ~p", [Users1]),
+
+ ?line ok = register_user(Pid, Id1),
+ ?line ok = register_user_monitor(Pid, Id2),
+
+ ?line Users2 = case which_users() of
+ [Id1, Id2] = U1 ->
+ U1;
+ [Id2, Id1] = U2 ->
+ U2;
+ Else ->
+ ?FAIL({invalid_users, Else})
+ end,
+ p("Users2: ~p", [Users2]),
+
+ ?line ok = simulate_crash(Pid),
+
+ ?SLEEP(1000),
+
+ ?line [Id1] = Users3 = which_users(),
+ p("Users3: ~p", [Users3]),
+
+ p("stop manager"),
+ ?line ok = snmpm:stop(),
+
+ p("end"),
+ ok.
+
+
+%% ------------------------------------------------------------------
+
+register_monitor_and_crash4(suite) -> [];
+register_monitor_and_crash4(doc) ->
+ "Start 2 user processes, "
+ "register-monitor one user per process "
+ "and crash the first user process.";
+register_monitor_and_crash4(Conf) when is_list(Conf) ->
+ put(tname,rlac4),
+ p("start"),
+ process_flag(trap_exit, true),
+
+ ConfDir = ?config(manager_conf_dir, Conf),
+ DbDir = ?config(manager_db_dir, Conf),
+
+ write_manager_conf(ConfDir),
+
+ Opts = [{server, [{verbosity, trace}]},
+ {net_if, [{verbosity, trace}]},
+ {note_store, [{verbosity, trace}]},
+ {config, [{verbosity, trace}, {dir, ConfDir}, {db_dir, DbDir}]}],
+
+ p("start manager"),
+ ?line ok = snmpm:start_link(Opts),
+
+ ?SLEEP(1000),
+
+ Id1 = make_ref(),
+ Id2 = make_ref(),
+
+ p("start user processes"),
+ ?line Pid1 = start_user(),
+ ?line Pid2 = start_user(),
+
+ ?line [] = Users1 = which_users(),
+ p("Users1: ~p", [Users1]),
+
+ ?line ok = register_user_monitor(Pid1, Id1),
+ ?line ok = register_user_monitor(Pid2, Id2),
+
+ ?line Users2 = case which_users() of
+ [Id1, Id2] = U1 ->
+ U1;
+ [Id2, Id1] = U2 ->
+ U2;
+ Else ->
+ ?FAIL({invalid_users, Else})
+ end,
+ p("Users2: ~p", [Users2]),
+
+ ?line ok = simulate_crash(Pid1),
+
+ ?SLEEP(1000),
+
+ ?line [Id2] = Users3 = which_users(),
+ p("Users3: ~p", [Users3]),
+
+ ?line stop_user(Pid2),
+
+ p("stop manager"),
+ ?line ok = snmpm:stop(),
+
+ p("end"),
+ ok.
+
+
+%% ------------------------------------------------------------------
+
+register_monitor_and_crash5(suite) -> [];
+register_monitor_and_crash5(doc) ->
+ "OTP-7961: "
+ "Start 2 user processes, "
+ "register-monitor a user for per process, "
+ "let each user register an agent "
+ "and crash the first user process.";
+register_monitor_and_crash5(Conf) when is_list(Conf) ->
+ put(tname,rlac4),
+ p("start"),
+ process_flag(trap_exit, true),
+
+ ConfDir = ?config(manager_conf_dir, Conf),
+ DbDir = ?config(manager_db_dir, Conf),
+
+ write_manager_conf(ConfDir),
+
+ Opts = [{server, [{verbosity, trace}]},
+ {net_if, [{verbosity, trace}]},
+ {note_store, [{verbosity, trace}]},
+ {config, [{verbosity, trace}, {dir, ConfDir}, {db_dir, DbDir}]}],
+
+ p("start manager"),
+ ?line ok = snmpm:start_link(Opts),
+
+ ?SLEEP(1000),
+
+ Id1 = gurka, %% make_ref(),
+ Id2 = tomat, %% make_ref(),
+
+ p("start user processes"),
+ ?line Pid1 = start_user(),
+ ?line Pid2 = start_user(),
+
+ ?line [] = Users1 = which_users(),
+ p("Users1: ~p", [Users1]),
+
+ ?line ok = register_user_monitor(Pid1, Id1),
+ ?line ok = register_user_monitor(Pid2, Id2),
+
+ LocalHost = snmp_test_lib:localhost(),
+
+ TargetName1 = "kalle1",
+ Address1 = LocalHost,
+ Port1 = 5001,
+ EngineId1 = "agentEngineId-1",
+
+ TargetName2 = "kalle2",
+ Address2 = LocalHost,
+ Port2 = 5002,
+ EngineId2 = "agentEngineId-2",
+
+ ?line ok = register_agent(Pid1,
+ Id1, TargetName1, [{address, Address1},
+ {port, Port1},
+ {engine_id, EngineId1}]),
+ ?line ok = register_agent(Pid2,
+ Id2, TargetName2, [{address, Address2},
+ {port, Port2},
+ {engine_id, EngineId2}]),
+
+ ?line Users2 = case which_users() of
+ [Id1, Id2] = U1 ->
+ U1;
+ [Id2, Id1] = U2 ->
+ U2;
+ U3 ->
+ ?FAIL({invalid_users, U3})
+ end,
+ p("Users2: ~p", [Users2]),
+
+ p("verify all agent(s): expect 2"),
+ ?line Agents1 = case which_agents() of
+ [TargetName1, TargetName2] = A1 ->
+ A1;
+ [TargetName2, TargetName1] = A2 ->
+ A2;
+ A3 ->
+ ?FAIL({invalid_agents, A3})
+ end,
+ p("Agents1: ~p", [Agents1]),
+
+ ?line ok = simulate_crash(Pid1),
+
+ p("wait some time"),
+ ?SLEEP(1000),
+
+ ?line [Id2] = Users3 = which_users(),
+ p("Users3: ~p", [Users3]),
+
+ ?line [TargetName2] = Agents2 = which_agents(),
+ p("Agents2: ~p", [Agents2]),
+
+ ?line stop_user(Pid2),
+
+ p("stop manager"),
+ ?line ok = snmpm:stop(),
+
+ p("end"),
+ ok.
+
+
+%% ------------------------------------------------------------------
+
+register_monitor_request_and_crash1(suite) -> [];
+register_monitor_request_and_crash1(doc) ->
+ "Start a single user process, "
+ "register-monitor one user, "
+ "send request and crash the user.";
+register_monitor_request_and_crash1(Conf) when is_list(Conf) ->
+ %% put(tname,rlrac1),
+ %% p("start"),
+ %% process_flag(trap_exit, true),
+ ?SKIP(not_yet_implemented).
+
+
+%% ------------------------------------------------------------------
+
+register_monitor_request_and_crash2(suite) -> [];
+register_monitor_request_and_crash2(doc) ->
+ "Start a single user process, "
+ "register-monitor 2 user (per that one process), "
+ "send a request for each user and crash the single user process.";
+register_monitor_request_and_crash2(Conf) when is_list(Conf) ->
+ %% put(tname,rlrac2),
+ %% p("start"),
+ %% process_flag(trap_exit, true),
+ ?SKIP(not_yet_implemented).
+
+
+%% ------------------------------------------------------------------
+
+register_monitor_request_and_crash3(suite) -> [];
+register_monitor_request_and_crash3(doc) ->
+ "Start a single user process, "
+ "register-monitor one user and register one user, "
+ "send a request for each user and crash the single user process.";
+register_monitor_request_and_crash3(Conf) when is_list(Conf) ->
+ %% put(tname,rlrac3),
+ %% p("start"),
+ %% process_flag(trap_exit, true),
+ ?SKIP(not_yet_implemented).
+
+
+%% ------------------------------------------------------------------
+
+register_monitor_request_and_crash4(suite) -> [];
+register_monitor_request_and_crash4(doc) ->
+ "Start 2 user processes, "
+ "register-monitor one user and register one user on the "
+ "first user process and do the same for the other user process, "
+ "then for each user, send a request and "
+ "crash the first user process.";
+register_monitor_request_and_crash4(Conf) when is_list(Conf) ->
+ %% put(tname,rlrac4),
+ %% p("start"),
+ %% process_flag(trap_exit, true),
+ ?SKIP(not_yet_implemented).
+
+
+
+%% ------------------------------------------------------------------
+
+otp7902(suite) -> [];
+otp7902(doc) ->
+ "OTP-7902 - Start old user and make sure it wors.";
+otp7902(Conf) when is_list(Conf) ->
+ put(tname, otp7902),
+ p("start"),
+ process_flag(trap_exit, true),
+
+ ConfDir = ?config(manager_conf_dir, Conf),
+ DbDir = ?config(manager_db_dir, Conf),
+
+ write_manager_conf(ConfDir),
+
+ Opts = [{server, [{verbosity, trace}]},
+ {net_if, [{verbosity, trace}]},
+ {note_store, [{verbosity, trace}]},
+ {config, [{verbosity, trace}, {dir, ConfDir}, {db_dir, DbDir}]}],
+
+ p("try starting manager"),
+ ok = snmpm:start_link(Opts),
+
+ ?SLEEP(1000),
+
+ ?line [] = Users1 = which_users(),
+ p("Users1: ~p", [Users1]),
+
+ ?line ok = snmp_manager_user_old:start(),
+
+ ?line [_] = Users2 = which_users(),
+ p("Users2: ~p", [Users2]),
+
+ ?line ok = snmp_manager_user_old:stop(),
+
+ ?line [] = Users3 = which_users(),
+ p("Users3: ~p", [Users3]),
+
+ ?line ok = snmpm:stop(),
+
+ p("end"),
+ ok.
+
+
+%% ------------------------------------------------------------------
+
+start_user() ->
+ {ok, Pid} = snmp_manager_user_test_lib:start_link(),
+ Pid.
+
+stop_user(Pid) ->
+ snmp_manager_user_test_lib:stop(Pid).
+
+simulate_crash(Pid) ->
+ snmp_manager_user_test_lib:simulate_crash(Pid, simulate_crash),
+ receive
+ {'EXIT', Pid, simulate_crash} ->
+ ok;
+ {'EXIT', Pid, Whatever} ->
+ {ok, Whatever}
+ after 5000 ->
+ {error, timeout}
+ end.
+
+register_user(Pid, Id) ->
+ snmp_manager_user_test_lib:register(Pid, Id).
+
+register_user_monitor(Pid, Id) ->
+ snmp_manager_user_test_lib:register_monitor(Pid, Id).
+
+unregister_user(Pid) ->
+ case snmp_manager_user_test_lib:unregister(Pid) of
+ {ok, Res} ->
+ case [R || R <- Res, R =/= ok] of
+ [] ->
+ ok;
+ Errs ->
+ {error, Errs}
+ end;
+ Error ->
+ Error
+ end.
+
+unregister_user(Pid, Id) ->
+ snmp_manager_user_test_lib:unregister(Pid, Id).
+
+
+register_agent(Pid, Id, TargetName, Config) ->
+ snmp_manager_user_test_lib:register_agent(Pid, Id, TargetName, Config).
+
+
+%% ------
+
+which_users() ->
+ snmpm:which_users().
+
+which_agents() ->
+ snmpm:which_agents().
+
+
+%% ------
+
+
+write_manager_conf(Dir) ->
+ Port = "5000",
+ MMS = "484",
+ EngineID = "\"mgrEngine\"",
+ Str = lists:flatten(
+ io_lib:format("%% Minimum manager config file\n"
+ "{port, ~s}.\n"
+ "{max_message_size, ~s}.\n"
+ "{engine_id, ~s}.\n",
+ [Port, MMS, EngineID])),
+ write_manager_conf(Dir, Str).
+
+write_manager_conf(Dir, Str) ->
+ write_conf_file(Dir, "manager.conf", Str).
+
+
+write_conf_file(Dir, File, Str) ->
+ ?line {ok, Fd} = file:open(filename:join(Dir, File), write),
+ ?line ok = io:format(Fd, "~s", [Str]),
+ file:close(Fd).
+
+
+%% ------
+
+p(F) ->
+ p(F, []).
+
+p(F, A) ->
+ p(get(tname), F, A).
+
+p(TName, F, A) ->
+ io:format("~w -> " ++ F ++ "~n", [TName|A]).
+
diff --git a/lib/snmp/test/snmp_manager_user_test_lib.erl b/lib/snmp/test/snmp_manager_user_test_lib.erl
new file mode 100644
index 0000000000..a49fe93178
--- /dev/null
+++ b/lib/snmp/test/snmp_manager_user_test_lib.erl
@@ -0,0 +1,422 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2004-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%
+%%
+
+%%----------------------------------------------------------------------
+%% Purpose: Utility functions for the (snmp manager) user test(s).
+%%----------------------------------------------------------------------
+
+-module(snmp_manager_user_test_lib).
+
+-behaviour(snmpm_user).
+
+
+%%----------------------------------------------------------------------
+%% Include files
+%%----------------------------------------------------------------------
+-include("test_server.hrl").
+-include("snmp_test_lib.hrl").
+
+
+%%----------------------------------------------------------------------
+%% External exports
+%%----------------------------------------------------------------------
+-export([
+ start_link/0, stop/1,
+ simulate_crash/2,
+ register/2, register/3,
+ register_monitor/2, register_monitor/3,
+ unregister/1, unregister/2,
+ register_agent/4
+ ]).
+
+%%----------------------------------------------------------------------
+%% Internal exports
+%%----------------------------------------------------------------------
+-export([
+ user/1
+ ]).
+
+-export([
+ handle_error/3,
+ handle_agent/4,
+ handle_pdu/4,
+ handle_pdu/5, % For backwards compatibillity
+ handle_trap/3,
+ handle_trap/4, % For backwards compatibillity
+ handle_inform/3,
+ handle_inform/4, % For backwards compatibillity
+ handle_report/3,
+ handle_report/4 % For backwards compatibillity
+ ]).
+
+
+-record(state, {parent, ids = []}).
+
+
+%%----------------------------------------------------------------------
+%% The user simulation API
+%%----------------------------------------------------------------------
+
+start_link() ->
+ S = #state{parent = self()},
+ proc_lib:start_link(?MODULE, user, [S]).
+
+stop(Pid) ->
+ cast(Pid, stop).
+
+simulate_crash(Pid, Reason) ->
+ call(Pid, {simulate_crash, Reason}).
+
+%% For backwards compatibillity
+register(Pid, Id) ->
+ call(Pid, {register, Id}).
+
+register(Pid, Id, DefaultAgentConfig) ->
+ call(Pid, {register, Id, DefaultAgentConfig}).
+
+%% For backwards compatibillity
+register_monitor(Pid, Id) ->
+ call(Pid, {register_monitor, Id}).
+
+register_monitor(Pid, Id, DefaultAgentConfig) ->
+ call(Pid, {register_monitor, Id, DefaultAgentConfig}).
+
+unregister(Pid) ->
+ call(Pid, unregister).
+
+unregister(Pid, Id) ->
+ call(Pid, {unregister, Id}).
+
+register_agent(Pid, Id, TargetName, AgentConfig) ->
+ call(Pid, {register_agent, Id, TargetName, AgentConfig}).
+
+user(#state{parent = Pid} = S) ->
+ proc_lib:init_ack(Pid, {ok, self()}),
+ user_loop(S).
+
+user_loop(#state{parent = Parent} = S) ->
+ receive
+ {stop, Parent} ->
+ exit(normal);
+
+ {{simulate_crash, Reason}, Parent, Ref} ->
+ reply(Parent, ok, Ref),
+ exit(Reason);
+
+ %% For backwards compatibillity
+ {{register, Id}, Parent, Ref} ->
+ IDs = S#state.ids,
+ case lists:member(Id, IDs) of
+ false ->
+ Res = snmpm:register_user(Id, ?MODULE, self()),
+ reply(Parent, Res, Ref),
+ user_loop(S#state{ids = [Id|IDs]});
+ true ->
+ reply(Parent, {error, already_registered}, Ref),
+ user_loop(S)
+ end;
+
+ {{register, Id, DefaultAgentConf}, Parent, Ref} ->
+ IDs = S#state.ids,
+ case lists:member(Id, IDs) of
+ false ->
+ Res = snmpm:register_user(Id, ?MODULE, self(),
+ DefaultAgentConf),
+ reply(Parent, Res, Ref),
+ user_loop(S#state{ids = [Id|IDs]});
+ true ->
+ reply(Parent, {error, already_registered}, Ref),
+ user_loop(S)
+ end;
+
+ %% For backwards compatibillity
+ {{register_monitor, Id}, Parent, Ref} ->
+ IDs = S#state.ids,
+ case lists:member(Id, IDs) of
+ false ->
+ Res = snmpm:register_user_monitor(Id, ?MODULE, self()),
+ reply(Parent, Res, Ref),
+ user_loop(S#state{ids = [Id|IDs]});
+ true ->
+ reply(Parent, {error, already_registered}, Ref),
+ user_loop(S)
+ end;
+
+ {{register_monitor, Id, DefaultAgentConf}, Parent, Ref} ->
+ IDs = S#state.ids,
+ case lists:member(Id, IDs) of
+ false ->
+ Res = snmpm:register_user_monitor(Id, ?MODULE, self(),
+ DefaultAgentConf),
+ reply(Parent, Res, Ref),
+ user_loop(S#state{ids = [Id|IDs]});
+ true ->
+ reply(Parent, {error, already_registered}, Ref),
+ user_loop(S)
+ end;
+
+ {unregister, Parent, Ref} ->
+ Res = [snmpm:unregister_user(Id) || Id <- S#state.ids],
+ reply(Parent, {ok, Res}, Ref),
+ user_loop(S);
+
+ {{unregister, Id}, Parent, Ref} ->
+ IDs = S#state.ids,
+ IDs2 =
+ case lists:member(Id, IDs) of
+ true ->
+ Res = snmpm:unregister_user(Id),
+ reply(Parent, Res, Ref),
+ lists:delete(Id, IDs);
+ false ->
+ reply(Parent, {error, not_registered}, Ref),
+ IDs
+ end,
+ user_loop(S#state{ids = IDs2});
+
+ {{register_agent, Id, TargetName, Config}, Parent, Ref} ->
+ IDs = S#state.ids,
+ case lists:member(Id, IDs) of
+ true ->
+ Res = snmpm:register_agent(Id, TargetName, Config),
+ reply(Parent, Res, Ref),
+ user_loop(S);
+ false ->
+ reply(Parent, {error, {unknown_user, Id}}, Ref),
+ user_loop(S)
+ end;
+
+
+
+ %% SNMP manager callback messages (from our callback API):
+
+ {handle_error, Pid, ReqId, Reason} ->
+ do_handle_error(Pid, ReqId, Reason),
+ user_loop(S);
+
+ {handle_agent, Pid, Addr, Port, SnmpInfo} ->
+ do_handle_agent(Pid, Addr, Port, SnmpInfo),
+ user_loop(S);
+
+ {handle_pdu, Pid, TargetName, ReqId, SnmpResponse} ->
+ do_handle_pdu(Pid, TargetName, ReqId, SnmpResponse),
+ user_loop(S);
+
+ {handle_pdu, Pid, Addr, Port, ReqId, SnmpResponse} ->
+ do_handle_pdu(Pid, Addr, Port, ReqId, SnmpResponse),
+ user_loop(S);
+
+ {handle_trap, Pid, TargetName, SnmpTrap} ->
+ do_handle_trap(Pid, TargetName, SnmpTrap),
+ user_loop(S);
+
+ {handle_trap, Pid, Addr, Port, SnmpTrap} ->
+ do_handle_trap(Pid, Addr, Port, SnmpTrap),
+ user_loop(S);
+
+ {handle_inform, Pid, TargetName, SnmpInform} ->
+ do_handle_inform(Pid, TargetName, SnmpInform),
+ user_loop(S);
+
+ {handle_inform, Pid, Addr, Port, SnmpInform} ->
+ do_handle_inform(Pid, Addr, Port, SnmpInform),
+ user_loop(S);
+
+ {handle_report, Pid, TargetName, SnmpReport} ->
+ do_handle_report(Pid, TargetName, SnmpReport),
+ user_loop(S);
+
+ {handle_report, Pid, Addr, Port, SnmpReport} ->
+ do_handle_report(Pid, Addr, Port, SnmpReport),
+ user_loop(S);
+
+ Unknown ->
+ info("received unknown message: ~n~p", [Unknown]),
+ user_loop(S)
+ end.
+
+
+%% -------------
+
+do_handle_error(Pid, ReqId, Reason) ->
+ info("received error callback:"
+ "~n ReqId: ~p"
+ "~n Reason: ~p", [ReqId, Reason]),
+ Pid ! {ignore, self()},
+ ok.
+
+
+do_handle_agent(Pid, Addr, Port, SnmpInfo) ->
+ info("received agent callback:"
+ "~n Addr: ~p"
+ "~n Port: ~p"
+ "~n SnmpInfo: ~p", [Addr, Port, SnmpInfo]),
+ Pid ! {ignore, self()},
+ ok.
+
+
+do_handle_pdu(Pid, TargetName, ReqId, SnmpResponse) ->
+ info("received pdu callback:"
+ "~n TargetName: ~p"
+ "~n ReqId: ~p"
+ "~n SnmpResponse: ~p", [TargetName, ReqId, SnmpResponse]),
+ Pid ! {ignore, self()},
+ ok.
+
+%% For backwards compatibillity
+do_handle_pdu(Pid, Addr, Port, ReqId, SnmpResponse) ->
+ info("received pdu callback:"
+ "~n Addr: ~p"
+ "~n Port: ~p"
+ "~n ReqId: ~p"
+ "~n SnmpResponse: ~p", [Addr, Port, ReqId, SnmpResponse]),
+ Pid ! {ignore, self()},
+ ok.
+
+
+do_handle_trap(Pid, TargetName, SnmpTrap) ->
+ info("received trap callback:"
+ "~n TargetName: ~p"
+ "~n SnmpTrap: ~p", [TargetName, SnmpTrap]),
+ Pid ! {ignore, self()},
+ ok.
+
+%% For backwards compatibillity
+do_handle_trap(Pid, Addr, Port, SnmpTrap) ->
+ info("received trap callback:"
+ "~n Addr: ~p"
+ "~n Port: ~p"
+ "~n SnmpTrap: ~p", [Addr, Port, SnmpTrap]),
+ Pid ! {ignore, self()},
+ ok.
+
+
+do_handle_inform(Pid, TargetName, SnmpInform) ->
+ info("received inform callback:"
+ "~n TargetName: ~p"
+ "~n SnmpInform: ~p", [TargetName, SnmpInform]),
+ Pid ! {ignore, self()},
+ ok.
+
+%% For backwards compatibillity
+do_handle_inform(Pid, Addr, Port, SnmpInform) ->
+ info("received inform callback:"
+ "~n Addr: ~p"
+ "~n Port: ~p"
+ "~n SnmpInform: ~p", [Addr, Port, SnmpInform]),
+ Pid ! {ignore, self()},
+ ok.
+
+
+do_handle_report(Pid, TargetName, SnmpReport) ->
+ info("received report callback:"
+ "~n TargetName: ~p"
+ "~n SnmpReport: ~p", [TargetName, SnmpReport]),
+ Pid ! {ignore, self()},
+ ok.
+
+%% For backwards compatibillity
+do_handle_report(Pid, Addr, Port, SnmpReport) ->
+ info("received report callback:"
+ "~n Addr: ~p"
+ "~n Port: ~p"
+ "~n SnmpReport: ~p", [Addr, Port, SnmpReport]),
+ Pid ! {ignore, self()},
+ ok.
+
+
+info(F, A) ->
+ error_logger:info_msg("USER SIMULATOR " ++ F ++ "~n", A).
+
+
+%% -------------
+
+call(UserPid, Req) ->
+ call(UserPid, Req, 5000).
+
+call(UserPid, Req, To) ->
+ Ref = make_ref(),
+ UserPid ! {Req, self(), Ref},
+ receive
+ {Reply, UserPid, Ref} ->
+ Reply
+ after To ->
+ {error, timeout}
+ end.
+
+reply(Pid, Reply, Ref) ->
+ Pid ! {Reply, self(), Ref}.
+
+cast(UserPid, Msg) ->
+ UserPid ! {Msg, self()},
+ ok.
+
+
+%%----------------------------------------------------------------------
+%% User callback functions:
+%%----------------------------------------------------------------------
+
+handle_error(ReqId, Reason, UserPid) ->
+ UserPid ! {handle_error, self(), ReqId, Reason},
+ ignore.
+
+
+handle_agent(Addr, Port, SnmpInfo, UserPid) ->
+ UserPid ! {handle_agent, self(), Addr, Port, SnmpInfo},
+ ignore.
+
+
+handle_pdu(TargetName, ReqId, SnmpResponse, UserPid) ->
+ UserPid ! {handle_pdu, self(), TargetName, ReqId, SnmpResponse},
+ ignore.
+
+%% For backwards compatibillity
+handle_pdu(Addr, Port, ReqId, SnmpResponse, UserPid) ->
+ UserPid ! {handle_pdu, self(), Addr, Port, ReqId, SnmpResponse},
+ ignore.
+
+
+handle_trap(TargetName, SnmpTrap, UserPid) ->
+ UserPid ! {handle_trap, self(), TargetName, SnmpTrap},
+ ok.
+
+%% For backwards compatibillity
+handle_trap(Addr, Port, SnmpTrap, UserPid) ->
+ UserPid ! {handle_trap, self(), Addr, Port, SnmpTrap},
+ ok.
+
+
+handle_inform(TargetName, SnmpInform, UserPid) ->
+ UserPid ! {handle_inform, self(), TargetName, SnmpInform},
+ ok.
+
+%% For backwards compatibillity
+handle_inform(Addr, Port, SnmpInform, UserPid) ->
+ UserPid ! {handle_inform, self(), Addr, Port, SnmpInform},
+ ok.
+
+
+handle_report(TargetName, SnmpReport, UserPid) ->
+ UserPid ! {handle_report, self(), TargetName, SnmpReport},
+ ok.
+
+%% For backwards compatibillity
+handle_report(Addr, Port, SnmpReport, UserPid) ->
+ UserPid ! {handle_report, self(), Addr, Port, SnmpReport},
+ ok.
diff --git a/lib/snmp/test/snmp_note_store_test.erl b/lib/snmp/test/snmp_note_store_test.erl
new file mode 100644
index 0000000000..8686a47468
--- /dev/null
+++ b/lib/snmp/test/snmp_note_store_test.erl
@@ -0,0 +1,306 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2004-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%
+%%
+
+%%----------------------------------------------------------------------
+%% Purpose:
+%%----------------------------------------------------------------------
+-module(snmp_note_store_test).
+
+%%----------------------------------------------------------------------
+%% Include files
+%%----------------------------------------------------------------------
+-include("test_server.hrl").
+-include("snmp_test_lib.hrl").
+
+
+%%----------------------------------------------------------------------
+%% External exports
+%%----------------------------------------------------------------------
+-export([
+ init_per_testcase/2, fin_per_testcase/2,
+ all/1,
+ start_and_stop/1,
+ notes/1,
+ info/1,
+ garbage_in/1
+ ]).
+
+%%----------------------------------------------------------------------
+%% Internal exports
+%%----------------------------------------------------------------------
+-export([
+ system_start_time/0
+ ]).
+
+%%----------------------------------------------------------------------
+%% Macros
+%%----------------------------------------------------------------------
+
+%%----------------------------------------------------------------------
+%% Records
+%%----------------------------------------------------------------------
+
+%%======================================================================
+%% External functions
+%%======================================================================
+
+init_per_testcase(_Case, Config) when is_list(Config) ->
+ Config.
+
+fin_per_testcase(_Case, Config) when is_list(Config) ->
+ Config.
+
+%%======================================================================
+%% Test case definitions
+%%======================================================================
+all(suite) ->
+ [
+ start_and_stop,
+ notes,
+ info,
+ garbage_in
+
+ ].
+
+
+%%======================================================================
+%% Test functions
+%%======================================================================
+
+
+%%======================================================================
+
+start_and_stop(suite) ->
+ [];
+start_and_stop(doc) ->
+ ["Simple start and stop."];
+start_and_stop(Config) when is_list(Config) ->
+
+ Prio = normal,
+ Mod = ?MODULE,
+ Opts = [{verbosity, trace}],
+ {ok, Pid} = snmp_note_store:start_link(Prio, Mod, Opts),
+ snmp_note_store:stop(Pid),
+
+ ok.
+
+
+%%======================================================================
+
+notes(suite) ->
+ [];
+notes(doc) ->
+ ["Testing that it does what it is actually supposed to do, "
+ "namilly to handle notes. "];
+notes(Config) when is_list(Config) ->
+
+ {ok, Handler, Pid} = note_store_handler_start(),
+
+ io:format("sleep some before we begin the tests~n", []),
+ ?SLEEP(timer:seconds(1)),
+
+ %% Default lifetime is infinity. A note with lifetime
+ %% infinity is permanent
+ io:format("create permanent note sune~n", []),
+ true = snmp_note_store:set_note(Pid, sune, 10),
+ 10 = snmp_note_store:get_note(Pid, sune),
+ 10 = snmp_note_store:get_note(Pid, sune),
+
+ %% Lifetime is in 1/100 sec ticks, so 500 equals 5 seconds
+ io:format("create 5 sec note kalle~n", []),
+ true = snmp_note_store:set_note(Pid, 500, kalle, hobbe),
+ io:format("wait 1 sec~n", []),
+ ?SLEEP(timer:seconds(1)),
+ io:format("get note kalle~n", []),
+ hobbe = snmp_note_store:get_note(Pid, kalle),
+ io:format("wait 5 sec~n", []),
+ ?SLEEP(timer:seconds(5)),
+ io:format("get note kalle again (now it should not exist)~n", []),
+ undefined = snmp_note_store:get_note(Pid, kalle),
+
+ io:format("create 5 sec note kalle~n", []),
+ true = snmp_note_store:set_note(Pid, 500, kalle, hobbe),
+ io:format("wait 6 sec (to allow timer to clean up note)~n", []),
+ ?SLEEP(timer:seconds(6)),
+ io:format("get note kalle - should not exist~n", []),
+ undefined = snmp_note_store:get_note(Pid, kalle),
+
+ io:format("read the permanent note sune again~n", []),
+ 10 = snmp_note_store:get_note(Pid, sune),
+
+ note_store_handler_stop(Handler),
+
+ ok.
+
+
+%%======================================================================
+
+info(suite) ->
+ [];
+info(doc) ->
+ ["Testing that we can retreive process info."];
+info(Config) when is_list(Config) ->
+
+ Prio = normal,
+ Mod = ?MODULE,
+ Opts = [{verbosity, trace}],
+ {ok, Pid} = snmp_note_store:start_link(Prio, Mod, Opts),
+
+ %% Get the info:
+ Info = snmp_note_store:info(Pid),
+ io:format("Info: ~p~n", [Info]),
+
+ %% Verify content
+ io:format("get process memory~n", []),
+ {value, {process_memory, ProcMem}} =
+ lists:keysearch(process_memory, 1, Info),
+ io:format("get notes process memory~n", []),
+ {value, {notes, NotesProcMem}} =
+ lists:keysearch(notes, 1, ProcMem),
+ io:format("verify notes process memory~n", []),
+ if
+ is_integer(NotesProcMem) andalso (NotesProcMem > 0) ->
+ ok;
+ true ->
+ throw({error, {bad_notes_proc_memery, NotesProcMem}})
+ end,
+ io:format("get timer process memory~n", []),
+ {value, {timer, TmrProcMem}} =
+ lists:keysearch(timer, 1, ProcMem),
+ io:format("verify timer process memory~n", []),
+ if
+ is_integer(TmrProcMem) andalso (TmrProcMem > 0) ->
+ ok;
+ true ->
+ throw({error, {bad_timer_proc_memery, TmrProcMem}})
+ end,
+ io:format("get db memory~n", []),
+ {value, {db_memory, DbMem}} =
+ lists:keysearch(db_memory, 1, Info),
+ io:format("get notes db memory~n", []),
+ {value, {notes, NotesDbMem}} =
+ lists:keysearch(notes, 1, DbMem),
+ io:format("verify notes db memory~n", []),
+ if
+ is_integer(NotesDbMem) andalso (NotesDbMem > 0) ->
+ ok;
+ true ->
+ throw({error, {bad_notes_db_memery, NotesDbMem}})
+ end,
+
+
+ snmp_note_store:stop(Pid),
+
+ ok.
+
+
+%%======================================================================
+
+garbage_in(suite) ->
+ [];
+garbage_in(doc) ->
+ ["Test that the process handles garbage sent to it."];
+garbage_in(Config) when is_list(Config) ->
+
+ io:format("start note_store server~n", []),
+ Prio = normal,
+ Mod = ?MODULE,
+ Opts = [{verbosity, trace}],
+ {ok, Pid} = snmp_note_store:start_link(Prio, Mod, Opts),
+
+ io:format("issue bad request~n", []),
+ {error, _} = gen_server:call(Pid, bad_request),
+
+ io:format("cast bad message~n", []),
+ gen_server:cast(Pid, bad_message),
+
+ io:format("bang bad info~n", []),
+ Pid ! bad_info,
+
+ io:format("verify note_Store server still alive and kicking~n", []),
+ Info = snmp_note_store:info(Pid),
+ if
+ is_list(Info) andalso (length(Info) > 0) ->
+ ok;
+ true ->
+ throw({error, {bad_info, Info}})
+ end,
+
+ io:format("stop note_store server~n", []),
+ snmp_note_store:stop(Pid),
+
+ io:format("done~n", []),
+ ok.
+
+
+%%======================================================================
+%% Internal functions
+%%======================================================================
+
+system_start_time() ->
+ note_store_handler ! {system_start_time, self()},
+ receive
+ {system_start_time, SysStartTime} ->
+ SysStartTime
+ end.
+
+note_store_handler_start() ->
+ Self = self(),
+ Fun = fun() -> note_store_handler(Self) end,
+ HandlerPid = spawn_link(Fun),
+ receive
+ {started, HandlerPid, NSPid} ->
+ {ok, HandlerPid, NSPid}
+ after 5000 ->
+ exit(HandlerPid, kill),
+ {error, timeout}
+ end.
+
+note_store_handler_stop(Pid) ->
+ Pid ! {stop, self()},
+ receive
+ {stopped, Pid} ->
+ ok
+ after 5000 ->
+ exit(Pid, kill),
+ {error, timeout}
+ end.
+
+note_store_handler(Parent) ->
+ erlang:register(note_store_handler, self()),
+ put(system_start_time, snmp_misc:now(cs)),
+ Prio = normal,
+ Mod = ?MODULE,
+ Opts = [{verbosity, trace}],
+ {ok, Pid} = snmp_note_store:start_link(Prio, Mod, Opts),
+ Parent ! {started, self(), Pid},
+ note_store_handler_loop(Parent, Pid).
+
+note_store_handler_loop(Parent, NSPid) ->
+ receive
+ {stop, Parent} ->
+ snmp_note_store:stop(NSPid),
+ Parent ! {stopped, self()},
+ exit(normal);
+ {system_start_time, Pid} ->
+ StartTime = get(system_start_time),
+ Pid ! {system_start_time, StartTime},
+ note_store_handler_loop(Parent, NSPid)
+ end.
+
diff --git a/lib/snmp/test/snmp_pdus_test.erl b/lib/snmp/test/snmp_pdus_test.erl
new file mode 100644
index 0000000000..d5add50f52
--- /dev/null
+++ b/lib/snmp/test/snmp_pdus_test.erl
@@ -0,0 +1,127 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2003-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%
+%%
+
+%%----------------------------------------------------------------------
+%% Purpose:
+%%----------------------------------------------------------------------
+-module(snmp_pdus_test).
+
+%%----------------------------------------------------------------------
+%% Include files
+%%----------------------------------------------------------------------
+-include("test_server.hrl").
+-include("snmp_test_lib.hrl").
+-include_lib("snmp/include/snmp_types.hrl").
+
+
+%%----------------------------------------------------------------------
+%% External exports
+%%----------------------------------------------------------------------
+-export([
+ all/1,
+ tickets/1,
+ otp7575/1,
+ init_per_testcase/2, fin_per_testcase/2
+ ]).
+
+
+%%----------------------------------------------------------------------
+%% Internal exports
+%%----------------------------------------------------------------------
+-export([
+ ]).
+
+
+%%----------------------------------------------------------------------
+%% Macros
+%%----------------------------------------------------------------------
+
+%%----------------------------------------------------------------------
+%% Records
+%%----------------------------------------------------------------------
+
+%%======================================================================
+%% External functions
+%%======================================================================
+
+init_per_testcase(_Case, Config) when is_list(Config) ->
+ Config.
+
+fin_per_testcase(_Case, Config) when is_list(Config) ->
+ Config.
+
+%%======================================================================
+%% Test case definitions
+%%======================================================================
+all(suite) ->
+ [
+ tickets
+ ].
+
+tickets(suite) ->
+ [
+ otp7575
+ ].
+
+
+
+%%======================================================================
+%% Test functions
+%%======================================================================
+
+otp7575(suite) -> [];
+otp7575(doc) -> ["OTP-7575"];
+otp7575(Config) when is_list(Config) ->
+ io:format("attempt to decode message with valid version~n", []),
+ MsgWithOkVersion = <<48,39,2,1,0,4,6,112,117,98,108,105,99,160,26,2,2,1,49,2,1,0,2,1,0,48,14,48,12,6,8,43,6,1,2,1,1,5,0,5,0>>,
+ case (catch dec_message(MsgWithOkVersion)) of
+ Msg when is_record(Msg, message) ->
+ ok;
+ Unexpected1 ->
+ exit({unexpected_decode_result, 1, Unexpected1})
+ end,
+
+ io:format("attempt to decode message with bad version~n", []),
+ MsgWithBadVersion = <<48,48,2,10,1,1,1,1,1,1,1,1,1,1,4,6,112,117,98,108,105,99,160,26,2,2,1,49,2,1,0,2,1,0,48,14,48,12,6,8,43,6,1,2,1,1,5,0,5,0>>,
+ case (catch dec_message(MsgWithBadVersion)) of
+ {'EXIT', {bad_version, BadVersion}} when is_integer(BadVersion) ->
+ ok;
+ Unexpected2 ->
+ exit({unexpected_decode_result, 2, Unexpected2})
+ end,
+
+ io:format("attempt to decode message with very bad version~n", []),
+ MsgWithVeryBadVersion = <<48,49,2,11,1,1,1,1,1,1,1,1,1,1,1,4,6,112,117,98,108,105,99,160,26,2,2,1,49,2,1,0,2,1,0,48,14,48,12,6,8,43,6,1,2,1,1,5,0,5,0>>,
+ case (catch dec_message(MsgWithVeryBadVersion)) of
+ {'EXIT', {bad_version, {VersionSize, MaxVersionSize}}} when (VersionSize > MaxVersionSize) ->
+ ok;
+ Unexpected3 ->
+ exit({unexpected_decode_result, 3, Unexpected3})
+ end,
+ io:format("done~n", []),
+ ok.
+
+
+%%======================================================================
+%% Internal functions
+%%======================================================================
+
+dec_message(B) when is_binary(B) ->
+ L = binary_to_list(B),
+ snmp_pdus:dec_message(L).
diff --git a/lib/snmp/test/snmp_test_data/ERICSSON-TOP-MIB.mib b/lib/snmp/test/snmp_test_data/ERICSSON-TOP-MIB.mib
new file mode 100644
index 0000000000..8b5f594426
--- /dev/null
+++ b/lib/snmp/test/snmp_test_data/ERICSSON-TOP-MIB.mib
@@ -0,0 +1,36 @@
+-- ERICSSON-TOP-MIB: Top-level MIB for Ericsson AB's
+-- 193 branch of the enterprise MIB tree.
+--
+-- ERICSSON-TOP-MIB.mib,v 1.1 2002/06/12 13:14:57 epkpart Exp
+--
+-- ERICSSON-TOP-MIB.mib,v
+-- Revision 1.1 2002/06/12 13:14:57 epkpart
+-- Initial revision
+--
+--
+-- Copyright (c) 2002 by Ericsson AB
+-- All rights reserved.
+--
+
+ERICSSON-TOP-MIB DEFINITIONS ::= BEGIN
+
+IMPORTS
+ MODULE-IDENTITY, enterprises
+ FROM SNMPv2-SMI;
+
+ericsson MODULE-IDENTITY
+ LAST-UPDATED
+ "200205280000Z"
+ ORGANIZATION
+ "Ericsson AB "
+ CONTACT-INFO
+ "David Partain <[email protected]>
+ or
+ whoever is currently responsible for the Ericsson
+ enterprise MIB tree branch (enterprises.193)."
+ DESCRIPTION
+ "This very small module is made available so that
+ developers within the Ericsson community can import the
+ 'ericsson' name into their own MIB modules."
+ ::= { enterprises 193 }
+END
diff --git a/lib/snmp/test/snmp_test_data/EX1-MIB.mib b/lib/snmp/test/snmp_test_data/EX1-MIB.mib
new file mode 100644
index 0000000000..5d9979d0b4
--- /dev/null
+++ b/lib/snmp/test/snmp_test_data/EX1-MIB.mib
@@ -0,0 +1,90 @@
+ EX1-MIB DEFINITIONS ::= BEGIN
+
+ IMPORTS
+ experimental FROM RFC1155-SMI
+ RowStatus FROM STANDARD-MIB
+ DisplayString FROM RFC1213-MIB
+ OBJECT-TYPE FROM RFC-1212
+ ;
+
+ example1 OBJECT IDENTIFIER ::= { experimental 7 }
+
+
+ myName OBJECT-TYPE
+ SYNTAX DisplayString (SIZE (0..255))
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "My own name"
+ ::= { example1 1 }
+
+ friendsTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF FriendsEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A list of friends."
+ ::= { example1 4 }
+
+ friendsEntry OBJECT-TYPE
+ SYNTAX FriendsEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ ""
+ INDEX { fIndex }
+ ::= { friendsTable 1 }
+
+ FriendsEntry ::=
+ SEQUENCE {
+ fIndex
+ INTEGER,
+ fName
+ DisplayString,
+ fAddress
+ DisplayString,
+ fStatus
+ RowStatus }
+
+ fIndex OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "number of friend"
+ ::= { friendsEntry 1 }
+
+ fName OBJECT-TYPE
+ SYNTAX DisplayString (SIZE (0..255))
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "Name of friend"
+ ::= { friendsEntry 2 }
+
+ fAddress OBJECT-TYPE
+ SYNTAX DisplayString (SIZE (0..255))
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "Address of friend"
+ ::= { friendsEntry 3 }
+
+ fStatus OBJECT-TYPE
+ SYNTAX RowStatus
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The status of this conceptual row."
+ ::= { friendsEntry 4 }
+
+
+ fTrap TRAP-TYPE
+ ENTERPRISE example1
+ VARIABLES { myName, fIndex }
+ DESCRIPTION
+ "This trap is sent something happens to
+ the friend specified by fIndex."
+ ::= 1
+
+ END
diff --git a/lib/snmp/test/snmp_test_data/Klas1-v2.mib b/lib/snmp/test/snmp_test_data/Klas1-v2.mib
new file mode 100644
index 0000000000..ebbd157841
--- /dev/null
+++ b/lib/snmp/test/snmp_test_data/Klas1-v2.mib
@@ -0,0 +1,128 @@
+ Klas1-V2 DEFINITIONS ::= BEGIN
+
+IMPORTS
+ MODULE-IDENTITY, OBJECT-TYPE, NOTIFICATION-TYPE,
+ TimeTicks, Counter32, snmpModules, mib-2, enterprises, IpAddress,
+ Integer32
+ FROM SNMPv2-SMI
+ DisplayString, TestAndIncr, TimeStamp, RowStatus, TruthValue,
+ TEXTUAL-CONVENTION
+ FROM SNMPv2-TC
+ MODULE-COMPLIANCE, OBJECT-GROUP, NOTIFICATION-GROUP
+ FROM SNMPv2-CONF;
+
+klas1v2 MODULE-IDENTITY
+ LAST-UPDATED "9511090000Z"
+ ORGANIZATION ""
+ CONTACT-INFO
+ ""
+ DESCRIPTION
+ "v2 variant of Klas1. Used for compatibility testing."
+ ::= { snmpModules 1 }
+
+ klas1 OBJECT IDENTIFIER ::= { mib-2 7 }
+
+
+ fname OBJECT-TYPE
+ SYNTAX DisplayString (SIZE (0..255))
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "A textual description of the entity. This value
+ printable ASCII characters."
+ ::= { klas1 1 }
+
+ friendsTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF FriendsEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A list of klas friends."
+ ::= { klas1 4 }
+
+ friendsEntry OBJECT-TYPE
+ SYNTAX FriendsEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "nope"
+ INDEX { fIndex }
+ ::= { friendsTable 1 }
+
+ FriendsEntry ::=
+ SEQUENCE {
+ fIndex
+ Integer32,
+ fName
+ DisplayString,
+ fStatus
+ RowStatus }
+
+ fIndex OBJECT-TYPE
+ SYNTAX Integer32
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "number of friend"
+ ::= { friendsEntry 1 }
+
+ fName OBJECT-TYPE
+ SYNTAX DisplayString (SIZE (0..255))
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "Name of friend"
+ ::= { friendsEntry 2 }
+
+ fStatus OBJECT-TYPE
+ SYNTAX RowStatus
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "The status of this conceptual row."
+ ::= { friendsEntry 3 }
+
+ kompissTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF KompissEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A list of klas kompiss."
+ ::= { klas1 5 }
+
+ kompissEntry OBJECT-TYPE
+ SYNTAX KompissEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "nope"
+ INDEX { fIndex }
+ ::= { kompissTable 1 }
+
+ KompissEntry ::=
+ SEQUENCE {
+ kName
+ DisplayString,
+ kStatus
+ RowStatus }
+
+ kName OBJECT-TYPE
+ SYNTAX DisplayString (SIZE (0..255))
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "Name of kompis"
+ ::= { kompissEntry 1 }
+
+ kStatus OBJECT-TYPE
+ SYNTAX RowStatus
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "The status of this conceptual row."
+ ::= { kompissEntry 2 }
+
+
+
+ END
+
diff --git a/lib/snmp/test/snmp_test_data/Klas1.mib b/lib/snmp/test/snmp_test_data/Klas1.mib
new file mode 100644
index 0000000000..b07dc4d241
--- /dev/null
+++ b/lib/snmp/test/snmp_test_data/Klas1.mib
@@ -0,0 +1,116 @@
+ Klas1 DEFINITIONS ::= BEGIN
+
+ IMPORTS
+ mib-2 FROM RFC1213-MIB
+ RowStatus FROM STANDARD-MIB
+ OBJECT-TYPE
+ FROM RFC-1212;
+
+ klas1 OBJECT IDENTIFIER ::= { mib-2 7 }
+
+ DisplayString ::=
+ OCTET STRING
+
+ fname OBJECT-TYPE
+ SYNTAX DisplayString (SIZE (0..255))
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "A textual description of the entity. This value
+ printable ASCII characters."
+ ::= { klas1 1 }
+
+ friendsTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF FriendsEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A list of klas friends."
+ ::= { klas1 4 }
+
+ friendsEntry OBJECT-TYPE
+ SYNTAX FriendsEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "nope"
+ INDEX { fIndex }
+ ::= { friendsTable 1 }
+
+ FriendsEntry ::=
+ SEQUENCE {
+ fIndex
+ INTEGER,
+ fName
+ DisplayString,
+ fStatus
+ RowStatus }
+
+ fIndex OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "number of friend"
+ ::= { friendsEntry 1 }
+
+ fName OBJECT-TYPE
+ SYNTAX DisplayString (SIZE (0..255))
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "Name of friend"
+ ::= { friendsEntry 2 }
+
+ fStatus OBJECT-TYPE
+ SYNTAX RowStatus
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The status of this conceptual row."
+ ::= { friendsEntry 3 }
+
+ kompissTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF KompissEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A list of klas kompiss."
+ ::= { klas1 5 }
+
+ kompissEntry OBJECT-TYPE
+ SYNTAX KompissEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "nope"
+ INDEX { fIndex }
+ ::= { kompissTable 1 }
+
+ KompissEntry ::=
+ SEQUENCE {
+ kName
+ DisplayString,
+ kStatus
+ RowStatus }
+
+ kName OBJECT-TYPE
+ SYNTAX DisplayString (SIZE (0..255))
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "Name of kompis"
+ ::= { kompissEntry 1 }
+
+ kStatus OBJECT-TYPE
+ SYNTAX RowStatus
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The status of this conceptual row."
+ ::= { kompissEntry 2 }
+
+
+
+ END
+
diff --git a/lib/snmp/test/snmp_test_data/Klas2.funcs b/lib/snmp/test/snmp_test_data/Klas2.funcs
new file mode 100644
index 0000000000..5dca2ef651
--- /dev/null
+++ b/lib/snmp/test/snmp_test_data/Klas2.funcs
@@ -0,0 +1,3 @@
+{friendsTable2, {snmp_generic, table_func, [{friendsTable2, mnesia}]}}.
+{kompissTable2, {snmp_generic, table_func, [{kompissTable2, mnesia}]}}.
+{fname2, {snmp_generic, variable_func, [{fname2, mnesia}]}}.
diff --git a/lib/snmp/test/snmp_test_data/Klas2.mib b/lib/snmp/test/snmp_test_data/Klas2.mib
new file mode 100644
index 0000000000..38ebf4ece7
--- /dev/null
+++ b/lib/snmp/test/snmp_test_data/Klas2.mib
@@ -0,0 +1,128 @@
+ Klas2 DEFINITIONS ::= BEGIN
+
+-- This MIB is used for testing the Mnesia implementation
+
+ IMPORTS
+ mib-2 FROM RFC1213-MIB
+ RowStatus FROM STANDARD-MIB
+ OBJECT-TYPE
+ FROM RFC-1212;
+
+ klas2 OBJECT IDENTIFIER ::= { mib-2 9 }
+
+ DisplayString ::=
+ OCTET STRING
+
+ fname2 OBJECT-TYPE
+ SYNTAX DisplayString (SIZE (0..255))
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "A textual description of the entity. This value
+ printable ASCII characters."
+ ::= { klas2 1 }
+
+ fint OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "write a neg. number to me if you dare..."
+ ::= { klas2 2 }
+
+
+ friendsTable2 OBJECT-TYPE
+ SYNTAX SEQUENCE OF FriendsEntry2
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A list of klas friends."
+ ::= { klas2 4 }
+
+ friendsEntry2 OBJECT-TYPE
+ SYNTAX FriendsEntry2
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "nope"
+ INDEX { fIndex2 }
+ ::= { friendsTable2 1 }
+
+ FriendsEntry2 ::=
+ SEQUENCE {
+ fIndex2
+ INTEGER,
+ fName2
+ DisplayString,
+ fStatus2
+ RowStatus }
+
+ fIndex2 OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "number of friend"
+ ::= { friendsEntry2 1 }
+
+ fName2 OBJECT-TYPE
+ SYNTAX DisplayString (SIZE (0..255))
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "Name of friend"
+ ::= { friendsEntry2 2 }
+
+ fStatus2 OBJECT-TYPE
+ SYNTAX RowStatus
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The status of this conceptual row."
+ ::= { friendsEntry2 3 }
+
+ kompissTable2 OBJECT-TYPE
+ SYNTAX SEQUENCE OF KompissEntry2
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A list of klas kompiss."
+ ::= { klas2 5 }
+
+ kompissEntry2 OBJECT-TYPE
+ SYNTAX KompissEntry2
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "nope"
+ INDEX { fIndex2 }
+ ::= { kompissTable2 1 }
+
+ KompissEntry2 ::=
+ SEQUENCE {
+ kName2
+ DisplayString,
+ kStatus2
+ RowStatus }
+
+ kName2 OBJECT-TYPE
+ SYNTAX DisplayString (SIZE (0..255))
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "Name of kompis"
+ DEFVAL { '4a4a4a'H }
+ ::= { kompissEntry2 1 }
+
+ kStatus2 OBJECT-TYPE
+ SYNTAX RowStatus
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The status of this conceptual row."
+ ::= { kompissEntry2 2 }
+
+
+
+ END
+
diff --git a/lib/snmp/test/snmp_test_data/Klas3.funcs b/lib/snmp/test/snmp_test_data/Klas3.funcs
new file mode 100644
index 0000000000..8ed45cc4ca
--- /dev/null
+++ b/lib/snmp/test/snmp_test_data/Klas3.funcs
@@ -0,0 +1,2 @@
+{fname3, {klas3, fname, []}}.
+{fname4, {klas3, fname4, []}}.
diff --git a/lib/snmp/test/snmp_test_data/Klas3.mib b/lib/snmp/test/snmp_test_data/Klas3.mib
new file mode 100644
index 0000000000..fc74e69ddd
--- /dev/null
+++ b/lib/snmp/test/snmp_test_data/Klas3.mib
@@ -0,0 +1,40 @@
+ Klas3 DEFINITIONS ::= BEGIN
+
+-- This MIB is used for testing the undo phase
+
+ IMPORTS
+ mib-2 FROM RFC1213-MIB
+ RowStatus FROM STANDARD-MIB
+ OBJECT-TYPE
+ FROM RFC-1212;
+
+ klas3 OBJECT IDENTIFIER ::= { mib-2 8 }
+
+ DisplayString ::=
+ OCTET STRING
+
+ fname3 OBJECT-TYPE
+ SYNTAX DisplayString (SIZE (0..255))
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "A textual description of the entity. This value
+ printable ASCII characters."
+ ::= { klas3 1 }
+
+ fname4 OBJECT-TYPE
+ SYNTAX INTEGER {
+ none(1),
+ snmpTrap(3)
+ }
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "A textual description of the entity. This value
+ printable ASCII characters."
+ ::= { klas3 2 }
+
+
+
+ END
+
diff --git a/lib/snmp/test/snmp_test_data/Klas4.funcs b/lib/snmp/test/snmp_test_data/Klas4.funcs
new file mode 100644
index 0000000000..ef36f225a6
--- /dev/null
+++ b/lib/snmp/test/snmp_test_data/Klas4.funcs
@@ -0,0 +1,3 @@
+{friendsTable3, {klas3, ftab, []}}.
+{friendsTable4, {klas3, ftab2, []}}.
+
diff --git a/lib/snmp/test/snmp_test_data/Klas4.mib b/lib/snmp/test/snmp_test_data/Klas4.mib
new file mode 100644
index 0000000000..36b82d7d08
--- /dev/null
+++ b/lib/snmp/test/snmp_test_data/Klas4.mib
@@ -0,0 +1,156 @@
+ Klas4 DEFINITIONS ::= BEGIN
+
+-- This MIB is used for testing the undo phase
+
+ IMPORTS
+ mib-2 FROM RFC1213-MIB
+ RowStatus FROM STANDARD-MIB
+ OBJECT-TYPE
+ FROM RFC-1212
+ klas3 FROM Klas3;
+
+ DisplayString ::=
+ OCTET STRING
+
+ friendsTable3 OBJECT-TYPE
+ SYNTAX SEQUENCE OF FriendsEntry3
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A list of klas friends."
+ ::= { klas3 4 }
+
+ friendsEntry3 OBJECT-TYPE
+ SYNTAX FriendsEntry3
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "nope"
+ INDEX { fIndex3 }
+ ::= { friendsTable3 1 }
+
+ FriendsEntry3 ::=
+ SEQUENCE {
+ fIndex3
+ INTEGER,
+ fStatus3
+ RowStatus }
+
+ fIndex3 OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "number of friend"
+ ::= { friendsEntry3 1 }
+
+ fStatus3 OBJECT-TYPE
+ SYNTAX RowStatus
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The status of this conceptual row."
+ ::= { friendsEntry3 2 }
+
+ friendsTable4 OBJECT-TYPE
+ SYNTAX SEQUENCE OF FriendsEntry4
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A list of klas friends."
+ ::= { klas3 5 }
+
+ friendsEntry4 OBJECT-TYPE
+ SYNTAX FriendsEntry4
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "nope"
+ INDEX { fIndex4 }
+ ::= { friendsTable4 1 }
+
+ FriendsEntry4 ::=
+ SEQUENCE {
+ fIndex4
+ INTEGER,
+ fName4
+ INTEGER,
+ fStatus4
+ RowStatus }
+
+ fIndex4 OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "number of friend"
+ ::= { friendsEntry4 1 }
+
+ fName4 OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "name of friend"
+ ::= { friendsEntry4 2 }
+
+ fStatus4 OBJECT-TYPE
+ SYNTAX RowStatus
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The status of this conceptual row."
+ ::= { friendsEntry4 3 }
+
+ friendsTable5 OBJECT-TYPE
+ SYNTAX SEQUENCE OF FriendsEntry5
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A list of klas friends."
+ ::= { klas3 6 }
+
+ friendsEntry5 OBJECT-TYPE
+ SYNTAX FriendsEntry5
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "nope"
+ INDEX { fIndex5 }
+ ::= { friendsTable5 1 }
+
+ FriendsEntry5 ::=
+ SEQUENCE {
+ fIndex5
+ INTEGER,
+ fName5
+ INTEGER,
+ fStatus5
+ RowStatus }
+
+ fIndex5 OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "number of friend"
+ ::= { friendsEntry5 1 }
+
+ fName5 OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "name of friend"
+ ::= { friendsEntry5 2 }
+
+ fStatus5 OBJECT-TYPE
+ SYNTAX RowStatus
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The status of this conceptual row."
+ ::= { friendsEntry5 3 }
+
+ END
+
diff --git a/lib/snmp/test/snmp_test_data/OLD-SNMPEA-MIB-v2.mib b/lib/snmp/test/snmp_test_data/OLD-SNMPEA-MIB-v2.mib
new file mode 100644
index 0000000000..4f8ce94792
--- /dev/null
+++ b/lib/snmp/test/snmp_test_data/OLD-SNMPEA-MIB-v2.mib
@@ -0,0 +1,480 @@
+OLD-SNMPEA-MIB-v2 DEFINITIONS ::= BEGIN
+
+IMPORTS
+ MODULE-IDENTITY, OBJECT-TYPE, NOTIFICATION-TYPE,
+ TimeTicks, Counter32, snmpModules, mib-2, enterprises, IpAddress,
+ Integer32
+ FROM SNMPv2-SMI
+ DisplayString, TestAndIncr, TimeStamp, RowStatus, TruthValue,
+ TEXTUAL-CONVENTION
+ FROM SNMPv2-TC
+ MODULE-COMPLIANCE, OBJECT-GROUP, NOTIFICATION-GROUP
+ FROM SNMPv2-CONF;
+
+internalMIBv2 MODULE-IDENTITY
+ LAST-UPDATED "9511090000Z"
+ ORGANIZATION ""
+ CONTACT-INFO
+ ""
+ DESCRIPTION
+ "v2 variant of INTERNAL-MIB. Used for compatibility testing."
+ ::= { snmpModules 1 }
+
+
+ericsson OBJECT IDENTIFIER ::= {enterprises 193}
+otp OBJECT IDENTIFIER ::= {ericsson 19}
+
+otpApplications
+ OBJECT IDENTIFIER ::= {otp 3}
+otpSnmpeaMIB OBJECT IDENTIFIER ::= { otpApplications 3 }
+otpSnmpeaMIBObjects
+ OBJECT IDENTIFIER ::= { otpSnmpeaMIB 2 }
+
+snmpeaAdm OBJECT IDENTIFIER ::= { otpSnmpeaMIBObjects 1}
+community OBJECT IDENTIFIER ::= { snmpeaAdm 1 }
+trap OBJECT IDENTIFIER ::= { snmpeaAdm 2 }
+view OBJECT IDENTIFIER ::= { snmpeaAdm 3 }
+
+ -- Datatype
+
+StorageType ::= TEXTUAL-CONVENTION
+ STATUS current
+ DESCRIPTION
+ "Describes the memory realization of a conceptual row. A
+ row which is volatile(2) is lost upon reboot. A row which
+ is either nonVolatile(3), permanent(4) or readOnly(5), is
+ backed up by stable storage. A row which is permanent(4)
+ can be changed but not deleted. A row which is readOnly(5)
+ cannot be changed nor deleted.
+
+ If the value of an object with this syntax is either
+ permanent(4) or readOnly(5), it cannot be modified.
+ Conversely, if the value is either other(1), volatile(2) or
+ nonVolatile(3), it cannot be modified to be permanent(4) or
+ readOnly(5).
+
+ Every usage of this textual convention is required to
+ specify the columnar objects which a permanent(4) row must
+ at a minimum allow to be writable."
+ SYNTAX INTEGER {
+ other(1), -- eh?
+ volatile(2), -- e.g., in RAM
+ nonVolatile(3), -- e.g., in NVRAM
+ permanent(4) -- e.g., partially in ROM
+ }
+
+ -- Managed Objects
+
+ intCommunityTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF IntCommunityEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "This table defines access for the different
+ communities.
+
+ When a request comes from a certain ip address,
+ referring to a community string, the mib view
+ and access corresponding to these are looked up
+ in this table. Then the operation is validatated against
+ the access, and all requested objects validated against
+ the mib view."
+ ::= { community 1}
+
+ intCommunityEntry OBJECT-TYPE
+ SYNTAX IntCommunityEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ ""
+ INDEX { intCommunityDestination, intCommunityString }
+ ::= { intCommunityTable 1 }
+
+ IntCommunityEntry ::=
+ SEQUENCE {
+ intCommunityDestination IpAddress,
+ intCommunityString DisplayString,
+ intCommunityViewIndex Integer32,
+ intCommunityAccess INTEGER,
+ intCommunityStatus RowStatus
+ }
+
+ intCommunityDestination OBJECT-TYPE
+ SYNTAX IpAddress
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "The ip address of a management station. The special
+ ip address {0.0.0.0} is a wildcard, meaning all possible
+ ip addresses. In this way, access can be granted to all
+ ip addressed for some communities."
+ ::= { intCommunityEntry 1 }
+
+ intCommunityString OBJECT-TYPE
+ SYNTAX DisplayString
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "The community string, defining the community."
+ ::= { intCommunityEntry 2 }
+
+ intCommunityViewIndex OBJECT-TYPE
+ SYNTAX Integer32
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "Identifies a mib view. Index into the
+ intViewTable."
+ ::= { intCommunityEntry 3 }
+
+ intCommunityAccess OBJECT-TYPE
+ SYNTAX INTEGER { read(1), readWrite(2) }
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "Defines which operations the manager can perform
+ on the objects in the mib view."
+ ::= { intCommunityEntry 4 }
+
+ intCommunityStatus OBJECT-TYPE
+ SYNTAX RowStatus
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "The status of this conceptual row in the
+ intCommunityTable."
+ ::= { intCommunityEntry 5 }
+
+ intAgentIpAddress OBJECT-TYPE
+ SYNTAX IpAddress
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The IP address of this agent."
+ ::= { community 2 }
+
+ intAgentUDPPort OBJECT-TYPE
+ SYNTAX INTEGER
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The UDP port the agent listens to."
+ DEFVAL { 161 }
+ ::= { community 3 }
+
+ intAgentMaxPacketSize OBJECT-TYPE
+ SYNTAX INTEGER (484..65535)
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The maximum packet size in bytes this agent will send to a
+ manager."
+ ::= { community 4 }
+
+
+ intAddressTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF IntAddressEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "This table holds UDP related information on each known
+ management station."
+ ::= { community 5 }
+
+
+ intAddressEntry OBJECT-TYPE
+ SYNTAX IntAddressEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ ""
+ INDEX { intAddressDestination }
+ ::= { intAddressTable 1 }
+
+ IntAddressEntry ::=
+ SEQUENCE {
+ intAddressDestination IpAddress,
+ intAddressUDPPort INTEGER,
+ intAddressMaxPacketSize INTEGER (484..65535),
+ intAddressStatus RowStatus
+ }
+
+ intAddressDestination OBJECT-TYPE
+ SYNTAX IpAddress
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "The ip address of the management station."
+ ::= { intAddressEntry 1 }
+
+ intAddressUDPPort OBJECT-TYPE
+ SYNTAX INTEGER
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "The UDP port to which traps will be sent to
+ this destination."
+ DEFVAL { 162 }
+ ::= { intAddressEntry 2 }
+
+ intAddressMaxPacketSize OBJECT-TYPE
+ SYNTAX INTEGER (484..65535)
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "The maximum packet size in bytes for Messages
+ sent to this destination. The max size of a packet
+ sent to this destination will be the minumim of
+ this variable and agentMaxPacketSize.0."
+ ::= { intAddressEntry 3 }
+
+ intAddressStatus OBJECT-TYPE
+ SYNTAX RowStatus
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "The status of this conceptual row in the
+ intAddressTable."
+ ::= { intAddressEntry 4 }
+
+ intTrapDestTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF IntTrapDestEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "The intTrapDestTable defines to which destination all traps
+ for a specific community should be sent."
+ ::= { trap 1 }
+
+ intTrapDestEntry OBJECT-TYPE
+ SYNTAX IntTrapDestEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ ""
+ INDEX { intTrapDestCommunityString, intTrapDestDestination }
+ ::= { intTrapDestTable 1 }
+
+ IntTrapDestEntry ::=
+ SEQUENCE {
+ intTrapDestCommunityString DisplayString,
+ intTrapDestDestination IpAddress,
+ intTrapDestStatus RowStatus
+ }
+
+ intTrapDestCommunityString OBJECT-TYPE
+ SYNTAX DisplayString (SIZE (0..255))
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ ""
+ ::= { intTrapDestEntry 1 }
+
+ intTrapDestDestination OBJECT-TYPE
+ SYNTAX IpAddress
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ ""
+ ::= { intTrapDestEntry 2 }
+
+ intTrapDestStatus OBJECT-TYPE
+ SYNTAX RowStatus
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "The status of this conceptual row in the
+ intTrapDestTable."
+ ::= { intTrapDestEntry 3 }
+
+ intViewTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF IntViewEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "Locally held information about the MIB views
+ known to this agent.
+
+ Each MIB view is defined by two
+ collections of view subtrees: the included view
+ subtrees, and the excluded view subtrees. Every
+ such subtree, both included and excluded, is
+ defined in this table.
+
+ To determine if a particular object instance is in
+ a particular MIB view, compare the object
+ instance's OBJECT IDENTIFIER with each of the MIB
+ view's entries in this table. If none match, then
+ the object instance is not in the MIB view. If
+ one or more match, then the object instance is
+ included in, or excluded from, the MIB view
+ according to the value of viewType in the entry
+ whose value of viewSubtree has the most sub-
+ identifiers. If multiple entries match and have
+ the same number of sub-identifiers, then the
+ lexicographically greatest instance of viewType
+ determines the inclusion or exclusion.
+
+ An object instance's OBJECT IDENTIFIER X matches
+ an entry in this table when the number of sub-
+ identifiers in X is at least as many as in the
+ value of viewSubtree for the entry, and each sub-
+ identifier in the value of viewSubtree matches its
+ corresponding sub-identifier in X. Two sub-
+ identifiers match either if the corresponding bit
+ of viewMask is zero (the 'wild card' value), or if
+ they are equal.
+
+ Due to this 'wild card' capability, we introduce
+ the term, a 'family' of view subtrees, to refer to
+ the set of subtrees defined by a particular
+ combination of values of viewSubtree and viewMask.
+ In the case where no 'wild card' is defined in
+ viewMask, the family of view subtrees reduces to a
+ single view subtree."
+ ::= { view 1 }
+
+ intViewEntry OBJECT-TYPE
+ SYNTAX IntViewEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "Information on a particular family of view
+ subtrees included in or excluded from a particular
+ MIB view.
+
+ Implementations must not restrict the number of
+ families of view subtrees for a given MIB view,
+ except as dictated by resource constraints on the
+ overall number of entries in the viewTable."
+ INDEX { intViewIndex, intViewSubtree }
+ ::= { intViewTable 1 }
+
+ IntViewEntry ::=
+ SEQUENCE {
+ intViewIndex INTEGER,
+ intViewSubtree OBJECT IDENTIFIER,
+ intViewMask OCTET STRING,
+ intViewType INTEGER,
+ intViewStorageType StorageType,
+ intViewStatus RowStatus
+ }
+
+
+ intViewIndex OBJECT-TYPE
+ SYNTAX INTEGER (1..65535)
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A unique value for each MIB view. The value for
+ each MIB view must remain constant at least from
+ one re-initialization of the entity's network
+ management system to the next re-initialization."
+ ::= { intViewEntry 1 }
+
+ intViewSubtree OBJECT-TYPE
+ SYNTAX OBJECT IDENTIFIER
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A MIB subtree."
+ ::= { intViewEntry 2 }
+
+ intViewMask OBJECT-TYPE
+ SYNTAX OCTET STRING (SIZE (0..16))
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "The bit mask which, in combination with the
+ corresponding instance of viewSubtree, defines a
+ family of view subtrees.
+
+ Each bit of this bit mask corresponds to a sub-
+ identifier of viewSubtree, with the most
+ significant bit of the i-th octet of this octet
+ string value (extended if necessary, see below)
+ corresponding to the (8*i - 7)-th sub-identifier,
+ and the least significant bit of the i-th octet of
+ this octet string corresponding to the (8*i)-th
+ sub-identifier, where i is in the range 1 through
+ 16.
+
+ Each bit of this bit mask specifies whether or not
+ the corresponding sub-identifiers must match when
+ determining if an OBJECT IDENTIFIER is in this
+ family of view subtrees; a '1' indicates that an
+ exact match must occur; a '0' indicates 'wild
+ card', i.e., any sub-identifier value matches.
+
+
+ Thus, the OBJECT IDENTIFIER X of an object
+ instance is contained in a family of view subtrees
+ if the following criteria are met:
+
+ for each sub-identifier of the value of
+ viewSubtree, either:
+
+ the i-th bit of viewMask is 0, or
+
+ the i-th sub-identifier of X is equal to
+ the i-th sub-identifier of the value of
+ viewSubtree.
+
+ If the value of this bit mask is M bits long and
+ there are more than M sub-identifiers in the
+ corresponding instance of viewSubtree, then the
+ bit mask is extended with 1's to be the required
+ length.
+
+ Note that when the value of this object is the
+ zero-length string, this extension rule results in
+ a mask of all-1's being used (i.e., no 'wild
+ card'), and the family of view subtrees is the one
+ view subtree uniquely identified by the
+ corresponding instance of viewSubtree."
+ DEFVAL { ''H }
+ ::= { intViewEntry 3 }
+
+
+ intViewType OBJECT-TYPE
+ SYNTAX INTEGER {
+ included(1),
+ excluded(2)
+ }
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "The status of a particular family of view
+ subtrees within the particular
+ MIB view. The value 'included(1)' indicates that
+ the corresponding instances of viewSubtree and
+ viewMask define a family of view subtrees included
+ in the MIB view. The value 'excluded(2)'
+ indicates that the corresponding instances of
+ viewSubtree and viewMask define a family of view
+ subtrees excluded from the MIB view."
+ DEFVAL { included }
+ ::= { intViewEntry 4 }
+
+ intViewStorageType OBJECT-TYPE
+ SYNTAX StorageType
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "The storage type for this conceptual row in the
+ intViewTable."
+ DEFVAL { nonVolatile }
+ ::= { intViewEntry 5 }
+
+ intViewStatus OBJECT-TYPE
+ SYNTAX RowStatus
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "The status of this conceptual row in the
+ intViewTable."
+ ::= { intViewEntry 6 }
+
+
+
+END
diff --git a/lib/snmp/test/snmp_test_data/OLD-SNMPEA-MIB.mib b/lib/snmp/test/snmp_test_data/OLD-SNMPEA-MIB.mib
new file mode 100644
index 0000000000..dd90d0ab50
--- /dev/null
+++ b/lib/snmp/test/snmp_test_data/OLD-SNMPEA-MIB.mib
@@ -0,0 +1,487 @@
+OLD-SNMPEA-MIB DEFINITIONS ::= BEGIN
+
+ IMPORTS
+ enterprises, IpAddress
+ FROM RFC1155-SMI
+ OBJECT-TYPE
+ FROM RFC-1212
+ DisplayString
+ FROM RFC1213-MIB
+ RowStatus
+ FROM STANDARD-MIB
+ ;
+
+-- MODULE-IDENTITY
+-- LAST-UPDATED "9709220900Z"
+-- ORGANIZATION "ETX/DN/S"
+-- CONTACT-INFO
+-- " Martin Bj�rklund
+--
+-- Postal: ERICSSON SOFTWARE TECHNOLOGY AB
+-- ERLANG SYSTEMS
+-- Box 1214
+-- S-164 28 KISTA, SWEDEN
+--
+-- Tel: +46 8 719 20 89
+-- E-mail: [email protected]"
+-- DESCRIPTION
+-- "This MIB module defines MIB objects for the SNMPEA
+-- component in OTP."
+-- REVISION "9709220900Z"
+-- DESCRIPTION
+-- "The initial version of this MIB module. It is the old
+-- INTERNAL-MIB renamed."
+
+ericsson OBJECT IDENTIFIER ::= {enterprises 193}
+otp OBJECT IDENTIFIER ::= {ericsson 19}
+
+otpApplications
+ OBJECT IDENTIFIER ::= {otp 3}
+otpSnmpeaMIB OBJECT IDENTIFIER ::= { otpApplications 3 }
+otpSnmpeaMIBObjects
+ OBJECT IDENTIFIER ::= { otpSnmpeaMIB 2 }
+
+snmpeaAdm OBJECT IDENTIFIER ::= { otpSnmpeaMIBObjects 1}
+community OBJECT IDENTIFIER ::= { snmpeaAdm 1 }
+trap OBJECT IDENTIFIER ::= { snmpeaAdm 2 }
+view OBJECT IDENTIFIER ::= { snmpeaAdm 3 }
+
+
+-- Textual Conventions
+
+StorageType ::=
+ INTEGER {
+ other(1), -- eh?
+ volatile(2), -- e.g., in RAM
+ nonVolatile(3), -- e.g., in NVRAM
+ permanent(4) -- e.g., in ROM
+ }
+
+-- The Administration Group
+--
+-- This group consists of objects to configure the access for
+-- managers to the MIB tree.
+--
+-- These objects were previously defined in INTERNAL-MIB
+
+
+intCommunityTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF IntCommunityEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "This table defines access for the different
+ communities.
+
+ When a request comes from a certain ip address,
+ referring to a community string, the mib view
+ and access corresponding to these are looked up
+ in this table. Then the operation is validatated against
+ the access, and all requested objects validated against
+ the mib view."
+ ::= { community 1}
+
+intCommunityEntry OBJECT-TYPE
+ SYNTAX IntCommunityEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ ""
+ INDEX { intCommunityDestination, intCommunityString }
+ ::= { intCommunityTable 1 }
+
+IntCommunityEntry ::=
+ SEQUENCE {
+ intCommunityDestination IpAddress,
+ intCommunityString DisplayString,
+ intCommunityViewIndex INTEGER,
+ intCommunityAccess INTEGER,
+ intCommunityStatus RowStatus
+ }
+
+intCommunityDestination OBJECT-TYPE
+ SYNTAX IpAddress
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "The ip address of a management station. The special
+ ip address {0.0.0.0} is a wildcard, meaning all possible
+ ip addresses. In this way, access can be granted to all
+ ip addressed for some communities."
+ ::= { intCommunityEntry 1 }
+
+intCommunityString OBJECT-TYPE
+ SYNTAX DisplayString
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "The community string, defining the community."
+ ::= { intCommunityEntry 2 }
+
+intCommunityViewIndex OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "Identifies a mib view. Index into the
+ intViewTable."
+ ::= { intCommunityEntry 3 }
+
+intCommunityAccess OBJECT-TYPE
+ SYNTAX INTEGER { read(1), readWrite(2) }
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "Defines which operations the manager can perform
+ on the objects in the mib view."
+ ::= { intCommunityEntry 4 }
+
+intCommunityStatus OBJECT-TYPE
+ SYNTAX RowStatus
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The status of this conceptual row in the
+ intCommunityTable."
+ ::= { intCommunityEntry 5 }
+
+intAgentIpAddress OBJECT-TYPE
+ SYNTAX IpAddress
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The IP address of this agent."
+ ::= { community 2 }
+
+intAgentUDPPort OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The UDP port the agent listens to."
+ ::= { community 3 }
+
+intAgentMaxPacketSize OBJECT-TYPE
+ SYNTAX INTEGER (484..65535)
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The maximum packet size in bytes this agent will send to a
+ manager."
+ ::= { community 4 }
+
+
+intAddressTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF IntAddressEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "This table holds UDP related information on each known
+ management station."
+ ::= { community 5 }
+
+
+intAddressEntry OBJECT-TYPE
+ SYNTAX IntAddressEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ ""
+ INDEX { intAddressDestination }
+ ::= { intAddressTable 1 }
+
+IntAddressEntry ::=
+ SEQUENCE {
+ intAddressDestination IpAddress,
+ intAddressUDPPort INTEGER,
+ intAddressMaxPacketSize INTEGER (484..65535),
+ intAddressStatus RowStatus
+ }
+
+intAddressDestination OBJECT-TYPE
+ SYNTAX IpAddress
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "The ip address of the management station."
+ ::= { intAddressEntry 1 }
+
+intAddressUDPPort OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The UDP port to which traps will be sent to
+ this destination."
+ DEFVAL { 162 }
+ ::= { intAddressEntry 2 }
+
+intAddressMaxPacketSize OBJECT-TYPE
+ SYNTAX INTEGER (484..65535)
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The maximum packet size in bytes for Messages
+ sent to this destination. The max size of a packet
+ sent to this destination will be the minumim of
+ this variable and agentMaxPacketSize.0."
+ ::= { intAddressEntry 3 }
+
+intAddressStatus OBJECT-TYPE
+ SYNTAX RowStatus
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The status of this conceptual row in the
+ intAddressTable."
+ ::= { intAddressEntry 4 }
+
+intTrapDestTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF IntTrapDestEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "The intTrapDestTable defines to which destination all traps
+ for a specific community should be sent."
+ ::= { trap 1 }
+
+intTrapDestEntry OBJECT-TYPE
+ SYNTAX IntTrapDestEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ ""
+ INDEX { intTrapDestCommunityString, intTrapDestDestination }
+ ::= { intTrapDestTable 1 }
+
+IntTrapDestEntry ::=
+ SEQUENCE {
+ intTrapDestCommunityString DisplayString,
+ intTrapDestDestination IpAddress,
+ intTrapDestStatus RowStatus,
+ intTrapDestSnmpVersion INTEGER
+ }
+
+intTrapDestCommunityString OBJECT-TYPE
+ SYNTAX DisplayString (SIZE (0..255))
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ ""
+ ::= { intTrapDestEntry 1 }
+
+intTrapDestDestination OBJECT-TYPE
+ SYNTAX IpAddress
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ ""
+ ::= { intTrapDestEntry 2 }
+
+intTrapDestStatus OBJECT-TYPE
+ SYNTAX RowStatus
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The status of this conceptual row in the
+ intTrapDestTable."
+ ::= { intTrapDestEntry 3 }
+
+intTrapDestSnmpVersion OBJECT-TYPE
+ SYNTAX INTEGER { v1(1), v2(2) }
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The SNMP version of the manager. If it is v1,
+ SNMPv1Traps are sent. If it is v2, SNMPv2Traps are sent"
+ ::= { intTrapDestEntry 4 }
+
+intViewTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF IntViewEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "Locally held information about the MIB views
+ known to this agent.
+
+ Each MIB view is defined by two
+ collections of view subtrees: the included view
+ subtrees, and the excluded view subtrees. Every
+ such subtree, both included and excluded, is
+ defined in this table.
+
+ To determine if a particular object instance is in
+ a particular MIB view, compare the object
+ instance's OBJECT IDENTIFIER with each of the MIB
+ view's entries in this table. If none match, then
+ the object instance is not in the MIB view. If
+ one or more match, then the object instance is
+ included in, or excluded from, the MIB view
+ according to the value of viewType in the entry
+ whose value of viewSubtree has the most sub-
+ identifiers. If multiple entries match and have
+ the same number of sub-identifiers, then the
+ lexicographically greatest instance of viewType
+ determines the inclusion or exclusion.
+
+ An object instance's OBJECT IDENTIFIER X matches
+ an entry in this table when the number of sub-
+ identifiers in X is at least as many as in the
+ value of viewSubtree for the entry, and each sub-
+ identifier in the value of viewSubtree matches its
+ corresponding sub-identifier in X. Two sub-
+ identifiers match either if the corresponding bit
+ of viewMask is zero (the 'wild card' value), or if
+ they are equal.
+
+ Due to this 'wild card' capability, we introduce
+ the term, a 'family' of view subtrees, to refer to
+ the set of subtrees defined by a particular
+ combination of values of viewSubtree and viewMask.
+ In the case where no 'wild card' is defined in
+ viewMask, the family of view subtrees reduces to a
+ single view subtree."
+ ::= { view 1 }
+
+intViewEntry OBJECT-TYPE
+ SYNTAX IntViewEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "Information on a particular family of view
+ subtrees included in or excluded from a particular
+ MIB view.
+
+ Implementations must not restrict the number of
+ families of view subtrees for a given MIB view,
+ except as dictated by resource constraints on the
+ overall number of entries in the viewTable."
+ INDEX { intViewIndex, intViewSubtree }
+ ::= { intViewTable 1 }
+
+IntViewEntry ::=
+ SEQUENCE {
+ intViewIndex INTEGER,
+ intViewSubtree OBJECT IDENTIFIER,
+ intViewMask OCTET STRING,
+ intViewType INTEGER,
+ intViewStorageType StorageType,
+ intViewStatus RowStatus
+ }
+
+
+intViewIndex OBJECT-TYPE
+ SYNTAX INTEGER (1..65535)
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A unique value for each MIB view. The value for
+ each MIB view must remain constant at least from
+ one re-initialization of the entity's network
+ management system to the next re-initialization."
+ ::= { intViewEntry 1 }
+
+intViewSubtree OBJECT-TYPE
+ SYNTAX OBJECT IDENTIFIER
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A MIB subtree."
+ ::= { intViewEntry 2 }
+
+intViewMask OBJECT-TYPE
+ SYNTAX OCTET STRING (SIZE (0..16))
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The bit mask which, in combination with the
+ corresponding instance of viewSubtree, defines a
+ family of view subtrees.
+
+ Each bit of this bit mask corresponds to a sub-
+ identifier of viewSubtree, with the most
+ significant bit of the i-th octet of this octet
+ string value (extended if necessary, see below)
+ corresponding to the (8*i - 7)-th sub-identifier,
+ and the least significant bit of the i-th octet of
+ this octet string corresponding to the (8*i)-th
+ sub-identifier, where i is in the range 1 through
+ 16.
+
+ Each bit of this bit mask specifies whether or not
+ the corresponding sub-identifiers must match when
+ determining if an OBJECT IDENTIFIER is in this
+ family of view subtrees; a '1' indicates that an
+ exact match must occur; a '0' indicates 'wild
+ card', i.e., any sub-identifier value matches.
+
+
+ Thus, the OBJECT IDENTIFIER X of an object
+ instance is contained in a family of view subtrees
+ if the following criteria are met:
+
+ for each sub-identifier of the value of
+ viewSubtree, either:
+
+ the i-th bit of viewMask is 0, or
+
+ the i-th sub-identifier of X is equal to
+ the i-th sub-identifier of the value of
+ viewSubtree.
+
+ If the value of this bit mask is M bits long and
+ there are more than M sub-identifiers in the
+ corresponding instance of viewSubtree, then the
+ bit mask is extended with 1's to be the required
+ length.
+
+ Note that when the value of this object is the
+ zero-length string, this extension rule results in
+ a mask of all-1's being used (i.e., no 'wild
+ card'), and the family of view subtrees is the one
+ view subtree uniquely identified by the
+ corresponding instance of viewSubtree."
+ DEFVAL { ''H }
+ ::= { intViewEntry 3 }
+
+
+intViewType OBJECT-TYPE
+ SYNTAX INTEGER {
+ included(1),
+ excluded(2)
+ }
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The status of a particular family of view
+ subtrees within the particular
+ MIB view. The value 'included(1)' indicates that
+ the corresponding instances of viewSubtree and
+ viewMask define a family of view subtrees included
+ in the MIB view. The value 'excluded(2)'
+ indicates that the corresponding instances of
+ viewSubtree and viewMask define a family of view
+ subtrees excluded from the MIB view."
+ DEFVAL { included }
+ ::= { intViewEntry 4 }
+
+intViewStorageType OBJECT-TYPE
+ SYNTAX StorageType
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The storage type for this conceptual row in the
+ intViewTable."
+ DEFVAL { nonVolatile }
+ ::= { intViewEntry 5 }
+
+intViewStatus OBJECT-TYPE
+ SYNTAX RowStatus
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The status of this conceptual row in the
+ intViewTable."
+ ::= { intViewEntry 6 }
+
+END
diff --git a/lib/snmp/test/snmp_test_data/PROXY.mib b/lib/snmp/test/snmp_test_data/PROXY.mib
new file mode 100644
index 0000000000..5eb31429e7
--- /dev/null
+++ b/lib/snmp/test/snmp_test_data/PROXY.mib
@@ -0,0 +1,60 @@
+PROXY DEFINITIONS ::= BEGIN
+
+ IMPORTS
+ Counter, TimeTicks, IpAddress, enterprises
+ FROM RFC1155-SMI
+ OBJECT-TYPE
+ FROM RFC-1212
+ mgmt, NetworkAddress, IpAddress, Counter, Gauge,
+ TimeTicks
+ FROM RFC1155-SMI
+ DisplayString, mib-2
+ FROM RFC1213-MIB
+ sysContact
+ FROM STANDARD-MIB
+ OBJECT-TYPE
+ FROM RFC-1212
+ intViewSubtree
+ FROM OTP-SNMPEA-MIB;
+
+
+ericsson OBJECT IDENTIFIER ::= {enterprises 193}
+proxy OBJECT IDENTIFIER ::= { ericsson 12 }
+
+
+ proxyTest OBJECT-TYPE
+ SYNTAX DisplayString (SIZE (0..255))
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "A textual description of the entity. This value
+ should include the full name and version
+ identification of the system's hardware type,
+ software operating-system, and networking
+ software. It is mandatory that this only contain
+ printable ASCII characters."
+ ::= { proxy 1 }
+
+
+ proxyTrap TRAP-TYPE
+ ENTERPRISE ericsson
+ VARIABLES { sysContact, proxyTest }
+ DESCRIPTION
+ "A linkUp trap signifies that the sending
+ protocol entity recognizes that one of the
+ communication links represented in the agent's
+ configuration has come up."
+ ::= 3
+
+ proxyTrap2 TRAP-TYPE
+ ENTERPRISE ericsson
+ VARIABLES { sysContact, proxyTest, intViewSubtree }
+ DESCRIPTION
+ "A linkUp trap signifies that the sending
+ protocol entity recognizes that one of the
+ communication links represented in the agent's
+ configuration has come up."
+ ::= 5
+
+
+END
diff --git a/lib/snmp/test/snmp_test_data/RFC1213-MIB.mib b/lib/snmp/test/snmp_test_data/RFC1213-MIB.mib
new file mode 100644
index 0000000000..0421e64d62
--- /dev/null
+++ b/lib/snmp/test/snmp_test_data/RFC1213-MIB.mib
@@ -0,0 +1,2888 @@
+ RFC1213-MIB DEFINITIONS ::= BEGIN
+
+ IMPORTS
+ mgmt, NetworkAddress, IpAddress, Counter, Gauge,
+ TimeTicks
+ FROM RFC1155-SMI
+ OBJECT-TYPE
+ FROM RFC-1212;
+
+ -- This MIB module uses the extended OBJECT-TYPE macro as
+ -- defined in [14];
+
+
+ -- MIB-II (same prefix as MIB-I)
+
+ mib-2 OBJECT IDENTIFIER ::= { mgmt 1 }
+
+ -- textual conventions
+
+ DisplayString ::=
+ OCTET STRING
+ -- This data type is used to model textual information taken
+ -- from the NVT ASCII character set. By convention, objects
+ -- with this syntax are declared as having
+
+
+
+ --
+ -- SIZE (0..255)
+
+ PhysAddress ::=
+ OCTET STRING
+ -- This data type is used to model media addresses. For many
+ -- types of media, this will be in a binary representation.
+ -- For example, an ethernet address would be represented as
+ -- a string of 6 octets.
+
+
+ -- groups in MIB-II
+
+ system OBJECT IDENTIFIER ::= { mib-2 1 }
+
+ interfaces OBJECT IDENTIFIER ::= { mib-2 2 }
+
+ at OBJECT IDENTIFIER ::= { mib-2 3 }
+
+ ip OBJECT IDENTIFIER ::= { mib-2 4 }
+
+ icmp OBJECT IDENTIFIER ::= { mib-2 5 }
+
+ tcp OBJECT IDENTIFIER ::= { mib-2 6 }
+
+ udp OBJECT IDENTIFIER ::= { mib-2 7 }
+
+ egp OBJECT IDENTIFIER ::= { mib-2 8 }
+
+ -- historical (some say hysterical)
+ -- cmot OBJECT IDENTIFIER ::= { mib-2 9 }
+
+ transmission OBJECT IDENTIFIER ::= { mib-2 10 }
+
+ snmp OBJECT IDENTIFIER ::= { mib-2 11 }
+
+
+ -- the System group
+
+ -- Implementation of the System group is mandatory for all
+ -- systems. If an agent is not configured to have a value
+ -- for any of these variables, a string of length 0 is
+ -- returned.
+
+ sysDescr OBJECT-TYPE
+ SYNTAX DisplayString (SIZE (0..255))
+ ACCESS read-only
+ STATUS mandatory
+
+
+
+
+
+ DESCRIPTION
+ "A textual description of the entity. This value
+ should include the full name and version
+ identification of the system's hardware type,
+ software operating-system, and networking
+ software. It is mandatory that this only contain
+ printable ASCII characters."
+ ::= { system 1 }
+
+ sysObjectID OBJECT-TYPE
+ SYNTAX OBJECT IDENTIFIER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The vendor's authoritative identification of the
+ network management subsystem contained in the
+ entity. This value is allocated within the SMI
+ enterprises subtree (1.3.6.1.4.1) and provides an
+ easy and unambiguous means for determining `what
+ kind of box' is being managed. For example, if
+ vendor `Flintstones, Inc.' was assigned the
+ subtree 1.3.6.1.4.1.4242, it could assign the
+ identifier 1.3.6.1.4.1.4242.1.1 to its `Fred
+ Router'."
+ ::= { system 2 }
+
+ sysUpTime OBJECT-TYPE
+ SYNTAX TimeTicks
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The time (in hundredths of a second) since the
+ network management portion of the system was last
+ re-initialized."
+ ::= { system 3 }
+
+ sysContact OBJECT-TYPE
+ SYNTAX DisplayString (SIZE (0..255))
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The textual identification of the contact person
+ for this managed node, together with information
+ on how to contact this person."
+ ::= { system 4 }
+
+ sysName OBJECT-TYPE
+ SYNTAX DisplayString (SIZE (0..255))
+
+
+
+
+
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "An administratively-assigned name for this
+ managed node. By convention, this is the node's
+ fully-qualified domain name."
+ ::= { system 5 }
+
+ sysLocation OBJECT-TYPE
+ SYNTAX DisplayString (SIZE (0..255))
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The physical location of this node (e.g.,
+ `telephone closet, 3rd floor')."
+ ::= { system 6 }
+
+ sysServices OBJECT-TYPE
+ SYNTAX INTEGER (0..127)
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "A value which indicates the set of services that
+ this entity primarily offers.
+
+ The value is a sum. This sum initially takes the
+ value zero, Then, for each layer, L, in the range
+ 1 through 7, that this node performs transactions
+ for, 2 raised to (L - 1) is added to the sum. For
+ example, a node which performs primarily routing
+ functions would have a value of 4 (2^(3-1)). In
+ contrast, a node which is a host offering
+ application services would have a value of 72
+ (2^(4-1) + 2^(7-1)). Note that in the context of
+ the Internet suite of protocols, values should be
+ calculated accordingly:
+
+ layer functionality
+ 1 physical (e.g., repeaters)
+ 2 datalink/subnetwork (e.g., bridges)
+ 3 internet (e.g., IP gateways)
+ 4 end-to-end (e.g., IP hosts)
+ 7 applications (e.g., mail relays)
+
+ For systems including OSI protocols, layers 5 and
+ 6 may also be counted."
+ ::= { system 7 }
+
+
+
+
+
+
+ -- the Interfaces group
+
+ -- Implementation of the Interfaces group is mandatory for
+ -- all systems.
+
+ ifNumber OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of network interfaces (regardless of
+ their current state) present on this system."
+ ::= { interfaces 1 }
+
+
+ -- the Interfaces table
+
+ -- The Interfaces table contains information on the entity's
+ -- interfaces. Each interface is thought of as being
+ -- attached to a `subnetwork'. Note that this term should
+ -- not be confused with `subnet' which refers to an
+ -- addressing partitioning scheme used in the Internet suite
+ -- of protocols.
+
+ ifTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF IfEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A list of interface entries. The number of
+ entries is given by the value of ifNumber."
+ ::= { interfaces 2 }
+
+ ifEntry OBJECT-TYPE
+ SYNTAX IfEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "An interface entry containing objects at the
+ subnetwork layer and below for a particular
+ interface."
+ INDEX { ifIndex }
+ ::= { ifTable 1 }
+
+ IfEntry ::=
+ SEQUENCE {
+ ifIndex
+ INTEGER,
+ ifDescr
+ DisplayString,
+ ifType
+ INTEGER,
+ ifMtu
+ INTEGER,
+ ifSpeed
+ Gauge,
+ ifPhysAddress
+ PhysAddress,
+ ifAdminStatus
+ INTEGER,
+ ifOperStatus
+ INTEGER,
+ ifLastChange
+ TimeTicks,
+ ifInOctets
+ Counter,
+ ifInUcastPkts
+ Counter,
+ ifInNUcastPkts
+ Counter,
+ ifInDiscards
+ Counter,
+ ifInErrors
+ Counter,
+ ifInUnknownProtos
+ Counter,
+ ifOutOctets
+ Counter,
+ ifOutUcastPkts
+ Counter,
+ ifOutNUcastPkts
+ Counter,
+ ifOutDiscards
+ Counter,
+ ifOutErrors
+ Counter,
+ ifOutQLen
+ Gauge,
+ ifSpecific
+ OBJECT IDENTIFIER
+ }
+
+ ifIndex OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+
+
+
+
+
+ DESCRIPTION
+ "A unique value for each interface. Its value
+ ranges between 1 and the value of ifNumber. The
+ value for each interface must remain constant at
+ least from one re-initialization of the entity's
+ network management system to the next re-
+ initialization."
+ ::= { ifEntry 1 }
+
+ ifDescr OBJECT-TYPE
+ SYNTAX DisplayString (SIZE (0..255))
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "A textual string containing information about the
+ interface. This string should include the name of
+ the manufacturer, the product name and the version
+ of the hardware interface."
+ ::= { ifEntry 2 }
+
+ ifType OBJECT-TYPE
+ SYNTAX INTEGER {
+ other(1), -- none of the following
+ regular1822(2),
+ hdh1822(3),
+ ddn-x25(4),
+ rfc877-x25(5),
+ ethernet-csmacd(6),
+ iso88023-csmacd(7),
+ iso88024-tokenBus(8),
+ iso88025-tokenRing(9),
+ iso88026-man(10),
+ starLan(11),
+ proteon-10Mbit(12),
+ proteon-80Mbit(13),
+ hyperchannel(14),
+ fddi(15),
+ lapb(16),
+ sdlc(17),
+ ds1(18), -- T-1
+ e1(19), -- european equiv. of T-1
+ basicISDN(20),
+ primaryISDN(21), -- proprietary serial
+ propPointToPointSerial(22),
+ ppp(23),
+ softwareLoopback(24),
+ eon(25), -- CLNP over IP [11]
+ ethernet-3Mbit(26),
+
+
+
+
+
+ nsip(27), -- XNS over IP
+ slip(28), -- generic SLIP
+ ultra(29), -- ULTRA technologies
+ ds3(30), -- T-3
+ sip(31), -- SMDS
+ frame-relay(32)
+ }
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The type of interface, distinguished according to
+ the physical/link protocol(s) immediately `below'
+ the network layer in the protocol stack."
+ ::= { ifEntry 3 }
+
+ ifMtu OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The size of the largest datagram which can be
+ sent/received on the interface, specified in
+ octets. For interfaces that are used for
+ transmitting network datagrams, this is the size
+ of the largest network datagram that can be sent
+ on the interface."
+ ::= { ifEntry 4 }
+
+ ifSpeed OBJECT-TYPE
+ SYNTAX Gauge
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "An estimate of the interface's current bandwidth
+ in bits per second. For interfaces which do not
+ vary in bandwidth or for those where no accurate
+ estimation can be made, this object should contain
+ the nominal bandwidth."
+ ::= { ifEntry 5 }
+
+ ifPhysAddress OBJECT-TYPE
+ SYNTAX PhysAddress
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The interface's address at the protocol layer
+ immediately `below' the network layer in the
+ protocol stack. For interfaces which do not have
+
+
+
+
+
+ such an address (e.g., a serial line), this object
+ should contain an octet string of zero length."
+ ::= { ifEntry 6 }
+
+ ifAdminStatus OBJECT-TYPE
+ SYNTAX INTEGER {
+ up(1), -- ready to pass packets
+ down(2),
+ testing(3) -- in some test mode
+ }
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The desired state of the interface. The
+ testing(3) state indicates that no operational
+ packets can be passed."
+ ::= { ifEntry 7 }
+
+ ifOperStatus OBJECT-TYPE
+ SYNTAX INTEGER {
+ up(1), -- ready to pass packets
+ down(2),
+ testing(3) -- in some test mode
+ }
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The current operational state of the interface.
+ The testing(3) state indicates that no operational
+ packets can be passed."
+ ::= { ifEntry 8 }
+
+ ifLastChange OBJECT-TYPE
+ SYNTAX TimeTicks
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The value of sysUpTime at the time the interface
+ entered its current operational state. If the
+ current state was entered prior to the last re-
+ initialization of the local network management
+ subsystem, then this object contains a zero
+ value."
+ ::= { ifEntry 9 }
+
+ ifInOctets OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+
+
+
+
+
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of octets received on the
+ interface, including framing characters."
+ ::= { ifEntry 10 }
+
+ ifInUcastPkts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of subnetwork-unicast packets
+ delivered to a higher-layer protocol."
+ ::= { ifEntry 11 }
+
+ ifInNUcastPkts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of non-unicast (i.e., subnetwork-
+ broadcast or subnetwork-multicast) packets
+ delivered to a higher-layer protocol."
+ ::= { ifEntry 12 }
+
+ ifInDiscards OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of inbound packets which were chosen
+ to be discarded even though no errors had been
+ detected to prevent their being deliverable to a
+ higher-layer protocol. One possible reason for
+ discarding such a packet could be to free up
+ buffer space."
+ ::= { ifEntry 13 }
+
+ ifInErrors OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of inbound packets that contained
+ errors preventing them from being deliverable to a
+ higher-layer protocol."
+ ::= { ifEntry 14 }
+
+
+
+
+
+
+ ifInUnknownProtos OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of packets received via the interface
+ which were discarded because of an unknown or
+ unsupported protocol."
+ ::= { ifEntry 15 }
+
+ ifOutOctets OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of octets transmitted out of the
+ interface, including framing characters."
+ ::= { ifEntry 16 }
+
+ ifOutUcastPkts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of packets that higher-level
+ protocols requested be transmitted to a
+ subnetwork-unicast address, including those that
+ were discarded or not sent."
+ ::= { ifEntry 17 }
+
+ ifOutNUcastPkts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of packets that higher-level
+ protocols requested be transmitted to a non-
+ unicast (i.e., a subnetwork-broadcast or
+ subnetwork-multicast) address, including those
+ that were discarded or not sent."
+ ::= { ifEntry 18 }
+
+ ifOutDiscards OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of outbound packets which were chosen
+
+
+
+
+
+ to be discarded even though no errors had been
+ detected to prevent their being transmitted. One
+ possible reason for discarding such a packet could
+ be to free up buffer space."
+ ::= { ifEntry 19 }
+
+ ifOutErrors OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of outbound packets that could not be
+ transmitted because of errors."
+ ::= { ifEntry 20 }
+
+ ifOutQLen OBJECT-TYPE
+ SYNTAX Gauge
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The length of the output packet queue (in
+ packets)."
+ ::= { ifEntry 21 }
+
+ ifSpecific OBJECT-TYPE
+ SYNTAX OBJECT IDENTIFIER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "A reference to MIB definitions specific to the
+ particular media being used to realize the
+ interface. For example, if the interface is
+ realized by an ethernet, then the value of this
+ object refers to a document defining objects
+ specific to ethernet. If this information is not
+ present, its value should be set to the OBJECT
+ IDENTIFIER { 0 0 }, which is a syntatically valid
+ object identifier, and any conformant
+ implementation of ASN.1 and BER must be able to
+ generate and recognize this value."
+ ::= { ifEntry 22 }
+
+
+ -- the Address Translation group
+
+ -- Implementation of the Address Translation group is
+ -- mandatory for all systems. Note however that this group
+ -- is deprecated by MIB-II. That is, it is being included
+
+
+
+
+
+ -- solely for compatibility with MIB-I nodes, and will most
+ -- likely be excluded from MIB-III nodes. From MIB-II and
+ -- onwards, each network protocol group contains its own
+ -- address translation tables.
+
+ -- The Address Translation group contains one table which is
+ -- the union across all interfaces of the translation tables
+ -- for converting a NetworkAddress (e.g., an IP address) into
+ -- a subnetwork-specific address. For lack of a better term,
+ -- this document refers to such a subnetwork-specific address
+ -- as a `physical' address.
+
+ -- Examples of such translation tables are: for broadcast
+ -- media where ARP is in use, the translation table is
+ -- equivalent to the ARP cache; or, on an X.25 network where
+ -- non-algorithmic translation to X.121 addresses is
+ -- required, the translation table contains the
+ -- NetworkAddress to X.121 address equivalences.
+
+ atTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF AtEntry
+ ACCESS not-accessible
+ STATUS deprecated
+ DESCRIPTION
+ "The Address Translation tables contain the
+ NetworkAddress to `physical' address equivalences.
+ Some interfaces do not use translation tables for
+ determining address equivalences (e.g., DDN-X.25
+ has an algorithmic method); if all interfaces are
+ of this type, then the Address Translation table
+ is empty, i.e., has zero entries."
+ ::= { at 1 }
+
+ atEntry OBJECT-TYPE
+ SYNTAX AtEntry
+ ACCESS not-accessible
+ STATUS deprecated
+ DESCRIPTION
+ "Each entry contains one NetworkAddress to
+ `physical' address equivalence."
+ INDEX { atIfIndex,
+ atNetAddress }
+ ::= { atTable 1 }
+
+ AtEntry ::=
+ SEQUENCE {
+ atIfIndex
+ INTEGER,
+
+
+
+
+
+ atPhysAddress
+ PhysAddress,
+ atNetAddress
+ NetworkAddress
+ }
+
+ atIfIndex OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-write
+ STATUS deprecated
+ DESCRIPTION
+ "The interface on which this entry's equivalence
+ is effective. The interface identified by a
+ particular value of this index is the same
+ interface as identified by the same value of
+ ifIndex."
+ ::= { atEntry 1 }
+
+ atPhysAddress OBJECT-TYPE
+ SYNTAX PhysAddress
+ ACCESS read-write
+ STATUS deprecated
+ DESCRIPTION
+ "The media-dependent `physical' address.
+
+ Setting this object to a null string (one of zero
+ length) has the effect of invaliding the
+ corresponding entry in the atTable object. That
+ is, it effectively dissasociates the interface
+ identified with said entry from the mapping
+ identified with said entry. It is an
+ implementation-specific matter as to whether the
+ agent removes an invalidated entry from the table.
+ Accordingly, management stations must be prepared
+ to receive tabular information from agents that
+ corresponds to entries not currently in use.
+ Proper interpretation of such entries requires
+ examination of the relevant atPhysAddress object."
+ ::= { atEntry 2 }
+
+ atNetAddress OBJECT-TYPE
+ SYNTAX NetworkAddress
+ ACCESS read-write
+ STATUS deprecated
+ DESCRIPTION
+ "The NetworkAddress (e.g., the IP address)
+ corresponding to the media-dependent `physical'
+ address."
+
+
+
+
+
+ ::= { atEntry 3 }
+
+
+ -- the IP group
+
+ -- Implementation of the IP group is mandatory for all
+ -- systems.
+
+ ipForwarding OBJECT-TYPE
+ SYNTAX INTEGER {
+ forwarding(1), -- acting as a gateway
+ not-forwarding(2) -- NOT acting as a gateway
+ }
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The indication of whether this entity is acting
+ as an IP gateway in respect to the forwarding of
+ datagrams received by, but not addressed to, this
+ entity. IP gateways forward datagrams. IP hosts
+ do not (except those source-routed via the host).
+
+ Note that for some managed nodes, this object may
+ take on only a subset of the values possible.
+ Accordingly, it is appropriate for an agent to
+ return a `badValue' response if a management
+ station attempts to change this object to an
+ inappropriate value."
+ ::= { ip 1 }
+
+ ipDefaultTTL OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The default value inserted into the Time-To-Live
+ field of the IP header of datagrams originated at
+ this entity, whenever a TTL value is not supplied
+ by the transport layer protocol."
+ ::= { ip 2 }
+
+ ipInReceives OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of input datagrams received from
+ interfaces, including those received in error."
+
+
+
+
+
+ ::= { ip 3 }
+
+ ipInHdrErrors OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of input datagrams discarded due to
+ errors in their IP headers, including bad
+ checksums, version number mismatch, other format
+ errors, time-to-live exceeded, errors discovered
+ in processing their IP options, etc."
+ ::= { ip 4 }
+
+ ipInAddrErrors OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of input datagrams discarded because
+ the IP address in their IP header's destination
+ field was not a valid address to be received at
+ this entity. This count includes invalid
+ addresses (e.g., 0.0.0.0) and addresses of
+ unsupported Classes (e.g., Class E). For entities
+ which are not IP Gateways and therefore do not
+ forward datagrams, this counter includes datagrams
+ discarded because the destination address was not
+ a local address."
+ ::= { ip 5 }
+
+ ipForwDatagrams OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of input datagrams for which this
+ entity was not their final IP destination, as a
+ result of which an attempt was made to find a
+ route to forward them to that final destination.
+ In entities which do not act as IP Gateways, this
+ counter will include only those packets which were
+ Source-Routed via this entity, and the Source-
+ Route option processing was successful."
+ ::= { ip 6 }
+
+ ipInUnknownProtos OBJECT-TYPE
+ SYNTAX Counter
+
+
+
+
+
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of locally-addressed datagrams
+ received successfully but discarded because of an
+ unknown or unsupported protocol."
+ ::= { ip 7 }
+
+ ipInDiscards OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of input IP datagrams for which no
+ problems were encountered to prevent their
+ continued processing, but which were discarded
+ (e.g., for lack of buffer space). Note that this
+ counter does not include any datagrams discarded
+ while awaiting re-assembly."
+ ::= { ip 8 }
+
+ ipInDelivers OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of input datagrams successfully
+ delivered to IP user-protocols (including ICMP)."
+ ::= { ip 9 }
+
+ ipOutRequests OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of IP datagrams which local IP
+ user-protocols (including ICMP) supplied to IP in
+ requests for transmission. Note that this counter
+ does not include any datagrams counted in
+ ipForwDatagrams."
+ ::= { ip 10 }
+
+ ipOutDiscards OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of output IP datagrams for which no
+
+
+
+
+
+ problem was encountered to prevent their
+ transmission to their destination, but which were
+ discarded (e.g., for lack of buffer space). Note
+ that this counter would include datagrams counted
+ in ipForwDatagrams if any such packets met this
+ (discretionary) discard criterion."
+ ::= { ip 11 }
+
+ ipOutNoRoutes OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of IP datagrams discarded because no
+ route could be found to transmit them to their
+ destination. Note that this counter includes any
+ packets counted in ipForwDatagrams which meet this
+ `no-route' criterion. Note that this includes any
+ datagarms which a host cannot route because all of
+ its default gateways are down."
+ ::= { ip 12 }
+
+ ipReasmTimeout OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The maximum number of seconds which received
+ fragments are held while they are awaiting
+ reassembly at this entity."
+ ::= { ip 13 }
+
+ ipReasmReqds OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of IP fragments received which needed
+ to be reassembled at this entity."
+ ::= { ip 14 }
+
+ ipReasmOKs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of IP datagrams successfully re-
+ assembled."
+
+
+
+
+
+ ::= { ip 15 }
+
+ ipReasmFails OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of failures detected by the IP re-
+ assembly algorithm (for whatever reason: timed
+ out, errors, etc). Note that this is not
+ necessarily a count of discarded IP fragments
+ since some algorithms (notably the algorithm in
+ RFC 815) can lose track of the number of fragments
+ by combining them as they are received."
+ ::= { ip 16 }
+
+ ipFragOKs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of IP datagrams that have been
+ successfully fragmented at this entity."
+ ::= { ip 17 }
+
+ ipFragFails OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of IP datagrams that have been
+ discarded because they needed to be fragmented at
+ this entity but could not be, e.g., because their
+ Don't Fragment flag was set."
+ ::= { ip 18 }
+
+ ipFragCreates OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of IP datagram fragments that have
+ been generated as a result of fragmentation at
+ this entity."
+ ::= { ip 19 }
+
+
+
+
+
+
+
+
+ -- the IP address table
+
+ -- The IP address table contains this entity's IP addressing
+ -- information.
+
+ ipAddrTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF IpAddrEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "The table of addressing information relevant to
+ this entity's IP addresses."
+ ::= { ip 20 }
+
+ ipAddrEntry OBJECT-TYPE
+ SYNTAX IpAddrEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "The addressing information for one of this
+ entity's IP addresses."
+ INDEX { ipAdEntAddr }
+ ::= { ipAddrTable 1 }
+
+ IpAddrEntry ::=
+ SEQUENCE {
+ ipAdEntAddr
+ IpAddress,
+ ipAdEntIfIndex
+ INTEGER,
+ ipAdEntNetMask
+ IpAddress,
+ ipAdEntBcastAddr
+ INTEGER,
+ ipAdEntReasmMaxSize
+ INTEGER (0..65535)
+ }
+
+ ipAdEntAddr OBJECT-TYPE
+ SYNTAX IpAddress
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The IP address to which this entry's addressing
+ information pertains."
+ ::= { ipAddrEntry 1 }
+
+
+
+
+
+
+
+ ipAdEntIfIndex OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The index value which uniquely identifies the
+ interface to which this entry is applicable. The
+ interface identified by a particular value of this
+ index is the same interface as identified by the
+ same value of ifIndex."
+ ::= { ipAddrEntry 2 }
+
+ ipAdEntNetMask OBJECT-TYPE
+ SYNTAX IpAddress
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The subnet mask associated with the IP address of
+ this entry. The value of the mask is an IP
+ address with all the network bits set to 1 and all
+ the hosts bits set to 0."
+ ::= { ipAddrEntry 3 }
+
+ ipAdEntBcastAddr OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The value of the least-significant bit in the IP
+ broadcast address used for sending datagrams on
+ the (logical) interface associated with the IP
+ address of this entry. For example, when the
+ Internet standard all-ones broadcast address is
+ used, the value will be 1. This value applies to
+ both the subnet and network broadcasts addresses
+ used by the entity on this (logical) interface."
+ ::= { ipAddrEntry 4 }
+
+ ipAdEntReasmMaxSize OBJECT-TYPE
+ SYNTAX INTEGER (0..65535)
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The size of the largest IP datagram which this
+ entity can re-assemble from incoming IP fragmented
+ datagrams received on this interface."
+ ::= { ipAddrEntry 5 }
+
+
+
+
+
+
+ -- the IP routing table
+
+ -- The IP routing table contains an entry for each route
+ -- presently known to this entity.
+
+ ipRouteTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF IpRouteEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "This entity's IP Routing table."
+ ::= { ip 21 }
+
+ ipRouteEntry OBJECT-TYPE
+ SYNTAX IpRouteEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A route to a particular destination."
+ INDEX { ipRouteDest }
+ ::= { ipRouteTable 1 }
+
+ IpRouteEntry ::=
+ SEQUENCE {
+ ipRouteDest
+ IpAddress,
+ ipRouteIfIndex
+ INTEGER,
+ ipRouteMetric1
+ INTEGER,
+ ipRouteMetric2
+ INTEGER,
+ ipRouteMetric3
+ INTEGER,
+ ipRouteMetric4
+ INTEGER,
+ ipRouteNextHop
+ IpAddress,
+ ipRouteType
+ INTEGER,
+ ipRouteProto
+ INTEGER,
+ ipRouteAge
+ INTEGER,
+ ipRouteMask
+ IpAddress,
+ ipRouteMetric5
+ INTEGER,
+
+
+
+
+
+ ipRouteInfo
+ OBJECT IDENTIFIER
+ }
+
+ ipRouteDest OBJECT-TYPE
+ SYNTAX IpAddress
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The destination IP address of this route. An
+ entry with a value of 0.0.0.0 is considered a
+ default route. Multiple routes to a single
+ destination can appear in the table, but access to
+ such multiple entries is dependent on the table-
+ access mechanisms defined by the network
+ management protocol in use."
+ ::= { ipRouteEntry 1 }
+
+ ipRouteIfIndex OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The index value which uniquely identifies the
+ local interface through which the next hop of this
+ route should be reached. The interface identified
+ by a particular value of this index is the same
+ interface as identified by the same value of
+ ifIndex."
+ ::= { ipRouteEntry 2 }
+
+ ipRouteMetric1 OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The primary routing metric for this route. The
+ semantics of this metric are determined by the
+ routing-protocol specified in the route's
+ ipRouteProto value. If this metric is not used,
+ its value should be set to -1."
+ ::= { ipRouteEntry 3 }
+
+ ipRouteMetric2 OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+
+
+
+
+
+ "An alternate routing metric for this route. The
+ semantics of this metric are determined by the
+ routing-protocol specified in the route's
+ ipRouteProto value. If this metric is not used,
+ its value should be set to -1."
+ ::= { ipRouteEntry 4 }
+
+ ipRouteMetric3 OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "An alternate routing metric for this route. The
+ semantics of this metric are determined by the
+ routing-protocol specified in the route's
+ ipRouteProto value. If this metric is not used,
+ its value should be set to -1."
+ ::= { ipRouteEntry 5 }
+
+ ipRouteMetric4 OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "An alternate routing metric for this route. The
+ semantics of this metric are determined by the
+ routing-protocol specified in the route's
+ ipRouteProto value. If this metric is not used,
+ its value should be set to -1."
+ ::= { ipRouteEntry 6 }
+
+ ipRouteNextHop OBJECT-TYPE
+ SYNTAX IpAddress
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The IP address of the next hop of this route.
+ (In the case of a route bound to an interface
+ which is realized via a broadcast media, the value
+ of this field is the agent's IP address on that
+ interface.)"
+ ::= { ipRouteEntry 7 }
+
+ ipRouteType OBJECT-TYPE
+ SYNTAX INTEGER {
+ other(1), -- none of the following
+
+ invalid(2), -- an invalidated route
+
+
+
+
+
+ -- route to directly
+ direct(3), -- connected (sub-)network
+
+ -- route to a non-local
+ indirect(4) -- host/network/sub-network
+ }
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The type of route. Note that the values
+ direct(3) and indirect(4) refer to the notion of
+ direct and indirect routing in the IP
+ architecture.
+
+ Setting this object to the value invalid(2) has
+ the effect of invalidating the corresponding entry
+ in the ipRouteTable object. That is, it
+ effectively dissasociates the destination
+ identified with said entry from the route
+ identified with said entry. It is an
+ implementation-specific matter as to whether the
+ agent removes an invalidated entry from the table.
+ Accordingly, management stations must be prepared
+ to receive tabular information from agents that
+ corresponds to entries not currently in use.
+ Proper interpretation of such entries requires
+ examination of the relevant ipRouteType object."
+ ::= { ipRouteEntry 8 }
+
+ ipRouteProto OBJECT-TYPE
+ SYNTAX INTEGER {
+ other(1), -- none of the following
+
+ -- non-protocol information,
+ -- e.g., manually configured
+ local(2), -- entries
+
+ -- set via a network
+ netmgmt(3), -- management protocol
+
+ -- obtained via ICMP,
+ icmp(4), -- e.g., Redirect
+
+ -- the remaining values are
+ -- all gateway routing
+ -- protocols
+ egp(5),
+ ggp(6),
+
+
+
+
+
+ hello(7),
+ rip(8),
+ is-is(9),
+ es-is(10),
+ ciscoIgrp(11),
+ bbnSpfIgp(12),
+ ospf(13),
+ bgp(14)
+ }
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The routing mechanism via which this route was
+ learned. Inclusion of values for gateway routing
+ protocols is not intended to imply that hosts
+ should support those protocols."
+ ::= { ipRouteEntry 9 }
+
+ ipRouteAge OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The number of seconds since this route was last
+ updated or otherwise determined to be correct.
+ Note that no semantics of `too old' can be implied
+ except through knowledge of the routing protocol
+ by which the route was learned."
+ ::= { ipRouteEntry 10 }
+
+ ipRouteMask OBJECT-TYPE
+ SYNTAX IpAddress
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "Indicate the mask to be logical-ANDed with the
+ destination address before being compared to the
+ value in the ipRouteDest field. For those systems
+ that do not support arbitrary subnet masks, an
+ agent constructs the value of the ipRouteMask by
+ determining whether the value of the correspondent
+ ipRouteDest field belong to a class-A, B, or C
+ network, and then using one of:
+
+ mask network
+ 255.0.0.0 class-A
+ 255.255.0.0 class-B
+ 255.255.255.0 class-C
+
+
+
+
+
+ If the value of the ipRouteDest is 0.0.0.0 (a
+ default route), then the mask value is also
+ 0.0.0.0. It should be noted that all IP routing
+ subsystems implicitly use this mechanism."
+ ::= { ipRouteEntry 11 }
+
+ ipRouteMetric5 OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "An alternate routing metric for this route. The
+ semantics of this metric are determined by the
+ routing-protocol specified in the route's
+ ipRouteProto value. If this metric is not used,
+ its value should be set to -1."
+ ::= { ipRouteEntry 12 }
+
+ ipRouteInfo OBJECT-TYPE
+ SYNTAX OBJECT IDENTIFIER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "A reference to MIB definitions specific to the
+ particular routing protocol which is responsible
+ for this route, as determined by the value
+ specified in the route's ipRouteProto value. If
+ this information is not present, its value should
+ be set to the OBJECT IDENTIFIER { 0 0 }, which is
+ a syntatically valid object identifier, and any
+ conformant implementation of ASN.1 and BER must be
+ able to generate and recognize this value."
+ ::= { ipRouteEntry 13 }
+
+
+ -- the IP Address Translation table
+
+ -- The IP address translation table contain the IpAddress to
+ -- `physical' address equivalences. Some interfaces do not
+ -- use translation tables for determining address
+ -- equivalences (e.g., DDN-X.25 has an algorithmic method);
+ -- if all interfaces are of this type, then the Address
+ -- Translation table is empty, i.e., has zero entries.
+
+ ipNetToMediaTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF IpNetToMediaEntry
+ ACCESS not-accessible
+ STATUS mandatory
+
+
+
+
+
+ DESCRIPTION
+ "The IP Address Translation table used for mapping
+ from IP addresses to physical addresses."
+ ::= { ip 22 }
+
+ ipNetToMediaEntry OBJECT-TYPE
+ SYNTAX IpNetToMediaEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "Each entry contains one IpAddress to `physical'
+ address equivalence."
+ INDEX { ipNetToMediaIfIndex,
+ ipNetToMediaNetAddress }
+ ::= { ipNetToMediaTable 1 }
+
+ IpNetToMediaEntry ::=
+ SEQUENCE {
+ ipNetToMediaIfIndex
+ INTEGER,
+ ipNetToMediaPhysAddress
+ PhysAddress,
+ ipNetToMediaNetAddress
+ IpAddress,
+ ipNetToMediaType
+ INTEGER
+ }
+
+ ipNetToMediaIfIndex OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The interface on which this entry's equivalence
+ is effective. The interface identified by a
+ particular value of this index is the same
+ interface as identified by the same value of
+ ifIndex."
+ ::= { ipNetToMediaEntry 1 }
+
+ ipNetToMediaPhysAddress OBJECT-TYPE
+ SYNTAX PhysAddress
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The media-dependent `physical' address."
+ ::= { ipNetToMediaEntry 2 }
+
+
+
+
+
+
+ ipNetToMediaNetAddress OBJECT-TYPE
+ SYNTAX IpAddress
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The IpAddress corresponding to the media-
+ dependent `physical' address."
+ ::= { ipNetToMediaEntry 3 }
+
+ ipNetToMediaType OBJECT-TYPE
+ SYNTAX INTEGER {
+ other(1), -- none of the following
+ invalid(2), -- an invalidated mapping
+ dynamic(3),
+ static(4)
+ }
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The type of mapping.
+
+ Setting this object to the value invalid(2) has
+ the effect of invalidating the corresponding entry
+ in the ipNetToMediaTable. That is, it effectively
+ dissasociates the interface identified with said
+ entry from the mapping identified with said entry.
+ It is an implementation-specific matter as to
+ whether the agent removes an invalidated entry
+ from the table. Accordingly, management stations
+ must be prepared to receive tabular information
+ from agents that corresponds to entries not
+ currently in use. Proper interpretation of such
+ entries requires examination of the relevant
+ ipNetToMediaType object."
+ ::= { ipNetToMediaEntry 4 }
+
+
+ -- additional IP objects
+
+ ipRoutingDiscards OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of routing entries which were chosen
+ to be discarded even though they are valid. One
+ possible reason for discarding such an entry could
+ be to free-up buffer space for other routing
+
+
+
+
+
+ entries."
+ ::= { ip 23 }
+
+
+ -- the ICMP group
+
+ -- Implementation of the ICMP group is mandatory for all
+ -- systems.
+
+ icmpInMsgs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of ICMP messages which the
+ entity received. Note that this counter includes
+ all those counted by icmpInErrors."
+ ::= { icmp 1 }
+
+ icmpInErrors OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP messages which the entity
+ received but determined as having ICMP-specific
+ errors (bad ICMP checksums, bad length, etc.)."
+ ::= { icmp 2 }
+
+ icmpInDestUnreachs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Destination Unreachable
+ messages received."
+ ::= { icmp 3 }
+
+ icmpInTimeExcds OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Time Exceeded messages
+ received."
+ ::= { icmp 4 }
+
+
+
+
+
+
+
+ icmpInParmProbs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Parameter Problem messages
+ received."
+ ::= { icmp 5 }
+
+ icmpInSrcQuenchs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Source Quench messages
+ received."
+ ::= { icmp 6 }
+
+ icmpInRedirects OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Redirect messages received."
+ ::= { icmp 7 }
+
+ icmpInEchos OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Echo (request) messages
+ received."
+ ::= { icmp 8 }
+
+ icmpInEchoReps OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Echo Reply messages received."
+ ::= { icmp 9 }
+
+ icmpInTimestamps OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+
+
+
+
+
+ "The number of ICMP Timestamp (request) messages
+ received."
+ ::= { icmp 10 }
+
+ icmpInTimestampReps OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Timestamp Reply messages
+ received."
+ ::= { icmp 11 }
+
+ icmpInAddrMasks OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Address Mask Request messages
+ received."
+ ::= { icmp 12 }
+
+ icmpInAddrMaskReps OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Address Mask Reply messages
+ received."
+ ::= { icmp 13 }
+
+ icmpOutMsgs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of ICMP messages which this
+ entity attempted to send. Note that this counter
+ includes all those counted by icmpOutErrors."
+ ::= { icmp 14 }
+
+ icmpOutErrors OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP messages which this entity did
+ not send due to problems discovered within ICMP
+
+
+
+
+
+ such as a lack of buffers. This value should not
+ include errors discovered outside the ICMP layer
+ such as the inability of IP to route the resultant
+ datagram. In some implementations there may be no
+ types of error which contribute to this counter's
+ value."
+ ::= { icmp 15 }
+
+ icmpOutDestUnreachs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Destination Unreachable
+ messages sent."
+ ::= { icmp 16 }
+
+ icmpOutTimeExcds OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Time Exceeded messages sent."
+ ::= { icmp 17 }
+
+ icmpOutParmProbs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Parameter Problem messages
+ sent."
+ ::= { icmp 18 }
+
+ icmpOutSrcQuenchs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Source Quench messages sent."
+ ::= { icmp 19 }
+
+ icmpOutRedirects OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Redirect messages sent. For a
+
+
+
+
+
+ host, this object will always be zero, since hosts
+ do not send redirects."
+ ::= { icmp 20 }
+
+ icmpOutEchos OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Echo (request) messages sent."
+ ::= { icmp 21 }
+
+ icmpOutEchoReps OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Echo Reply messages sent."
+ ::= { icmp 22 }
+
+ icmpOutTimestamps OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Timestamp (request) messages
+ sent."
+ ::= { icmp 23 }
+
+ icmpOutTimestampReps OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Timestamp Reply messages
+ sent."
+ ::= { icmp 24 }
+
+ icmpOutAddrMasks OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Address Mask Request messages
+ sent."
+ ::= { icmp 25 }
+
+
+
+
+
+
+
+ icmpOutAddrMaskReps OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Address Mask Reply messages
+ sent."
+ ::= { icmp 26 }
+
+
+ -- the TCP group
+
+ -- Implementation of the TCP group is mandatory for all
+ -- systems that implement the TCP.
+
+ -- Note that instances of object types that represent
+ -- information about a particular TCP connection are
+ -- transient; they persist only as long as the connection
+ -- in question.
+
+ tcpRtoAlgorithm OBJECT-TYPE
+ SYNTAX INTEGER {
+ other(1), -- none of the following
+
+ constant(2), -- a constant rto
+ rsre(3), -- MIL-STD-1778, Appendix B
+ vanj(4) -- Van Jacobson's algorithm [10]
+ }
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The algorithm used to determine the timeout value
+ used for retransmitting unacknowledged octets."
+ ::= { tcp 1 }
+
+ tcpRtoMin OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The minimum value permitted by a TCP
+ implementation for the retransmission timeout,
+ measured in milliseconds. More refined semantics
+ for objects of this type depend upon the algorithm
+ used to determine the retransmission timeout. In
+ particular, when the timeout algorithm is rsre(3),
+ an object of this type has the semantics of the
+ LBOUND quantity described in RFC 793."
+
+
+
+
+
+ ::= { tcp 2 }
+
+
+ tcpRtoMax OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The maximum value permitted by a TCP
+ implementation for the retransmission timeout,
+ measured in milliseconds. More refined semantics
+ for objects of this type depend upon the algorithm
+ used to determine the retransmission timeout. In
+ particular, when the timeout algorithm is rsre(3),
+ an object of this type has the semantics of the
+ UBOUND quantity described in RFC 793."
+ ::= { tcp 3 }
+
+ tcpMaxConn OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The limit on the total number of TCP connections
+ the entity can support. In entities where the
+ maximum number of connections is dynamic, this
+ object should contain the value -1."
+ ::= { tcp 4 }
+
+ tcpActiveOpens OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of times TCP connections have made a
+ direct transition to the SYN-SENT state from the
+ CLOSED state."
+ ::= { tcp 5 }
+
+ tcpPassiveOpens OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of times TCP connections have made a
+ direct transition to the SYN-RCVD state from the
+ LISTEN state."
+ ::= { tcp 6 }
+
+
+
+
+
+ tcpAttemptFails OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of times TCP connections have made a
+ direct transition to the CLOSED state from either
+ the SYN-SENT state or the SYN-RCVD state, plus the
+ number of times TCP connections have made a direct
+ transition to the LISTEN state from the SYN-RCVD
+ state."
+ ::= { tcp 7 }
+
+ tcpEstabResets OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of times TCP connections have made a
+ direct transition to the CLOSED state from either
+ the ESTABLISHED state or the CLOSE-WAIT state."
+ ::= { tcp 8 }
+
+ tcpCurrEstab OBJECT-TYPE
+ SYNTAX Gauge
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of TCP connections for which the
+ current state is either ESTABLISHED or CLOSE-
+ WAIT."
+ ::= { tcp 9 }
+
+ tcpInSegs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of segments received, including
+ those received in error. This count includes
+ segments received on currently established
+ connections."
+ ::= { tcp 10 }
+
+ tcpOutSegs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+
+
+
+
+
+ DESCRIPTION
+ "The total number of segments sent, including
+ those on current connections but excluding those
+ containing only retransmitted octets."
+ ::= { tcp 11 }
+
+ tcpRetransSegs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of segments retransmitted - that
+ is, the number of TCP segments transmitted
+ containing one or more previously transmitted
+ octets."
+ ::= { tcp 12 }
+
+
+ -- the TCP Connection table
+
+ -- The TCP connection table contains information about this
+ -- entity's existing TCP connections.
+
+ tcpConnTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF TcpConnEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A table containing TCP connection-specific
+ information."
+ ::= { tcp 13 }
+
+ tcpConnEntry OBJECT-TYPE
+ SYNTAX TcpConnEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "Information about a particular current TCP
+ connection. An object of this type is transient,
+ in that it ceases to exist when (or soon after)
+ the connection makes the transition to the CLOSED
+ state."
+ INDEX { tcpConnLocalAddress,
+ tcpConnLocalPort,
+ tcpConnRemAddress,
+ tcpConnRemPort }
+ ::= { tcpConnTable 1 }
+
+
+
+
+
+
+ TcpConnEntry ::=
+ SEQUENCE {
+ tcpConnState
+ INTEGER,
+ tcpConnLocalAddress
+ IpAddress,
+ tcpConnLocalPort
+ INTEGER (0..65535),
+ tcpConnRemAddress
+ IpAddress,
+ tcpConnRemPort
+ INTEGER (0..65535)
+ }
+
+ tcpConnState OBJECT-TYPE
+ SYNTAX INTEGER {
+ closed(1),
+ listen(2),
+ synSent(3),
+ synReceived(4),
+ established(5),
+ finWait1(6),
+ finWait2(7),
+ closeWait(8),
+ lastAck(9),
+ closing(10),
+ timeWait(11),
+ deleteTCB(12)
+ }
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The state of this TCP connection.
+
+ The only value which may be set by a management
+ station is deleteTCB(12). Accordingly, it is
+ appropriate for an agent to return a `badValue'
+ response if a management station attempts to set
+ this object to any other value.
+
+ If a management station sets this object to the
+ value deleteTCB(12), then this has the effect of
+ deleting the TCB (as defined in RFC 793) of the
+ corresponding connection on the managed node,
+ resulting in immediate termination of the
+ connection.
+
+ As an implementation-specific option, a RST
+
+
+
+
+
+ segment may be sent from the managed node to the
+ other TCP endpoint (note however that RST segments
+ are not sent reliably)."
+ ::= { tcpConnEntry 1 }
+
+ tcpConnLocalAddress OBJECT-TYPE
+ SYNTAX IpAddress
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The local IP address for this TCP connection. In
+ the case of a connection in the listen state which
+ is willing to accept connections for any IP
+ interface associated with the node, the value
+ 0.0.0.0 is used."
+ ::= { tcpConnEntry 2 }
+
+ tcpConnLocalPort OBJECT-TYPE
+ SYNTAX INTEGER (0..65535)
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The local port number for this TCP connection."
+ ::= { tcpConnEntry 3 }
+
+ tcpConnRemAddress OBJECT-TYPE
+ SYNTAX IpAddress
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The remote IP address for this TCP connection."
+ ::= { tcpConnEntry 4 }
+
+ tcpConnRemPort OBJECT-TYPE
+ SYNTAX INTEGER (0..65535)
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The remote port number for this TCP connection."
+ ::= { tcpConnEntry 5 }
+
+
+ -- additional TCP objects
+
+ tcpInErrs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+
+
+
+
+
+ DESCRIPTION
+ "The total number of segments received in error
+ (e.g., bad TCP checksums)."
+ ::= { tcp 14 }
+
+ tcpOutRsts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of TCP segments sent containing the
+ RST flag."
+ ::= { tcp 15 }
+
+
+ -- the UDP group
+
+ -- Implementation of the UDP group is mandatory for all
+ -- systems which implement the UDP.
+
+ udpInDatagrams OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of UDP datagrams delivered to
+ UDP users."
+ ::= { udp 1 }
+
+ udpNoPorts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of received UDP datagrams for
+ which there was no application at the destination
+ port."
+ ::= { udp 2 }
+
+ udpInErrors OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of received UDP datagrams that could
+ not be delivered for reasons other than the lack
+ of an application at the destination port."
+ ::= { udp 3 }
+
+
+
+
+
+ udpOutDatagrams OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of UDP datagrams sent from this
+ entity."
+ ::= { udp 4 }
+
+
+ -- the UDP Listener table
+
+ -- The UDP listener table contains information about this
+ -- entity's UDP end-points on which a local application is
+ -- currently accepting datagrams.
+
+ udpTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF UdpEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A table containing UDP listener information."
+ ::= { udp 5 }
+
+ udpEntry OBJECT-TYPE
+ SYNTAX UdpEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "Information about a particular current UDP
+ listener."
+ INDEX { udpLocalAddress, udpLocalPort }
+ ::= { udpTable 1 }
+
+ UdpEntry ::=
+ SEQUENCE {
+ udpLocalAddress
+ IpAddress,
+ udpLocalPort
+ INTEGER (0..65535)
+ }
+
+ udpLocalAddress OBJECT-TYPE
+ SYNTAX IpAddress
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The local IP address for this UDP listener. In
+
+
+
+
+
+ the case of a UDP listener which is willing to
+ accept datagrams for any IP interface associated
+ with the node, the value 0.0.0.0 is used."
+ ::= { udpEntry 1 }
+
+ udpLocalPort OBJECT-TYPE
+ SYNTAX INTEGER (0..65535)
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The local port number for this UDP listener."
+ ::= { udpEntry 2 }
+
+
+ -- the EGP group
+
+ -- Implementation of the EGP group is mandatory for all
+ -- systems which implement the EGP.
+
+ egpInMsgs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of EGP messages received without
+ error."
+ ::= { egp 1 }
+
+ egpInErrors OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of EGP messages received that proved
+ to be in error."
+ ::= { egp 2 }
+
+ egpOutMsgs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of locally generated EGP
+ messages."
+ ::= { egp 3 }
+
+ egpOutErrors OBJECT-TYPE
+ SYNTAX Counter
+
+
+
+
+
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of locally generated EGP messages not
+ sent due to resource limitations within an EGP
+ entity."
+ ::= { egp 4 }
+
+
+ -- the EGP Neighbor table
+
+ -- The EGP neighbor table contains information about this
+ -- entity's EGP neighbors.
+
+ egpNeighTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF EgpNeighEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "The EGP neighbor table."
+ ::= { egp 5 }
+
+ egpNeighEntry OBJECT-TYPE
+ SYNTAX EgpNeighEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "Information about this entity's relationship with
+ a particular EGP neighbor."
+ INDEX { egpNeighAddr }
+ ::= { egpNeighTable 1 }
+
+ EgpNeighEntry ::=
+ SEQUENCE {
+ egpNeighState
+ INTEGER,
+ egpNeighAddr
+ IpAddress,
+ egpNeighAs
+ INTEGER,
+ egpNeighInMsgs
+ Counter,
+ egpNeighInErrs
+ Counter,
+ egpNeighOutMsgs
+ Counter,
+ egpNeighOutErrs
+ Counter,
+
+
+
+
+
+ egpNeighInErrMsgs
+ Counter,
+ egpNeighOutErrMsgs
+ Counter,
+ egpNeighStateUps
+ Counter,
+ egpNeighStateDowns
+ Counter,
+ egpNeighIntervalHello
+ INTEGER,
+ egpNeighIntervalPoll
+ INTEGER,
+ egpNeighMode
+ INTEGER,
+ egpNeighEventTrigger
+ INTEGER
+ }
+
+ egpNeighState OBJECT-TYPE
+ SYNTAX INTEGER {
+ idle(1),
+ acquisition(2),
+ down(3),
+ up(4),
+ cease(5)
+ }
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The EGP state of the local system with respect to
+ this entry's EGP neighbor. Each EGP state is
+ represented by a value that is one greater than
+ the numerical value associated with said state in
+ RFC 904."
+ ::= { egpNeighEntry 1 }
+
+ egpNeighAddr OBJECT-TYPE
+ SYNTAX IpAddress
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The IP address of this entry's EGP neighbor."
+ ::= { egpNeighEntry 2 }
+
+ egpNeighAs OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+
+
+
+
+
+ DESCRIPTION
+ "The autonomous system of this EGP peer. Zero
+ should be specified if the autonomous system
+ number of the neighbor is not yet known."
+ ::= { egpNeighEntry 3 }
+
+ egpNeighInMsgs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of EGP messages received without error
+ from this EGP peer."
+ ::= { egpNeighEntry 4 }
+
+ egpNeighInErrs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of EGP messages received from this EGP
+ peer that proved to be in error (e.g., bad EGP
+ checksum)."
+ ::= { egpNeighEntry 5 }
+
+ egpNeighOutMsgs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of locally generated EGP messages to
+ this EGP peer."
+ ::= { egpNeighEntry 6 }
+
+ egpNeighOutErrs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of locally generated EGP messages not
+ sent to this EGP peer due to resource limitations
+ within an EGP entity."
+ ::= { egpNeighEntry 7 }
+
+ egpNeighInErrMsgs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+
+
+
+
+
+ DESCRIPTION
+ "The number of EGP-defined error messages received
+ from this EGP peer."
+ ::= { egpNeighEntry 8 }
+
+ egpNeighOutErrMsgs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of EGP-defined error messages sent to
+ this EGP peer."
+ ::= { egpNeighEntry 9 }
+
+ egpNeighStateUps OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of EGP state transitions to the UP
+ state with this EGP peer."
+ ::= { egpNeighEntry 10 }
+
+ egpNeighStateDowns OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of EGP state transitions from the UP
+ state to any other state with this EGP peer."
+ ::= { egpNeighEntry 11 }
+
+ egpNeighIntervalHello OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The interval between EGP Hello command
+ retransmissions (in hundredths of a second). This
+ represents the t1 timer as defined in RFC 904."
+ ::= { egpNeighEntry 12 }
+
+ egpNeighIntervalPoll OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The interval between EGP poll command
+
+
+
+
+
+ retransmissions (in hundredths of a second). This
+ represents the t3 timer as defined in RFC 904."
+ ::= { egpNeighEntry 13 }
+
+ egpNeighMode OBJECT-TYPE
+ SYNTAX INTEGER { active(1), passive(2) }
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The polling mode of this EGP entity, either
+ passive or active."
+ ::= { egpNeighEntry 14 }
+
+ egpNeighEventTrigger OBJECT-TYPE
+ SYNTAX INTEGER { start(1), stop(2) }
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "A control variable used to trigger operator-
+ initiated Start and Stop events. When read, this
+ variable always returns the most recent value that
+ egpNeighEventTrigger was set to. If it has not
+ been set since the last initialization of the
+ network management subsystem on the node, it
+ returns a value of `stop'.
+
+ When set, this variable causes a Start or Stop
+ event on the specified neighbor, as specified on
+ pages 8-10 of RFC 904. Briefly, a Start event
+ causes an Idle peer to begin neighbor acquisition
+ and a non-Idle peer to reinitiate neighbor
+ acquisition. A stop event causes a non-Idle peer
+ to return to the Idle state until a Start event
+ occurs, either via egpNeighEventTrigger or
+ otherwise."
+ ::= { egpNeighEntry 15 }
+
+
+ -- additional EGP objects
+
+ egpAs OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The autonomous system number of this EGP entity."
+ ::= { egp 6 }
+
+
+
+
+
+
+ -- the Transmission group
+
+ -- Based on the transmission media underlying each interface
+ -- on a system, the corresponding portion of the Transmission
+ -- group is mandatory for that system.
+
+ -- When Internet-standard definitions for managing
+ -- transmission media are defined, the transmission group is
+ -- used to provide a prefix for the names of those objects.
+
+ -- Typically, such definitions reside in the experimental
+ -- portion of the MIB until they are "proven", then as a
+ -- part of the Internet standardization process, the
+ -- definitions are accordingly elevated and a new object
+ -- identifier, under the transmission group is defined. By
+ -- convention, the name assigned is:
+ --
+ -- type OBJECT IDENTIFIER ::= { transmission number }
+ --
+ -- where "type" is the symbolic value used for the media in
+ -- the ifType column of the ifTable object, and "number" is
+ -- the actual integer value corresponding to the symbol.
+
+
+ -- the SNMP group
+
+ -- Implementation of the SNMP group is mandatory for all
+ -- systems which support an SNMP protocol entity. Some of
+ -- the objects defined below will be zero-valued in those
+ -- SNMP implementations that are optimized to support only
+ -- those functions specific to either a management agent or
+ -- a management station. In particular, it should be
+ -- observed that the objects below refer to an SNMP entity,
+ -- and there may be several SNMP entities residing on a
+ -- managed node (e.g., if the node is hosting acting as
+ -- a management station).
+
+ snmpInPkts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of Messages delivered to the
+ SNMP entity from the transport service."
+ ::= { snmp 1 }
+
+ snmpOutPkts OBJECT-TYPE
+ SYNTAX Counter
+
+
+
+
+
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Messages which were
+ passed from the SNMP protocol entity to the
+ transport service."
+ ::= { snmp 2 }
+
+ snmpInBadVersions OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Messages which were
+ delivered to the SNMP protocol entity and were for
+ an unsupported SNMP version."
+ ::= { snmp 3 }
+
+ snmpInBadCommunityNames OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Messages delivered to
+ the SNMP protocol entity which used a SNMP
+ community name not known to said entity."
+ ::= { snmp 4 }
+
+ snmpInBadCommunityUses OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Messages delivered to
+ the SNMP protocol entity which represented an SNMP
+ operation which was not allowed by the SNMP
+ community named in the Message."
+ ::= { snmp 5 }
+
+ snmpInASNParseErrs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of ASN.1 or BER errors
+ encountered by the SNMP protocol entity when
+ decoding received SNMP Messages."
+ ::= { snmp 6 }
+
+
+
+
+
+ -- { snmp 7 } is not used
+
+ snmpInTooBigs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP PDUs which were
+ delivered to the SNMP protocol entity and for
+ which the value of the error-status field is
+ `tooBig'."
+ ::= { snmp 8 }
+
+ snmpInNoSuchNames OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP PDUs which were
+ delivered to the SNMP protocol entity and for
+ which the value of the error-status field is
+ `noSuchName'."
+ ::= { snmp 9 }
+
+ snmpInBadValues OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP PDUs which were
+ delivered to the SNMP protocol entity and for
+ which the value of the error-status field is
+ `badValue'."
+ ::= { snmp 10 }
+
+ snmpInReadOnlys OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number valid SNMP PDUs which were
+ delivered to the SNMP protocol entity and for
+ which the value of the error-status field is
+ `readOnly'. It should be noted that it is a
+ protocol error to generate an SNMP PDU which
+ contains the value `readOnly' in the error-status
+ field, as such this object is provided as a means
+ of detecting incorrect implementations of the
+
+
+
+
+
+ SNMP."
+ ::= { snmp 11 }
+
+ snmpInGenErrs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP PDUs which were
+ delivered to the SNMP protocol entity and for
+ which the value of the error-status field is
+ `genErr'."
+ ::= { snmp 12 }
+
+ snmpInTotalReqVars OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of MIB objects which have been
+ retrieved successfully by the SNMP protocol entity
+ as the result of receiving valid SNMP Get-Request
+ and Get-Next PDUs."
+ ::= { snmp 13 }
+
+ snmpInTotalSetVars OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of MIB objects which have been
+ altered successfully by the SNMP protocol entity
+ as the result of receiving valid SNMP Set-Request
+ PDUs."
+ ::= { snmp 14 }
+
+ snmpInGetRequests OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Get-Request PDUs which
+ have been accepted and processed by the SNMP
+ protocol entity."
+ ::= { snmp 15 }
+
+ snmpInGetNexts OBJECT-TYPE
+ SYNTAX Counter
+
+
+
+
+
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Get-Next PDUs which have
+ been accepted and processed by the SNMP protocol
+ entity."
+ ::= { snmp 16 }
+
+ snmpInSetRequests OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Set-Request PDUs which
+ have been accepted and processed by the SNMP
+ protocol entity."
+ ::= { snmp 17 }
+
+ snmpInGetResponses OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Get-Response PDUs which
+ have been accepted and processed by the SNMP
+ protocol entity."
+ ::= { snmp 18 }
+
+ snmpInTraps OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Trap PDUs which have
+ been accepted and processed by the SNMP protocol
+ entity."
+ ::= { snmp 19 }
+
+ snmpOutTooBigs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP PDUs which were
+ generated by the SNMP protocol entity and for
+ which the value of the error-status field is
+ `tooBig.'"
+ ::= { snmp 20 }
+
+
+
+
+
+ snmpOutNoSuchNames OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP PDUs which were
+ generated by the SNMP protocol entity and for
+ which the value of the error-status is
+ `noSuchName'."
+ ::= { snmp 21 }
+
+ snmpOutBadValues OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP PDUs which were
+ generated by the SNMP protocol entity and for
+ which the value of the error-status field is
+ `badValue'."
+ ::= { snmp 22 }
+
+ -- { snmp 23 } is not used
+
+ snmpOutGenErrs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP PDUs which were
+ generated by the SNMP protocol entity and for
+ which the value of the error-status field is
+ `genErr'."
+ ::= { snmp 24 }
+
+ snmpOutGetRequests OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Get-Request PDUs which
+ have been generated by the SNMP protocol entity."
+ ::= { snmp 25 }
+
+ snmpOutGetNexts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+
+
+
+
+
+ DESCRIPTION
+ "The total number of SNMP Get-Next PDUs which have
+ been generated by the SNMP protocol entity."
+ ::= { snmp 26 }
+
+ snmpOutSetRequests OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Set-Request PDUs which
+ have been generated by the SNMP protocol entity."
+ ::= { snmp 27 }
+
+ snmpOutGetResponses OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Get-Response PDUs which
+ have been generated by the SNMP protocol entity."
+ ::= { snmp 28 }
+
+ snmpOutTraps OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Trap PDUs which have
+ been generated by the SNMP protocol entity."
+ ::= { snmp 29 }
+
+ snmpEnableAuthenTraps OBJECT-TYPE
+ SYNTAX INTEGER { enabled(1), disabled(2) }
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "Indicates whether the SNMP agent process is
+ permitted to generate authentication-failure
+ traps. The value of this object overrides any
+ configuration information; as such, it provides a
+ means whereby all authentication-failure traps may
+ be disabled.
+
+ Note that it is strongly recommended that this
+ object be stored in non-volatile memory so that it
+ remains constant between re-initializations of the
+ network management system."
+
+
+
+
+
+ ::= { snmp 30 }
+
+ END
+
diff --git a/lib/snmp/test/snmp_test_data/SA-MIB.funcs b/lib/snmp/test/snmp_test_data/SA-MIB.funcs
new file mode 100644
index 0000000000..71757beb6f
--- /dev/null
+++ b/lib/snmp/test/snmp_test_data/SA-MIB.funcs
@@ -0,0 +1,5 @@
+{saBadValue, {sa, sa_bad_value, []}}.
+{saGenErr, {sa, sa_gen_err, []}}.
+{saTooBig, {sa, sa_too_big, []}}.
+{saFel, {sa, sa_fel, []}}.
+{saTest, {snmp_generic, variable_func, [{saTest, volatile}]}}.
diff --git a/lib/snmp/test/snmp_test_data/SA-MIB.mib b/lib/snmp/test/snmp_test_data/SA-MIB.mib
new file mode 100644
index 0000000000..c5953ee17c
--- /dev/null
+++ b/lib/snmp/test/snmp_test_data/SA-MIB.mib
@@ -0,0 +1,93 @@
+SA-MIB DEFINITIONS ::= BEGIN
+
+ IMPORTS
+ Counter, TimeTicks, IpAddress
+ FROM RFC1155-SMI
+ OBJECT-TYPE
+ FROM RFC-1212
+ mgmt, NetworkAddress, IpAddress, Counter, Gauge,
+ TimeTicks, enterprises
+ FROM RFC1155-SMI
+ DisplayString, mib-2
+ FROM RFC1213-MIB
+ sysContact
+ FROM STANDARD-MIB
+ OBJECT-TYPE
+ FROM RFC-1212
+ intViewSubtree
+ FROM OLD-SNMPEA-MIB;
+
+
+ericsson OBJECT IDENTIFIER ::= {enterprises 193}
+sa OBJECT IDENTIFIER ::= { ericsson 2 }
+
+
+ saTest OBJECT-TYPE
+ SYNTAX DisplayString (SIZE (0..255))
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "A textual description of the entity. This value
+ should include the full name and version
+ identification of the system's hardware type,
+ software operating-system, and networking
+ software. It is mandatory that this only contain
+ printable ASCII characters."
+ ::= { sa 1 }
+
+
+ saBadValue OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The instrum is_set_ok will return badValue"
+ ::= { sa 2 }
+
+ saGenErr OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The instrum set will return genErr"
+ ::= { sa 3 }
+
+ saTooBig OBJECT-TYPE
+ SYNTAX OCTET STRING
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The instrum get will return a 500 byte list"
+ ::= { sa 4 }
+
+ saFel OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The instrumget will return undefined"
+ ::= { sa 5 }
+
+
+ saTrap TRAP-TYPE
+ ENTERPRISE ericsson
+ VARIABLES { sysContact, saTest }
+ DESCRIPTION
+ "A linkUp trap signifies that the sending
+ protocol entity recognizes that one of the
+ communication links represented in the agent's
+ configuration has come up."
+ ::= 1
+
+ saTrap2 TRAP-TYPE
+ ENTERPRISE ericsson
+ VARIABLES { sysContact, saTest, intViewSubtree }
+ DESCRIPTION
+ "A linkUp trap signifies that the sending
+ protocol entity recognizes that one of the
+ communication links represented in the agent's
+ configuration has come up."
+ ::= 2
+
+
+END
diff --git a/lib/snmp/test/snmp_test_data/SNMPv2-MIB.funcs b/lib/snmp/test/snmp_test_data/SNMPv2-MIB.funcs
new file mode 100644
index 0000000000..8fe25bb477
--- /dev/null
+++ b/lib/snmp/test/snmp_test_data/SNMPv2-MIB.funcs
@@ -0,0 +1,28 @@
+%% The system group
+{sysUpTime, {snmp_standard_mib, sys_up_time, []}}.
+{sysDescr, {snmp_generic, variable_func, [{sysDescr, permanent}]}}.
+{sysObjectID, {snmp_generic, variable_func, [{sysObjectID, permanent}]}}.
+{sysContact, {snmp_generic, variable_func, [{sysContact, permanent}]}}.
+{sysName, {snmp_generic, variable_func, [{sysName, permanent}]}}.
+{sysLocation, {snmp_generic, variable_func, [{sysLocation, permanent}]}}.
+{sysServices, {snmp_generic, variable_func, [{sysServices, permanent}]}}.
+
+{sysORLastChange, {snmp_generic, variable_func, [{sysORLastChange, volatile}]}}.
+{sysORTable, {snmp_standard_mib, sys_or_table, []}}.
+
+%% Snmp special objects
+{snmpEnableAuthenTraps, {snmp_standard_mib, snmp_enable_authen_traps, []}}.
+{snmpSetSerialNo, {snmp_standard_mib, snmp_set_serial_no, []}}.
+
+%% Counters
+{snmpInPkts, {snmp_standard_mib, variable_func, [snmpInPkts]}}.
+{snmpInBadVersions, {snmp_standard_mib, variable_func, [snmpInBadVersions]}}.
+{snmpInBadCommunityNames, {snmp_standard_mib, variable_func, [snmpInBadCommunityNames]}}.
+{snmpInBadCommunityUses, {snmp_standard_mib, variable_func, [snmpInBadCommunityUses]}}.
+{snmpInASNParseErrs, {snmp_standard_mib, variable_func, [snmpInASNParseErrs]}}.
+{snmpProxyDrops, {snmp_standard_mib, variable_func, [snmpProxyDrops]}}.
+{snmpSilentDrops, {snmp_standard_mib, variable_func, [snmpSilentDrops]}}.
+
+%% Dummy objects, included in notifications
+{snmpTrapEnterprise, {snmp_standard_mib, dummy, []}}.
+{snmpTrapOID, {snmp_standard_mib, dummy, []}}.
diff --git a/lib/snmp/test/snmp_test_data/SNMPv2-MIB.mib b/lib/snmp/test/snmp_test_data/SNMPv2-MIB.mib
new file mode 100644
index 0000000000..e45d9d91da
--- /dev/null
+++ b/lib/snmp/test/snmp_test_data/SNMPv2-MIB.mib
@@ -0,0 +1,767 @@
+SNMPv2-MIB DEFINITIONS ::= BEGIN
+
+IMPORTS
+ MODULE-IDENTITY, OBJECT-TYPE, NOTIFICATION-TYPE,
+ TimeTicks, Counter32, snmpModules, mib-2
+ FROM SNMPv2-SMI
+ DisplayString, TestAndIncr, TimeStamp
+ FROM SNMPv2-TC
+ MODULE-COMPLIANCE, OBJECT-GROUP, NOTIFICATION-GROUP
+ FROM SNMPv2-CONF;
+
+snmpMIB MODULE-IDENTITY
+ LAST-UPDATED "9511090000Z"
+ ORGANIZATION "IETF SNMPv2 Working Group"
+ CONTACT-INFO
+ " Marshall T. Rose
+
+ Postal: Dover Beach Consulting, Inc.
+ 420 Whisman Court
+ Mountain View, CA 94043-2186
+ US
+
+ Tel: +1 415 968 1052
+
+ DESCRIPTION
+ "The MIB module for SNMPv2 entities."
+ REVISION "9304010000Z"
+ DESCRIPTION
+ "The initial revision of this MIB module was published as
+ RFC 1450."
+ ::= { snmpModules 1 }
+
+
+snmpMIBObjects OBJECT IDENTIFIER ::= { snmpMIB 1 }
+
+-- ::= { snmpMIBObjects 1 } this OID is obsolete
+-- ::= { snmpMIBObjects 2 } this OID is obsolete
+-- ::= { snmpMIBObjects 3 } this OID is obsolete
+
+
+-- the System group
+--
+-- a collection of objects common to all managed systems.
+
+system OBJECT IDENTIFIER ::= { mib-2 1 }
+
+sysDescr OBJECT-TYPE
+ SYNTAX DisplayString (SIZE (0..255))
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "A textual description of the entity. This value should
+ include the full name and version identification of the
+ system's hardware type, software operating-system, and
+ networking software."
+ ::= { system 1 }
+
+sysObjectID OBJECT-TYPE
+
+
+ SYNTAX OBJECT IDENTIFIER
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The vendor's authoritative identification of the network
+ management subsystem contained in the entity. This value is
+ allocated within the SMI enterprises subtree (1.3.6.1.4.1)
+ and provides an easy and unambiguous means for determining
+ `what kind of box' is being managed. For example, if vendor
+ `Flintstones, Inc.' was assigned the subtree
+ 1.3.6.1.4.1.4242, it could assign the identifier
+ 1.3.6.1.4.1.4242.1.1 to its `Fred Router'."
+ ::= { system 2 }
+
+sysUpTime OBJECT-TYPE
+ SYNTAX TimeTicks
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The time (in hundredths of a second) since the network
+ management portion of the system was last re-initialized."
+ ::= { system 3 }
+
+sysContact OBJECT-TYPE
+ SYNTAX DisplayString (SIZE (0..255))
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The textual identification of the contact person for this
+ managed node, together with information on how to contact
+ this person. If no contact information is known, the value
+ is the zero-length string."
+ ::= { system 4 }
+
+sysName OBJECT-TYPE
+ SYNTAX DisplayString (SIZE (0..255))
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "An administratively-assigned name for this managed node.
+ By convention, this is the node's fully-qualified domain
+ name. If the name is unknown, the value is the zero-length
+ string."
+ ::= { system 5 }
+
+sysLocation OBJECT-TYPE
+ SYNTAX DisplayString (SIZE (0..255))
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The physical location of this node (e.g., `telephone
+ closet, 3rd floor'). If the location is unknown, the value
+ is the zero-length string."
+ ::= { system 6 }
+
+sysServices OBJECT-TYPE
+ SYNTAX INTEGER (0..127)
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "A value which indicates the set of services that this
+ entity may potentially offers. The value is a sum. This
+ sum initially takes the value zero, Then, for each layer, L,
+ in the range 1 through 7, that this node performs
+ transactions for, 2 raised to (L - 1) is added to the sum.
+ For example, a node which performs only routing functions
+ would have a value of 4 (2^(3-1)). In contrast, a node
+ which is a host offering application services would have a
+ value of 72 (2^(4-1) + 2^(7-1)). Note that in the context
+ of the Internet suite of protocols, values should be
+ calculated accordingly:
+
+ layer functionality
+ 1 physical (e.g., repeaters)
+ 2 datalink/subnetwork (e.g., bridges)
+ 3 internet (e.g., supports the IP)
+ 4 end-to-end (e.g., supports the TCP)
+ 7 applications (e.g., supports the SMTP)
+
+ For systems including OSI protocols, layers 5 and 6 may also
+ be counted."
+ ::= { system 7 }
+
+
+-- object resource information
+--
+-- a collection of objects which describe the SNMPv2 entity's
+-- (statically and dynamically configurable) support of
+-- various MIB modules.
+
+sysORLastChange OBJECT-TYPE
+ SYNTAX TimeStamp
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The value of sysUpTime at the time of the most recent
+ change in state or value of any instance of sysORID."
+ ::= { system 8 }
+
+sysORTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF SysOREntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "The (conceptual) table listing the capabilities of the
+ local SNMPv2 entity acting in an agent role with respect to
+ various MIB modules. SNMPv2 entities having dynamically-
+ configurable support of MIB modules will have a
+ dynamically-varying number of conceptual rows."
+ ::= { system 9 }
+
+sysOREntry OBJECT-TYPE
+ SYNTAX SysOREntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "An entry (conceptual row) in the sysORTable."
+ INDEX { sysORIndex }
+ ::= { sysORTable 1 }
+
+SysOREntry ::= SEQUENCE {
+ sysORIndex INTEGER,
+ sysORID OBJECT IDENTIFIER,
+ sysORDescr DisplayString,
+ sysORUpTime TimeStamp
+}
+
+sysORIndex OBJECT-TYPE
+ SYNTAX INTEGER (1..2147483647)
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "The auxiliary variable used for identifying instances of
+ the columnar objects in the sysORTable."
+ ::= { sysOREntry 1 }
+
+sysORID OBJECT-TYPE
+ SYNTAX OBJECT IDENTIFIER
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "An authoritative identification of a capabilities statement
+ with respect to various MIB modules supported by the local
+ SNMPv2 entity acting in an agent role."
+
+ ::= { sysOREntry 2 }
+
+sysORDescr OBJECT-TYPE
+ SYNTAX DisplayString
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "A textual description of the capabilities identified by the
+ corresponding instance of sysORID."
+ ::= { sysOREntry 3 }
+
+sysORUpTime OBJECT-TYPE
+ SYNTAX TimeStamp
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The value of sysUpTime at the time this conceptual row was
+ last instanciated."
+ ::= { sysOREntry 4 }
+
+
+-- the SNMP group
+--
+-- a collection of objects providing basic instrumentation and
+-- control of an SNMP entity.
+
+snmp OBJECT IDENTIFIER ::= { mib-2 11 }
+
+snmpInPkts OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The total number of messages delivered to the SNMP entity
+ from the transport service."
+ ::= { snmp 1 }
+
+snmpInBadVersions OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The total number of SNMP messages which were delivered to
+ the SNMP entity and were for an unsupported SNMP version."
+ ::= { snmp 3 }
+
+snmpInBadCommunityNames OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The total number of SNMP messages delivered to the SNMP
+ entity which used a SNMP community name not known to said
+ entity."
+ ::= { snmp 4 }
+
+snmpInBadCommunityUses OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The total number of SNMP messages delivered to the SNMP
+ entity which represented an SNMP operation which was not
+ allowed by the SNMP community named in the message."
+ ::= { snmp 5 }
+
+snmpInASNParseErrs OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The total number of ASN.1 or BER errors encountered by the
+ SNMP entity when decoding received SNMP messages."
+ ::= { snmp 6 }
+
+snmpEnableAuthenTraps OBJECT-TYPE
+ SYNTAX INTEGER { enabled(1), disabled(2) }
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "Indicates whether the SNMP entity is permitted to generate
+ authenticationFailure traps. The value of this object
+ overrides any configuration information; as such, it
+ provides a means whereby all authenticationFailure traps may
+ be disabled.
+
+ Note that it is strongly recommended that this object be
+ stored in non-volatile memory so that it remains constant
+ across re-initializations of the network management system."
+ ::= { snmp 30 }
+
+snmpSilentDrops OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The total number of GetRequest-PDUs, GetNextRequest-PDUs,
+ GetBulkRequest-PDUs, SetRequest-PDUs, and InformRequest-PDUs
+ delivered to the SNMP entity which were silently dropped
+ because the size of a reply containing an alternate
+ Response-PDU with an empty variable-bindings field was
+ greater than either a local constraint or the maximum
+ message size associated with the originator of the request."
+ ::= { snmp 31 }
+
+snmpProxyDrops OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The total number of GetRequest-PDUs, GetNextRequest-PDUs,
+ GetBulkRequest-PDUs, SetRequest-PDUs, and InformRequest-PDUs
+ delivered to the SNMP entity which were silently dropped
+ because the transmission of the (possibly translated)
+ message to a proxy target failed in a manner (other than a
+ time-out) such that no Response-PDU could be returned."
+ ::= { snmp 32 }
+
+
+-- information for notifications
+--
+-- a collection of objects which allow the SNMPv2 entity, when
+-- acting in an agent role, to be configured to generate
+-- SNMPv2-Trap-PDUs.
+
+snmpTrap OBJECT IDENTIFIER ::= { snmpMIBObjects 4 }
+
+
+snmpTrapOID OBJECT-TYPE
+ SYNTAX OBJECT IDENTIFIER
+ MAX-ACCESS accessible-for-notify
+ STATUS current
+ DESCRIPTION
+ "The authoritative identification of the notification
+ currently being sent. This variable occurs as the second
+ varbind in every SNMPv2-Trap-PDU and InformRequest-PDU."
+ ::= { snmpTrap 1 }
+
+-- ::= { snmpTrap 2 } this OID is obsolete
+
+snmpTrapEnterprise OBJECT-TYPE
+ SYNTAX OBJECT IDENTIFIER
+ MAX-ACCESS accessible-for-notify
+ STATUS current
+ DESCRIPTION
+ "The authoritative identification of the enterprise
+ associated with the trap currently being sent. When a
+ SNMPv2 proxy agent is mapping an RFC1157 Trap-PDU into a
+ SNMPv2-Trap-PDU, this variable occurs as the last varbind."
+ ::= { snmpTrap 3 }
+
+-- ::= { snmpTrap 4 } this OID is obsolete
+
+
+-- well-known traps
+
+snmpTraps OBJECT IDENTIFIER ::= { snmpMIBObjects 5 }
+
+coldStart NOTIFICATION-TYPE
+ STATUS current
+ DESCRIPTION
+ "A coldStart trap signifies that the SNMPv2 entity, acting
+ in an agent role, is reinitializing itself and that its
+ configuration may have been altered."
+ ::= { snmpTraps 1 }
+
+warmStart NOTIFICATION-TYPE
+ STATUS current
+ DESCRIPTION
+ "A warmStart trap signifies that the SNMPv2 entity, acting
+ in an agent role, is reinitializing itself such that its
+ configuration is unaltered."
+ ::= { snmpTraps 2 }
+
+-- Note the linkDown NOTIFICATION-TYPE ::= { snmpTraps 3 }
+-- and the linkUp NOTIFICATION-TYPE ::= { snmpTraps 4 }
+-- are defined in RFC 1573
+
+authenticationFailure NOTIFICATION-TYPE
+ STATUS current
+ DESCRIPTION
+ "An authenticationFailure trap signifies that the SNMPv2
+ entity, acting in an agent role, has received a protocol
+ message that is not properly authenticated. While all
+ implementations of the SNMPv2 must be capable of generating
+ this trap, the snmpEnableAuthenTraps object indicates
+ whether this trap will be generated."
+ ::= { snmpTraps 5 }
+
+-- Note the egpNeighborLoss NOTIFICATION-TYPE ::= { snmpTraps 6 }
+-- is defined in RFC 1213
+-- the set group
+--
+-- a collection of objects which allow several cooperating
+-- SNMPv2 entities, all acting in a manager role, to
+-- coordinate their use of the SNMPv2 set operation.
+
+snmpSet OBJECT IDENTIFIER ::= { snmpMIBObjects 6 }
+
+
+snmpSetSerialNo OBJECT-TYPE
+ SYNTAX TestAndIncr
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "An advisory lock used to allow several cooperating SNMPv2
+ entities, all acting in a manager role, to coordinate their
+ use of the SNMPv2 set operation.
+
+ This object is used for coarse-grain coordination. To
+ achieve fine-grain coordination, one or more similar objects
+ might be defined within each MIB group, as appropriate."
+ ::= { snmpSet 1 }
+
+
+-- conformance information
+
+snmpMIBConformance
+ OBJECT IDENTIFIER ::= { snmpMIB 2 }
+
+snmpMIBCompliances
+ OBJECT IDENTIFIER ::= { snmpMIBConformance 1 }
+snmpMIBGroups OBJECT IDENTIFIER ::= { snmpMIBConformance 2 }
+
+
+-- compliance statements
+
+-- ::= { snmpMIBCompliances 1 } this OID is obsolete
+
+snmpBasicCompliance MODULE-COMPLIANCE
+ STATUS current
+ DESCRIPTION
+ "The compliance statement for SNMPv2 entities which
+ implement the SNMPv2 MIB."
+ MODULE -- this module
+ MANDATORY-GROUPS { snmpGroup, snmpSetGroup, systemGroup,
+ snmpBasicNotificationsGroup }
+
+ GROUP snmpCommunityGroup
+ DESCRIPTION
+ "This group is mandatory for SNMPv2 entities which
+ support community-based authentication."
+
+ ::= { snmpMIBCompliances 2 }
+
+
+-- units of conformance
+
+-- ::= { snmpMIBGroups 1 } this OID is obsolete
+-- ::= { snmpMIBGroups 2 } this OID is obsolete
+-- ::= { snmpMIBGroups 3 } this OID is obsolete
+-- ::= { snmpMIBGroups 4 } this OID is obsolete
+
+snmpGroup OBJECT-GROUP
+ OBJECTS { snmpInPkts,
+ snmpInBadVersions,
+ snmpInASNParseErrs,
+ snmpSilentDrops,
+ snmpProxyDrops,
+ snmpEnableAuthenTraps }
+ STATUS current
+ DESCRIPTION
+ "A collection of objects providing basic instrumentation and
+ control of an SNMPv2 entity."
+ ::= { snmpMIBGroups 8 }
+
+snmpCommunityGroup OBJECT-GROUP
+ OBJECTS { snmpInBadCommunityNames,
+ snmpInBadCommunityUses }
+ STATUS current
+ DESCRIPTION
+ "A collection of objects providing basic instrumentation of
+ a SNMPv2 entity which supports community-based
+ authentication."
+ ::= { snmpMIBGroups 9 }
+
+snmpSetGroup OBJECT-GROUP
+ OBJECTS { snmpSetSerialNo }
+ STATUS current
+ DESCRIPTION
+ "A collection of objects which allow several cooperating
+ SNMPv2 entities, all acting in a manager role, to coordinate
+ their use of the SNMPv2 set operation."
+ ::= { snmpMIBGroups 5 }
+
+systemGroup OBJECT-GROUP
+ OBJECTS { sysDescr, sysObjectID, sysUpTime,
+ sysContact, sysName, sysLocation,
+ sysServices,
+ sysORLastChange, sysORID,
+ sysORUpTime, sysORDescr }
+ STATUS current
+ DESCRIPTION
+ "The system group defines objects which are common to all
+ managed systems."
+ ::= { snmpMIBGroups 6 }
+
+snmpBasicNotificationsGroup NOTIFICATION-GROUP
+ NOTIFICATIONS { coldStart, authenticationFailure }
+ STATUS current
+ DESCRIPTION
+ "The two notifications which an SNMPv2 entity is required to
+ implement."
+ ::= { snmpMIBGroups 7 }
+
+
+-- definitions in RFC 1213 made obsolete by the inclusion of a
+-- subset of the snmp group in this MIB
+
+snmpOutPkts OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS obsolete
+ DESCRIPTION
+ "The total number of SNMP Messages which were
+ passed from the SNMP protocol entity to the
+ transport service."
+ ::= { snmp 2 }
+
+-- { snmp 7 } is not used
+
+snmpInTooBigs OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS obsolete
+ DESCRIPTION
+ "The total number of SNMP PDUs which were
+ delivered to the SNMP protocol entity and for
+ which the value of the error-status field is
+ `tooBig'."
+ ::= { snmp 8 }
+
+snmpInNoSuchNames OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS obsolete
+ DESCRIPTION
+ "The total number of SNMP PDUs which were
+ delivered to the SNMP protocol entity and for
+ which the value of the error-status field is
+ `noSuchName'."
+ ::= { snmp 9 }
+
+snmpInBadValues OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS obsolete
+ DESCRIPTION
+ "The total number of SNMP PDUs which were
+ delivered to the SNMP protocol entity and for
+ which the value of the error-status field is
+ `badValue'."
+ ::= { snmp 10 }
+
+snmpInReadOnlys OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS obsolete
+ DESCRIPTION
+ "The total number valid SNMP PDUs which were
+ delivered to the SNMP protocol entity and for
+ which the value of the error-status field is
+ `readOnly'. It should be noted that it is a
+ protocol error to generate an SNMP PDU which
+ contains the value `readOnly' in the error-status
+ field, as such this object is provided as a means
+ of detecting incorrect implementations of the
+ SNMP."
+ ::= { snmp 11 }
+
+snmpInGenErrs OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS obsolete
+ DESCRIPTION
+ "The total number of SNMP PDUs which were
+ delivered to the SNMP protocol entity and for
+ which the value of the error-status field is
+ `genErr'."
+ ::= { snmp 12 }
+
+snmpInTotalReqVars OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS obsolete
+ DESCRIPTION
+ "The total number of MIB objects which have been
+ retrieved successfully by the SNMP protocol entity
+ as the result of receiving valid SNMP Get-Request
+ and Get-Next PDUs."
+ ::= { snmp 13 }
+
+snmpInTotalSetVars OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS obsolete
+ DESCRIPTION
+ "The total number of MIB objects which have been
+ altered successfully by the SNMP protocol entity
+ as the result of receiving valid SNMP Set-Request
+ PDUs."
+ ::= { snmp 14 }
+
+snmpInGetRequests OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS obsolete
+ DESCRIPTION
+ "The total number of SNMP Get-Request PDUs which
+ have been accepted and processed by the SNMP
+ protocol entity."
+ ::= { snmp 15 }
+
+snmpInGetNexts OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS obsolete
+ DESCRIPTION
+ "The total number of SNMP Get-Next PDUs which have
+ been accepted and processed by the SNMP protocol
+ entity."
+ ::= { snmp 16 }
+
+snmpInSetRequests OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS obsolete
+ DESCRIPTION
+ "The total number of SNMP Set-Request PDUs which
+ have been accepted and processed by the SNMP
+ protocol entity."
+ ::= { snmp 17 }
+
+snmpInGetResponses OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS obsolete
+ DESCRIPTION
+ "The total number of SNMP Get-Response PDUs which
+ have been accepted and processed by the SNMP
+ protocol entity."
+ ::= { snmp 18 }
+
+snmpInTraps OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS obsolete
+ DESCRIPTION
+ "The total number of SNMP Trap PDUs which have
+ been accepted and processed by the SNMP protocol
+ entity."
+ ::= { snmp 19 }
+
+snmpOutTooBigs OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS obsolete
+ DESCRIPTION
+ "The total number of SNMP PDUs which were
+ generated by the SNMP protocol entity and for
+ which the value of the error-status field is
+ `tooBig.'"
+ ::= { snmp 20 }
+
+snmpOutNoSuchNames OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS obsolete
+ DESCRIPTION
+ "The total number of SNMP PDUs which were
+ generated by the SNMP protocol entity and for
+ which the value of the error-status is
+ `noSuchName'."
+ ::= { snmp 21 }
+
+snmpOutBadValues OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS obsolete
+ DESCRIPTION
+ "The total number of SNMP PDUs which were
+ generated by the SNMP protocol entity and for
+ which the value of the error-status field is
+ `badValue'."
+ ::= { snmp 22 }
+
+
+-- { snmp 23 } is not used
+
+snmpOutGenErrs OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS obsolete
+ DESCRIPTION
+ "The total number of SNMP PDUs which were
+ generated by the SNMP protocol entity and for
+ which the value of the error-status field is
+ `genErr'."
+ ::= { snmp 24 }
+
+snmpOutGetRequests OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS obsolete
+ DESCRIPTION
+ "The total number of SNMP Get-Request PDUs which
+ have been generated by the SNMP protocol entity."
+ ::= { snmp 25 }
+
+snmpOutGetNexts OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS obsolete
+ DESCRIPTION
+ "The total number of SNMP Get-Next PDUs which have
+ been generated by the SNMP protocol entity."
+ ::= { snmp 26 }
+
+snmpOutSetRequests OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS obsolete
+ DESCRIPTION
+ "The total number of SNMP Set-Request PDUs which
+ have been generated by the SNMP protocol entity."
+ ::= { snmp 27 }
+
+snmpOutGetResponses OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS obsolete
+ DESCRIPTION
+ "The total number of SNMP Get-Response PDUs which
+ have been generated by the SNMP protocol entity."
+ ::= { snmp 28 }
+
+snmpOutTraps OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS obsolete
+ DESCRIPTION
+ "The total number of SNMP Trap PDUs which have
+ been generated by the SNMP protocol entity."
+ ::= { snmp 29 }
+
+snmpObsoleteGroup OBJECT-GROUP
+ OBJECTS { snmpOutPkts, snmpInTooBigs, snmpInNoSuchNames,
+ snmpInBadValues, snmpInReadOnlys, snmpInGenErrs,
+ snmpInTotalReqVars, snmpInTotalSetVars,
+ snmpInGetRequests, snmpInGetNexts, snmpInSetRequests,
+ snmpInGetResponses, snmpInTraps, snmpOutTooBigs,
+ snmpOutNoSuchNames, snmpOutBadValues, snmpOutGenErrs,
+ snmpOutGetRequests, snmpOutGetNexts, snmpOutSetRequests,
+ snmpOutGetResponses, snmpOutTraps }
+ STATUS obsolete
+ DESCRIPTION
+ "A collection of objects from RFC 1213 made obsolete by this
+ MIB."
+ ::= { snmpMIBGroups 10 }
+
+END
diff --git a/lib/snmp/test/snmp_test_data/STANDARD-MIB.funcs b/lib/snmp/test/snmp_test_data/STANDARD-MIB.funcs
new file mode 100644
index 0000000000..a0b105c2fd
--- /dev/null
+++ b/lib/snmp/test/snmp_test_data/STANDARD-MIB.funcs
@@ -0,0 +1,8 @@
+{sysUpTime, {snmp_standard_mib, sys_up_time, []}}.
+{sysDescr, {snmp_generic, variable_func, [{sysDescr, permanent}]}}.
+{sysObjectID, {snmp_generic, variable_func, [{sysObjectID, permanent}]}}.
+{sysContact, {snmp_generic, variable_func, [{sysContact, permanent}]}}.
+{sysName, {snmp_generic, variable_func, [{sysName, permanent}]}}.
+{sysLocation, {snmp_generic, variable_func, [{sysLocation, permanent}]}}.
+{sysServices, {snmp_generic, variable_func, [{sysServices, permanent}]}}.
+{snmpEnableAuthenTraps, {snmp_standard_mib, snmp_enable_authen_traps, []}}.
diff --git a/lib/snmp/test/snmp_test_data/STANDARD-MIB.mib b/lib/snmp/test/snmp_test_data/STANDARD-MIB.mib
new file mode 100644
index 0000000000..552b8a3e48
--- /dev/null
+++ b/lib/snmp/test/snmp_test_data/STANDARD-MIB.mib
@@ -0,0 +1,528 @@
+STANDARD-MIB DEFINITIONS ::= BEGIN
+
+ IMPORTS
+ Counter, TimeTicks
+ FROM RFC1155-SMI
+ OBJECT-TYPE
+ FROM RFC-1212
+ DisplayString, mib-2
+ FROM RFC1213-MIB
+ ;
+
+
+-- Standard Datatypes
+
+-- From SNMPv2 (rfc1903)
+TruthValue ::=
+-- Represents a boolean value
+ INTEGER { true(1), false(2) }
+
+-- From SNMPv2 (rfc1903)
+DateAndTime ::=
+-- DESCRIPTION
+-- "A date-time specification.
+--
+-- field octets contents range
+-- 1 1-2 year 0..65536
+-- 2 3 month 1..12
+-- 3 4 day 1..31
+-- 4 5 hour 0..23
+-- 5 6 minutes 0..59
+-- 6 7 seconds 0..60
+-- (use 60 for leap-second)
+-- 7 8 deci-seconds 0..9
+-- 8 9 direction from UTC '+' / '-'
+-- 9 10 hours from UTC 0..11
+-- 10 11 minutes from UTC 0..59
+--
+-- For example, Tuesday May 26, 1992 at 1:30:15 PM EDT would be
+-- displayed as:
+--
+-- 1992-5-26,13:30:15.0,-4:0
+--
+-- Note that if only local time is known, then timezone
+-- information (fields 8-10) is not present."
+ OCTET STRING (SIZE (8 | 11))
+
+-- From SNMPv2 (rfc1903)
+RowStatus ::=
+ INTEGER {
+ -- the following two values are states:
+ -- these values may be read or written
+ active(1),
+ notInService(2),
+
+ -- the following value is a state:
+ -- this value may be read, but not written
+ notReady(3),
+
+ -- the following three values are
+ -- actions: these values may be written,
+ -- but are never read
+ createAndGo(4),
+ createAndWait(5),
+ destroy(6)
+ }
+
+
+system OBJECT IDENTIFIER ::= { mib-2 1 }
+snmp OBJECT IDENTIFIER ::= { mib-2 11 }
+
+
+-- the System group
+
+-- Implementation of the System group is mandatory for all
+-- systems. If an agent is not configured to have a value
+-- for any of these variables, a string of length 0 is
+-- returned.
+
+sysDescr OBJECT-TYPE
+ SYNTAX DisplayString (SIZE (0..255))
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "A textual description of the entity. This value
+ should include the full name and version
+ identification of the system's hardware type,
+ software operating-system, and networking
+ software. It is mandatory that this only contain
+ printable ASCII characters."
+ ::= { system 1 }
+
+sysObjectID OBJECT-TYPE
+ SYNTAX OBJECT IDENTIFIER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The vendor's authoritative identification of the
+ network management subsystem contained in the
+ entity. This value is allocated within the SMI
+ enterprises subtree (1.3.6.1.4.1) and provides an
+ easy and unambiguous means for determining `what
+ kind of box' is being managed. For example, if
+ vendor `Flintstones, Inc.' was assigned the
+ subtree 1.3.6.1.4.1.4242, it could assign the
+ identifier 1.3.6.1.4.1.4242.1.1 to its `Fred
+ Router'."
+ ::= { system 2 }
+
+sysUpTime OBJECT-TYPE
+ SYNTAX TimeTicks
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The time (in hundredths of a second) since the
+ network management portion of the system was last
+ re-initialized."
+ ::= { system 3 }
+
+sysContact OBJECT-TYPE
+ SYNTAX DisplayString (SIZE (0..255))
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The textual identification of the contact person
+ for this managed node, together with information
+ on how to contact this person."
+ ::= { system 4 }
+
+sysName OBJECT-TYPE
+ SYNTAX DisplayString (SIZE (0..255))
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "An administratively-assigned name for this
+ managed node. By convention, this is the node's
+ fully-qualified domain name."
+ ::= { system 5 }
+
+sysLocation OBJECT-TYPE
+ SYNTAX DisplayString (SIZE (0..255))
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The physical location of this node (e.g.,
+ `telephone closet, 3rd floor')."
+ ::= { system 6 }
+
+sysServices OBJECT-TYPE
+ SYNTAX INTEGER (0..127)
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "A value which indicates the set of services that
+ this entity primarily offers.
+
+ The value is a sum. This sum initially takes the
+ value zero, Then, for each layer, L, in the range
+ 1 through 7, that this node performs transactions
+ for, 2 raised to (L - 1) is added to the sum. For
+ example, a node which performs primarily routing
+ functions would have a value of 4 (2^(3-1)). In
+ contrast, a node which is a host offering
+ application services would have a value of 72
+ (2^(4-1) + 2^(7-1)). Note that in the context of
+ the Internet suite of protocols, values should be
+ calculated accordingly:
+
+ layer functionality
+ 1 physical (e.g., repeaters)
+ 2 datalink/subnetwork (e.g., bridges)
+ 3 internet (e.g., IP gateways)
+ 4 end-to-end (e.g., IP hosts)
+ 7 applications (e.g., mail relays)
+
+ For systems including OSI protocols, layers 5 and
+ 6 may also be counted."
+ ::= { system 7 }
+
+
+ -- the SNMP group
+
+ -- Implementation of the SNMP group is mandatory for all
+ -- systems which support an SNMP protocol entity. Some of
+ -- the objects defined below will be zero-valued in those
+ -- SNMP implementations that are optimized to support only
+ -- those functions specific to either a management agent or
+ -- a management station. In particular, it should be
+ -- observed that the objects below refer to an SNMP entity,
+ -- and there may be several SNMP entities residing on a
+ -- managed node (e.g., if the node is hosting acting as
+ -- a management station).
+
+snmpInPkts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of Messages delivered to the
+ SNMP entity from the transport service."
+ ::= { snmp 1 }
+
+snmpOutPkts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Messages which were
+ passed from the SNMP protocol entity to the
+ transport service."
+ ::= { snmp 2 }
+
+snmpInBadVersions OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Messages which were
+ delivered to the SNMP protocol entity and were for
+ an unsupported SNMP version."
+ ::= { snmp 3 }
+
+snmpInBadCommunityNames OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Messages delivered to
+ the SNMP protocol entity which used a SNMP
+ community name not known to said entity."
+ ::= { snmp 4 }
+
+snmpInBadCommunityUses OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Messages delivered to
+ the SNMP protocol entity which represented an SNMP
+ operation which was not allowed by the SNMP
+ community named in the Message."
+ ::= { snmp 5 }
+
+snmpInASNParseErrs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of ASN.1 or BER errors
+ encountered by the SNMP protocol entity when
+ decoding received SNMP Messages."
+ ::= { snmp 6 }
+
+ -- { snmp 7 } is not used
+
+snmpInTooBigs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP PDUs which were
+ delivered to the SNMP protocol entity and for
+ which the value of the error-status field is
+ `tooBig'."
+ ::= { snmp 8 }
+
+snmpInNoSuchNames OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP PDUs which were
+ delivered to the SNMP protocol entity and for
+ which the value of the error-status field is
+ `noSuchName'."
+ ::= { snmp 9 }
+
+snmpInBadValues OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP PDUs which were
+ delivered to the SNMP protocol entity and for
+ which the value of the error-status field is
+ `badValue'."
+ ::= { snmp 10 }
+
+snmpInReadOnlys OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number valid SNMP PDUs which were
+ delivered to the SNMP protocol entity and for
+ which the value of the error-status field is
+ `readOnly'. It should be noted that it is a
+ protocol error to generate an SNMP PDU which
+ contains the value `readOnly' in the error-status
+ field, as such this object is provided as a means
+ of detecting incorrect implementations of the
+ SNMP."
+ ::= { snmp 11 }
+
+snmpInGenErrs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP PDUs which were
+ delivered to the SNMP protocol entity and for
+ which the value of the error-status field is
+ `genErr'."
+ ::= { snmp 12 }
+
+snmpInTotalReqVars OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of MIB objects which have been
+ retrieved successfully by the SNMP protocol entity
+ as the result of receiving valid SNMP Get-Request
+ and Get-Next PDUs."
+ ::= { snmp 13 }
+
+snmpInTotalSetVars OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of MIB objects which have been
+ altered successfully by the SNMP protocol entity
+ as the result of receiving valid SNMP Set-Request
+ PDUs."
+ ::= { snmp 14 }
+
+snmpInGetRequests OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Get-Request PDUs which
+ have been accepted and processed by the SNMP
+ protocol entity."
+ ::= { snmp 15 }
+
+snmpInGetNexts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Get-Next PDUs which have
+ been accepted and processed by the SNMP protocol
+ entity."
+ ::= { snmp 16 }
+
+snmpInSetRequests OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Set-Request PDUs which
+ have been accepted and processed by the SNMP
+ protocol entity."
+ ::= { snmp 17 }
+
+snmpInGetResponses OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Get-Response PDUs which
+ have been accepted and processed by the SNMP
+ protocol entity."
+ ::= { snmp 18 }
+
+snmpInTraps OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Trap PDUs which have
+ been accepted and processed by the SNMP protocol
+ entity."
+ ::= { snmp 19 }
+
+snmpOutTooBigs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP PDUs which were
+ generated by the SNMP protocol entity and for
+ which the value of the error-status field is
+ `tooBig.'"
+ ::= { snmp 20 }
+
+snmpOutNoSuchNames OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP PDUs which were
+ generated by the SNMP protocol entity and for
+ which the value of the error-status is
+ `noSuchName'."
+ ::= { snmp 21 }
+
+snmpOutBadValues OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP PDUs which were
+ generated by the SNMP protocol entity and for
+ which the value of the error-status field is
+ `badValue'."
+ ::= { snmp 22 }
+
+ -- { snmp 23 } is not used
+
+snmpOutGenErrs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP PDUs which were
+ generated by the SNMP protocol entity and for
+ which the value of the error-status field is
+ `genErr'."
+ ::= { snmp 24 }
+
+snmpOutGetRequests OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Get-Request PDUs which
+ have been generated by the SNMP protocol entity."
+ ::= { snmp 25 }
+
+snmpOutGetNexts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Get-Next PDUs which have
+ been generated by the SNMP protocol entity."
+ ::= { snmp 26 }
+
+snmpOutSetRequests OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Set-Request PDUs which
+ have been generated by the SNMP protocol entity."
+ ::= { snmp 27 }
+
+snmpOutGetResponses OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Get-Response PDUs which
+ have been generated by the SNMP protocol entity."
+ ::= { snmp 28 }
+
+snmpOutTraps OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Trap PDUs which have
+ been generated by the SNMP protocol entity."
+ ::= { snmp 29 }
+
+snmpEnableAuthenTraps OBJECT-TYPE
+ SYNTAX INTEGER { enabled(1), disabled(2) }
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "Indicates whether the SNMP agent process is
+ permitted to generate authentication-failure
+ traps. The value of this object overrides any
+ configuration information; as such, it provides a
+ means whereby all authentication-failure traps may
+ be disabled.
+
+ Note that it is strongly recommended that this
+ object be stored in non-volatile memory so that it
+ remains constant between re-initializations of the
+ network management system."
+ ::= { snmp 30 }
+
+coldStart TRAP-TYPE
+ ENTERPRISE snmp
+ DESCRIPTION
+ "A coldStart trap signifies that the sending
+ protocol entity is reinitializing itself such
+ that the agent's configuration or the rotocol
+ entity implementation may be altered."
+ ::= 0
+
+warmStart TRAP-TYPE
+ ENTERPRISE snmp
+ DESCRIPTION
+ "A warmStart trap signifies that the sending
+ protocol entity is reinitializing itself such
+ that neither the agent configuration nor the
+ protocol entity implementation is altered."
+ ::= 1
+
+authenticationFailure TRAP-TYPE
+ ENTERPRISE snmp
+ DESCRIPTION
+ "An authenticationFailure trap signifies that
+ the sending protocol entity is the addressee
+ of a protocol message that is not properly
+ authenticated. While implementations of the
+ SNMP must be capable of generating this trap,
+ they must also be capable of suppressing the
+ emission of such traps via an implementation-
+ specific mechanism."
+ ::= 4
+
+END
+
diff --git a/lib/snmp/test/snmp_test_data/Test1.funcs b/lib/snmp/test/snmp_test_data/Test1.funcs
new file mode 100644
index 0000000000..a9ef7a34fe
--- /dev/null
+++ b/lib/snmp/test/snmp_test_data/Test1.funcs
@@ -0,0 +1,7 @@
+{bits1, {test1, bits1, []}}.
+{bits2, {test1, bits2, []}}.
+{bits3, {test1, bits3, []}}.
+{bits4, {test1, bits4, []}}.
+{opaqueObj, {test1, opaque_obj, []}}.
+{cnt64, {test1, cnt64, []}}.
+{multiStr, {test1, multiStr, []}}.
diff --git a/lib/snmp/test/snmp_test_data/Test1.mib b/lib/snmp/test/snmp_test_data/Test1.mib
new file mode 100644
index 0000000000..d324b1f1e7
--- /dev/null
+++ b/lib/snmp/test/snmp_test_data/Test1.mib
@@ -0,0 +1,370 @@
+Test1 DEFINITIONS ::= BEGIN
+
+IMPORTS
+ MODULE-IDENTITY, OBJECT-TYPE, NOTIFICATION-TYPE,
+ TimeTicks, Counter32, snmpModules, mib-2, enterprises, IpAddress,
+ Integer32, Counter64, Opaque
+ FROM SNMPv2-SMI
+ DisplayString, TestAndIncr, TimeStamp, RowStatus, TruthValue,
+ TEXTUAL-CONVENTION
+ FROM SNMPv2-TC
+ MODULE-COMPLIANCE, OBJECT-GROUP, NOTIFICATION-GROUP
+ FROM SNMPv2-CONF
+ sysLocation, sysContact
+ FROM SNMPv2-MIB
+ ;
+
+snmpMIB MODULE-IDENTITY
+ LAST-UPDATED "9511090000Z"
+ ORGANIZATION ""
+ CONTACT-INFO
+ ""
+ DESCRIPTION
+ "Test mib"
+ ::= { snmpModules 1 }
+
+
+test OBJECT IDENTIFIER ::= { mib-2 15 }
+testTrap OBJECT IDENTIFIER ::= { test 0 }
+
+bits1 OBJECT-TYPE
+ SYNTAX BITS { b0(0), b1(1), b2(2) }
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ ""
+ ::= { test 1 }
+
+bits2 OBJECT-TYPE
+ SYNTAX BITS { b0(0), b1(1), b2(2), b3(3), b4(4), b5(5), b6(6), b7(7),
+ b8(8), b9(9), b10(10), b11(11), b12(12), b13(13), b14(14), b15(15) }
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ ""
+ ::= { test 2 }
+
+bits3 OBJECT-TYPE
+ SYNTAX BITS { b0(0), b1(1), b2(2) }
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ ""
+ ::= { test 3 }
+
+bits4 OBJECT-TYPE
+ SYNTAX BITS { b0(0), b1(1), b2(2) }
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ ""
+ ::= { test 4 }
+
+testTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF TestEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "Used to test IMPLIED with one string."
+ ::= { test 5 }
+
+testEntry OBJECT-TYPE
+ SYNTAX TestEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "An entry (conceptual row) in the sysORTable."
+ INDEX { IMPLIED testIndex }
+ ::= { testTable 1 }
+
+TestEntry ::= SEQUENCE {
+ testIndex DisplayString,
+ testDescr DisplayString,
+ testStatus RowStatus
+}
+
+testIndex OBJECT-TYPE
+ SYNTAX DisplayString
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "The auxiliary variable used for identifying instances of
+ the columnar objects in the sysORTable."
+ ::= { testEntry 1 }
+
+testDescr OBJECT-TYPE
+ SYNTAX DisplayString
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "A textual description of the capabilities identified by the
+ corresponding instance of sysORID."
+ ::= { testEntry 2 }
+testStatus OBJECT-TYPE
+ SYNTAX RowStatus
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "The status of this conceptual row."
+ ::= { testEntry 3 }
+
+
+testTable2 OBJECT-TYPE
+ SYNTAX SEQUENCE OF TestEntry2
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "Used to test IMPLIED with more than one index."
+ ::= { test 6 }
+
+testEntry2 OBJECT-TYPE
+ SYNTAX TestEntry2
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "An entry (conceptual row) in the sysORTable."
+ INDEX { testIndex1, IMPLIED testIndex2 }
+ ::= { testTable2 1 }
+
+TestEntry2 ::= SEQUENCE {
+ testIndex1 Integer32,
+ testIndex2 DisplayString,
+ testDescr2 DisplayString,
+ testStatus2 RowStatus
+}
+
+testIndex1 OBJECT-TYPE
+ SYNTAX Integer32
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "The auxiliary variable used for identifying instances of
+ the columnar objects in the sysORTable."
+ ::= { testEntry2 1 }
+
+testIndex2 OBJECT-TYPE
+ SYNTAX DisplayString
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "The auxiliary variable used for identifying instances of
+ the columnar objects in the sysORTable."
+ ::= { testEntry2 2 }
+
+testDescr2 OBJECT-TYPE
+ SYNTAX DisplayString
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "A textual description of the capabilities identified by the
+ corresponding instance of sysORID."
+ ::= { testEntry2 3 }
+
+testStatus2 OBJECT-TYPE
+ SYNTAX RowStatus
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "The status of this conceptual row."
+ ::= { testEntry2 4 }
+
+sparseTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF SparseEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "Used to test sparse table"
+ ::= { test 7 }
+
+sparseEntry OBJECT-TYPE
+ SYNTAX SparseEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "An entry (conceptual row) in the sysORTable."
+ INDEX { sparseIndex }
+ ::= { sparseTable 1 }
+
+SparseEntry ::= SEQUENCE {
+ sparseIndex Integer32,
+ sparseObj DisplayString,
+ sparseObj2 DisplayString,
+ sparseDescr DisplayString,
+ sparseStatus RowStatus
+}
+
+sparseIndex OBJECT-TYPE
+ SYNTAX Integer32
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "The auxiliary variable used for identifying instances of
+ the columnar objects in the sysORTable."
+ ::= { sparseEntry 1 }
+
+sparseObj OBJECT-TYPE
+ SYNTAX DisplayString
+ MAX-ACCESS not-accessible
+ STATUS obsolete
+ DESCRIPTION
+ "The auxiliary variable used for identifying instances of
+ the columnar objects in the sysORTable."
+ ::= { sparseEntry 2 }
+
+sparseObj2 OBJECT-TYPE
+ SYNTAX DisplayString
+ MAX-ACCESS not-accessible
+ STATUS deprecated
+ DESCRIPTION
+ "The auxiliary variable used for identifying instances of
+ the columnar objects in the sysORTable."
+ ::= { sparseEntry 3 }
+
+sparseDescr OBJECT-TYPE
+ SYNTAX DisplayString
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "A textual description of the capabilities identified by the
+ corresponding instance of sysORID."
+ ::= { sparseEntry 4 }
+
+sparseStatus OBJECT-TYPE
+ SYNTAX RowStatus
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "The status of this conceptual row."
+ ::= { sparseEntry 6 }
+
+sparseStr OBJECT-TYPE
+ SYNTAX DisplayString
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "A textual description of the capabilities identified by the
+ corresponding instance of sysORID."
+ DEFVAL { "slut" }
+ ::= { test 8 }
+
+cntTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF CntEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ ""
+ ::= { test 9 }
+
+cntEntry OBJECT-TYPE
+ SYNTAX CntEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "An entry (conceptual row) in the sysORTable."
+ INDEX { cntIndex }
+ ::= { cntTable 1 }
+
+CntEntry ::= SEQUENCE {
+ cntIndex Integer32,
+ cntCnt Counter64,
+ cntStatus RowStatus,
+ cntDescr DisplayString
+}
+
+cntIndex OBJECT-TYPE
+ SYNTAX Integer32
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "The auxiliary variable used for identifying instances of
+ the columnar objects in the sysORTable."
+ ::= { cntEntry 1 }
+
+cntCnt OBJECT-TYPE
+ SYNTAX Counter64
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "Counter64 object - not visible in v1"
+ DEFVAL { 0 }
+ ::= { cntEntry 5 }
+
+cntStatus OBJECT-TYPE
+ SYNTAX RowStatus
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "The status of this conceptual row."
+ ::= { cntEntry 7 }
+
+cntDescr OBJECT-TYPE
+ SYNTAX DisplayString
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "A textual description of the capabilities identified by the
+ corresponding instance of sysORID."
+ DEFVAL { "descr" }
+ ::= { cntEntry 8 }
+
+cntStr OBJECT-TYPE
+ SYNTAX DisplayString
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "A textual description of the capabilities identified by the
+ corresponding instance of sysORID."
+ DEFVAL { "slut" }
+ ::= { test 10 }
+
+cnt64 OBJECT-TYPE
+ SYNTAX Counter64
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "not visible in v1"
+ ::= { test 11 }
+
+cnt64Str OBJECT-TYPE
+ SYNTAX DisplayString
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "Used to stop get-next from cnt64"
+ DEFVAL { "after cnt64" }
+ ::= { test 12 }
+
+opaqueObj OBJECT-TYPE
+ SYNTAX Opaque
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "A textual description of the capabilities identified by the
+ corresponding instance of sysORID."
+ ::= { test 13 }
+
+multiStr OBJECT-TYPE
+ SYNTAX DisplayString
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "Used to block agent for testing multi threaded impl"
+ DEFVAL { "no" }
+ ::= { test 14 }
+
+
+cntTrap NOTIFICATION-TYPE
+ OBJECTS { sysContact, cnt64, sysLocation }
+ STATUS current
+ DESCRIPTION
+ "Test that coutner64 is deleted from v1 trap"
+ ::= { testTrap 1 }
+
+mtTrap NOTIFICATION-TYPE
+ OBJECTS { multiStr }
+ STATUS current
+ DESCRIPTION
+ ""
+ ::= { testTrap 2 }
+
+END
diff --git a/lib/snmp/test/snmp_test_data/Test2.funcs b/lib/snmp/test/snmp_test_data/Test2.funcs
new file mode 100644
index 0000000000..326ba8405c
--- /dev/null
+++ b/lib/snmp/test/snmp_test_data/Test2.funcs
@@ -0,0 +1,10 @@
+{tDescr2, {test2, tDescr, [2]}}.
+{tDescr3, {test2, tDescr, [3]}}.
+{tDescr4, {test2, tDescr, [4]}}.
+{tInt3, {test2, tInt, [3]}}.
+{tTable, {test2, tTable, []}}.
+{tTable2, {test2, tTable2, []}}.
+{tGenErr1, {test2, tGenErr, [1]}}.
+{tGenErr2, {test2, tGenErr, [2]}}.
+{tGenErr3, {test2, tGenErr, [3]}}.
+{tTooBig, {test2, tTooBig, []}}.
diff --git a/lib/snmp/test/snmp_test_data/Test2.mib b/lib/snmp/test/snmp_test_data/Test2.mib
new file mode 100644
index 0000000000..81f36175c0
--- /dev/null
+++ b/lib/snmp/test/snmp_test_data/Test2.mib
@@ -0,0 +1,246 @@
+Test2 DEFINITIONS ::= BEGIN
+
+IMPORTS
+ MODULE-IDENTITY, OBJECT-TYPE, NOTIFICATION-TYPE,
+ TimeTicks, Counter32, snmpModules, mib-2, enterprises, IpAddress,
+ Integer32, OBJECT-IDENTITY
+ FROM SNMPv2-SMI
+ DisplayString, TestAndIncr, TimeStamp, RowStatus, TruthValue,
+ TEXTUAL-CONVENTION
+ FROM SNMPv2-TC
+ MODULE-COMPLIANCE, OBJECT-GROUP, NOTIFICATION-GROUP
+ FROM SNMPv2-CONF;
+
+snmpMIB MODULE-IDENTITY
+ LAST-UPDATED "9511090000Z"
+ ORGANIZATION ""
+ CONTACT-INFO
+ ""
+ DESCRIPTION
+ "Test mib, used to test processing of requests."
+ ::= { snmpModules 1 }
+
+
+test2 OBJECT IDENTIFIER ::= { mib-2 16 }
+test3 OBJECT IDENTIFIER ::= { mib-2 17 }
+
+xDescr OBJECT-TYPE
+ SYNTAX DisplayString
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "Outside mibview"
+ ::= { test3 1 }
+
+xDescr2 OBJECT-TYPE
+ SYNTAX DisplayString
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ ""
+ ::= { test3 2 }
+
+
+tDescr OBJECT-TYPE
+ SYNTAX DisplayString
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "Outside mibview"
+ ::= { test2 1 }
+
+tDescr2 OBJECT-TYPE
+ SYNTAX DisplayString
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ ""
+ ::= { test2 2 }
+
+tDescr3 OBJECT-TYPE
+ SYNTAX DisplayString
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ ""
+ ::= { test2 3 }
+
+tDescr4 OBJECT-TYPE
+ SYNTAX DisplayString
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ ""
+ ::= { test2 4 }
+
+tTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF TEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "The (conceptual) table listing the capabilities of the
+ local SNMPv2 entity acting in an agent role with respect to
+ various MIB modules. SNMPv2 entities having dynamically-
+ configurable support of MIB modules will have a
+ dynamically-varying number of conceptual rows."
+ ::= { test2 5 }
+
+tEntry OBJECT-TYPE
+ SYNTAX TEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "An entry (conceptual row) in the sysORTable."
+ INDEX { tIndex }
+ ::= { tTable 1 }
+
+TEntry ::= SEQUENCE {
+ tIndex DisplayString,
+ tDescrX DisplayString,
+ tCnt Counter32
+}
+
+tIndex OBJECT-TYPE
+ SYNTAX DisplayString
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "The auxiliary variable used for identifying instances of
+ the columnar objects in the sysORTable."
+ ::= { tEntry 1 }
+
+tDescrX OBJECT-TYPE
+ SYNTAX DisplayString
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "A textual description of the capabilities identified by the
+ corresponding instance of sysORID."
+ ::= { tEntry 2 }
+
+tCnt OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "A textual description of the capabilities identified by the
+ corresponding instance of sysORID."
+ ::= { tEntry 3 }
+
+testErr OBJECT-IDENTITY
+ STATUS current
+ DESCRIPTION
+ ""
+ ::= { test2 6 }
+
+tTooBig OBJECT-TYPE
+ SYNTAX OCTET STRING
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "This object will generate a tooBig error"
+ ::= { testErr 1 }
+
+tGenErr1 OBJECT-TYPE
+ SYNTAX DisplayString
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "This object will generate a genErr error"
+ ::= { testErr 2 }
+
+tGenErr2 OBJECT-TYPE
+ SYNTAX INTEGER
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "This object will generate a genErr error"
+ ::= { testErr 3 }
+
+tGenErr3 OBJECT-TYPE
+ SYNTAX INTEGER
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "This object will generate a genErr error"
+ ::= { testErr 4 }
+
+tStr OBJECT-TYPE
+ SYNTAX DisplayString (SIZE (1..4))
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ ""
+ ::= { test2 7 }
+
+tInt1 OBJECT-TYPE
+ SYNTAX INTEGER (1..4)
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ ""
+ ::= { test2 8 }
+
+tInt2 OBJECT-TYPE
+ SYNTAX INTEGER { v1(1), v2(2) }
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ ""
+ ::= { test2 9 }
+
+tInt3 OBJECT-TYPE
+ SYNTAX INTEGER (1..7) -- (1..4 | 6..7)
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ ""
+ ::= { test2 10 }
+
+
+tTable2 OBJECT-TYPE
+ SYNTAX SEQUENCE OF TEntry2
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "The (conceptual) table listing the capabilities of the
+ local SNMPv2 entity acting in an agent role with respect to
+ various MIB modules. SNMPv2 entities having dynamically-
+ configurable support of MIB modules will have a
+ dynamically-varying number of conceptual rows."
+ ::= { snmpModules 99 }
+
+tEntry2 OBJECT-TYPE
+ SYNTAX TEntry2
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "An entry (conceptual row) in the sysORTable."
+ INDEX { tIndex2 }
+ ::= { tTable2 1 }
+
+TEntry2 ::= SEQUENCE {
+ tIndex2 DisplayString,
+ tCnt2 Counter32
+}
+
+tIndex2 OBJECT-TYPE
+ SYNTAX DisplayString
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "The auxiliary variable used for identifying instances of
+ the columnar objects in the sysORTable."
+ ::= { tEntry2 1 }
+
+tCnt2 OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "A textual description of the capabilities identified by the
+ corresponding instance of sysORID."
+ ::= { tEntry2 2 }
+
+
+END
diff --git a/lib/snmp/test/snmp_test_data/TestTrap.mib b/lib/snmp/test/snmp_test_data/TestTrap.mib
new file mode 100644
index 0000000000..afa97f1188
--- /dev/null
+++ b/lib/snmp/test/snmp_test_data/TestTrap.mib
@@ -0,0 +1,44 @@
+TestTrap DEFINITIONS ::= BEGIN
+
+ IMPORTS
+ Counter, TimeTicks, IpAddress
+ FROM RFC1155-SMI
+ OBJECT-TYPE
+ FROM RFC-1212
+ mgmt, NetworkAddress, IpAddress, Counter, Gauge,
+ TimeTicks
+ FROM RFC1155-SMI
+ DisplayString, snmp, system,sysContact, ifIndex
+ FROM RFC1213-MIB
+ OBJECT-TYPE
+ FROM RFC-1212;
+
+
+
+ testTrap1 TRAP-TYPE
+ ENTERPRISE snmp
+ VARIABLES { sysContact }
+ DESCRIPTION
+ ""
+ ::= 1
+
+ testTrap2 TRAP-TYPE
+ ENTERPRISE system
+ VARIABLES { sysContact }
+ DESCRIPTION
+ ""
+ ::= 1
+
+
+ linkDown TRAP-TYPE
+ ENTERPRISE snmp
+ VARIABLES { ifIndex }
+ DESCRIPTION
+ "A linkDown trap signifies that the sending
+ protocol entity recognizes a failure in one of
+ the communication links represented in the
+ agent's configuration."
+ ::= 2
+
+
+END
diff --git a/lib/snmp/test/snmp_test_data/TestTrapv2.mib b/lib/snmp/test/snmp_test_data/TestTrapv2.mib
new file mode 100644
index 0000000000..679ddc14b0
--- /dev/null
+++ b/lib/snmp/test/snmp_test_data/TestTrapv2.mib
@@ -0,0 +1,71 @@
+TestTrapv2 DEFINITIONS ::= BEGIN
+
+IMPORTS
+ MODULE-IDENTITY, OBJECT-TYPE, NOTIFICATION-TYPE,
+ TimeTicks, Counter32, snmpModules, mib-2, enterprises, IpAddress,
+ Integer32
+ FROM SNMPv2-SMI
+ DisplayString, TestAndIncr, TimeStamp, RowStatus, TruthValue,
+ TEXTUAL-CONVENTION
+ FROM SNMPv2-TC
+ MODULE-COMPLIANCE, OBJECT-GROUP, NOTIFICATION-GROUP
+ FROM SNMPv2-CONF
+
+ system, snmp, ifIndex, ifAdminStatus, ifOperStatus
+ FROM RFC1213-MIB
+ snmpTraps
+ FROM SNMPv2-MIB;
+
+testTrapv2 MODULE-IDENTITY
+ LAST-UPDATED "9511090000Z"
+ ORGANIZATION "IETF SNMPv2 Working Group"
+ CONTACT-INFO
+ " Marshall T. Rose
+
+ Postal: Dover Beach Consulting, Inc.
+ 420 Whisman Court
+ Mountain View, CA 94043-2186
+ US
+
+ Tel: +1 415 968 1052
+
+ DESCRIPTION
+ "The MIB module for SNMPv2 entities."
+ REVISION "9304010000Z"
+ DESCRIPTION
+ "The initial revision of this MIB module was published as
+ RFC 1450."
+ ::= { system 100 }
+
+
+tst OBJECT IDENTIFIER ::= { system 0 }
+
+testTrapv21 NOTIFICATION-TYPE
+ STATUS current
+ DESCRIPTION
+ "This trap is exactly the v2 correspondance of testTrap1 in
+ TestTrap mib."
+ ::= { snmp 1 }
+
+testTrapv22 NOTIFICATION-TYPE
+ STATUS current
+ DESCRIPTION
+ "This trap is exactly the v2 correspondance of testTrap2 in
+ TestTrap mib."
+ ::= { system 0 1 }
+
+linkUp NOTIFICATION-TYPE
+ OBJECTS { ifIndex, ifAdminStatus, ifOperStatus }
+ STATUS current
+ DESCRIPTION
+ "A linkUp trap signifies that the SNMPv2 entity,
+ acting in an agent role, has detected that the
+ ifOperStatus object for one of its communication links
+ has transitioned out of the down state."
+ ::= { snmpTraps 4 }
+
+
+
+
+END
diff --git a/lib/snmp/test/snmp_test_lib.erl b/lib/snmp/test/snmp_test_lib.erl
new file mode 100644
index 0000000000..2586b66a13
--- /dev/null
+++ b/lib/snmp/test/snmp_test_lib.erl
@@ -0,0 +1,525 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2002-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%
+%%
+
+-module(snmp_test_lib).
+
+-include_lib("kernel/include/file.hrl").
+
+
+-export([hostname/0, hostname/1, localhost/0, os_type/0, sz/1,
+ display_suite_info/1]).
+-export([non_pc_tc_maybe_skip/4, os_based_skip/1]).
+-export([replace_config/3, set_config/3, get_config/2, get_config/3]).
+-export([fail/3, skip/3]).
+-export([millis/0, millis_diff/2, hours/1, minutes/1, seconds/1, sleep/1]).
+-export([flush_mqueue/0, trap_exit/0, trap_exit/1]).
+-export([ping/1, local_nodes/0, nodes_on/1]).
+-export([start_node/2]).
+-export([is_app_running/1,
+ is_crypto_running/0, is_mnesia_running/0, is_snmp_running/0]).
+-export([crypto_start/0, crypto_support/0]).
+-export([watchdog/3, watchdog_start/1, watchdog_start/2, watchdog_stop/1]).
+-export([del_dir/1]).
+-export([cover/1]).
+-export([p/2, print/5]).
+
+
+%% ----------------------------------------------------------------------
+%% Misc functions
+%%
+
+hostname() ->
+ hostname(node()).
+
+hostname(Node) ->
+ from($@, atom_to_list(Node)).
+
+from(H, [H | T]) -> T;
+from(H, [_ | T]) -> from(H, T);
+from(_H, []) -> [].
+
+localhost() ->
+ {ok, Ip} = snmp_misc:ip(net_adm:localhost()),
+ Ip.
+
+sz(L) when is_list(L) ->
+ length(L);
+sz(B) when is_binary(B) ->
+ size(B);
+sz(O) ->
+ {unknown_size,O}.
+
+
+os_type() ->
+ case (catch test_server:os_type()) of
+ {'EXIT', _} ->
+ %% Pre-R10 test server does not have this function
+ os:type();
+ OsType ->
+ OsType
+ end.
+
+display_suite_info(SUITE) when is_atom(SUITE) ->
+ (catch do_display_suite_info(SUITE)).
+
+do_display_suite_info(SUITE) ->
+ MI = SUITE:module_info(),
+ case (catch display_version(MI)) of
+ ok ->
+ ok;
+ _ ->
+ case (catch display_app_version(MI)) of
+ ok ->
+ ok;
+ _ ->
+ io:format("No version info available for test suite ~p~n",
+ [?MODULE])
+ end
+ end.
+
+display_version(MI) ->
+ {value, {compile, CI}} = lists:keysearch(compile, 1, MI),
+ {value, {options, CO}} = lists:keysearch(options, 1, CI),
+ Version = version_of_compiler_options(CO),
+ io:format("~p version info: "
+ "~n Version: ~p"
+ "~n", [?MODULE, Version]),
+ ok.
+
+version_of_compiler_options([{d, version, Version} | _]) ->
+ Version;
+version_of_compiler_options([_ | T]) ->
+ version_of_compiler_options(T).
+
+display_app_version(MI) ->
+ {value, {attributes, Attrs}} = lists:keysearch(attributes, 1, MI),
+ {value, {vsn, Vsn}} = lists:keysearch(vsn, 1, Attrs),
+ {value, {app_vsn, AppVsn}} = lists:keysearch(app_vsn, 1, Attrs),
+ io:format("~p version info: "
+ "~n VSN: ~p"
+ "~n App vsn: ~s"
+ "~n", [?MODULE, Vsn, AppVsn]),
+ ok.
+
+
+%% ----------------------------------------------------------------
+%% Conditional skip of testcases
+%%
+
+non_pc_tc_maybe_skip(Config, Condition, File, Line)
+ when is_list(Config) andalso is_function(Condition) ->
+ %% Check if we shall skip the skip
+ case os:getenv("TS_OS_BASED_SKIP") of
+ "false" ->
+ ok;
+ _ ->
+ case lists:keysearch(ts, 1, Config) of
+ {value, {ts, snmp}} ->
+ %% Always run the testcase if we are using our own
+ %% test-server...
+ ok;
+ _ ->
+ case Condition() of
+ true ->
+ skip(non_pc_testcase, File, Line);
+ false ->
+ ok
+ end
+ end
+ end.
+
+
+os_based_skip(any) ->
+ io:format("os_based_skip(any) -> entry"
+ "~n", []),
+ true;
+os_based_skip(Skippable) when is_list(Skippable) ->
+ io:format("os_based_skip -> entry with"
+ "~n Skippable: ~p"
+ "~n", [Skippable]),
+ {OsFam, OsName} =
+ case os:type() of
+ {_Fam, _Name} = FamAndName ->
+ FamAndName;
+ Fam ->
+ {Fam, undefined}
+ end,
+ io:format("os_based_skip -> os-type: "
+ "~n OsFam: ~p"
+ "~n OsName: ~p"
+ "~n", [OsFam, OsName]),
+ case lists:member(OsFam, Skippable) of
+ true ->
+ true;
+ false ->
+ case lists:keysearch(OsFam, 1, Skippable) of
+ {value, {OsFam, OsName}} ->
+ true;
+ {value, {OsFam, OsNames}} when is_list(OsNames) ->
+ lists:member(OsName, OsNames);
+ _ ->
+ false
+ end
+ end;
+os_based_skip(_Crap) ->
+ io:format("os_based_skip -> entry with"
+ "~n _Crap: ~p"
+ "~n", [_Crap]),
+ false.
+
+
+%% ----------------------------------------------------------------
+%% Test suite utility functions
+%%
+
+replace_config(Key, Config, NewValue) ->
+ lists:keyreplace(Key, 1, Config, {Key, NewValue}).
+
+set_config(Key, Def, Config) ->
+ case get_config(Key, Config) of
+ undefined ->
+ [{Key, Def}|Config];
+ _ ->
+ Config
+ end.
+
+get_config(Key,C) ->
+ get_config(Key,C,undefined).
+
+get_config(Key,C,Default) ->
+ case lists:keysearch(Key,1,C) of
+ {value,{Key,Val}} ->
+ Val;
+ _ ->
+ Default
+ end.
+
+
+fail(Reason, Mod, Line) ->
+ exit({suite_failed, Reason, Mod, Line}).
+
+skip(Reason, Module, Line) ->
+ String = lists:flatten(io_lib:format("Skipping ~p(~p): ~p~n",
+ [Module, Line, Reason])),
+ exit({skipped, String}).
+
+
+%% ----------------------------------------------------------------
+%% Time related function
+%%
+
+millis() ->
+ erlang:now().
+
+millis_diff(A,B) ->
+ T1 = (element(1,A)*1000000) + element(2,A) + (element(3,A)/1000000),
+ T2 = (element(1,B)*1000000) + element(2,B) + (element(3,B)/1000000),
+ T1 - T2.
+
+hours(N) -> trunc(N * 1000 * 60 * 60).
+minutes(N) -> trunc(N * 1000 * 60).
+seconds(N) -> trunc(N * 1000).
+
+
+sleep(infinity) ->
+ receive
+ after infinity ->
+ ok
+ end;
+sleep(MSecs) ->
+ receive
+ after trunc(MSecs) ->
+ ok
+ end,
+ ok.
+
+
+%% ----------------------------------------------------------------
+%% Process utility function
+%%
+
+flush_mqueue() ->
+ io:format("~p~n", [lists:reverse(flush_mqueue([]))]).
+
+flush_mqueue(MQ) ->
+ receive
+ Any ->
+ flush_mqueue([Any|MQ])
+ after 0 ->
+ MQ
+ end.
+
+
+trap_exit() ->
+ {trap_exit,Flag} = process_info(self(),trap_exit),Flag.
+
+trap_exit(Flag) ->
+ process_flag(trap_exit,Flag).
+
+
+
+%% ----------------------------------------------------------------
+%% Node utility functions
+%%
+
+ping(N) ->
+ case net_adm:ping(N) of
+ pang ->
+ error;
+ pong ->
+ ok
+ end.
+
+local_nodes() ->
+ nodes_on(net_adm:localhost()).
+
+nodes_on(Host) when is_list(Host) ->
+ net_adm:world_list([list_to_atom(Host)]).
+
+
+start_node(Name, Args) ->
+ Opts = [{cleanup,false}, {args,Args}],
+ test_server:start_node(Name, slave, Opts).
+
+
+%% ----------------------------------------------------------------
+%% Application and Crypto utility functions
+%%
+
+is_app_running(App) when is_atom(App) ->
+ Apps = application:which_applications(),
+ lists:keymember(App,1,Apps).
+
+is_crypto_running() ->
+ is_app_running(crypto).
+
+is_mnesia_running() ->
+ is_app_running(mnesia).
+
+is_snmp_running() ->
+ is_app_running(snmp).
+
+crypto_start() ->
+ case (catch crypto:start()) of
+ ok ->
+ ok;
+ {error, {already_started,crypto}} ->
+ ok;
+ {'EXIT', Reason} ->
+ {error, {exit, Reason}};
+ Else ->
+ Else
+ end.
+
+crypto_support() ->
+ crypto_support([md5_mac_96, sha_mac_96], []).
+
+crypto_support([], []) ->
+ yes;
+crypto_support([], Acc) ->
+ {no, Acc};
+crypto_support([Func|Funcs], Acc) ->
+ case is_crypto_supported(Func) of
+ true ->
+ crypto_support(Funcs, Acc);
+ false ->
+ crypto_support(Funcs, [Func|Acc])
+ end.
+
+is_crypto_supported(Func) ->
+ %% The 'catch' handles the case when 'crypto' is
+ %% not present in the system (or not started).
+ case (catch lists:member(Func, crypto:info())) of
+ true -> true;
+ _ -> false
+ end.
+
+
+%% ----------------------------------------------------------------
+%% Watchdog functions
+%%
+
+watchdog_start(Timeout) ->
+ watchdog_start(unknown, Timeout).
+
+watchdog_start(Case, Timeout) ->
+ spawn_link(?MODULE, watchdog, [Case, Timeout, self()]).
+
+watchdog_stop(Pid) ->
+ unlink(Pid),
+ exit(Pid, kill),
+ ok.
+
+watchdog(Case, Timeout0, Pid) ->
+ process_flag(priority, max),
+ Timeout = timeout(Timeout0),
+ receive
+ after Timeout ->
+ Mon = erlang:monitor(process, Pid),
+ case erlang:process_info(Pid) of
+ undefined ->
+ ok;
+ ProcInfo ->
+ Line =
+ case lists:keysearch(dictionary, 1, ProcInfo) of
+ {value, {_, Dict}} when is_list(Dict) ->
+ case lists:keysearch(test_server_loc, 1, Dict) of
+ {value, {_, {_Mod, L}}} when is_integer(L) ->
+ L;
+ _ ->
+ 0
+ end;
+ _ -> % This borders on paranoia, but...
+ 0
+ end,
+ Trap = {timetrap_timeout, Timeout, Line},
+ exit(Pid, Trap),
+ receive
+ {'DOWN', Mon, process, Pid, _} ->
+ ok
+ after 10000 ->
+ warning_msg("Failed stopping "
+ "test case ~p process ~p "
+ "[~w] after ~w: killing instead",
+ [Case, Pid, Line, Timeout]),
+ exit(Pid, kill)
+ end
+ end
+ end.
+
+warning_msg(F, A) ->
+ (catch error_logger:warning_msg(F ++ "~n", A)).
+
+timeout(T) ->
+ trunc(timeout(T, os:type())).
+
+timeout(T, vxworks) ->
+ 5 * T * timetrap_scale_factor();
+timeout(T, _) ->
+ T * timetrap_scale_factor().
+
+timetrap_scale_factor() ->
+ case (catch test_server:timetrap_scale_factor()) of
+ {'EXIT', _} ->
+ 1;
+ N ->
+ N
+ end.
+
+
+%% ----------------------------------------------------------------------
+%% file & dir functions
+%%
+
+del_dir(Dir) when is_list(Dir) ->
+ (catch do_del_dir(Dir)).
+
+do_del_dir(Dir) ->
+ io:format("delete directory ~s~n", [Dir]),
+ case file:list_dir(Dir) of
+ {ok, Files} ->
+ Files2 = [filename:join(Dir, File) || File <- Files],
+ del_dir2(Files2),
+ case file:del_dir(Dir) of
+ ok ->
+ io:format("directory ~s deleted~n", [Dir]),
+ ok;
+ {error, eexist} = Error1 ->
+ io:format("directory not empty: ~n", []),
+ {ok, Files3} = file:list_dir(Dir),
+ io:format("found additional files: ~n~p~n",
+ [Files3]),
+ throw(Error1);
+ {error, Reason2} = Error2 ->
+ io:format("failed deleting directory: ~w~n", [Reason2]),
+ throw(Error2)
+ end;
+ Else ->
+ Else
+ end.
+
+del_dir2([]) ->
+ ok;
+del_dir2([File|Files]) ->
+ del_file_or_dir(File),
+ del_dir2(Files).
+
+del_file_or_dir(FileOrDir) ->
+ case file:read_file_info(FileOrDir) of
+ {ok, #file_info{type = directory}} ->
+ do_del_dir(FileOrDir);
+ {ok, _} ->
+ io:format(" delete file ~s~n", [FileOrDir]),
+ case file:delete(FileOrDir) of
+ ok ->
+ io:format(" => deleted~n", []),
+ ok;
+ {error, Reason} = Error ->
+ io:format(" => failed - ~w~n", [Reason]),
+ throw(Error)
+ end;
+
+ _ ->
+ ok
+ end.
+
+
+%% ----------------------------------------------------------------------
+%% cover functions
+%%
+
+cover([Suite, Case] = Args) when is_atom(Suite) andalso is_atom(Case) ->
+ Mods0 = cover:compile_directory("../src"),
+ Mods1 = [Mod || {ok, Mod} <- Mods0],
+ snmp_test_server:t(Args),
+ Files0 = [cover:analyse_to_file(Mod) || Mod <- Mods1],
+ [io:format("Cover output: ~s~n", [File]) || {ok, File} <- Files0],
+ ok.
+
+
+%% ----------------------------------------------------------------------
+%% (debug) Print functions
+%%
+
+p(Mod, Case) when is_atom(Mod) andalso is_atom(Case) ->
+ case get(test_case) of
+ undefined ->
+ put(test_case, Case),
+ p("~n~n************ ~w:~w ************", [Mod, Case]);
+ _ ->
+ ok
+ end;
+
+p(F, A) when is_list(F) andalso is_list(A) ->
+ io:format(user, F ++ "~n", A).
+
+print(Prefix, Module, Line, Format, Args) ->
+ io:format("*** [~s] ~s ~p ~p ~p:~p *** " ++ Format ++ "~n",
+ [format_timestamp(now()),
+ Prefix, node(), self(), Module, Line|Args]).
+
+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).
+
diff --git a/lib/snmp/test/snmp_test_lib.hrl b/lib/snmp/test/snmp_test_lib.hrl
new file mode 100644
index 0000000000..8cc3f75dc5
--- /dev/null
+++ b/lib/snmp/test/snmp_test_lib.hrl
@@ -0,0 +1,151 @@
+%%<copyright>
+%% <year>2002-2008</year>
+%% <holder>Ericsson AB, All Rights Reserved</holder>
+%%</copyright>
+%%<legalnotice>
+%% 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.
+%%
+%% The Initial Developer of the Original Code is Ericsson AB.
+%%</legalnotice>
+%%
+%%----------------------------------------------------------------------
+%% Purpose: Define common macros for testing
+%%----------------------------------------------------------------------
+
+%% - (some of the) Macros stolen from the test server -
+
+%% -define(line,put(test_server_loc,{?MODULE,?LINE}),).
+
+
+%% - Misc macros -
+
+-ifndef(APPLICATION).
+-define(APPLICATION, snmp).
+-endif.
+
+-define(SCONF(K,D,C), snmp_test_lib:set_config(K,D,C)).
+-define(GCONF(K,C), snmp_test_lib:get_config(K,C)).
+-define(RCONF(K,C,V), snmp_test_lib:replace_config(K,C,V)).
+-define(HOSTNAME(N), snmp_test_lib:hostname(N)).
+-define(LOCALHOST(), snmp_test_lib:localhost()).
+-define(SZ(X), snmp_test_lib:sz(X)).
+-define(OSTYPE(), snmp_test_lib:os_type()).
+-define(DISPLAY_SUITE_INFO(), snmp_test_lib:display_suite_info(?MODULE)).
+
+
+%% - Test case macros -
+-define(OS_BASED_SKIP(Skippable),
+ snmp_test_lib:os_based_skip(Skippable)).
+-define(NON_PC_TC_MAYBE_SKIP(Config, Condition),
+ snmp_test_lib:non_pc_tc_maybe_skip(Config, Condition, ?MODULE, ?LINE)).
+-define(SKIP(Reason), snmp_test_lib:skip(Reason, ?MODULE, ?LINE)).
+-define(FAIL(Reason), snmp_test_lib:fail(Reason, ?MODULE, ?LINE)).
+
+
+%% - Time macros -
+
+-ifdef(DONT_USE_TEST_SERVER).
+-define(HOURS(N), snmp_test_lib:hours(N)).
+-define(MINS(N), snmp_test_lib:minutes(N)).
+-define(SECS(N), snmp_test_lib:seconds(N)).
+-else.
+-define(HOURS(N), test_server:hours(N)).
+-define(MINS(N), test_server:minutes(N)).
+-define(SECS(N), test_server:seconds(N)).
+-endif.
+
+-ifdef(DONT_USE_TEST_SERVER).
+-define(WD_START(T), snmp_test_lib:watchdog_start(T)).
+-define(WD_STOP(P), snmp_test_lib:watchdog_stop(P)).
+-else.
+-define(WD_START(T), test_server:timetrap(T)).
+-define(WD_STOP(P), test_server:timetrap_cancel(P)).
+-endif.
+
+-define(SLEEP(MSEC), snmp_test_lib:sleep(MSEC)).
+-define(M(), snmp_test_lib:millis()).
+-define(MDIFF(A,B), snmp_test_lib:millis_diff(A,B)).
+
+%% - Process utility macros -
+
+-define(FLUSH(), snmp_test_lib:flush_mqueue()).
+-define(ETRAP_GET(), snmp_test_lib:trap_exit()).
+-define(ETRAP_SET(O), snmp_test_lib:trap_exit(O)).
+
+
+%% - Node utility macros -
+
+-define(PING(N), snmp_test_lib:ping(N)).
+-define(LNODES(), snmp_test_lib:local_nodes()).
+-define(NODES(H), snmp_test_lib:nodes_on(H)).
+-define(START_NODE(N,A), snmp_test_lib:start_node(N,A)).
+
+
+%% - Application and Crypto utility macros -
+
+-define(IS_APP_RUNNING(A), snmp_test_lib:is_app_running(A)).
+-define(IS_SNMP_RUNNING(), snmp_test_lib:is_snmp_running()).
+-define(IS_MNESIA_RUNNING(), snmp_test_lib:is_mnesia_running()).
+-define(IS_CRYPTO_RUNNING(), snmp_test_lib:is_crypto_running()).
+-define(CRYPTO_START(), snmp_test_lib:crypto_start()).
+-define(CRYPTO_SUPPORT(), snmp_test_lib:crypto_support()).
+
+
+%% - Dir macros -
+
+-define(DEL_DIR(D), snmp_test_lib:del_dir(D)).
+
+
+%% - Print macros
+
+-define(P(C), snmp_test_lib:p(?MODULE, C)).
+-define(P1(F), snmp_test_lib:p(F, [])).
+-define(P2(F, A), snmp_test_lib:p(F, A)).
+
+-ifdef(snmp_debug).
+-ifndef(snmp_log).
+-define(snmp_log,true).
+-endif.
+-ifndef(snmp_error).
+-define(snmp_error,true).
+-endif.
+-else.
+-ifdef(snmp_log).
+-ifndef(snmp_error).
+-define(snmp_error,true).
+-endif.
+-endif.
+-endif.
+
+-ifdef(snmp_debug).
+-define(DBG(F,A),?PRINT("DBG",F,A)).
+-else.
+-define(DBG(F,A),ok).
+-endif.
+
+-ifdef(snmp_log).
+-define(LOG(F,A),?PRINT("LOG",F,A)).
+-else.
+-define(LOG(F,A),ok).
+-endif.
+
+-ifdef(snmp_error).
+-define(ERR(F,A),?PRINT("ERR",F,A)).
+-else.
+-define(ERR(F,A),ok).
+-endif.
+
+-define(INF(F,A),?PRINT("INF",F,A)).
+
+-define(PRINT(P,F,A),
+ snmp_test_lib:print(P,?MODULE,?LINE,F,A)).
+
diff --git a/lib/snmp/test/snmp_test_manager.erl b/lib/snmp/test/snmp_test_manager.erl
new file mode 100644
index 0000000000..9d9c52ef8d
--- /dev/null
+++ b/lib/snmp/test/snmp_test_manager.erl
@@ -0,0 +1,388 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2005-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%
+%%
+
+%%----------------------------------------------------------------------
+%% This module implements an SNMP manager used in the test suite
+%%----------------------------------------------------------------------
+%%
+
+-module(snmp_test_manager).
+
+-behaviour(gen_server).
+-behaviour(snmpm_user).
+
+
+%% External exports
+-export([
+ start_link/0, start_link/1,
+ stop/0,
+
+ sync_get/1, sync_get/2,
+ sync_get_next/1, sync_get_next/2,
+ sync_get_bulk/3,
+ sync_set/1, sync_set/2
+ ]).
+
+
+%% Manager callback API:
+-export([
+ handle_error/3,
+ handle_agent/4,
+ handle_pdu/4,
+ handle_trap/3,
+ handle_inform/3,
+ handle_report/3
+ ]).
+
+
+%% gen_server callbacks
+-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
+ code_change/3, terminate/2]).
+
+-record(state, {mgr, parent, req, agent_target_name}).
+
+-define(SERVER, ?MODULE).
+-define(USER, ?MODULE).
+
+
+%%%-------------------------------------------------------------------
+%%% API
+%%%-------------------------------------------------------------------
+
+start_link() ->
+ start_link([]).
+
+start_link(Opts) ->
+ gen_server:start_link({local, ?SERVER}, ?MODULE, [self(), Opts], []).
+
+stop() ->
+ call(stop).
+
+
+sync_get(Oids) ->
+ sync_get(Oids, fun(X) -> {ok, X} end).
+
+sync_get(Oids, Verify) when is_list(Oids) and is_function(Verify) ->
+ Verify(call({sync_get, Oids})).
+
+
+sync_get_next(Oids) ->
+ sync_get_next(Oids, fun(X) -> {ok, X} end).
+
+sync_get_next(Oids, Verify) when is_list(Oids) and is_function(Verify) ->
+ Verify(call({sync_get_next, Oids})).
+
+
+sync_get_bulk(NR, MR, Oids) ->
+ sync_get_bulk(NR, MR, Oids, fun(X) -> {ok, X} end).
+
+sync_get_bulk(NR, MR, Oids, Verify)
+ when is_integer(NR) and is_integer(MR) and
+ is_list(Oids) and is_function(Verify) ->
+ Verify(call({sync_get_bulk, NR, MR, Oids})).
+
+
+sync_set(VarsAndVals) ->
+ sync_set(VarsAndVals, fun(X) -> {ok, X} end).
+
+sync_set(VarsAndVals, Verify)
+ when is_list(VarsAndVals) and is_function(Verify) ->
+ Verify(call({sync_set, VarsAndVals})).
+
+
+%%%-------------------------------------------------------------------
+%%% Callback functions from gen_server
+%%%-------------------------------------------------------------------
+
+%%--------------------------------------------------------------------
+%% Func: init/1
+%% Returns: {ok, State} |
+%% {ok, State, Timeout} |
+%% ignore |
+%% {stop, Reason}
+%%--------------------------------------------------------------------
+init([Parent, Opts]) ->
+ process_flag(trap_exit, true),
+ case (catch do_init(Opts)) of
+ {ok, State} ->
+ {ok, State#state{parent = Parent}};
+ {error, Reason} ->
+ {stop, Reason}
+ end.
+
+do_init(Opts) ->
+ {MgrDir, MgrConf, MgrOpts, AgentTargetName, AgentConf} = parse_opts(Opts),
+ ok = snmp_config:write_manager_config(MgrDir, "", MgrConf),
+ {ok, Pid} = snmpm:start_link(MgrOpts),
+ ok = snmpm:register_user(?USER, ?MODULE, self()),
+ ok = snmpm:register_agent(?USER, AgentTargetName, AgentConf),
+ {ok, #state{mgr = Pid, agent_target_name = AgentTargetName}}.
+
+
+parse_opts(Opts) ->
+ %% Manager config (written to the manager.conf file)
+ %% Addr = get_opt(addr, Opts, ?HOSTNAME()),
+ Port = get_opt(port, Opts, 5000),
+ EngineId = get_opt(engine_id, Opts, "mgrEngine"),
+ MMS = get_opt(max_message_size, Opts, 484),
+
+ MgrConf = [%% {address, Addr},
+ {port, Port},
+ {engine_id, EngineId},
+ {max_message_size, MMS}],
+
+
+ %% Manager options
+ MgrOpts = get_opt(options, Opts),
+ MgrDir = get_opt(dir, get_opt(config, MgrOpts, [])),
+
+
+ %% Retreive the agent configuration
+ AgentConf = get_opt(agent_config, Opts),
+ AgentTarget = get_opt(agent_target, Opts),
+ {MgrDir, MgrConf, MgrOpts, AgentTarget, AgentConf}.
+
+
+get_opt(Key, Opts) ->
+ case lists:keysearch(Key, 1, Opts) of
+ {value, {Key, Val}} ->
+ Val;
+ false ->
+ throw({error, {missing_mandatory, Key}})
+ end.
+
+get_opt(Key, Opts, Def) ->
+ case lists:keysearch(Key, 1, Opts) of
+ {value, {Key, Val}} ->
+ Val;
+ false ->
+ Def
+ end.
+
+
+%%--------------------------------------------------------------------
+%% Func: handle_call/3
+%% Returns: {reply, Reply, State} |
+%% {reply, Reply, State, Timeout} |
+%% {noreply, State} |
+%% {noreply, State, Timeout} |
+%% {stop, Reason, Reply, State} | (terminate/2 is called)
+%% {stop, Reason, State} (terminate/2 is called)
+%%--------------------------------------------------------------------
+handle_call(stop, _From, S) ->
+ (catch snmpm:stop()),
+ {stop, normal, S};
+
+handle_call({sync_get, Oids}, _From,
+ #state{agent_target_name = TargetName} = S) ->
+ Reply = (catch snmpm:sync_get(?USER, TargetName, Oids)),
+ {reply, Reply, S};
+
+handle_call({sync_get_next, Oids}, _From,
+ #state{agent_target_name = TargetName} = S) ->
+ Reply = (catch snmpm:sync_get_next(?USER, TargetName, Oids)),
+ {reply, Reply, S};
+
+handle_call({sync_get_bulk, NR, MR, Oids}, _From,
+ #state{agent_target_name = TargetName} = S) ->
+ Reply = (catch snmpm:sync_get_bulk(?USER, TargetName, NR, MR, Oids)),
+ {reply, Reply, S};
+
+handle_call({sync_set, VarsAndVals}, _From,
+ #state{agent_target_name = TargetName} = S) ->
+ Reply = (catch snmpm:sync_set(?USER, TargetName, VarsAndVals)),
+ {reply, Reply, S};
+
+handle_call(Req, From, State) ->
+ error_msg("received unknown request ~n~p~nFrom ~p", [Req, From]),
+ {reply, {error, unknown_request}, State}.
+
+
+%%--------------------------------------------------------------------
+%% Func: handle_cast/2
+%% Returns: {noreply, State} |
+%% {noreply, State, Timeout} |
+%% {stop, Reason, State} (terminate/2 is called)
+%%--------------------------------------------------------------------
+handle_cast(Msg, State) ->
+ error_msg("received unknown message ~n~p", [Msg]),
+ {noreply, State}.
+
+
+%%--------------------------------------------------------------------
+%% Func: handle_info/2
+%% Returns: {noreply, State} |
+%% {noreply, State, Timeout} |
+%% {stop, Reason, State} (terminate/2 is called)
+%%--------------------------------------------------------------------
+handle_info({snmp_error, ReqId, Reason},
+ #state{parent = P} = State) ->
+ info_msg("received snmp error: "
+ "~n ReqId: ~w"
+ "~n Reason: ~p", [ReqId, Reason]),
+ P ! {snmp_error, ReqId, Reason},
+ {noreply, State};
+
+handle_info({snmp_agent, Addr, Port, Info, Pid},
+ #state{parent = P} = State) ->
+ error_msg("detected new agent: "
+ "~n Addr: ~w"
+ "~n Port: ~p"
+ "~n Info: ~p", [Addr, Port, Info]),
+ Pid ! {snmp_agent_reply, ignore, self()},
+ P ! {snmp_agent, Addr, Port, Info},
+ {noreply, State};
+
+handle_info({snmp_pdu, TargetName, ReqId, Resp},
+ #state{parent = P} = State) ->
+ info_msg("received snmp pdu: "
+ "~n TargetName: ~p"
+ "~n ReqId: ~w"
+ "~n Resp: ~p", [TargetName, ReqId, Resp]),
+ P ! {snmp_pdu, TargetName, ReqId, Resp},
+ {noreply, State};
+
+handle_info({snmp_trap, TargetName, Info, Pid},
+ #state{parent = P} = State) ->
+ info_msg("received snmp trap: "
+ "~n TargetName: ~p"
+ "~n Info: ~p", [TargetName, Info]),
+ Pid ! {snmp_trap_reply, ignore, self()},
+ P ! {snmp_trap, TargetName, Info},
+ {noreply, State};
+
+handle_info({snmp_inform, TargetName, Info, Pid},
+ #state{parent = P} = State) ->
+ info_msg("received snmp inform: "
+ "~n TargetName: ~p"
+ "~n Info: ~p", [TargetName, Info]),
+ Pid ! {snmp_inform_reply, ignore, self()},
+ P ! {snmp_inform, TargetName, Info},
+ {noreply, State};
+
+handle_info({snmp_report, TargetName, Info, Pid},
+ #state{parent = P} = State) ->
+ info_msg("received snmp report: "
+ "~n TargetName: ~p"
+ "~n Info: ~p", [TargetName, Info]),
+ Pid ! {snmp_report_reply, ignore, self()},
+ P ! {snmp_report, TargetName, Info},
+ {noreply, State};
+
+handle_info(Info, State) ->
+ error_msg("received unknown info: "
+ "~n Info: ~p", [Info]),
+ {noreply, State}.
+
+
+%%--------------------------------------------------------------------
+%% Func: terminate/2
+%% Purpose: Shutdown the server
+%% Returns: any (ignored by gen_server)
+%%--------------------------------------------------------------------
+terminate(_Reason, _State) ->
+ ok.
+
+
+code_change({down, _Vsn}, State, _Extra) ->
+ {ok, State};
+
+% upgrade
+code_change(_Vsn, State, _Extra) ->
+ {ok, State}.
+
+
+%%%-------------------------------------------------------------------
+%%% Internal functions
+%%%-------------------------------------------------------------------
+
+
+
+
+%% --------------------------------------------------------------------------
+%%
+%% SNMP manager callback functions
+%%
+%% --------------------------------------------------------------------------
+
+handle_error(ReqId, Reason, Pid) ->
+ Pid ! {snmp_error, ReqId, Reason},
+ ignore.
+
+
+handle_agent(Addr, Port, SnmpInfo, Pid) ->
+ Pid ! {snmp_agent, Addr, Port, SnmpInfo, self()},
+ receive
+ {snmp_agent_reply, Reply, Pid} ->
+ Reply
+ after 10000 ->
+ ignore
+ end.
+
+
+handle_pdu(TargetName, ReqId, SnmpResponse, Pid) ->
+ Pid ! {snmp_pdu, TargetName, ReqId, SnmpResponse},
+ ignore.
+
+
+handle_trap(TargetName, SnmpTrapInfo, Pid) ->
+ Pid ! {snmp_trap, TargetName, SnmpTrapInfo, self()},
+ receive
+ {snmp_trap_reply, Reply, Pid} ->
+ Reply
+ after 10000 ->
+ ignore
+ end.
+
+
+handle_inform(TargetName, SnmpInfo, Pid) ->
+ Pid ! {snmp_inform, TargetName, SnmpInfo, self()},
+ receive
+ {snmp_inform_reply, Reply, Pid} ->
+ Reply
+ after 10000 ->
+ ignore
+ end.
+
+
+handle_report(TargetName, SnmpInfo, Pid) ->
+ Pid ! {snmp_report, TargetName, SnmpInfo, self()},
+ receive
+ {snmp_report_reply, Reply, Pid} ->
+ Reply
+ after 10000 ->
+ ignore
+ end.
+
+
+%%----------------------------------------------------------------------
+
+call(Req) ->
+ gen_server:call(?SERVER, Req, infinity).
+
+% cast(Msg) ->
+% gen_server:cast(?SERVER, Msg).
+
+info_msg(F, A) ->
+ catch error_logger:info_msg("*** TEST-MANAGER: " ++ F ++ "~n", A).
+
+error_msg(F, A) ->
+ catch error_logger:error_msg("*** TEST-MANAGER: " ++ F ++ "~n", A).
+
+
diff --git a/lib/snmp/test/snmp_test_mgr.erl b/lib/snmp/test/snmp_test_mgr.erl
new file mode 100644
index 0000000000..085dc8600f
--- /dev/null
+++ b/lib/snmp/test/snmp_test_mgr.erl
@@ -0,0 +1,1139 @@
+%%
+%% %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%
+%%
+
+-module(snmp_test_mgr).
+
+%%----------------------------------------------------------------------
+%% This module implements a simple SNMP manager for Erlang.
+%%----------------------------------------------------------------------
+
+%% c(snmp_test_mgr).
+%% snmp_test_mgr:start().
+%% snmp_test_mgr:g([[sysContact,0]]).
+
+%% snmp_test_mgr:start([{engine_id, "mbjk's engine"}, v3, {agent, "clip"}, {mibs, ["../mibs/SNMPv2-MIB"]}]).
+
+%% snmp_test_mgr:start([{engine_id, "agentEngine"}, {user, "iwl_test"}, {dir, "mgr_conf"}, {sec_level, authPriv}, v3, {agent, "clip"}]).
+
+%% User interface
+-export([start_link/1, start/1, stop/0,
+ d/0, discovery/0,
+ g/1, s/1, gn/1, gn/0, r/0, gb/3, rpl/1,
+ send_bytes/1,
+ expect/2,expect/3,expect/4,expect/6,get_response/2,
+ receive_response/0,
+ purify_oid/1,
+ oid_to_name/1, name_to_oid/1]).
+
+%% Internal exports
+-export([get_oid_from_varbind/1,
+ var_and_value_to_varbind/2, flatten_oid/2, make_vb/1]).
+-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2]).
+
+-include_lib("snmp/include/snmp_types.hrl").
+-include_lib("snmp/include/STANDARD-MIB.hrl").
+
+-record(state,{dbg = true,
+ quiet,
+ parent,
+ timeout = 3500,
+ print_traps = true,
+ mini_mib,
+ packet_server,
+ last_sent_pdu,
+ last_received_pdu}).
+
+-define(SERVER, ?MODULE).
+-define(PACK_SERV, snmp_test_mgr_misc).
+
+start_link(Options) ->
+ gen_server:start_link({local, ?SERVER}, ?MODULE, {Options, self()}, []).
+
+start(Options) ->
+ gen_server:start({local, ?SERVER}, ?MODULE, {Options, self()}, []).
+
+stop() ->
+ call(stop).
+
+d() ->
+ discovery().
+
+discovery() ->
+ call(discovery).
+
+g(Oids) ->
+ cast({get, Oids}).
+
+%% VarsAndValues is: {PlainOid, o|s|i, Value} (unknown mibs) | {Oid, Value}
+s(VarsAndValues) ->
+ cast({set, VarsAndValues}).
+
+gn(Oids) when is_list(Oids) ->
+ cast({get_next, Oids});
+gn(N) when is_integer(N) ->
+ cast({iter_get_next, N}).
+gn() ->
+ cast(iter_get_next).
+
+r() ->
+ cast(resend_pdu).
+
+gb(NonRepeaters, MaxRepetitions, Oids) ->
+ cast({bulk, {NonRepeaters, MaxRepetitions, Oids}}).
+
+rpl(RespPdu) ->
+ cast({response, RespPdu}).
+
+send_bytes(Bytes) ->
+ cast({send_bytes, Bytes}).
+
+purify_oid(Oid) ->
+ call({purify_oid, Oid}, 5000).
+
+oid_to_name(Oid) ->
+ call({oid_to_name, Oid}, 5000).
+
+name_to_oid(Name) ->
+ call({name_to_oid, Name}, 5000).
+
+
+%%----------------------------------------------------------------------
+%% Purpose: For writing test sequences
+%% Args: Y=any (varbinds) | trap | timeout | VarBinds | ErrStatus
+%% Returns: ok|{error, Id, Reason}
+%%----------------------------------------------------------------------
+expect(Id,Y) -> echo_errors(expect_impl(Id,Y)).
+expect(Id,v2trap,VBs) -> echo_errors(expect_impl(Id,v2trap,VBs));
+expect(Id,report,VBs) -> echo_errors(expect_impl(Id,report,VBs));
+expect(Id,{inform, Reply},VBs) ->
+ echo_errors(expect_impl(Id,{inform,Reply},VBs)).
+expect(Id,Err,Idx,VBs) -> echo_errors(expect_impl(Id,Err,Idx,VBs)).
+expect(Id,trap, Enterp, Generic, Specific, ExpectedVarbinds) ->
+ echo_errors(expect_impl(Id,trap,Enterp,Generic,
+ Specific,ExpectedVarbinds)).
+
+%%-----------------------------------------------------------------
+%% Purpose: For writing test sequences
+%%-----------------------------------------------------------------
+get_response(Id, Vars) -> echo_errors(get_response_impl(Id, Vars)).
+
+%%----------------------------------------------------------------------
+%% Receives a response from the agent.
+%% Returns: a PDU or {error, Reason}.
+%% It doesn't receive traps though.
+%%----------------------------------------------------------------------
+receive_response() ->
+ receive_response(get_timeout()).
+
+receive_response(Timeout) ->
+ d("await response within ~w ms",[Timeout]),
+ receive
+ {snmp_pdu, PDU} when is_record(PDU, pdu) ->
+ d("received PDU: ~n\t~p",[PDU]),
+ PDU
+ after Timeout ->
+ d("response timeout",[]),
+ {error, timeout}
+ end.
+
+
+get_timeout() ->
+ case get(receive_response_timeout) of
+ Int when is_integer(Int) and (Int > 0) ->
+ Int;
+ _ ->
+ get_timeout(os:type())
+ end.
+
+get_timeout(vxworks) -> 7000;
+get_timeout(_) -> 3500.
+
+%%----------------------------------------------------------------------
+%% Receives a trap from the agent.
+%% Returns: TrapPdu|{error, Reason}
+%%----------------------------------------------------------------------
+receive_trap(Timeout) ->
+ d("await trap within ~w ms",[Timeout]),
+ receive
+ {snmp_pdu, PDU} when is_record(PDU, trappdu) ->
+ d("received trap-PDU: ~n\t~p",[PDU]),
+ PDU
+ after Timeout ->
+ d("trap timeout",[]),
+ {error, timeout}
+ end.
+
+%%----------------------------------------------------------------------
+%% Options: List of
+%% {agent_udp, UDPPort}, {agent, Agent}
+%% Optional:
+%% {community, String ("public" is default}, quiet,
+%% {mibs, List of Filenames}, {trap_udp, UDPPort (default 5000)},
+%%----------------------------------------------------------------------
+init({Options, CallerPid}) ->
+ put(sname, mgr),
+ put(verbosity, debug),
+ {A1,A2,A3} = erlang:now(),
+ random:seed(A1,A2,A3),
+ case (catch is_options_ok(Options)) of
+ true ->
+ put(debug, get_value(debug, Options, false)),
+ d("init -> (~p) extract options",[self()]),
+ PacksDbg = get_value(packet_server_debug, Options, false),
+ io:format("[~w] ~p -> PacksDbg: ~p~n", [?MODULE, self(), PacksDbg]),
+ RecBufSz = get_value(recbuf, Options, 1024),
+ io:format("[~w] ~p -> RecBufSz: ~p~n", [?MODULE, self(), RecBufSz]),
+ Mibs = get_value(mibs, Options, []),
+ io:format("[~w] ~p -> Mibs: ~p~n", [?MODULE, self(), Mibs]),
+ Udp = get_value(agent_udp, Options, 4000),
+ io:format("[~w] ~p -> Udp: ~p~n", [?MODULE, self(), Udp]),
+ User = get_value(user, Options, "initial"),
+ io:format("[~w] ~p -> User: ~p~n", [?MODULE, self(), User]),
+ EngineId = get_value(engine_id, Options, "agentEngine"),
+ io:format("[~w] ~p -> EngineId: ~p~n", [?MODULE, self(), EngineId]),
+ CtxEngineId = get_value(context_engine_id, Options, EngineId),
+ io:format("[~w] ~p -> CtxEngineId: ~p~n", [?MODULE, self(), CtxEngineId]),
+ TrapUdp = get_value(trap_udp, Options, 5000),
+ io:format("[~w] ~p -> TrapUdp: ~p~n", [?MODULE, self(), TrapUdp]),
+ Dir = get_value(dir, Options, "."),
+ io:format("[~w] ~p -> Dir: ~p~n", [?MODULE, self(), Dir]),
+ SecLevel = get_value(sec_level, Options, noAuthNoPriv),
+ io:format("[~w] ~p -> SecLevel: ~p~n", [?MODULE, self(), SecLevel]),
+ MiniMIB = snmp_mini_mib:create(Mibs),
+ io:format("[~w] ~p -> MiniMIB: ~p~n", [?MODULE, self(), MiniMIB]),
+ Version = case lists:member(v2, Options) of
+ true -> 'version-2';
+ false ->
+ case lists:member(v3, Options) of
+ true -> 'version-3';
+ false -> 'version-1'
+ end
+ end,
+ io:format("[~w] ~p -> Version: ~p~n", [?MODULE, self(), Version]),
+ Com = case Version of
+ 'version-3' ->
+ get_value(context, Options, "");
+ _ ->
+ get_value(community, Options, "public")
+ end,
+ io:format("[~w] ~p -> Com: ~p~n", [?MODULE, self(), Com]),
+ VsnHdrD =
+ {Com, User, EngineId, CtxEngineId, mk_seclevel(SecLevel)},
+ io:format("[~w] ~p -> VsnHdrD: ~p~n", [?MODULE, self(), VsnHdrD]),
+ AgIp = case snmp_misc:assq(agent, Options) of
+ {value, Tuple4} when is_tuple(Tuple4) andalso
+ (size(Tuple4) =:= 4) ->
+ Tuple4;
+ {value, Host} when is_list(Host) ->
+ {ok, Ip} = snmp_misc:ip(Host),
+ Ip
+ end,
+ io:format("[~w] ~p -> AgIp: ~p~n", [?MODULE, self(), AgIp]),
+ Quiet = lists:member(quiet, Options),
+ io:format("[~w] ~p -> Quiet: ~p~n", [?MODULE, self(), Quiet]),
+ PackServ = start_packet_server(Quiet, Options, CallerPid,
+ AgIp, Udp, TrapUdp,
+ VsnHdrD, Version, Dir, RecBufSz,
+ PacksDbg),
+ d("init -> packet server: ~p",[PackServ]),
+ State = #state{parent = CallerPid,
+ quiet = Quiet,
+ mini_mib = MiniMIB,
+ packet_server = PackServ},
+ d("init -> done",[]),
+ {ok, State};
+
+ {error, Reason} ->
+ {stop,Reason}
+ end.
+
+start_packet_server(false, _Options, _CallerPid, AgIp, Udp, TrapUdp,
+ VsnHdrD, Version, Dir, RecBufSz, PacksDbg) ->
+ d("start_packet_server -> entry", []),
+ ?PACK_SERV:start_link_packet({msg, self()},
+ AgIp, Udp, TrapUdp,
+ VsnHdrD, Version, Dir, RecBufSz,
+ PacksDbg);
+start_packet_server(true, Options, CallerPid, AgIp, Udp, TrapUdp,
+ VsnHdrD, Version, Dir, RecBufSz, PacksDbg) ->
+ Type = get_value(receive_type, Options, pdu),
+ d("start_packet_server -> entry with"
+ "~n CallerPid: ~p"
+ "~n when"
+ "~n Type: ~p",[CallerPid, Type]),
+ ?PACK_SERV:start_link_packet({Type, CallerPid},
+ AgIp, Udp, TrapUdp,
+ VsnHdrD, Version, Dir, RecBufSz,
+ PacksDbg).
+
+is_options_ok([{mibs,List}|Opts]) when is_list(List) ->
+ is_options_ok(Opts);
+is_options_ok([quiet|Opts]) ->
+ is_options_ok(Opts);
+is_options_ok([{agent,_}|Opts]) ->
+ is_options_ok(Opts);
+is_options_ok([{agent_udp,Int}|Opts]) when is_integer(Int) ->
+ is_options_ok(Opts);
+is_options_ok([{trap_udp,Int}|Opts]) when is_integer(Int) ->
+ is_options_ok(Opts);
+is_options_ok([{community,List}|Opts]) when is_list(List) ->
+ is_options_ok(Opts);
+is_options_ok([{dir,List}|Opts]) when is_list(List) ->
+ is_options_ok(Opts);
+is_options_ok([{sec_level,noAuthNoPriv}|Opts]) ->
+ is_options_ok(Opts);
+is_options_ok([{sec_level,authNoPriv}|Opts]) ->
+ is_options_ok(Opts);
+is_options_ok([{sec_level,authPriv}|Opts]) ->
+ is_options_ok(Opts);
+is_options_ok([{context,List}|Opts]) when is_list(List) ->
+ is_options_ok(Opts);
+is_options_ok([{user,List}|Opts]) when is_list(List) ->
+ is_options_ok(Opts);
+is_options_ok([{engine_id,List}|Opts]) when is_list(List) ->
+ is_options_ok(Opts);
+is_options_ok([{context_engine_id,List}|Opts]) when is_list(List) ->
+ is_options_ok(Opts);
+is_options_ok([v1|Opts]) ->
+ is_options_ok(Opts);
+is_options_ok([v2|Opts]) ->
+ is_options_ok(Opts);
+is_options_ok([v3|Opts]) ->
+ is_options_ok(Opts);
+is_options_ok([{debug,Bool}|Opts]) ->
+ case is_bool(Bool) of
+ ok ->
+ is_options_ok(Opts);
+ error ->
+ {error, {bad_option, debug, Bool}}
+ end;
+is_options_ok([{packet_server_debug,Bool}|Opts]) ->
+ case is_bool(Bool) of
+ ok ->
+ is_options_ok(Opts);
+ error ->
+ {error, {bad_option, packet_server_debug, Bool}}
+ end;
+is_options_ok([{recbuf,Sz}|Opts]) when (0 < Sz) and (Sz =< 65535) ->
+ is_options_ok(Opts);
+is_options_ok([InvOpt|_]) ->
+ {error,{invalid_option,InvOpt}};
+is_options_ok([]) -> true.
+
+is_bool(true) -> ok;
+is_bool(false) -> ok;
+is_bool(_) -> error.
+
+mk_seclevel(noAuthNoPriv) -> 0;
+mk_seclevel(authNoPriv) -> 1;
+mk_seclevel(authPriv) -> 3.
+
+
+handle_call({purify_oid, Oid}, _From, #state{mini_mib = MiniMib} = State) ->
+ d("handle_call -> purify_oid for ~p",[Oid]),
+ Reply = (catch purify_oid(Oid, MiniMib)),
+ {reply, Reply, State};
+
+handle_call({find_pure_oid, XOid}, _From, State) ->
+ d("handle_call -> find_pure_oid for ~p",[XOid]),
+ {reply, catch flatten_oid(XOid, State#state.mini_mib), State};
+
+handle_call({oid_to_name, Oid}, _From, State) ->
+ d("handle_call -> oid_to_name for Oid: ~p",[Oid]),
+ Reply =
+ case lists:keysearch(Oid, 1, State#state.mini_mib) of
+ {value, {_Oid, Name, _Type}} ->
+ {ok, Name};
+ false ->
+ {error, {no_such_oid, Oid}}
+ end,
+ {reply, Reply, State};
+
+handle_call({name_to_oid, Name}, _From, State) ->
+ d("handle_call -> name_to_oid for Name: ~p",[Name]),
+ Reply =
+ case lists:keysearch(Name, 2, State#state.mini_mib) of
+ {value, {Oid, _Name, _Type}} ->
+ {ok, Oid};
+ false ->
+ {error, {no_such_name, Name}}
+ end,
+ {reply, Reply, State};
+
+handle_call(stop, _From, #state{mini_mib = MiniMIB} = State) ->
+ d("handle_call -> stop request",[]),
+ snmp_mini_mib:delete(MiniMIB),
+ {stop, normal, ok, State#state{mini_mib = undefined}};
+
+handle_call(discovery, _From, State) ->
+ d("handle_call -> discovery",[]),
+ {Reply, NewState} = execute_discovery(State),
+ {reply, Reply, NewState}.
+
+
+handle_cast({get, Oids}, State) ->
+ d("handle_cast -> get request for ~p", [Oids]),
+ {noreply, execute_request(get, Oids, State)};
+
+handle_cast({set, VariablesAndValues}, State) ->
+ d("handle_cast -> set request for ~p", [VariablesAndValues]),
+ {noreply, execute_request(set, VariablesAndValues, State)};
+
+handle_cast({get_next, Oids}, State) ->
+ d("handle_cast -> get-next request for ~p", [Oids]),
+ {noreply, execute_request(get_next, Oids, State)};
+
+handle_cast(iter_get_next, State)
+ when is_record(State#state.last_received_pdu, pdu) ->
+ d("handle_cast -> iter_get_next request", []),
+ PrevPDU = State#state.last_received_pdu,
+ Oids = [get_oid_from_varbind(Vb) || Vb <- PrevPDU#pdu.varbinds],
+ {noreply, execute_request(get_next, Oids, State)};
+
+handle_cast(iter_get_next, State) ->
+ ?PACK_SERV:error("[Iterated get-next] No Response PDU to "
+ "start iterating from.", []),
+ {noreply, State};
+
+handle_cast({iter_get_next, N}, State) ->
+ d("handle_cast -> iter_get_next(~p) request",[N]),
+ if
+ is_record(State#state.last_received_pdu, pdu) ->
+ PDU = get_next_iter_impl(N, State#state.last_received_pdu,
+ State#state.mini_mib,
+ State#state.packet_server),
+ {noreply, State#state{last_received_pdu = PDU}};
+ true ->
+ ?PACK_SERV:error("[Iterated get-next] No Response PDU to "
+ "start iterating from.", []),
+ {noreply, State}
+ end;
+
+handle_cast(resend_pdu, #state{last_sent_pdu = PDU} = State) ->
+ d("handle_cast -> resend_pdu request when"
+ "~n PDU = ~p", [PDU]),
+ send_pdu(PDU#pdu{request_id = make_request_id()},
+ State#state.mini_mib,
+ State#state.packet_server),
+ {noreply, State};
+
+handle_cast({bulk, Args}, State) ->
+ d("handle_bulk -> bulk request for ~p", [Args]),
+ {noreply, execute_request(bulk, Args, State)};
+
+handle_cast({response, RespPdu}, State) ->
+ d("handle_cast -> response request with ~p", [RespPdu]),
+ ?PACK_SERV:send_pdu(RespPdu, State#state.packet_server),
+ {noreply, State};
+
+handle_cast({send_bytes, Bytes}, State) ->
+ d("handle_cast -> send-bytes request for ~p bytes", [sizeOf(Bytes)]),
+ ?PACK_SERV:send_bytes(Bytes, State#state.packet_server),
+ {noreply, State};
+
+handle_cast(Msg, State) ->
+ d("handle_cast -> unknown message: "
+ "~n ~p", [Msg]),
+ {noreply, State}.
+
+
+handle_info({snmp_msg, Msg, Ip, Udp}, State) ->
+ io:format("* Got PDU: ~s", [?PACK_SERV:format_hdr(Msg)]),
+ PDU = ?PACK_SERV:get_pdu(Msg),
+ echo_pdu(PDU, State#state.mini_mib),
+ case PDU#pdu.type of
+ 'inform-request' ->
+ %% Generate a response...
+ RespPDU = PDU#pdu{type = 'get-response',
+ error_status = noError,
+ error_index = 0},
+ RespMsg = ?PACK_SERV:set_pdu(Msg, RespPDU),
+ ?PACK_SERV:send_msg(RespMsg, State#state.packet_server, Ip, Udp);
+ _Else ->
+ ok
+ end,
+ {noreply, State#state{last_received_pdu = PDU}};
+
+handle_info(Info, State) ->
+ d("handle_info -> unknown info: "
+ "~n ~p", [Info]),
+ {noreply, State}.
+
+
+terminate(Reason, State) ->
+ d("terminate -> with Reason: ~n\t~p",[Reason]),
+ ?PACK_SERV:stop(State#state.packet_server).
+
+
+%%----------------------------------------------------------------------
+%% Returns: A new State
+%%----------------------------------------------------------------------
+execute_discovery(State) ->
+ Pdu = make_discovery_pdu(),
+ Reply = ?PACK_SERV:send_discovery_pdu(Pdu, State#state.packet_server),
+ {Reply, State#state{last_sent_pdu = Pdu}}.
+
+
+execute_request(Operation, Data, State) ->
+ case (catch make_pdu(Operation, Data, State#state.mini_mib)) of
+ {error, {Format, Data2}} ->
+ report_error(State, Format, Data2),
+ State;
+ {error, _Reason} ->
+ State;
+ PDU when is_record(PDU, pdu) ->
+ send_pdu(PDU, State#state.mini_mib, State#state.packet_server),
+ State#state{last_sent_pdu = PDU}
+ end.
+
+report_error(#state{quiet = true, parent = Pid}, Format, Args) ->
+ Reason = lists:flatten(io_lib:format(Format, Args)),
+ Pid ! {oid_error, Reason};
+report_error(_, Format, Args) ->
+ ?PACK_SERV:error(Format, Args).
+
+
+get_oid_from_varbind(#varbind{oid = Oid}) -> Oid.
+
+send_pdu(PDU, _MiniMIB, PackServ) ->
+ ?PACK_SERV:send_pdu(PDU, PackServ).
+
+%%----------------------------------------------------------------------
+%% Purpose: Unnesting of oids like [myTable, 3, 4, "hej", 45] to
+%% [1,2,3,3,4,104,101,106,45]
+%%----------------------------------------------------------------------
+
+purify_oid([A|T], MiniMib) when is_atom(A) ->
+ Oid2 =
+ case snmp_mini_mib:oid(MiniMib, A) of
+ false ->
+ throw({error, {unknown_aliasname, A}});
+ Oid ->
+ lists:flatten([Oid|T])
+ end,
+ {ok, verify_pure_oid(Oid2)};
+purify_oid(L, _) when is_list(L) ->
+ {ok, verify_pure_oid(lists:flatten(L))};
+purify_oid(X, _) ->
+ {error, {invalid_oid, X}}.
+
+verify_pure_oid([]) ->
+ [];
+verify_pure_oid([H | T]) when is_integer(H) and (H >= 0) ->
+ [H | verify_pure_oid(T)];
+verify_pure_oid([H | _]) ->
+ throw({error, {not_pure_oid, H}}).
+
+flatten_oid(XOid, DB) ->
+ Oid = case XOid of
+ [A|T] when is_atom(A) ->
+ [remove_atom(A, DB)|T];
+ L when is_list(L) ->
+ XOid;
+ Shit ->
+ throw({error,
+ {"Invalid oid, not a list of integers: ~w", [Shit]}})
+ end,
+ check_is_pure_oid(lists:flatten(Oid)).
+
+remove_atom(AliasName, DB) when is_atom(AliasName) ->
+ case snmp_mini_mib:oid(DB, AliasName) of
+ false ->
+ throw({error, {"Unknown aliasname in oid: ~w", [AliasName]}});
+ Oid ->
+ Oid
+ end;
+remove_atom(X, _DB) ->
+ X.
+
+%%----------------------------------------------------------------------
+%% Throws if not a list of integers
+%%----------------------------------------------------------------------
+check_is_pure_oid([]) -> [];
+check_is_pure_oid([X | T]) when is_integer(X) and (X >= 0) ->
+ [X | check_is_pure_oid(T)];
+check_is_pure_oid([X | _T]) ->
+ throw({error, {"Invalid oid, it contains a non-integer: ~w", [X]}}).
+
+get_next_iter_impl(0, PrevPDU, _MiniMIB, _PackServ) ->
+ PrevPDU;
+get_next_iter_impl(N, PrevPDU, MiniMIB, PackServ) ->
+ Oids = [get_oid_from_varbind(Vb) || Vb <- PrevPDU#pdu.varbinds],
+ PDU = make_pdu(get_next, Oids, MiniMIB),
+ send_pdu(PDU, MiniMIB, PackServ),
+ case receive_response() of
+ {error, timeout} ->
+ io:format("(timeout)~n"),
+ get_next_iter_impl(N, PrevPDU, MiniMIB, PackServ);
+ {error, _Reason} ->
+ PrevPDU;
+ RPDU when is_record(RPDU, pdu) ->
+ io:format("(~w)", [N]),
+ echo_pdu(RPDU, MiniMIB),
+ get_next_iter_impl(N-1, RPDU, MiniMIB, PackServ)
+ end.
+
+%%--------------------------------------------------
+%% Used to resend a PDU. Takes the old PDU and
+%% generates a fresh one (with a new requestID).
+%%--------------------------------------------------
+
+make_pdu(set, VarsAndValues, MiniMIB) ->
+ VBs = [var_and_value_to_varbind(VAV, MiniMIB) || VAV <- VarsAndValues],
+ make_pdu_impl(set, VBs);
+make_pdu(bulk, {NonRepeaters, MaxRepetitions, Oids}, MiniMIB) ->
+ Foids = [flatten_oid(Oid, MiniMIB) || Oid <- Oids],
+ #pdu{type = 'get-bulk-request',
+ request_id = make_request_id(),
+ error_status = NonRepeaters,
+ error_index = MaxRepetitions,
+ varbinds = [make_vb(Oid) || Oid <- Foids]};
+make_pdu(Operation, Oids, MiniMIB) ->
+ Foids = [flatten_oid(Oid, MiniMIB) || Oid <- Oids],
+ make_pdu_impl(Operation, Foids).
+
+make_pdu_impl(get, Oids) ->
+ #pdu{type = 'get-request',
+ request_id = make_request_id(),
+ error_status = noError,
+ error_index = 0,
+ varbinds = [make_vb(Oid) || Oid <- Oids]};
+
+make_pdu_impl(get_next, Oids) ->
+ #pdu{type = 'get-next-request',
+ request_id = make_request_id(),
+ error_status = noError,
+ error_index = 0,
+ varbinds = [make_vb(Oid) || Oid <- Oids]};
+
+make_pdu_impl(set, Varbinds) ->
+ #pdu{type = 'set-request',
+ request_id = make_request_id(),
+ error_status = noError,
+ error_index = 0,
+ varbinds = Varbinds}.
+
+make_discovery_pdu() ->
+ make_pdu_impl(get, []).
+
+var_and_value_to_varbind({Oid, Type, Value}, MiniMIB) ->
+ Oid2 = flatten_oid(Oid, MiniMIB),
+ #varbind{oid = Oid2,
+ variabletype = char_to_type(Type),
+ value = Value};
+var_and_value_to_varbind({XOid, Value}, MiniMIB) ->
+ Oid = flatten_oid(XOid, MiniMIB),
+ #varbind{oid = Oid,
+ variabletype = snmp_mini_mib:type(MiniMIB, Oid),
+ value = Value}.
+
+char_to_type(o) ->
+ 'OBJECT IDENTIFIER';
+char_to_type(i) ->
+ 'INTEGER';
+char_to_type(u) ->
+ 'Unsigned32';
+char_to_type(g) -> % Gauge, Gauge32
+ 'Unsigned32';
+char_to_type(s) ->
+ 'OCTET STRING'.
+
+make_vb(Oid) ->
+ #varbind{oid = Oid, variabletype = 'NULL', value = 'NULL'}.
+
+make_request_id() ->
+ random:uniform(16#FFFFFFF-1).
+
+echo_pdu(PDU, MiniMIB) ->
+ io:format("~s", [snmp_misc:format_pdu(PDU, MiniMIB)]).
+
+
+%%----------------------------------------------------------------------
+%% Test Sequence
+%%----------------------------------------------------------------------
+echo_errors({error, Id, {ExpectedFormat, ExpectedData}, {Format, Data}})->
+ io:format("* Unexpected Behaviour * Id: ~w.~n"
+ " Expected: " ++ ExpectedFormat ++ "~n"
+ " Got: " ++ Format ++ "~n",
+ [Id] ++ ExpectedData ++ Data),
+ {error, Id, {ExpectedFormat, ExpectedData}, {Format, Data}};
+echo_errors(ok) -> ok;
+echo_errors({ok, Val}) -> {ok, Val}.
+
+get_response_impl(Id, Vars) ->
+ case receive_response() of
+ #pdu{type = 'get-response',
+ error_status = noError,
+ error_index = 0,
+ varbinds = VBs} ->
+ match_vars(Id, find_pure_oids2(Vars), VBs, []);
+
+ #pdu{type = Type2,
+ request_id = ReqId,
+ error_status = Err2,
+ error_index = Index2} ->
+ {error,
+ Id,
+ {"Type: ~w, ErrStat: ~w, Idx: ~w, RequestId: ~w",
+ ['get-response', noError, 0, ReqId]},
+ {"Type: ~w, ErrStat: ~w, Idx: ~w",
+ [Type2, Err2, Index2]}};
+
+ {error, Reason} ->
+ format_reason(Id, Reason)
+ end.
+
+
+
+%%----------------------------------------------------------------------
+%% Returns: ok | {error, Id, {ExpectedFormat, ExpectedData}, {Format, Data}}
+%%----------------------------------------------------------------------
+expect_impl(Id, any) ->
+ io:format("expect_impl(~w, any) -> entry ~n", [Id]),
+ case receive_response() of
+ PDU when is_record(PDU, pdu) -> ok;
+ {error, Reason} -> format_reason(Id, Reason)
+ end;
+
+expect_impl(Id, return) ->
+ io:format("expect_impl(~w, return) -> entry ~n", [Id]),
+ case receive_response() of
+ PDU when is_record(PDU, pdu) -> {ok, PDU};
+ {error, Reason} -> format_reason(Id, Reason)
+ end;
+
+expect_impl(Id, trap) ->
+ io:format("expect_impl(~w, trap) -> entry ~n", [Id]),
+ case receive_trap(3500) of
+ PDU when is_record(PDU, trappdu) -> ok;
+ {error, Reason} -> format_reason(Id, Reason)
+ end;
+
+expect_impl(Id, timeout) ->
+ io:format("expect_impl(~w, timeout) -> entry ~n", [Id]),
+ receive
+ X ->
+ io:format("expect_impl(~w, timeout) -> "
+ "received unexpected message: ~n~p~n", [Id, X]),
+ {error, Id, {"Timeout", []}, {"Message ~w", [X]}}
+ after 3500 ->
+ ok
+ end;
+
+expect_impl(Id, Err) when is_atom(Err) ->
+ io:format("expect_impl(~w, ~w) -> entry ~n", [Id, Err]),
+ case receive_response() of
+ #pdu{error_status = Err} ->
+ ok;
+
+ #pdu{request_id = ReqId,
+ error_status = OtherErr} ->
+ io:format("expect_impl(~w, ~w) -> "
+ "received pdu (~w) with unexpected error-status: "
+ "~n~p~n", [Id, Err, ReqId, OtherErr]),
+ {error, Id, {"ErrorStatus: ~w, RequestId: ~w", [Err,ReqId]},
+ {"ErrorStatus: ~w", [OtherErr]}};
+
+ {error, Reason} ->
+ format_reason(Id, Reason)
+ end;
+
+expect_impl(Id, ExpectedVarbinds) when is_list(ExpectedVarbinds) ->
+ io:format("expect_impl(~w) -> entry with"
+ "~n ExpectedVarbinds: ~p~n", [Id, ExpectedVarbinds]),
+ case receive_response() of
+ #pdu{type = 'get-response',
+ error_status = noError,
+ error_index = 0,
+ varbinds = VBs} ->
+ io:format("expect_impl(~w) -> received pdu with"
+ "~n VBs: ~p~n", [Id, VBs]),
+ check_vars(Id, find_pure_oids(ExpectedVarbinds), VBs);
+
+ #pdu{type = Type2,
+ request_id = ReqId,
+ error_status = Err2,
+ error_index = Index2} ->
+ io:format("expect_impl(~w) -> received unexpected pdu with"
+ "~n Type2: ~p"
+ "~n ReqId: ~p"
+ "~n Err2: ~p"
+ "~n Index2: ~p"
+ "~n", [Id, Type2, ReqId, Err2, Index2]),
+ {error, Id, {"Type: ~w, ErrStat: ~w, Idx: ~w, RequestId: ~w",
+ ['get-response', noError, 0, ReqId]},
+ {"Type: ~w, ErrStat: ~w, Idx: ~w", [Type2, Err2, Index2]}};
+
+ {error, Reason} ->
+ format_reason(Id, Reason)
+ end.
+
+expect_impl(Id, v2trap, ExpectedVarbinds) when is_list(ExpectedVarbinds) ->
+ io:format("expect_impl(~w, v2trap) -> entry with"
+ "~n ExpectedVarbinds: ~p~n", [Id, ExpectedVarbinds]),
+ case receive_response() of
+ #pdu{type = 'snmpv2-trap',
+ error_status = noError,
+ error_index = 0,
+ varbinds = VBs} ->
+ io:format("expect_impl(~w, v2trap) -> received pdu with"
+ "~n VBs: ~p~n", [Id, VBs]),
+ check_vars(Id, find_pure_oids(ExpectedVarbinds), VBs);
+
+ #pdu{type = Type2,
+ request_id = ReqId,
+ error_status = Err2,
+ error_index = Index2} ->
+ io:format("expect_impl(~w, v2trap) -> received unexpected pdu with"
+ "~n Type2: ~p"
+ "~n ReqId: ~p"
+ "~n Err2: ~p"
+ "~n Index2: ~p"
+ "~n", [Id, Type2, ReqId, Err2, Index2]),
+ {error, Id, {"Type: ~w, ErrStat: ~w, Idx: ~w, RequestId: ~w",
+ ['snmpv2-trap', noError, 0, ReqId]},
+ {"Type: ~w, ErrStat: ~w, Idx: ~w", [Type2, Err2, Index2]}};
+
+ {error, Reason} ->
+ format_reason(Id, Reason)
+ end;
+
+expect_impl(Id, report, ExpectedVarbinds) when is_list(ExpectedVarbinds) ->
+ io:format("expect_impl(~w, report) -> entry with"
+ "~n ExpectedVarbinds: ~p~n", [Id, ExpectedVarbinds]),
+ case receive_response() of
+ #pdu{type = 'report',
+ error_status = noError,
+ error_index = 0,
+ varbinds = VBs} ->
+ io:format("expect_impl(~w, report) -> received pdu with"
+ "~n VBs: ~p~n", [Id, VBs]),
+ check_vars(Id, find_pure_oids(ExpectedVarbinds), VBs);
+
+ #pdu{type = Type2,
+ request_id = ReqId,
+ error_status = Err2,
+ error_index = Index2} ->
+ io:format("expect_impl(~w, report) -> received unexpected pdu with"
+ "~n Type2: ~p"
+ "~n ReqId: ~p"
+ "~n Err2: ~p"
+ "~n Index2: ~p"
+ "~n", [Id, Type2, ReqId, Err2, Index2]),
+ {error, Id, {"Type: ~w, ErrStat: ~w, Idx: ~w, RequestId: ~w",
+ [report, noError, 0, ReqId]},
+ {"Type: ~w, ErrStat: ~w, Idx: ~w", [Type2, Err2, Index2]}};
+
+ {error, Reason} ->
+ format_reason(Id, Reason)
+ end;
+
+expect_impl(Id, {inform, Reply}, ExpectedVarbinds)
+ when is_list(ExpectedVarbinds) ->
+ io:format("expect_impl(~w, inform) -> entry with"
+ "~n Reply: ~p"
+ "~n ExpectedVarbinds: ~p"
+ "~n", [Id, Reply, ExpectedVarbinds]),
+ Resp = receive_response(),
+ case Resp of
+ #pdu{type = 'inform-request',
+ error_status = noError,
+ error_index = 0,
+ varbinds = VBs} ->
+ io:format("expect_impl(~w, inform) -> received pdu with"
+ "~n VBs: ~p~n", [Id, VBs]),
+ case check_vars(Id, find_pure_oids(ExpectedVarbinds), VBs) of
+ ok when (Reply == true) ->
+ io:format("expect_impl(~w, inform) -> send ok response"
+ "~n", [Id]),
+ RespPDU = Resp#pdu{type = 'get-response',
+ error_status = noError,
+ error_index = 0},
+ ?MODULE:rpl(RespPDU),
+ ok;
+ ok when (element(1, Reply) == error) ->
+ io:format("expect_impl(~w, inform) -> send error response"
+ "~n", [Id]),
+ {error, Status, Index} = Reply,
+ RespPDU = Resp#pdu{type = 'get-response',
+ error_status = Status,
+ error_index = Index},
+ ?MODULE:rpl(RespPDU),
+ ok;
+ ok when (Reply == false) ->
+ io:format("expect_impl(~w, inform) -> no response sent"
+ "~n", [Id]),
+ ok;
+ Else ->
+ io:format("expect_impl(~w, inform) -> "
+ "~n Else: ~p"
+ "~n", [Id, Else]),
+ Else
+ end;
+
+ #pdu{type = Type2,
+ request_id = ReqId,
+ error_status = Err2,
+ error_index = Index2} ->
+ io:format("expect_impl(~w, inform) -> received unexpected pdu with"
+ "~n Type2: ~p"
+ "~n ReqId: ~p"
+ "~n Err2: ~p"
+ "~n Index2: ~p"
+ "~n", [Id, Type2, ReqId, Err2, Index2]),
+ {error, Id, {"Type: ~w, ErrStat: ~w, Idx: ~w, RequestId: ~w",
+ ['inform-request', noError, 0, ReqId]},
+ {"Type: ~w, ErrStat: ~w, Idx: ~w", [Type2, Err2, Index2]}};
+
+ {error, Reason} ->
+ io:format("expect_impl(~w, inform) -> receive failed"
+ "~n Reason: ~p"
+ "~n", [Id, Reason]),
+ format_reason(Id, Reason)
+ end.
+
+expect_impl(Id, Err, Index, any) ->
+ io:format("expect_impl(~w, any) -> entry with"
+ "~n Err: ~p"
+ "~n Index: ~p"
+ "~n", [Id, Err, Index]),
+ case receive_response() of
+ #pdu{type = 'get-response',
+ error_status = Err,
+ error_index = Index} ->
+ io:format("expect_impl(~w, any) -> received expected pdu"
+ "~n", [Id]),
+ ok;
+
+ #pdu{type = 'get-response', error_status = Err} when (Index == any) ->
+ io:format("expect_impl(~w, any) -> received expected pdu (any)"
+ "~n", [Id]),
+ ok;
+
+ #pdu{type = 'get-response',
+ request_id = ReqId,
+ error_status = Err,
+ error_index = Idx} when is_list(Index) ->
+ io:format("expect_impl(~w, any) -> received pdu: "
+ "~n ReqId: ~p"
+ "~n Err: ~p"
+ "~n Idx: ~p"
+ "~n", [Id, ReqId, Err, Idx]),
+ case lists:member(Idx, Index) of
+ true ->
+ ok;
+ false ->
+ {error, Id, {"ErrStat: ~w, Idx: ~w, RequestId: ~w",
+ [Err, Index, ReqId]},
+ {"ErrStat: ~w, Idx: ~w", [Err, Idx]}}
+ end;
+
+ #pdu{type = Type2,
+ request_id = ReqId,
+ error_status = Err2,
+ error_index = Index2} ->
+ io:format("expect_impl(~w, any) -> received unexpected pdu: "
+ "~n Type2: ~p"
+ "~n ReqId: ~p"
+ "~n Err2: ~p"
+ "~n Index2: ~p"
+ "~n", [Id, Type2, ReqId, Err2, Index2]),
+ {error, Id, {"Type: ~w, ErrStat: ~w, Idx: ~w, RequestId: ~w",
+ ['get-response', Err, Index, ReqId]},
+ {"Type: ~w, ErrStat: ~w, Idx: ~w", [Type2, Err2, Index2]}};
+
+ {error, Reason} ->
+ format_reason(Id, Reason)
+ end;
+
+expect_impl(Id, Err, Index, ExpectedVarbinds) ->
+ io:format("expect_impl(~w) -> entry with"
+ "~n Err: ~p"
+ "~n Index: ~p"
+ "~n ExpectedVarbinds: ~p"
+ "~n", [Id, Err, Index, ExpectedVarbinds]),
+ PureVBs = find_pure_oids(ExpectedVarbinds),
+ case receive_response() of
+ #pdu{type = 'get-response',
+ error_status = Err,
+ error_index = Index,
+ varbinds = VBs} ->
+ check_vars(Id, PureVBs, VBs);
+
+ #pdu{type = 'get-response',
+ error_status = Err,
+ varbinds = VBs} when (Index == any) ->
+ check_vars(Id, PureVBs, VBs);
+
+ #pdu{type = 'get-response',
+ request_id = ReqId,
+ error_status = Err,
+ error_index = Idx,
+ varbinds = VBs} when is_list(Index) ->
+ case lists:member(Idx, Index) of
+ true ->
+ check_vars(Id, PureVBs, VBs);
+ false ->
+ {error,Id,
+ {"ErrStat: ~w, Idx: ~w, Varbinds: ~w, RequestId: ~w",
+ [Err,Index,PureVBs,ReqId]},
+ {"ErrStat: ~w, Idx: ~w, Varbinds: ~w",
+ [Err,Idx,VBs]}}
+ end;
+
+ #pdu{type = Type2,
+ request_id = ReqId,
+ error_status = Err2,
+ error_index = Index2,
+ varbinds = VBs} ->
+ {error,Id,
+ {"Type: ~w, ErrStat: ~w, Idx: ~w, Varbinds: ~w, RequestId: ~w",
+ ['get-response',Err,Index,PureVBs,ReqId]},
+ {"Type: ~w, ErrStat: ~w Idx: ~w Varbinds: ~w",
+ [Type2,Err2,Index2,VBs]}};
+
+ {error, Reason} ->
+ format_reason(Id, Reason)
+ end.
+
+expect_impl(Id, trap, Enterp, Generic, Specific, ExpectedVarbinds) ->
+ PureE = find_pure_oid(Enterp),
+ case receive_trap(3500) of
+ #trappdu{enterprise = PureE,
+ generic_trap = Generic,
+ specific_trap = Specific,
+ varbinds = VBs} ->
+ check_vars(Id, find_pure_oids(ExpectedVarbinds), VBs);
+
+ #trappdu{enterprise = Ent2,
+ generic_trap = G2,
+ specific_trap = Spec2,
+ varbinds = VBs} ->
+ {error, Id,
+ {"Enterprise: ~w, Generic: ~w, Specific: ~w, Varbinds: ~w",
+ [PureE, Generic, Specific, ExpectedVarbinds]},
+ {"Enterprise: ~w, Generic: ~w, Specific: ~w, Varbinds: ~w",
+ [Ent2, G2, Spec2, VBs]}};
+
+ {error, Reason} ->
+ format_reason(Id, Reason)
+ end.
+
+format_reason(Id, Reason) ->
+ {error, Id, {"?", []}, {"~w", [Reason]}}.
+
+%%----------------------------------------------------------------------
+%% Args: Id, ExpectedVarbinds, GotVarbinds
+%% Returns: ok
+%% Fails: if not ok
+%%----------------------------------------------------------------------
+check_vars(_Id,[], []) ->
+ ok;
+check_vars(Id,Vars, []) ->
+ {error, Id, {"More Varbinds (~w)", [Vars]}, {"Too few", []}};
+check_vars(Id,[], Varbinds) ->
+ {error,Id, {"Fewer Varbinds", []}, {"Too many (~w)", [Varbinds]}};
+check_vars(Id,[{_XOid, any} | Vars], [#varbind{oid = _Oid} |Vbs]) ->
+ check_vars(Id,Vars, Vbs);
+check_vars(Id,[{Oid, Val} | Vars], [#varbind{oid = Oid, value = Val} |Vbs]) ->
+ check_vars(Id,Vars, Vbs);
+check_vars(Id,[{Oid, Val} | _], [#varbind{oid = Oid, value = Val2} |_]) ->
+ {error, Id, {" Varbind: ~w = ~w", [Oid, Val]}, {"Value: ~w", [Val2]}};
+check_vars(Id,[{Oid, _Val} | _], [#varbind{oid = Oid2, value = _Val2} |_]) ->
+ {error, Id, {"Oid: ~w", [Oid]}, {"Oid: ~w", [Oid2]}}.
+
+match_vars(Id, [Oid|T], [#varbind{oid = Oid, value = Value} | Vbs], Res) ->
+ match_vars(Id, T, Vbs, [Value | Res]);
+match_vars(_Id, [], [], Res) ->
+ {ok, lists:reverse(Res)};
+match_vars(Id, [Oid | _], [#varbind{oid = Oid2}], _Res) ->
+ {error, Id, {" Oid: ~w", [Oid]}, {"Oid2: ~w", [Oid2]}};
+match_vars(Id, Vars, [], _Res) ->
+ {error, Id, {"More Varbinds (~w)", [Vars]}, {"Too few", []}};
+match_vars(Id, [], Varbinds, _Res) ->
+ {error,Id, {"Fewer Varbinds", []}, {"Too many (~w)", [Varbinds]}}.
+
+
+
+find_pure_oids([]) -> [];
+find_pure_oids([{XOid, Q}|T]) ->
+ [{find_pure_oid(XOid), Q} | find_pure_oids(T)].
+
+find_pure_oids2([]) -> [];
+find_pure_oids2([XOid|T]) ->
+ [find_pure_oid(XOid) | find_pure_oids2(T)].
+
+
+%%----------------------------------------------------------------------
+%% Returns: Oid
+%% Fails: malformed oids
+%%----------------------------------------------------------------------
+find_pure_oid(XOid) ->
+ case gen_server:call(?MODULE, {find_pure_oid, XOid}, infinity) of
+ {error, {Format, Data}} ->
+ ok = io:format(Format, Data),
+ exit(malformed_oid);
+ Oid when is_list(Oid) -> Oid
+ end.
+
+get_value(Opt, Opts, Default) ->
+ case snmp_misc:assq(Opt,Opts) of
+ {value, C} -> C;
+ false -> Default
+ end.
+
+
+%%----------------------------------------------------------------------
+
+call(Req) ->
+ call(Req, infinity).
+
+call(Req, To) ->
+ gen_server:call(?SERVER, Req, To).
+
+cast(Msg) ->
+ gen_server:cast(?SERVER, Msg).
+
+
+%%----------------------------------------------------------------------
+%% Debug
+%%----------------------------------------------------------------------
+
+sizeOf(L) when is_list(L) ->
+ length(lists:flatten(L));
+sizeOf(B) when is_binary(B) ->
+ size(B).
+
+d(F,A) -> d(get(debug),F,A).
+
+d(true,F,A) ->
+ io:format("*** [~s] MGR_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).
+
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).
+
diff --git a/lib/snmp/test/snmp_test_server.erl b/lib/snmp/test/snmp_test_server.erl
new file mode 100644
index 0000000000..d0a5185452
--- /dev/null
+++ b/lib/snmp/test/snmp_test_server.erl
@@ -0,0 +1,416 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2003-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%
+%%
+
+%%----------------------------------------------------------------------
+%% Purpose: Lightweight test server
+%%----------------------------------------------------------------------
+
+-module(snmp_test_server).
+
+-compile(export_all).
+
+-export([
+ run/1, run/2,
+
+ error/3,
+ skip/3,
+ fatal_skip/3,
+
+ init_per_testcase/2,
+ fin_per_testcase/2
+ ]).
+
+-include("snmp_test_lib.hrl").
+
+-define(GLOBAL_LOGGER, snmp_global_logger).
+-define(TEST_CASE_SUP, snmp_test_case_supervisor).
+
+-define(d(F,A),d(F,A,?LINE)).
+
+-ifndef(snmp_priv_dir).
+-define(snmp_priv_dir, "run-" ++ timestamp()).
+-endif.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Evaluates a test case or test suite
+%% Returns a list of failing test cases:
+%%
+%% {Mod, Fun, ExpectedRes, ActualRes}
+%%----------------------------------------------------------------------
+
+run([Mod, Fun]) when is_atom(Mod) andalso is_atom(Fun) ->
+ Res = run({Mod, Fun}, default_config(Mod)),
+ display_result(Res),
+ Res;
+run({Mod, _Fun} = Case) when is_atom(Mod) ->
+ io:format("~n", []),
+ Res = run(Case, default_config(Mod)),
+ display_result(Res),
+ Res;
+run(Mod) when is_atom(Mod) ->
+ io:format("~n", []),
+ Res = run(Mod, default_config(Mod)),
+ display_result(Res),
+ Res;
+run([Mod]) when is_atom(Mod) ->
+ io:format("~n", []),
+ Res = run(Mod, default_config(Mod)),
+ display_result(Res),
+ Res.
+
+
+run({Mod, Fun}, Config) when is_atom(Mod) andalso
+ is_atom(Fun) andalso
+ is_list(Config) ->
+ ?d("run(~p,~p) -> entry", [Mod, Fun]),
+ case (catch apply(Mod, Fun, [suite])) of
+ [] ->
+ io:format("~n~n*** Eval: ~p ***************~n",
+ [{Mod, Fun}]),
+ case eval(Mod, Fun, Config) of
+ {ok, _, _} ->
+ [];
+ Other ->
+ [Other]
+ end;
+
+ Cases when is_list(Cases) ->
+ io:format("~n*** Expand: ~p ...~n", [{Mod, Fun}]),
+ Map = fun(Case) when is_atom(Case) -> {Mod, Case};
+ (Case) -> Case
+ end,
+ run(lists:map(Map, Cases), Config);
+
+ {conf, InitSuite, Cases, FinishSuite} when is_atom(InitSuite) andalso
+ is_list(Cases) andalso
+ is_atom(FinishSuite) ->
+ ?d("run -> conf: "
+ "~n InitSuite: ~p"
+ "~n Cases: ~p"
+ "~n FinishSuite: ~p", [InitSuite, Cases, FinishSuite]),
+ do_suite(Mod, InitSuite, Cases, FinishSuite, Config);
+
+ {req, _, SubCases} when is_list(SubCases) ->
+ ?d("run -> req: "
+ "~n SubCases: ~p", [SubCases]),
+ do_subcases(Mod, Fun, SubCases, Config, []);
+
+ {req, _, Conf} ->
+ ?d("run -> req: "
+ "~n Conf: ~p", [Conf]),
+ do_subcases(Mod, Fun, [Conf], Config, []);
+
+ {'EXIT', {undef, _}} ->
+ io:format("~n*** Undefined: ~p~n", [{Mod, Fun}]),
+ [{nyi, {Mod, Fun}, ok}];
+
+ Error ->
+ io:format("~n*** Ignoring: ~p: ~p~n", [{Mod, Fun}, Error]),
+ [{failed, {Mod, Fun}, Error}]
+ end;
+
+run(Mod, Config) when is_atom(Mod) andalso is_list(Config) ->
+ run({Mod, all}, Config);
+
+run(Cases, Config) when is_list(Cases) andalso is_list(Config) ->
+ Errors = [run(Case, Config) || Case <- Cases],
+ lists:append(Errors);
+
+run(Bad, _Config) ->
+ [{badarg, Bad, ok}].
+
+
+do_suite(Mod, Init, Cases, Finish, Config0) ->
+ ?d("do_suite -> entry with"
+ "~n Mod: ~p"
+ "~n Init: ~p"
+ "~n Cases: ~p"
+ "~n Finish: ~p"
+ "~n Config0: ~p", [Mod, Init, Cases, Finish, Config0]),
+ case (catch apply(Mod, Init, [Config0])) of
+ Config when is_list(Config) ->
+ io:format("~n*** Expand: ~p ...~n", [Mod]),
+ Map = fun(Case) when is_atom(Case) -> {Mod, Case};
+ (Case) -> Case
+ end,
+ Res = run(lists:map(Map, Cases), Config),
+ (catch apply(Mod, Finish, [Config])),
+ Res;
+
+ {'EXIT', {skipped, Reason}} ->
+ io:format(" => skipping: ~p~n", [Reason]),
+ SkippedCases =
+ [{skipped, {Mod, Case}, suite_init_skipped} || Case <- Cases],
+ lists:flatten([[{skipped, {Mod, Init}, Reason}],
+ SkippedCases,
+ [{skipped, {Mod, Finish}, suite_init_skipped}]]);
+
+ Error ->
+ io:format(" => init (~p) failed: ~n~p~n", [Init, Error]),
+ InitResult =
+ [{failed, {Mod, Init}, Error}],
+ SkippedCases =
+ [{skipped, {Mod, Case}, suite_init_failed} || Case <- Cases],
+ FinResult =
+ case (catch apply(Mod, Finish, [Config0])) of
+ ok ->
+ [];
+ FinConfig when is_list(FinConfig) ->
+ [];
+ FinError ->
+ [{failed, {Mod, Finish}, FinError}]
+ end,
+ lists:flatten([InitResult, SkippedCases, FinResult])
+
+ end.
+
+
+do_subcases(_Mod, _Fun, [], _Config, Acc) ->
+ lists:flatten(lists:reverse(Acc));
+do_subcases(Mod, Fun, [{conf, Init, Cases, Finish}|SubCases], Config, Acc)
+ when is_atom(Init) andalso is_list(Cases) andalso is_atom(Finish) ->
+ R = case (catch apply(Mod, Init, [Config])) of
+ Conf when is_list(Conf) ->
+ io:format("~n*** Expand: ~p ...~n", [{Mod, Fun}]),
+ Map = fun(Case) when is_atom(Case) -> {Mod, Case};
+ (Case) -> Case
+ end,
+ Res = run(lists:map(Map, Cases), Conf),
+ (catch apply(Mod, Finish, [Conf])),
+ Res;
+
+ {'EXIT', {skipped, Reason}} ->
+ io:format(" => skipping: ~p~n", [Reason]),
+ [{skipped, {Mod, Fun}, Reason}];
+
+ Error ->
+ io:format(" => init (~p) failed: ~n~p~n", [Init, Error]),
+ (catch apply(Mod, Finish, [Config])),
+ [{failed, {Mod, Fun}, Error}]
+ end,
+ do_subcases(Mod, Fun, SubCases, Config, [R|Acc]);
+do_subcases(Mod, Fun, [SubCase|SubCases], Config, Acc) when atom(SubCase) ->
+ R = do_case(Mod, SubCase, Config),
+ do_subcases(Mod, Fun, SubCases,Config, [R|Acc]).
+
+
+do_case(M, F, C) ->
+ io:format("~n~n*** Eval: ~p ***************~n", [{M, F}]),
+ case eval(M, F, C) of
+ {ok, _, _} ->
+ [];
+ Other ->
+ [Other]
+ end.
+
+
+eval(Mod, Fun, Config) ->
+ Flag = process_flag(trap_exit, true),
+ global:register_name(?TEST_CASE_SUP, self()),
+ Config2 = Mod:init_per_testcase(Fun, Config),
+ Self = self(),
+ Eval = fun() -> do_eval(Self, Mod, Fun, Config2) end,
+ Pid = spawn_link(Eval),
+ R = wait_for_evaluator(Pid, Mod, Fun, Config2, []),
+ Mod:fin_per_testcase(Fun, Config2),
+ global:unregister_name(?TEST_CASE_SUP),
+ process_flag(trap_exit, Flag),
+ R.
+
+wait_for_evaluator(Pid, Mod, Fun, Config, Errors) ->
+ Pre = lists:concat(["TEST CASE: ", Fun]),
+ receive
+ {'EXIT', _Watchdog, watchdog_timeout} ->
+ io:format("*** ~s WATCHDOG TIMEOUT~n", [Pre]),
+ exit(Pid, kill),
+ {failed, {Mod, Fun}, watchdog_timeout};
+ {done, Pid, ok} when Errors =:= [] ->
+ io:format("*** ~s OK~n", [Pre]),
+ {ok, {Mod, Fun}, Errors};
+ {done, Pid, {ok, _}} when Errors =:= [] ->
+ io:format("*** ~s OK~n", [Pre]),
+ {ok, {Mod, Fun}, Errors};
+ {done, Pid, Fail} ->
+ io:format("*** ~s FAILED~n~p~n", [Pre, Fail]),
+ {failed, {Mod, Fun}, Fail};
+ {'EXIT', Pid, {skipped, Reason}} ->
+ io:format("*** ~s SKIPPED~n~p~n", [Pre, Reason]),
+ {skipped, {Mod, Fun}, Errors};
+ {'EXIT', Pid, Reason} ->
+ io:format("*** ~s CRASHED~n~p~n", [Pre, Reason]),
+ {crashed, {Mod, Fun}, [{'EXIT', Reason} | Errors]};
+ {fail, Pid, Reason} ->
+ io:format("*** ~s FAILED~n~p~n", [Pre, Reason]),
+ wait_for_evaluator(Pid, Mod, Fun, Config, Errors ++ [Reason])
+ end.
+
+do_eval(ReplyTo, Mod, Fun, Config) ->
+ case (catch apply(Mod, Fun, [Config])) of
+ {'EXIT', {skipped, Reason}} ->
+ ReplyTo ! {'EXIT', self(), {skipped, Reason}};
+ Other ->
+ ReplyTo ! {done, self(), Other}
+ end,
+ unlink(ReplyTo),
+ exit(shutdown).
+
+
+display_result([]) ->
+ io:format("TEST OK~n", []);
+
+display_result(Errors) when is_list(Errors) ->
+ Nyi = [MF || {nyi, MF, _} <- Errors],
+ Skipped = [{MF, Reason} || {skipped, MF, Reason} <- Errors],
+ Crashed = [{MF, Reason} || {crashed, MF, Reason} <- Errors],
+ Failed = [{MF, Reason} || {failed, MF, Reason} <- Errors],
+ display_skipped(Skipped),
+ display_crashed(Crashed),
+ display_failed(Failed),
+ display_summery(Nyi, Skipped, Crashed, Failed).
+
+display_summery(Nyi, Skipped, Crashed, Failed) ->
+ io:format("~nTest case summery:~n", []),
+ display_summery(Nyi, "not yet implemented"),
+ display_summery(Skipped, "skipped"),
+ display_summery(Crashed, "crashed"),
+ display_summery(Failed, "failed"),
+ io:format("~n", []).
+
+display_summery([], _) ->
+ ok;
+display_summery(Res, Info) ->
+ io:format(" ~w test cases ~s~n", [length(Res), Info]).
+
+display_skipped([]) ->
+ io:format("Skipped test cases: -~n", []);
+display_skipped(Skipped) ->
+ io:format("Skipped test cases:~n", []),
+ [io:format(" ~p => ~p~n", [MF, Reason]) || {MF, Reason} <- Skipped],
+ io:format("~n", []).
+
+display_crashed([]) ->
+ io:format("Crashed test cases: -~n", []);
+display_crashed(Crashed) ->
+ io:format("Crashed test cases:~n", []),
+ [io:format(" ~p => ~p~n", [MF, Reason]) || {MF, Reason} <- Crashed],
+ io:format("~n", []).
+
+display_failed([]) ->
+ io:format("Failed test cases: -~n", []);
+display_failed(Failed) ->
+ io:format("Failed test cases:~n", []),
+ [io:format(" ~p => ~p~n", [MF, Reason]) || {MF, Reason} <- Failed],
+ io:format("~n", []).
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Verify that the actual result of a test case matches the exected one
+%% Returns the actual result
+%% Stores the result in the process dictionary if mismatch
+
+error(Actual, Mod, Line) ->
+ global:send(?GLOBAL_LOGGER, {failed, Mod, Line}),
+ log("<ERROR> Bad result: ~p~n", [Actual], Mod, Line),
+ case global:whereis_name(?TEST_CASE_SUP) of
+ undefined ->
+ ignore;
+ Pid ->
+ Pid ! {fail, self(), {Actual, Mod, Line}}
+ end,
+ Actual.
+
+skip(Actual, Mod, Line) ->
+ log("Skipping test case~n", [], Mod, Line),
+ exit({skipped, {Actual, Mod, Line}}).
+
+fatal_skip(Actual, Mod, Line) ->
+ error(Actual, Mod, Line),
+ exit(shutdown).
+
+
+log(Format, Args, Mod, Line) ->
+ case global:whereis_name(?GLOBAL_LOGGER) of
+ undefined ->
+ io:format(user, "~p(~p): " ++ Format, [Mod, Line] ++ Args);
+ Pid ->
+ io:format(Pid, "~p(~p): " ++ Format, [Mod, Line] ++ Args)
+ end.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Test server callbacks
+
+init_per_testcase(_Case, Config) ->
+ global:register_name(?GLOBAL_LOGGER, group_leader()),
+ Config.
+
+fin_per_testcase(_Case, _Config) ->
+ global:unregister_name(?GLOBAL_LOGGER),
+ ok.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%% Internal utility functions
+
+default_config(Mod) ->
+ PrivDir0 = ?snmp_priv_dir,
+ case filename:pathtype(PrivDir0) of
+ absolute ->
+ ok;
+ _ ->
+ case file:make_dir(Mod) of
+ ok ->
+ ok;
+ {error, eexist} ->
+ ok
+ end,
+ PrivDir = filename:join(Mod, PrivDir0),
+ case file:make_dir(PrivDir) of
+ ok ->
+ ok;
+ {error, eexist} ->
+ ok;
+ Error ->
+ ?FAIL({failed_creating_subsuite_top_dir, Error})
+ end,
+ [{priv_dir, PrivDir}]
+ end.
+
+
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+d(F, A, L) ->
+ d(true, F, A, L).
+ %% d(get(dbg), F, A, L).
+
+d(true, F, A, L) ->
+ io:format("STS[~w] ~p " ++ F ++ "~n", [L,self()|A]);
+d(_, _, _, _) ->
+ ok.
+
+timestamp() ->
+ {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",
+ [YYYY,MM,DD,Hour,Min,Sec]),
+ lists:flatten(FormatDate).
+
diff --git a/lib/snmp/test/snmp_test_suite.erl b/lib/snmp/test/snmp_test_suite.erl
new file mode 100644
index 0000000000..a6e203eba3
--- /dev/null
+++ b/lib/snmp/test/snmp_test_suite.erl
@@ -0,0 +1,35 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 2008-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%
+%%
+
+%%----------------------------------------------------------------------
+%% Purpose: Each snmp test suite implements this behaviour
+%%----------------------------------------------------------------------
+
+-module(snmp_test_suite).
+
+-export([behaviour_info/1]).
+
+behaviour_info(callbacks) ->
+ [
+ {all, 1},
+ {init_per_testcase, 2},
+ {fin_per_testcase, 2}
+ ];
+behaviour_info(_Other) ->
+ undefined.
diff --git a/lib/snmp/test/test-mibs/Bitsindex-error.mib b/lib/snmp/test/test-mibs/Bitsindex-error.mib
new file mode 100644
index 0000000000..0ba7467996
--- /dev/null
+++ b/lib/snmp/test/test-mibs/Bitsindex-error.mib
@@ -0,0 +1,94 @@
+ Bitsindex-error DEFINITIONS ::= BEGIN
+
+ IMPORTS
+ OBJECT-TYPE
+ FROM RFC-1212;
+
+ klas1 OBJECT IDENTIFIER ::= { private 7 }
+
+ RowStatus ::=
+ INTEGER {
+ -- the following two values are states:
+ -- these values may be read or written
+ active(1),
+ notInService(2),
+
+ -- the following value is a state:
+ -- this value may be read, but not written
+ notReady(3),
+
+ -- the following three values are
+ -- actions: these values may be written,
+ -- but are never read
+ createAndGo(4),
+ createAndWait(5),
+ destroy(6)
+ }
+
+
+ friendsTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF FriendsEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A list of klas friends."
+ ::= { klas1 4 }
+
+ friendsEntry OBJECT-TYPE
+ SYNTAX FriendsEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "nope"
+ INDEX { fIndex }
+ ::= { friendsTable 1 }
+
+ FriendsEntry ::=
+ SEQUENCE {
+ fIndex
+ BITS,
+ fName
+ OCTET STRING,
+ fStatus
+ INTEGER }
+
+ fIndex OBJECT-TYPE
+ SYNTAX BITS {tihi(0)}
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "number of friend"
+ ::= { friendsEntry 1 }
+
+ fName OBJECT-TYPE
+ SYNTAX OCTET STRING (SIZE (0..255))
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "Name of friend"
+ ::= { friendsEntry 2 }
+
+ fStatus OBJECT-TYPE
+ SYNTAX RowStatus
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The status of this conceptual row."
+ ::= { friendsEntry 3 }
+
+ authenticationFajlure TRAP-TYPE
+ ENTERPRISE klas1
+ DESCRIPTION
+ "An authenticationFailure trap signifies that
+ the sending protocol entity is the addressee
+ of a protocol message that is not properly
+ authenticated. While implementations of the
+ SNMP must be capable of generating this trap,
+ they must also be capable of suppressing the
+ emission of such traps via an implementation-
+ specific mechanism."
+ ::= 4
+
+
+ END
+
diff --git a/lib/snmp/test/test-mibs/ENTITY-MIB.mib b/lib/snmp/test/test-mibs/ENTITY-MIB.mib
new file mode 100644
index 0000000000..a70c26ed3a
--- /dev/null
+++ b/lib/snmp/test/test-mibs/ENTITY-MIB.mib
@@ -0,0 +1,784 @@
+ENTITY-MIB DEFINITIONS ::= BEGIN
+
+IMPORTS
+ MODULE-IDENTITY, OBJECT-TYPE,
+ mib-2, NOTIFICATION-TYPE
+ FROM SNMPv2-SMI
+ TDomain, TAddress, DisplayString, TEXTUAL-CONVENTION,
+ AutonomousType, RowPointer, TimeStamp
+ FROM SNMPv2-TC
+ MODULE-COMPLIANCE, OBJECT-GROUP
+ FROM SNMPv2-CONF;
+
+entityMIB MODULE-IDENTITY
+ LAST-UPDATED "9605160000Z"
+ ORGANIZATION "IETF ENTMIB Working Group"
+ CONTACT-INFO
+ " WG E-mail: [email protected]
+ Subscribe: [email protected]
+ msg body: subscribe entmib
+
+ Keith McCloghrie
+ ENTMIB Working Group Chair
+ Cisco Systems Inc.
+ 170 West Tasman Drive
+ San Jose, CA 95134
+ 408-526-5260
+
+ Andy Bierman
+ ENTMIB Working Group Editor
+ Cisco Systems Inc.
+ 170 West Tasman Drive
+ San Jose, CA 95134
+ 408-527-3711
+ DESCRIPTION
+ "The MIB module for representing multiple logical
+ entities supported by a single SNMP agent."
+ ::= { mib-2 47 }
+
+entityMIBObjects OBJECT IDENTIFIER ::= { entityMIB 1 }
+
+-- MIB contains four groups
+
+entityPhysical OBJECT IDENTIFIER ::= { entityMIBObjects 1 }
+entityLogical OBJECT IDENTIFIER ::= { entityMIBObjects 2 }
+
+
+entityMapping OBJECT IDENTIFIER ::= { entityMIBObjects 3 }
+entityGeneral OBJECT IDENTIFIER ::= { entityMIBObjects 4 }
+
+
+-- Textual Conventions
+PhysicalIndex ::= TEXTUAL-CONVENTION
+ STATUS current
+ DESCRIPTION
+ "An arbitrary value which uniquely identifies the physical
+ entity. The value is a small positive integer; index values
+ for different physical entities are not necessarily
+ contiguous."
+ SYNTAX INTEGER (1..2147483647)
+
+
+PhysicalClass ::= TEXTUAL-CONVENTION
+ STATUS current
+ DESCRIPTION
+ "An enumerated value which provides an indication of the
+ general hardware type of a particular physical entity."
+ SYNTAX INTEGER {
+ other(1),
+ unknown(2),
+ chassis(3),
+ backplane(4),
+ container(5), -- e.g. slot or daughter-card holder
+ powerSupply(6),
+ fan(7),
+ sensor(8),
+ module(9), -- e.g. plug-in card or daughter-card
+ port(10)
+ }
+
+-- The Physical Entity Table
+
+entPhysicalTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF EntPhysicalEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "This table contains one row per physical entity. There is
+ always at least one row for an 'overall' physical entity."
+ ::= { entityPhysical 1 }
+
+entPhysicalEntry OBJECT-TYPE
+ SYNTAX EntPhysicalEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+
+
+ DESCRIPTION
+ "Information about a particular physical entity.
+
+ Each entry provides objects (entPhysicalDescr,
+ entPhysicalVendorType, and entPhysicalClass) to help an NMS
+ identify and characterize the entry, and objects
+ (entPhysicalContainedIn and entPhysicalParentRelPos) to help
+ an NMS relate the particular entry to other entries in this
+ table."
+ INDEX { entPhysicalIndex }
+ ::= { entPhysicalTable 1 }
+
+EntPhysicalEntry ::= SEQUENCE {
+ entPhysicalIndex PhysicalIndex,
+ entPhysicalDescr DisplayString,
+ entPhysicalVendorType AutonomousType,
+ entPhysicalContainedIn INTEGER,
+ entPhysicalClass PhysicalClass,
+ entPhysicalParentRelPos INTEGER,
+ entPhysicalName DisplayString
+}
+
+entPhysicalIndex OBJECT-TYPE
+ SYNTAX PhysicalIndex
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "The index for this entry."
+ ::= { entPhysicalEntry 1 }
+
+entPhysicalDescr OBJECT-TYPE
+ SYNTAX DisplayString
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "A textual description of physical entity. This object
+ should contain a string which identifies the manufacturer's
+ name for the physical entity, and should be set to a
+ distinct value for each version or model of the physical
+ entity. "
+ ::= { entPhysicalEntry 2 }
+
+entPhysicalVendorType OBJECT-TYPE
+ SYNTAX AutonomousType
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "An indication of the vendor-specific hardware type of the
+
+
+ physical entity. Note that this is different from the
+ definition of MIB-II's sysObjectID.
+
+ An agent should set this object to a enterprise-specific
+ registration identifier value indicating the specific
+ equipment type in detail. The associated instance of
+ entPhysicalClass is used to indicate the general type of
+ hardware device.
+
+ If no vendor-specific registration identifier exists for
+ this physical entity, or the value is unknown by this agent,
+ then the value { 0 0 } is returned."
+ ::= { entPhysicalEntry 3 }
+
+entPhysicalContainedIn OBJECT-TYPE
+ SYNTAX INTEGER (0..2147483647)
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The value of entPhysicalIndex for the physical entity which
+ 'contains' this physical entity. A value of zero indicates
+ this physical entity is not contained in any other physical
+ entity. Note that the set of 'containment' relationships
+ define a strict hierarchy; that is, recursion is not
+ allowed."
+ ::= { entPhysicalEntry 4 }
+
+entPhysicalClass OBJECT-TYPE
+ SYNTAX PhysicalClass
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "An indication of the general hardware type of the physical
+ entity.
+
+ An agent should set this object to the standard enumeration
+ value which most accurately indicates the general class of
+ the physical entity, or the primary class if there is more
+ than one.
+
+ If no appropriate standard registration identifier exists
+ for this physical entity, then the value 'other(1)' is
+ returned. If the value is unknown by this agent, then the
+ value 'unknown(2)' is returned."
+ ::= { entPhysicalEntry 5 }
+
+entPhysicalParentRelPos OBJECT-TYPE
+ SYNTAX INTEGER (-1..2147483647)
+
+
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "An indication of the relative position of this 'child'
+ component among all its 'sibling' components. Sibling
+ components are defined as entPhysicalEntries which share the
+ same instance values of each of the entPhysicalContainedIn
+ and entPhysicalClass objects.
+
+ An NMS can use this object to identify the relative ordering
+ for all sibling components of a particular parent
+ (identified by the entPhysicalContainedIn instance in each
+ sibling entry).
+
+ This value should match any external labeling of the
+ physical component if possible. For example, for a module
+ labeled as 'card #3', entPhysicalParentRelPos should have
+ the value '3'.
+
+ If the physical position of this component does not match
+ any external numbering or clearly visible ordering, then
+ user documentation or other external reference material
+ should be used to determine the parent-relative position. If
+ this is not possible, then the the agent should assign a
+ consistent (but possibly arbitrary) ordering to a given set
+ of 'sibling' components, perhaps based on internal
+ representation of the components.
+
+ If the agent cannot determine the parent-relative position
+ for some reason, or if the associated value of
+ entPhysicalContainedIn is '0', then the value '-1' is
+ returned. Otherwise a non-negative integer is returned,
+ indicating the parent-relative position of this physical
+ entity.
+
+ Parent-relative ordering normally starts from '1' and
+ continues to 'N', where 'N' represents the highest
+ positioned child entity. However, if the physical entities
+ (e.g. slots) are labeled from a starting position of zero,
+ then the first sibling should be associated with a
+ entPhysicalParentRelPos value of '0'. Note that this
+ ordering may be sparse or dense, depending on agent
+ implementation.
+
+ The actual values returned are not globally meaningful, as
+ each 'parent' component may use different numbering
+ algorithms. The ordering is only meaningful among siblings
+ of the same parent component.
+
+
+ The agent should retain parent-relative position values
+ across reboots, either through algorithmic assignment or use
+ of non-volatile storage."
+ ::= { entPhysicalEntry 6 }
+
+
+entPhysicalName OBJECT-TYPE
+ SYNTAX DisplayString
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The textual name of the physical entity. The value of this
+ object should be the name of the component as assigned by
+ the local device and should be suitable for use in commands
+ entered at the device's `console'. This might be a text
+ name, such as `console' or a simple component number (e.g.
+ port or module number), such as `1', depending on the
+ physical component naming syntax of the device.
+
+ If there is no local name, or this object is otherwise not
+ applicable, then this object contains a zero-length string.
+
+ Note that the value of entPhysicalName for two physical
+ entities will be the same in the event that the console
+ interface does not distinguish between them, e.g., slot-1
+ and the card in slot-1."
+ ::= { entPhysicalEntry 7 }
+
+-- The Logical Entity Table
+entLogicalTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF EntLogicalEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "This table contains one row per logical entity. At least
+ one entry must exist."
+ ::= { entityLogical 1 }
+
+entLogicalEntry OBJECT-TYPE
+ SYNTAX EntLogicalEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "Information about a particular logical entity. Entities
+ may be managed by this agent or other SNMP agents (possibly)
+ in the same chassis."
+ INDEX { entLogicalIndex }
+ ::= { entLogicalTable 1 }
+
+
+EntLogicalEntry ::= SEQUENCE {
+ entLogicalIndex INTEGER,
+ entLogicalDescr DisplayString,
+ entLogicalType AutonomousType,
+ entLogicalCommunity OCTET STRING,
+ entLogicalTAddress TAddress,
+ entLogicalTDomain TDomain
+}
+
+entLogicalIndex OBJECT-TYPE
+ SYNTAX INTEGER (1..2147483647)
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "The value of this object uniquely identifies the logical
+ entity. The value is a small positive integer; index values
+ for different logical entities are are not necessarily
+ contiguous."
+ ::= { entLogicalEntry 1 }
+
+entLogicalDescr OBJECT-TYPE
+ SYNTAX DisplayString
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "A textual description of the logical entity. This object
+ should contain a string which identifies the manufacturer's
+ name for the logical entity, and should be set to a distinct
+ value for each version of the logical entity. "
+ ::= { entLogicalEntry 2 }
+
+entLogicalType OBJECT-TYPE
+ SYNTAX AutonomousType
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "An indication of the type of logical entity. This will
+ typically be the OBJECT IDENTIFIER name of the node in the
+ SMI's naming hierarchy which represents the major MIB
+ module, or the majority of the MIB modules, supported by the
+ logical entity. For example:
+ a logical entity of a regular host/router -> mib-2
+ a logical entity of a 802.1d bridge -> dot1dBridge
+ a logical entity of a 802.3 repeater -> snmpDot3RptrMgmt
+ If an appropriate node in the SMI's naming hierarchy cannot
+ be identified, the value 'mib-2' should be used."
+ ::= { entLogicalEntry 3 }
+
+
+
+entLogicalCommunity OBJECT-TYPE
+ SYNTAX OCTET STRING (SIZE (1..255))
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "An SNMPv1 or SNMPv2C community-string which can be used to
+ access detailed management information for this logical
+ entity. The agent should allow read access with this
+ community string (to an appropriate subset of all managed
+ objects) and may also choose to return a community string
+ based on the privileges of the request used to read this
+ object. Note that an agent may choose to return a community
+ string with read-only privileges, even if this object is
+ accessed with a read-write community string. However, the
+ agent must take care not to return a community string which
+ allows more privileges than the community string used to
+ access this object.
+
+ A compliant SNMP agent may wish to conserve naming scopes by
+ representing multiple logical entities in a single 'main'
+ naming scope. This is possible when the logical entities
+ represented by the same value of entLogicalCommunity have no
+ object instances in common. For example, 'bridge1' and
+ 'repeater1' may be part of the main naming scope, but at
+ least one additional community string is needed to represent
+ 'bridge2' and 'repeater2'.
+
+ Logical entities 'bridge1' and 'repeater1' would be
+ represented by sysOREntries associated with the 'main'
+ naming scope.
+
+ For agents not accessible via SNMPv1 or SNMPv2C, the value
+ of this object is the empty-string."
+ ::= { entLogicalEntry 4 }
+
+entLogicalTAddress OBJECT-TYPE
+ SYNTAX TAddress
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The transport service address by which the logical entity
+ receives network management traffic, formatted according to
+ the corresponding value of entLogicalTDomain.
+
+ For snmpUDPDomain, a TAddress is 6 octets long, the initial
+ 4 octets containing the IP-address in network-byte order and
+ the last 2 containing the UDP port in network-byte order.
+ Consult 'Transport Mappings for Version 2 of the Simple
+
+
+ Network Management Protocol' (RFC 1906 [8]) for further
+ information on snmpUDPDomain."
+ ::= { entLogicalEntry 5 }
+
+entLogicalTDomain OBJECT-TYPE
+ SYNTAX TDomain
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "Indicates the kind of transport service by which the
+ logical entity receives network management traffic.
+ Possible values for this object are presently found in the
+ Transport Mappings for SNMPv2 document (RFC 1906 [8])."
+ ::= { entLogicalEntry 6 }
+
+entLPMappingTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF EntLPMappingEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "This table contains zero or more rows of logical entity to
+ physical equipment associations. For each logical entity
+ known by this agent, there are zero or more mappings to the
+ physical resources which are used to realize that logical
+ entity.
+
+ An agent should limit the number and nature of entries in
+ this table such that only meaningful and non-redundant
+ information is returned. For example, in a system which
+ contains a single power supply, mappings between logical
+ entities and the power supply are not useful and should not
+ be included.
+
+ Also, only the most appropriate physical component which is
+ closest to the root of a particular containment tree should
+ be identified in an entLPMapping entry.
+
+ For example, suppose a bridge is realized on a particular
+ module, and all ports on that module are ports on this
+ bridge. A mapping between the bridge and the module would be
+ useful, but additional mappings between the bridge and each
+ of the ports on that module would be redundant (since the
+ entPhysicalContainedIn hierarchy can provide the same
+ information). If, on the other hand, more than one bridge
+ was utilizing ports on this module, then mappings between
+ each bridge and the ports it used would be appropriate.
+
+ Also, in the case of a single backplane repeater, a mapping
+
+
+ for the backplane to the single repeater entity is not
+ necessary."
+ ::= { entityMapping 1 }
+
+entLPMappingEntry OBJECT-TYPE
+ SYNTAX EntLPMappingEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "Information about a particular logical entity to physical
+ equipment association. Note that the nature of the
+ association is not specifically identified in this entry. It
+ is expected that sufficient information exists in the MIBs
+ used to manage a particular logical entity to infer how
+ physical component information is utilized."
+ INDEX { entLogicalIndex, entLPPhysicalIndex }
+ ::= { entLPMappingTable 1 }
+
+EntLPMappingEntry ::= SEQUENCE {
+ entLPPhysicalIndex PhysicalIndex
+}
+
+entLPPhysicalIndex OBJECT-TYPE
+ SYNTAX PhysicalIndex
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The value of this object identifies the index value of a
+ particular entPhysicalEntry associated with the indicated
+ entLogicalEntity."
+ ::= { entLPMappingEntry 1 }
+
+-- logical entity/component to alias table
+entAliasMappingTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF EntAliasMappingEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "This table contains zero or more rows, representing
+ mappings of logical entity and physical component to
+ external MIB identifiers. Each physical port in the system
+ may be associated with a mapping to an external identifier,
+ which itself is associated with a particular logical
+ entity's naming scope. A 'wildcard' mechanism is provided to
+ indicate that an identifier is associated with more than one
+ logical entity."
+ ::= { entityMapping 2 }
+
+
+
+entAliasMappingEntry OBJECT-TYPE
+ SYNTAX EntAliasMappingEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "Information about a particular physical equipment, logical
+ entity to external identifier binding. Each logical
+ entity/physical component pair may be associated with one
+ alias mapping. The logical entity index may also be used as
+ a 'wildcard' (refer to the entAliasLogicalIndexOrZero object
+ DESCRIPTION clause for details.)
+
+ Note that only entPhysicalIndex values which represent
+ physical ports (i.e. associated entPhysicalClass value is
+ 'port(10)') are permitted to exist in this table."
+ INDEX { entPhysicalIndex, entAliasLogicalIndexOrZero }
+ ::= { entAliasMappingTable 1 }
+
+EntAliasMappingEntry ::= SEQUENCE {
+ entAliasLogicalIndexOrZero INTEGER,
+ entAliasMappingIdentifier RowPointer
+}
+
+entAliasLogicalIndexOrZero OBJECT-TYPE
+ SYNTAX INTEGER (0..2147483647)
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "The value of this object uniquely identifies the logical
+ entity which defines the naming scope for the associated
+ instance of the 'entAliasMappingIdentifier' object.
+
+ If this object has a non-zero value, then it identifies the
+ logical entity named by the same value of entLogicalIndex.
+
+ If this object has a value of zero, then the mapping between
+ the physical component and the alias identifier for this
+ entAliasMapping entry is associated with all unspecified
+ logical entities. That is, a value of zero (the default
+ mapping) identifies any logical entity which does not have
+ an explicit entry in this table for a particular
+ entPhysicalIndex/entAliasMappingIdentifier pair.
+
+ For example, to indicate that a particular interface (e.g.
+ physical component 33) is identified by the same value of
+ ifIndex for all logical entities, the following instance
+ might exist:
+
+
+
+ entAliasMappingIdentifier.33.0 = ifIndex.5
+
+ In the event an entPhysicalEntry is associated differently
+ for some logical entities, additional entAliasMapping
+ entries may exist, e.g.:
+
+ entAliasMappingIdentifier.33.0 = ifIndex.6
+ entAliasMappingIdentifier.33.4 = ifIndex.1
+ entAliasMappingIdentifier.33.5 = ifIndex.1
+ entAliasMappingIdentifier.33.10 = ifIndex.12
+
+ Note that entries with non-zero entAliasLogicalIndexOrZero
+ index values have precedence over any zero-indexed entry. In
+ this example, all logical entities except 4, 5, and 10,
+ associate physical entity 33 with ifIndex.6."
+ ::= { entAliasMappingEntry 1 }
+
+
+entAliasMappingIdentifier OBJECT-TYPE
+ SYNTAX RowPointer
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The value of this object identifies a particular conceptual
+ row associated with the indicated entPhysicalIndex and
+ entLogicalIndex pair.
+
+ Since only physical ports are modeled in this table, only
+ entries which represent interfaces or ports are allowed. If
+ an ifEntry exists on behalf of a particular physical port,
+ then this object should identify the associated 'ifEntry'.
+ For repeater ports, the appropriate row in the
+ 'rptrPortGroupTable' should be identified instead.
+
+ For example, suppose a physical port was represented by
+ entPhysicalEntry.3, entLogicalEntry.15 existed for a
+ repeater, and entLogicalEntry.22 existed for a bridge. Then
+ there might be two related instances of
+ entAliasMappingIdentifier:
+ entAliasMappingIdentifier.3.15 == rptrPortGroupIndex.5.2
+ entAliasMappingIdentifier.3.22 == ifIndex.17
+ It is possible that other mappings (besides interfaces and
+ repeater ports) may be defined in the future, as required.
+
+ Bridge ports are identified by examining the Bridge MIB and
+ appropriate ifEntries associated with each 'dot1dBasePort',
+ and are thus not represented in this table."
+ ::= { entAliasMappingEntry 2 }
+
+
+-- physical mapping table
+entPhysicalContainsTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF EntPhysicalContainsEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A table which exposes the container/containee relationships
+ between physical entities. This table provides equivalent
+ information found by constructing the virtual containment
+ tree for a given entPhysicalTable but in a more direct
+ format."
+ ::= { entityMapping 3 }
+
+entPhysicalContainsEntry OBJECT-TYPE
+ SYNTAX EntPhysicalContainsEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A single container/containee relationship."
+ INDEX { entPhysicalIndex, entPhysicalChildIndex }
+ ::= { entPhysicalContainsTable 1 }
+
+EntPhysicalContainsEntry ::= SEQUENCE {
+ entPhysicalChildIndex PhysicalIndex
+}
+
+entPhysicalChildIndex OBJECT-TYPE
+ SYNTAX PhysicalIndex
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The value of entPhysicalIndex for the contained physical
+ entity."
+ ::= { entPhysicalContainsEntry 1 }
+
+-- last change time stamp for the whole MIB
+entLastChangeTime OBJECT-TYPE
+ SYNTAX TimeStamp
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The value of sysUpTime at the time any of these events
+ occur:
+ * a conceptual row is created or deleted in any
+ of these tables:
+ - entPhysicalTable
+ - entLogicalTable
+ - entLPMappingTable
+
+
+ - entAliasMappingTable
+ - entPhysicalContainsTable
+
+ * any instance in the following list of objects
+ changes value:
+ - entPhysicalDescr
+ - entPhysicalVendorType
+ - entPhysicalContainedIn
+ - entPhysicalClass
+ - entPhysicalParentRelPos
+ - entPhysicalName
+ - entLogicalDescr
+ - entLogicalType
+ - entLogicalCommunity
+ - entLogicalTAddress
+ - entLogicalTDomain
+ - entAliasMappingIdentifier "
+ ::= { entityGeneral 1 }
+
+-- Entity MIB Trap Definitions
+entityMIBTraps OBJECT IDENTIFIER ::= { entityMIB 2 }
+entityMIBTrapPrefix OBJECT IDENTIFIER ::= { entityMIBTraps 0 }
+
+entConfigChange NOTIFICATION-TYPE
+ STATUS current
+ DESCRIPTION
+ "An entConfigChange trap is sent when the value of
+ entLastChangeTime changes. It can be utilized by an NMS to
+ trigger logical/physical entity table maintenance polls.
+
+ An agent must not generate more than one entConfigChange
+ 'trap-event' in a five second period, where a 'trap-event'
+ is the transmission of a single trap PDU to a list of trap
+ destinations. If additional configuration changes occur
+ within the five second 'throttling' period, then these
+ trap-events should be suppressed by the agent. An NMS should
+ periodically check the value of entLastChangeTime to detect
+ any missed entConfigChange trap-events, e.g. due to
+ throttling or transmission loss."
+ ::= { entityMIBTrapPrefix 1 }
+
+-- conformance information
+entityConformance OBJECT IDENTIFIER ::= { entityMIB 3 }
+
+entityCompliances OBJECT IDENTIFIER ::= { entityConformance 1 }
+entityGroups OBJECT IDENTIFIER ::= { entityConformance 2 }
+
+-- compliance statements
+
+
+entityCompliance MODULE-COMPLIANCE
+ STATUS current
+ DESCRIPTION
+ "The compliance statement for SNMP entities which implement
+ the Entity MIB."
+ MODULE -- this module
+ MANDATORY-GROUPS { entityPhysicalGroup,
+ entityLogicalGroup,
+ entityMappingGroup,
+ entityGeneralGroup,
+ entityNotificationsGroup }
+ ::= { entityCompliances 1 }
+
+-- MIB groupings
+
+entityPhysicalGroup OBJECT-GROUP
+ OBJECTS {
+ entPhysicalDescr,
+ entPhysicalVendorType,
+ entPhysicalContainedIn,
+ entPhysicalClass,
+ entPhysicalParentRelPos,
+ entPhysicalName
+ }
+ STATUS current
+ DESCRIPTION
+ "The collection of objects which are used to represent
+ physical system components, for which a single agent
+ provides management information."
+ ::= { entityGroups 1 }
+
+entityLogicalGroup OBJECT-GROUP
+ OBJECTS {
+ entLogicalDescr,
+ entLogicalType,
+ entLogicalCommunity,
+ entLogicalTAddress,
+ entLogicalTDomain
+ }
+ STATUS current
+ DESCRIPTION
+ "The collection of objects which are used to represent the
+ list of logical entities for which a single agent provides
+ management information."
+ ::= { entityGroups 2 }
+
+entityMappingGroup OBJECT-GROUP
+ OBJECTS {
+
+
+ entLPPhysicalIndex,
+ entAliasMappingIdentifier,
+ entPhysicalChildIndex
+ }
+ STATUS current
+ DESCRIPTION
+ "The collection of objects which are used to represent the
+ associations between multiple logical entities, physical
+ components, interfaces, and port identifiers for which a
+ single agent provides management information."
+ ::= { entityGroups 3 }
+
+entityGeneralGroup OBJECT-GROUP
+ OBJECTS {
+ entLastChangeTime
+ }
+ STATUS current
+ DESCRIPTION
+ "The collection of objects which are used to represent
+ general entity information for which a single agent provides
+ management information."
+ ::= { entityGroups 4 }
+
+entityNotificationsGroup NOTIFICATION-GROUP
+ NOTIFICATIONS { entConfigChange }
+ STATUS current
+ DESCRIPTION
+ "The collection of notifications used to indicate Entity MIB
+ data consistency and general status information."
+ ::= { entityGroups 5 }
+
+
+END
+
+
+
diff --git a/lib/snmp/test/test-mibs/INTERNAL-MIB.mib b/lib/snmp/test/test-mibs/INTERNAL-MIB.mib
new file mode 100644
index 0000000000..62d3777fc2
--- /dev/null
+++ b/lib/snmp/test/test-mibs/INTERNAL-MIB.mib
@@ -0,0 +1,463 @@
+INTERNAL-MIB DEFINITIONS ::= BEGIN
+
+ IMPORTS
+ IpAddress
+ FROM RFC1155-SMI
+ DisplayString, mib-2
+ FROM RFC1213-MIB
+ OBJECT-TYPE
+ FROM RFC-1212
+ TruthValue, RowStatus
+ FROM STANDARD-MIB
+ ;
+
+
+
+-- Object Identifiers for all the Managed Objects must be defined
+-- if this MIB (or parts of it) shall be loaded.
+-- It is entirely up to the implementation to assign OIDs for the
+-- objects. The SNMP agent does not rely on the OIDs, but on the
+-- symbolic names of the managed objects.
+
+ericsson OBJECT IDENTIFIER ::= {enterprises 193}
+snmpAdm OBJECT IDENTIFIER ::= {ericsson 1}
+community OBJECT IDENTIFIER ::= {snmpAdm 1}
+trap OBJECT IDENTIFIER ::= {snmpAdm 2}
+view OBJECT IDENTIFIER ::= {snmpAdm 3}
+
+
+ -- Datatype
+
+ StorageType ::=
+ INTEGER {
+ other(1), -- eh?
+ volatile(2), -- e.g., in RAM
+ nonVolatile(3), -- e.g., in NVRAM
+ permanent(4) -- e.g., in ROM
+ }
+
+ -- Managed Objects
+
+ intCommunityTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF IntCommunityEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "This table defines access for the different
+ communities.
+
+ When a request comes from a certain ip address,
+ referring to a community string, the mib view
+ and access corresponding to these are looked up
+ in this table. Then the operation is validatated against
+ the access, and all requested objects validated against
+ the mib view."
+ ::= { community 1}
+
+ intCommunityEntry OBJECT-TYPE
+ SYNTAX IntCommunityEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ ""
+ INDEX { intCommunityDestination, intCommunityString }
+ ::= { intCommunityTable 1 }
+
+ IntCommunityEntry ::=
+ SEQUENCE {
+ intCommunityDestination IpAddress,
+ intCommunityString DisplayString,
+ intCommunityViewIndex INTEGER,
+ intCommunityAccess INTEGER,
+ intCommunityStatus RowStatus
+ }
+
+ intCommunityDestination OBJECT-TYPE
+ SYNTAX IpAddress
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "The ip address of a management station. The special
+ ip address {0.0.0.0} is a wildcard, meaning all possible
+ ip addresses. In this way, access can be granted to all
+ ip addressed for some communities."
+ ::= { intCommunityEntry 1 }
+
+ intCommunityString OBJECT-TYPE
+ SYNTAX DisplayString
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "The community string, defining the community."
+ ::= { intCommunityEntry 2 }
+
+ intCommunityViewIndex OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "Identifies a mib view. Index into the
+ intViewTable."
+ ::= { intCommunityEntry 3 }
+
+ intCommunityAccess OBJECT-TYPE
+ SYNTAX INTEGER { read(1), readWrite(2) }
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "Defines which operations the manager can perform
+ on the objects in the mib view."
+ ::= { intCommunityEntry 4 }
+
+ intCommunityStatus OBJECT-TYPE
+ SYNTAX RowStatus
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The status of this conceptual row in the
+ intCommunityTable."
+ ::= { intCommunityEntry 5 }
+
+ intAgentIpAddress OBJECT-TYPE
+ SYNTAX IpAddress
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The IP address of this agent."
+ ::= { community 2 }
+
+ intAgentUDPPort OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The UDP port the agent listens to."
+ ::= { community 3 }
+
+ intAgentMaxPacketSize OBJECT-TYPE
+ SYNTAX INTEGER (484..65535)
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The maximum packet size in bytes this agent will send to a
+ manager."
+ ::= { community 4 }
+
+
+ intAddressTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF IntAddressEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "This table holds UDP related information on each known
+ management station."
+ ::= { community 5 }
+
+
+ intAddressEntry OBJECT-TYPE
+ SYNTAX IntAddressEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ ""
+ INDEX { intAddressDestination }
+ ::= { intAddressTable 1 }
+
+ IntAddressEntry ::=
+ SEQUENCE {
+ intAddressDestination IpAddress,
+ intAddressUDPPort INTEGER,
+ intAddressMaxPacketSize INTEGER (484..65535),
+ intAddressStatus RowStatus
+ }
+
+ intAddressDestination OBJECT-TYPE
+ SYNTAX IpAddress
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "The ip address of the management station."
+ ::= { intAddressEntry 1 }
+
+ intAddressUDPPort OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The UDP port to which traps will be sent to
+ this destination."
+ DEFVAL { 162 }
+ ::= { intAddressEntry 2 }
+
+ intAddressMaxPacketSize OBJECT-TYPE
+ SYNTAX INTEGER (484..65535)
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The maximum packet size in bytes for Messages
+ sent to this destination. The max size of a packet
+ sent to this destination will be the minumim of
+ this variable and agentMaxPacketSize.0."
+ ::= { intAddressEntry 3 }
+
+ intAddressStatus OBJECT-TYPE
+ SYNTAX RowStatus
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The status of this conceptual row in the
+ intAddressTable."
+ ::= { intAddressEntry 4 }
+
+ intTrapDestTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF IntTrapDestEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "The intTrapDestTable defines to which destination all traps
+ for a specific community should be sent."
+ ::= { trap 1 }
+
+ intTrapDestEntry OBJECT-TYPE
+ SYNTAX IntTrapDestEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ ""
+ INDEX { intTrapDestCommunityString, intTrapDestDestination }
+ ::= { intTrapDestTable 1 }
+
+ IntTrapDestEntry ::=
+ SEQUENCE {
+ intTrapDestCommunityString DisplayString,
+ intTrapDestDestination IpAddress,
+ intTrapDestStatus RowStatus,
+ intTrapDestSnmpVersion INTEGER
+ }
+
+ intTrapDestCommunityString OBJECT-TYPE
+ SYNTAX DisplayString (SIZE (0..255))
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ ""
+ ::= { intTrapDestEntry 1 }
+
+ intTrapDestDestination OBJECT-TYPE
+ SYNTAX IpAddress
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ ""
+ ::= { intTrapDestEntry 2 }
+
+ intTrapDestStatus OBJECT-TYPE
+ SYNTAX RowStatus
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The status of this conceptual row in the
+ intTrapDestTable."
+ ::= { intTrapDestEntry 3 }
+
+ intTrapDestSnmpVersion OBJECT-TYPE
+ SYNTAX INTEGER { v1(1), v2c(2) }
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The SNMP version of the manager. If it is v1,
+ SNMPv1Traps are sent. If it is v2c,
+ SNMPv2Traps are sent"
+ ::= { intTrapDestEntry 4 }
+
+ intViewTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF IntViewEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "Locally held information about the MIB views
+ known to this agent.
+
+ Each MIB view is defined by two
+ collections of view subtrees: the included view
+ subtrees, and the excluded view subtrees. Every
+ such subtree, both included and excluded, is
+ defined in this table.
+
+ To determine if a particular object instance is in
+ a particular MIB view, compare the object
+ instance's OBJECT IDENTIFIER with each of the MIB
+ view's entries in this table. If none match, then
+ the object instance is not in the MIB view. If
+ one or more match, then the object instance is
+ included in, or excluded from, the MIB view
+ according to the value of viewType in the entry
+ whose value of viewSubtree has the most sub-
+ identifiers. If multiple entries match and have
+ the same number of sub-identifiers, then the
+ lexicographically greatest instance of viewType
+ determines the inclusion or exclusion.
+
+ An object instance's OBJECT IDENTIFIER X matches
+ an entry in this table when the number of sub-
+ identifiers in X is at least as many as in the
+ value of viewSubtree for the entry, and each sub-
+ identifier in the value of viewSubtree matches its
+ corresponding sub-identifier in X. Two sub-
+ identifiers match either if the corresponding bit
+ of viewMask is zero (the 'wild card' value), or if
+ they are equal.
+
+ Due to this 'wild card' capability, we introduce
+ the term, a 'family' of view subtrees, to refer to
+ the set of subtrees defined by a particular
+ combination of values of viewSubtree and viewMask.
+ In the case where no 'wild card' is defined in
+ viewMask, the family of view subtrees reduces to a
+ single view subtree."
+ ::= { view 1 }
+
+ intViewEntry OBJECT-TYPE
+ SYNTAX IntViewEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "Information on a particular family of view
+ subtrees included in or excluded from a particular
+ MIB view.
+
+ Implementations must not restrict the number of
+ families of view subtrees for a given MIB view,
+ except as dictated by resource constraints on the
+ overall number of entries in the viewTable."
+ INDEX { intViewIndex, intViewSubtree }
+ ::= { intViewTable 1 }
+
+ IntViewEntry ::=
+ SEQUENCE {
+ intViewIndex INTEGER,
+ intViewSubtree OBJECT IDENTIFIER,
+ intViewMask OCTET STRING,
+ intViewType INTEGER,
+ intViewStorageType StorageType,
+ intViewStatus RowStatus
+ }
+
+
+ intViewIndex OBJECT-TYPE
+ SYNTAX INTEGER (1..65535)
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A unique value for each MIB view. The value for
+ each MIB view must remain constant at least from
+ one re-initialization of the entity's network
+ management system to the next re-initialization."
+ ::= { intViewEntry 1 }
+
+ intViewSubtree OBJECT-TYPE
+ SYNTAX OBJECT IDENTIFIER
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A MIB subtree."
+ ::= { intViewEntry 2 }
+
+ intViewMask OBJECT-TYPE
+ SYNTAX OCTET STRING (SIZE (0..16))
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The bit mask which, in combination with the
+ corresponding instance of viewSubtree, defines a
+ family of view subtrees.
+
+ Each bit of this bit mask corresponds to a sub-
+ identifier of viewSubtree, with the most
+ significant bit of the i-th octet of this octet
+ string value (extended if necessary, see below)
+ corresponding to the (8*i - 7)-th sub-identifier,
+ and the least significant bit of the i-th octet of
+ this octet string corresponding to the (8*i)-th
+ sub-identifier, where i is in the range 1 through
+ 16.
+
+ Each bit of this bit mask specifies whether or not
+ the corresponding sub-identifiers must match when
+ determining if an OBJECT IDENTIFIER is in this
+ family of view subtrees; a '1' indicates that an
+ exact match must occur; a '0' indicates 'wild
+ card', i.e., any sub-identifier value matches.
+
+
+ Thus, the OBJECT IDENTIFIER X of an object
+ instance is contained in a family of view subtrees
+ if the following criteria are met:
+
+ for each sub-identifier of the value of
+ viewSubtree, either:
+
+ the i-th bit of viewMask is 0, or
+
+ the i-th sub-identifier of X is equal to
+ the i-th sub-identifier of the value of
+ viewSubtree.
+
+ If the value of this bit mask is M bits long and
+ there are more than M sub-identifiers in the
+ corresponding instance of viewSubtree, then the
+ bit mask is extended with 1's to be the required
+ length.
+
+ Note that when the value of this object is the
+ zero-length string, this extension rule results in
+ a mask of all-1's being used (i.e., no 'wild
+ card'), and the family of view subtrees is the one
+ view subtree uniquely identified by the
+ corresponding instance of viewSubtree."
+ DEFVAL { ''H }
+ ::= { intViewEntry 3 }
+
+
+ intViewType OBJECT-TYPE
+ SYNTAX INTEGER {
+ included(1),
+ excluded(2)
+ }
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The status of a particular family of view
+ subtrees within the particular
+ MIB view. The value 'included(1)' indicates that
+ the corresponding instances of viewSubtree and
+ viewMask define a family of view subtrees included
+ in the MIB view. The value 'excluded(2)'
+ indicates that the corresponding instances of
+ viewSubtree and viewMask define a family of view
+ subtrees excluded from the MIB view."
+ DEFVAL { included }
+ ::= { intViewEntry 4 }
+
+ intViewStorageType OBJECT-TYPE
+ SYNTAX StorageType
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The storage type for this conceptual row in the
+ intViewTable."
+ DEFVAL { nonVolatile }
+ ::= { intViewEntry 5 }
+
+ intViewStatus OBJECT-TYPE
+ SYNTAX RowStatus
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The status of this conceptual row in the
+ intViewTable."
+ ::= { intViewEntry 6 }
+
+
+
+END
diff --git a/lib/snmp/test/test-mibs/Klas1.mib b/lib/snmp/test/test-mibs/Klas1.mib
new file mode 100644
index 0000000000..987c7a6d95
--- /dev/null
+++ b/lib/snmp/test/test-mibs/Klas1.mib
@@ -0,0 +1,118 @@
+ Klas1 DEFINITIONS ::= BEGIN
+
+ IMPORTS
+ OBJECT-TYPE
+ FROM RFC-1212;
+
+ klas1 OBJECT IDENTIFIER ::= { private 7 }
+
+ DisplayString ::=
+ OCTET STRING
+
+
+ Q2 ::= DisplayString (SIZE (0..25))
+
+ RowStatus ::=
+ INTEGER {
+ -- the following two values are states:
+ -- these values may be read or written
+ active(1),
+ notInService(2),
+
+ -- the following value is a state:
+ -- this value may be read, but not written
+ notReady(3),
+
+ -- the following three values are
+ -- actions: these values may be written,
+ -- but are never read
+ createAndGo(4),
+ createAndWait(5),
+ destroy(6)
+ }
+
+
+ fint OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "A textual description of the entity. This value
+ printable ASCII characters."
+ ::= { klas1 0 1 }
+
+ fname OBJECT-TYPE
+ SYNTAX DisplayString (SIZE (0..255))
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "A textual description of the entity. This value
+ printable ASCII characters."
+ ::= { klas1 1 }
+
+ friendsTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF FriendsEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A list of klas friends."
+ ::= { klas1 4 }
+
+ friendsEntry OBJECT-TYPE
+ SYNTAX FriendsEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "nope"
+ INDEX { fIndex }
+ ::= { friendsTable 1 }
+
+ FriendsEntry ::=
+ SEQUENCE {
+ fIndex
+ INTEGER,
+ fName
+ OCTET STRING,
+ fStatus
+ INTEGER }
+
+ fIndex OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "number of friend"
+ ::= { friendsEntry 1 }
+
+ fName OBJECT-TYPE
+ SYNTAX OCTET STRING (SIZE (0..255))
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "Name of friend"
+ ::= { friendsEntry 2 }
+
+ fStatus OBJECT-TYPE
+ SYNTAX RowStatus
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The status of this conceptual row."
+ ::= { friendsEntry 3 }
+
+ authenticationFajlure TRAP-TYPE
+ ENTERPRISE klas1
+ DESCRIPTION
+ "An authenticationFailure trap signifies that
+ the sending protocol entity is the addressee
+ of a protocol message that is not properly
+ authenticated. While implementations of the
+ SNMP must be capable of generating this trap,
+ they must also be capable of suppressing the
+ emission of such traps via an implementation-
+ specific mechanism."
+ ::= 4
+
+
+ END
+
diff --git a/lib/snmp/test/test-mibs/Oid1-error.mib b/lib/snmp/test/test-mibs/Oid1-error.mib
new file mode 100644
index 0000000000..ee9c649f9d
--- /dev/null
+++ b/lib/snmp/test/test-mibs/Oid1-error.mib
@@ -0,0 +1,26 @@
+ Oid1-error DEFINITIONS ::= BEGIN
+
+ IMPORTS
+ OBJECT-TYPE
+ FROM RFC-1212;
+
+ klas1 OBJECT IDENTIFIER ::= { private 7 }
+
+ ok OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ ""
+ ::= { klas1 0 1 }
+
+ error OBJECT-TYPE
+ SYNTAX TestOfUndefinedType (SIZE (0..255))
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ ""
+ ::= { klas1 1 0}
+
+ END
+
diff --git a/lib/snmp/test/test-mibs/README b/lib/snmp/test/test-mibs/README
new file mode 100644
index 0000000000..f23d3151c2
--- /dev/null
+++ b/lib/snmp/test/test-mibs/README
@@ -0,0 +1,19 @@
+MIBs ending with *-error.mib should give compilation error. No others.
+
+All standards MIBs should be original, without modifications.
+*If* there is some small modification for some reason you shall be
+able to find a comment about it by searching "erlsnmpmodification".
+Tickets are found in comments (search "OTP-<no>").
+
+One good compilation order:
+
+snmpc:compile("RMON-MIB").
+snmpc:compile("RFC1271-MIB").
+snmpc:compile("TOKEN-RING-RMON-MIB").
+snmpc:compile("SNMPv2-TC").
+snmpc:compile("RMON2-MIB").
+snmpc:compile("ENTITY-MIB").
+snmpc:compile("SNMPv2-MIB").
+snmpc:compile("SNMPv2-USEC-MIB").
+snmpc:compile("STANDARD-MIB").
+snmpc:compile("INTERNAL-MIB").
diff --git a/lib/snmp/test/test-mibs/RFC1213-MIB.mib b/lib/snmp/test/test-mibs/RFC1213-MIB.mib
new file mode 100644
index 0000000000..0421e64d62
--- /dev/null
+++ b/lib/snmp/test/test-mibs/RFC1213-MIB.mib
@@ -0,0 +1,2888 @@
+ RFC1213-MIB DEFINITIONS ::= BEGIN
+
+ IMPORTS
+ mgmt, NetworkAddress, IpAddress, Counter, Gauge,
+ TimeTicks
+ FROM RFC1155-SMI
+ OBJECT-TYPE
+ FROM RFC-1212;
+
+ -- This MIB module uses the extended OBJECT-TYPE macro as
+ -- defined in [14];
+
+
+ -- MIB-II (same prefix as MIB-I)
+
+ mib-2 OBJECT IDENTIFIER ::= { mgmt 1 }
+
+ -- textual conventions
+
+ DisplayString ::=
+ OCTET STRING
+ -- This data type is used to model textual information taken
+ -- from the NVT ASCII character set. By convention, objects
+ -- with this syntax are declared as having
+
+
+
+ --
+ -- SIZE (0..255)
+
+ PhysAddress ::=
+ OCTET STRING
+ -- This data type is used to model media addresses. For many
+ -- types of media, this will be in a binary representation.
+ -- For example, an ethernet address would be represented as
+ -- a string of 6 octets.
+
+
+ -- groups in MIB-II
+
+ system OBJECT IDENTIFIER ::= { mib-2 1 }
+
+ interfaces OBJECT IDENTIFIER ::= { mib-2 2 }
+
+ at OBJECT IDENTIFIER ::= { mib-2 3 }
+
+ ip OBJECT IDENTIFIER ::= { mib-2 4 }
+
+ icmp OBJECT IDENTIFIER ::= { mib-2 5 }
+
+ tcp OBJECT IDENTIFIER ::= { mib-2 6 }
+
+ udp OBJECT IDENTIFIER ::= { mib-2 7 }
+
+ egp OBJECT IDENTIFIER ::= { mib-2 8 }
+
+ -- historical (some say hysterical)
+ -- cmot OBJECT IDENTIFIER ::= { mib-2 9 }
+
+ transmission OBJECT IDENTIFIER ::= { mib-2 10 }
+
+ snmp OBJECT IDENTIFIER ::= { mib-2 11 }
+
+
+ -- the System group
+
+ -- Implementation of the System group is mandatory for all
+ -- systems. If an agent is not configured to have a value
+ -- for any of these variables, a string of length 0 is
+ -- returned.
+
+ sysDescr OBJECT-TYPE
+ SYNTAX DisplayString (SIZE (0..255))
+ ACCESS read-only
+ STATUS mandatory
+
+
+
+
+
+ DESCRIPTION
+ "A textual description of the entity. This value
+ should include the full name and version
+ identification of the system's hardware type,
+ software operating-system, and networking
+ software. It is mandatory that this only contain
+ printable ASCII characters."
+ ::= { system 1 }
+
+ sysObjectID OBJECT-TYPE
+ SYNTAX OBJECT IDENTIFIER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The vendor's authoritative identification of the
+ network management subsystem contained in the
+ entity. This value is allocated within the SMI
+ enterprises subtree (1.3.6.1.4.1) and provides an
+ easy and unambiguous means for determining `what
+ kind of box' is being managed. For example, if
+ vendor `Flintstones, Inc.' was assigned the
+ subtree 1.3.6.1.4.1.4242, it could assign the
+ identifier 1.3.6.1.4.1.4242.1.1 to its `Fred
+ Router'."
+ ::= { system 2 }
+
+ sysUpTime OBJECT-TYPE
+ SYNTAX TimeTicks
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The time (in hundredths of a second) since the
+ network management portion of the system was last
+ re-initialized."
+ ::= { system 3 }
+
+ sysContact OBJECT-TYPE
+ SYNTAX DisplayString (SIZE (0..255))
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The textual identification of the contact person
+ for this managed node, together with information
+ on how to contact this person."
+ ::= { system 4 }
+
+ sysName OBJECT-TYPE
+ SYNTAX DisplayString (SIZE (0..255))
+
+
+
+
+
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "An administratively-assigned name for this
+ managed node. By convention, this is the node's
+ fully-qualified domain name."
+ ::= { system 5 }
+
+ sysLocation OBJECT-TYPE
+ SYNTAX DisplayString (SIZE (0..255))
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The physical location of this node (e.g.,
+ `telephone closet, 3rd floor')."
+ ::= { system 6 }
+
+ sysServices OBJECT-TYPE
+ SYNTAX INTEGER (0..127)
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "A value which indicates the set of services that
+ this entity primarily offers.
+
+ The value is a sum. This sum initially takes the
+ value zero, Then, for each layer, L, in the range
+ 1 through 7, that this node performs transactions
+ for, 2 raised to (L - 1) is added to the sum. For
+ example, a node which performs primarily routing
+ functions would have a value of 4 (2^(3-1)). In
+ contrast, a node which is a host offering
+ application services would have a value of 72
+ (2^(4-1) + 2^(7-1)). Note that in the context of
+ the Internet suite of protocols, values should be
+ calculated accordingly:
+
+ layer functionality
+ 1 physical (e.g., repeaters)
+ 2 datalink/subnetwork (e.g., bridges)
+ 3 internet (e.g., IP gateways)
+ 4 end-to-end (e.g., IP hosts)
+ 7 applications (e.g., mail relays)
+
+ For systems including OSI protocols, layers 5 and
+ 6 may also be counted."
+ ::= { system 7 }
+
+
+
+
+
+
+ -- the Interfaces group
+
+ -- Implementation of the Interfaces group is mandatory for
+ -- all systems.
+
+ ifNumber OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of network interfaces (regardless of
+ their current state) present on this system."
+ ::= { interfaces 1 }
+
+
+ -- the Interfaces table
+
+ -- The Interfaces table contains information on the entity's
+ -- interfaces. Each interface is thought of as being
+ -- attached to a `subnetwork'. Note that this term should
+ -- not be confused with `subnet' which refers to an
+ -- addressing partitioning scheme used in the Internet suite
+ -- of protocols.
+
+ ifTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF IfEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A list of interface entries. The number of
+ entries is given by the value of ifNumber."
+ ::= { interfaces 2 }
+
+ ifEntry OBJECT-TYPE
+ SYNTAX IfEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "An interface entry containing objects at the
+ subnetwork layer and below for a particular
+ interface."
+ INDEX { ifIndex }
+ ::= { ifTable 1 }
+
+ IfEntry ::=
+ SEQUENCE {
+ ifIndex
+ INTEGER,
+ ifDescr
+ DisplayString,
+ ifType
+ INTEGER,
+ ifMtu
+ INTEGER,
+ ifSpeed
+ Gauge,
+ ifPhysAddress
+ PhysAddress,
+ ifAdminStatus
+ INTEGER,
+ ifOperStatus
+ INTEGER,
+ ifLastChange
+ TimeTicks,
+ ifInOctets
+ Counter,
+ ifInUcastPkts
+ Counter,
+ ifInNUcastPkts
+ Counter,
+ ifInDiscards
+ Counter,
+ ifInErrors
+ Counter,
+ ifInUnknownProtos
+ Counter,
+ ifOutOctets
+ Counter,
+ ifOutUcastPkts
+ Counter,
+ ifOutNUcastPkts
+ Counter,
+ ifOutDiscards
+ Counter,
+ ifOutErrors
+ Counter,
+ ifOutQLen
+ Gauge,
+ ifSpecific
+ OBJECT IDENTIFIER
+ }
+
+ ifIndex OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+
+
+
+
+
+ DESCRIPTION
+ "A unique value for each interface. Its value
+ ranges between 1 and the value of ifNumber. The
+ value for each interface must remain constant at
+ least from one re-initialization of the entity's
+ network management system to the next re-
+ initialization."
+ ::= { ifEntry 1 }
+
+ ifDescr OBJECT-TYPE
+ SYNTAX DisplayString (SIZE (0..255))
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "A textual string containing information about the
+ interface. This string should include the name of
+ the manufacturer, the product name and the version
+ of the hardware interface."
+ ::= { ifEntry 2 }
+
+ ifType OBJECT-TYPE
+ SYNTAX INTEGER {
+ other(1), -- none of the following
+ regular1822(2),
+ hdh1822(3),
+ ddn-x25(4),
+ rfc877-x25(5),
+ ethernet-csmacd(6),
+ iso88023-csmacd(7),
+ iso88024-tokenBus(8),
+ iso88025-tokenRing(9),
+ iso88026-man(10),
+ starLan(11),
+ proteon-10Mbit(12),
+ proteon-80Mbit(13),
+ hyperchannel(14),
+ fddi(15),
+ lapb(16),
+ sdlc(17),
+ ds1(18), -- T-1
+ e1(19), -- european equiv. of T-1
+ basicISDN(20),
+ primaryISDN(21), -- proprietary serial
+ propPointToPointSerial(22),
+ ppp(23),
+ softwareLoopback(24),
+ eon(25), -- CLNP over IP [11]
+ ethernet-3Mbit(26),
+
+
+
+
+
+ nsip(27), -- XNS over IP
+ slip(28), -- generic SLIP
+ ultra(29), -- ULTRA technologies
+ ds3(30), -- T-3
+ sip(31), -- SMDS
+ frame-relay(32)
+ }
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The type of interface, distinguished according to
+ the physical/link protocol(s) immediately `below'
+ the network layer in the protocol stack."
+ ::= { ifEntry 3 }
+
+ ifMtu OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The size of the largest datagram which can be
+ sent/received on the interface, specified in
+ octets. For interfaces that are used for
+ transmitting network datagrams, this is the size
+ of the largest network datagram that can be sent
+ on the interface."
+ ::= { ifEntry 4 }
+
+ ifSpeed OBJECT-TYPE
+ SYNTAX Gauge
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "An estimate of the interface's current bandwidth
+ in bits per second. For interfaces which do not
+ vary in bandwidth or for those where no accurate
+ estimation can be made, this object should contain
+ the nominal bandwidth."
+ ::= { ifEntry 5 }
+
+ ifPhysAddress OBJECT-TYPE
+ SYNTAX PhysAddress
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The interface's address at the protocol layer
+ immediately `below' the network layer in the
+ protocol stack. For interfaces which do not have
+
+
+
+
+
+ such an address (e.g., a serial line), this object
+ should contain an octet string of zero length."
+ ::= { ifEntry 6 }
+
+ ifAdminStatus OBJECT-TYPE
+ SYNTAX INTEGER {
+ up(1), -- ready to pass packets
+ down(2),
+ testing(3) -- in some test mode
+ }
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The desired state of the interface. The
+ testing(3) state indicates that no operational
+ packets can be passed."
+ ::= { ifEntry 7 }
+
+ ifOperStatus OBJECT-TYPE
+ SYNTAX INTEGER {
+ up(1), -- ready to pass packets
+ down(2),
+ testing(3) -- in some test mode
+ }
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The current operational state of the interface.
+ The testing(3) state indicates that no operational
+ packets can be passed."
+ ::= { ifEntry 8 }
+
+ ifLastChange OBJECT-TYPE
+ SYNTAX TimeTicks
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The value of sysUpTime at the time the interface
+ entered its current operational state. If the
+ current state was entered prior to the last re-
+ initialization of the local network management
+ subsystem, then this object contains a zero
+ value."
+ ::= { ifEntry 9 }
+
+ ifInOctets OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+
+
+
+
+
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of octets received on the
+ interface, including framing characters."
+ ::= { ifEntry 10 }
+
+ ifInUcastPkts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of subnetwork-unicast packets
+ delivered to a higher-layer protocol."
+ ::= { ifEntry 11 }
+
+ ifInNUcastPkts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of non-unicast (i.e., subnetwork-
+ broadcast or subnetwork-multicast) packets
+ delivered to a higher-layer protocol."
+ ::= { ifEntry 12 }
+
+ ifInDiscards OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of inbound packets which were chosen
+ to be discarded even though no errors had been
+ detected to prevent their being deliverable to a
+ higher-layer protocol. One possible reason for
+ discarding such a packet could be to free up
+ buffer space."
+ ::= { ifEntry 13 }
+
+ ifInErrors OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of inbound packets that contained
+ errors preventing them from being deliverable to a
+ higher-layer protocol."
+ ::= { ifEntry 14 }
+
+
+
+
+
+
+ ifInUnknownProtos OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of packets received via the interface
+ which were discarded because of an unknown or
+ unsupported protocol."
+ ::= { ifEntry 15 }
+
+ ifOutOctets OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of octets transmitted out of the
+ interface, including framing characters."
+ ::= { ifEntry 16 }
+
+ ifOutUcastPkts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of packets that higher-level
+ protocols requested be transmitted to a
+ subnetwork-unicast address, including those that
+ were discarded or not sent."
+ ::= { ifEntry 17 }
+
+ ifOutNUcastPkts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of packets that higher-level
+ protocols requested be transmitted to a non-
+ unicast (i.e., a subnetwork-broadcast or
+ subnetwork-multicast) address, including those
+ that were discarded or not sent."
+ ::= { ifEntry 18 }
+
+ ifOutDiscards OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of outbound packets which were chosen
+
+
+
+
+
+ to be discarded even though no errors had been
+ detected to prevent their being transmitted. One
+ possible reason for discarding such a packet could
+ be to free up buffer space."
+ ::= { ifEntry 19 }
+
+ ifOutErrors OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of outbound packets that could not be
+ transmitted because of errors."
+ ::= { ifEntry 20 }
+
+ ifOutQLen OBJECT-TYPE
+ SYNTAX Gauge
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The length of the output packet queue (in
+ packets)."
+ ::= { ifEntry 21 }
+
+ ifSpecific OBJECT-TYPE
+ SYNTAX OBJECT IDENTIFIER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "A reference to MIB definitions specific to the
+ particular media being used to realize the
+ interface. For example, if the interface is
+ realized by an ethernet, then the value of this
+ object refers to a document defining objects
+ specific to ethernet. If this information is not
+ present, its value should be set to the OBJECT
+ IDENTIFIER { 0 0 }, which is a syntatically valid
+ object identifier, and any conformant
+ implementation of ASN.1 and BER must be able to
+ generate and recognize this value."
+ ::= { ifEntry 22 }
+
+
+ -- the Address Translation group
+
+ -- Implementation of the Address Translation group is
+ -- mandatory for all systems. Note however that this group
+ -- is deprecated by MIB-II. That is, it is being included
+
+
+
+
+
+ -- solely for compatibility with MIB-I nodes, and will most
+ -- likely be excluded from MIB-III nodes. From MIB-II and
+ -- onwards, each network protocol group contains its own
+ -- address translation tables.
+
+ -- The Address Translation group contains one table which is
+ -- the union across all interfaces of the translation tables
+ -- for converting a NetworkAddress (e.g., an IP address) into
+ -- a subnetwork-specific address. For lack of a better term,
+ -- this document refers to such a subnetwork-specific address
+ -- as a `physical' address.
+
+ -- Examples of such translation tables are: for broadcast
+ -- media where ARP is in use, the translation table is
+ -- equivalent to the ARP cache; or, on an X.25 network where
+ -- non-algorithmic translation to X.121 addresses is
+ -- required, the translation table contains the
+ -- NetworkAddress to X.121 address equivalences.
+
+ atTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF AtEntry
+ ACCESS not-accessible
+ STATUS deprecated
+ DESCRIPTION
+ "The Address Translation tables contain the
+ NetworkAddress to `physical' address equivalences.
+ Some interfaces do not use translation tables for
+ determining address equivalences (e.g., DDN-X.25
+ has an algorithmic method); if all interfaces are
+ of this type, then the Address Translation table
+ is empty, i.e., has zero entries."
+ ::= { at 1 }
+
+ atEntry OBJECT-TYPE
+ SYNTAX AtEntry
+ ACCESS not-accessible
+ STATUS deprecated
+ DESCRIPTION
+ "Each entry contains one NetworkAddress to
+ `physical' address equivalence."
+ INDEX { atIfIndex,
+ atNetAddress }
+ ::= { atTable 1 }
+
+ AtEntry ::=
+ SEQUENCE {
+ atIfIndex
+ INTEGER,
+
+
+
+
+
+ atPhysAddress
+ PhysAddress,
+ atNetAddress
+ NetworkAddress
+ }
+
+ atIfIndex OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-write
+ STATUS deprecated
+ DESCRIPTION
+ "The interface on which this entry's equivalence
+ is effective. The interface identified by a
+ particular value of this index is the same
+ interface as identified by the same value of
+ ifIndex."
+ ::= { atEntry 1 }
+
+ atPhysAddress OBJECT-TYPE
+ SYNTAX PhysAddress
+ ACCESS read-write
+ STATUS deprecated
+ DESCRIPTION
+ "The media-dependent `physical' address.
+
+ Setting this object to a null string (one of zero
+ length) has the effect of invaliding the
+ corresponding entry in the atTable object. That
+ is, it effectively dissasociates the interface
+ identified with said entry from the mapping
+ identified with said entry. It is an
+ implementation-specific matter as to whether the
+ agent removes an invalidated entry from the table.
+ Accordingly, management stations must be prepared
+ to receive tabular information from agents that
+ corresponds to entries not currently in use.
+ Proper interpretation of such entries requires
+ examination of the relevant atPhysAddress object."
+ ::= { atEntry 2 }
+
+ atNetAddress OBJECT-TYPE
+ SYNTAX NetworkAddress
+ ACCESS read-write
+ STATUS deprecated
+ DESCRIPTION
+ "The NetworkAddress (e.g., the IP address)
+ corresponding to the media-dependent `physical'
+ address."
+
+
+
+
+
+ ::= { atEntry 3 }
+
+
+ -- the IP group
+
+ -- Implementation of the IP group is mandatory for all
+ -- systems.
+
+ ipForwarding OBJECT-TYPE
+ SYNTAX INTEGER {
+ forwarding(1), -- acting as a gateway
+ not-forwarding(2) -- NOT acting as a gateway
+ }
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The indication of whether this entity is acting
+ as an IP gateway in respect to the forwarding of
+ datagrams received by, but not addressed to, this
+ entity. IP gateways forward datagrams. IP hosts
+ do not (except those source-routed via the host).
+
+ Note that for some managed nodes, this object may
+ take on only a subset of the values possible.
+ Accordingly, it is appropriate for an agent to
+ return a `badValue' response if a management
+ station attempts to change this object to an
+ inappropriate value."
+ ::= { ip 1 }
+
+ ipDefaultTTL OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The default value inserted into the Time-To-Live
+ field of the IP header of datagrams originated at
+ this entity, whenever a TTL value is not supplied
+ by the transport layer protocol."
+ ::= { ip 2 }
+
+ ipInReceives OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of input datagrams received from
+ interfaces, including those received in error."
+
+
+
+
+
+ ::= { ip 3 }
+
+ ipInHdrErrors OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of input datagrams discarded due to
+ errors in their IP headers, including bad
+ checksums, version number mismatch, other format
+ errors, time-to-live exceeded, errors discovered
+ in processing their IP options, etc."
+ ::= { ip 4 }
+
+ ipInAddrErrors OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of input datagrams discarded because
+ the IP address in their IP header's destination
+ field was not a valid address to be received at
+ this entity. This count includes invalid
+ addresses (e.g., 0.0.0.0) and addresses of
+ unsupported Classes (e.g., Class E). For entities
+ which are not IP Gateways and therefore do not
+ forward datagrams, this counter includes datagrams
+ discarded because the destination address was not
+ a local address."
+ ::= { ip 5 }
+
+ ipForwDatagrams OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of input datagrams for which this
+ entity was not their final IP destination, as a
+ result of which an attempt was made to find a
+ route to forward them to that final destination.
+ In entities which do not act as IP Gateways, this
+ counter will include only those packets which were
+ Source-Routed via this entity, and the Source-
+ Route option processing was successful."
+ ::= { ip 6 }
+
+ ipInUnknownProtos OBJECT-TYPE
+ SYNTAX Counter
+
+
+
+
+
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of locally-addressed datagrams
+ received successfully but discarded because of an
+ unknown or unsupported protocol."
+ ::= { ip 7 }
+
+ ipInDiscards OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of input IP datagrams for which no
+ problems were encountered to prevent their
+ continued processing, but which were discarded
+ (e.g., for lack of buffer space). Note that this
+ counter does not include any datagrams discarded
+ while awaiting re-assembly."
+ ::= { ip 8 }
+
+ ipInDelivers OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of input datagrams successfully
+ delivered to IP user-protocols (including ICMP)."
+ ::= { ip 9 }
+
+ ipOutRequests OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of IP datagrams which local IP
+ user-protocols (including ICMP) supplied to IP in
+ requests for transmission. Note that this counter
+ does not include any datagrams counted in
+ ipForwDatagrams."
+ ::= { ip 10 }
+
+ ipOutDiscards OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of output IP datagrams for which no
+
+
+
+
+
+ problem was encountered to prevent their
+ transmission to their destination, but which were
+ discarded (e.g., for lack of buffer space). Note
+ that this counter would include datagrams counted
+ in ipForwDatagrams if any such packets met this
+ (discretionary) discard criterion."
+ ::= { ip 11 }
+
+ ipOutNoRoutes OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of IP datagrams discarded because no
+ route could be found to transmit them to their
+ destination. Note that this counter includes any
+ packets counted in ipForwDatagrams which meet this
+ `no-route' criterion. Note that this includes any
+ datagarms which a host cannot route because all of
+ its default gateways are down."
+ ::= { ip 12 }
+
+ ipReasmTimeout OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The maximum number of seconds which received
+ fragments are held while they are awaiting
+ reassembly at this entity."
+ ::= { ip 13 }
+
+ ipReasmReqds OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of IP fragments received which needed
+ to be reassembled at this entity."
+ ::= { ip 14 }
+
+ ipReasmOKs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of IP datagrams successfully re-
+ assembled."
+
+
+
+
+
+ ::= { ip 15 }
+
+ ipReasmFails OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of failures detected by the IP re-
+ assembly algorithm (for whatever reason: timed
+ out, errors, etc). Note that this is not
+ necessarily a count of discarded IP fragments
+ since some algorithms (notably the algorithm in
+ RFC 815) can lose track of the number of fragments
+ by combining them as they are received."
+ ::= { ip 16 }
+
+ ipFragOKs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of IP datagrams that have been
+ successfully fragmented at this entity."
+ ::= { ip 17 }
+
+ ipFragFails OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of IP datagrams that have been
+ discarded because they needed to be fragmented at
+ this entity but could not be, e.g., because their
+ Don't Fragment flag was set."
+ ::= { ip 18 }
+
+ ipFragCreates OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of IP datagram fragments that have
+ been generated as a result of fragmentation at
+ this entity."
+ ::= { ip 19 }
+
+
+
+
+
+
+
+
+ -- the IP address table
+
+ -- The IP address table contains this entity's IP addressing
+ -- information.
+
+ ipAddrTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF IpAddrEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "The table of addressing information relevant to
+ this entity's IP addresses."
+ ::= { ip 20 }
+
+ ipAddrEntry OBJECT-TYPE
+ SYNTAX IpAddrEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "The addressing information for one of this
+ entity's IP addresses."
+ INDEX { ipAdEntAddr }
+ ::= { ipAddrTable 1 }
+
+ IpAddrEntry ::=
+ SEQUENCE {
+ ipAdEntAddr
+ IpAddress,
+ ipAdEntIfIndex
+ INTEGER,
+ ipAdEntNetMask
+ IpAddress,
+ ipAdEntBcastAddr
+ INTEGER,
+ ipAdEntReasmMaxSize
+ INTEGER (0..65535)
+ }
+
+ ipAdEntAddr OBJECT-TYPE
+ SYNTAX IpAddress
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The IP address to which this entry's addressing
+ information pertains."
+ ::= { ipAddrEntry 1 }
+
+
+
+
+
+
+
+ ipAdEntIfIndex OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The index value which uniquely identifies the
+ interface to which this entry is applicable. The
+ interface identified by a particular value of this
+ index is the same interface as identified by the
+ same value of ifIndex."
+ ::= { ipAddrEntry 2 }
+
+ ipAdEntNetMask OBJECT-TYPE
+ SYNTAX IpAddress
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The subnet mask associated with the IP address of
+ this entry. The value of the mask is an IP
+ address with all the network bits set to 1 and all
+ the hosts bits set to 0."
+ ::= { ipAddrEntry 3 }
+
+ ipAdEntBcastAddr OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The value of the least-significant bit in the IP
+ broadcast address used for sending datagrams on
+ the (logical) interface associated with the IP
+ address of this entry. For example, when the
+ Internet standard all-ones broadcast address is
+ used, the value will be 1. This value applies to
+ both the subnet and network broadcasts addresses
+ used by the entity on this (logical) interface."
+ ::= { ipAddrEntry 4 }
+
+ ipAdEntReasmMaxSize OBJECT-TYPE
+ SYNTAX INTEGER (0..65535)
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The size of the largest IP datagram which this
+ entity can re-assemble from incoming IP fragmented
+ datagrams received on this interface."
+ ::= { ipAddrEntry 5 }
+
+
+
+
+
+
+ -- the IP routing table
+
+ -- The IP routing table contains an entry for each route
+ -- presently known to this entity.
+
+ ipRouteTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF IpRouteEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "This entity's IP Routing table."
+ ::= { ip 21 }
+
+ ipRouteEntry OBJECT-TYPE
+ SYNTAX IpRouteEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A route to a particular destination."
+ INDEX { ipRouteDest }
+ ::= { ipRouteTable 1 }
+
+ IpRouteEntry ::=
+ SEQUENCE {
+ ipRouteDest
+ IpAddress,
+ ipRouteIfIndex
+ INTEGER,
+ ipRouteMetric1
+ INTEGER,
+ ipRouteMetric2
+ INTEGER,
+ ipRouteMetric3
+ INTEGER,
+ ipRouteMetric4
+ INTEGER,
+ ipRouteNextHop
+ IpAddress,
+ ipRouteType
+ INTEGER,
+ ipRouteProto
+ INTEGER,
+ ipRouteAge
+ INTEGER,
+ ipRouteMask
+ IpAddress,
+ ipRouteMetric5
+ INTEGER,
+
+
+
+
+
+ ipRouteInfo
+ OBJECT IDENTIFIER
+ }
+
+ ipRouteDest OBJECT-TYPE
+ SYNTAX IpAddress
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The destination IP address of this route. An
+ entry with a value of 0.0.0.0 is considered a
+ default route. Multiple routes to a single
+ destination can appear in the table, but access to
+ such multiple entries is dependent on the table-
+ access mechanisms defined by the network
+ management protocol in use."
+ ::= { ipRouteEntry 1 }
+
+ ipRouteIfIndex OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The index value which uniquely identifies the
+ local interface through which the next hop of this
+ route should be reached. The interface identified
+ by a particular value of this index is the same
+ interface as identified by the same value of
+ ifIndex."
+ ::= { ipRouteEntry 2 }
+
+ ipRouteMetric1 OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The primary routing metric for this route. The
+ semantics of this metric are determined by the
+ routing-protocol specified in the route's
+ ipRouteProto value. If this metric is not used,
+ its value should be set to -1."
+ ::= { ipRouteEntry 3 }
+
+ ipRouteMetric2 OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+
+
+
+
+
+ "An alternate routing metric for this route. The
+ semantics of this metric are determined by the
+ routing-protocol specified in the route's
+ ipRouteProto value. If this metric is not used,
+ its value should be set to -1."
+ ::= { ipRouteEntry 4 }
+
+ ipRouteMetric3 OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "An alternate routing metric for this route. The
+ semantics of this metric are determined by the
+ routing-protocol specified in the route's
+ ipRouteProto value. If this metric is not used,
+ its value should be set to -1."
+ ::= { ipRouteEntry 5 }
+
+ ipRouteMetric4 OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "An alternate routing metric for this route. The
+ semantics of this metric are determined by the
+ routing-protocol specified in the route's
+ ipRouteProto value. If this metric is not used,
+ its value should be set to -1."
+ ::= { ipRouteEntry 6 }
+
+ ipRouteNextHop OBJECT-TYPE
+ SYNTAX IpAddress
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The IP address of the next hop of this route.
+ (In the case of a route bound to an interface
+ which is realized via a broadcast media, the value
+ of this field is the agent's IP address on that
+ interface.)"
+ ::= { ipRouteEntry 7 }
+
+ ipRouteType OBJECT-TYPE
+ SYNTAX INTEGER {
+ other(1), -- none of the following
+
+ invalid(2), -- an invalidated route
+
+
+
+
+
+ -- route to directly
+ direct(3), -- connected (sub-)network
+
+ -- route to a non-local
+ indirect(4) -- host/network/sub-network
+ }
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The type of route. Note that the values
+ direct(3) and indirect(4) refer to the notion of
+ direct and indirect routing in the IP
+ architecture.
+
+ Setting this object to the value invalid(2) has
+ the effect of invalidating the corresponding entry
+ in the ipRouteTable object. That is, it
+ effectively dissasociates the destination
+ identified with said entry from the route
+ identified with said entry. It is an
+ implementation-specific matter as to whether the
+ agent removes an invalidated entry from the table.
+ Accordingly, management stations must be prepared
+ to receive tabular information from agents that
+ corresponds to entries not currently in use.
+ Proper interpretation of such entries requires
+ examination of the relevant ipRouteType object."
+ ::= { ipRouteEntry 8 }
+
+ ipRouteProto OBJECT-TYPE
+ SYNTAX INTEGER {
+ other(1), -- none of the following
+
+ -- non-protocol information,
+ -- e.g., manually configured
+ local(2), -- entries
+
+ -- set via a network
+ netmgmt(3), -- management protocol
+
+ -- obtained via ICMP,
+ icmp(4), -- e.g., Redirect
+
+ -- the remaining values are
+ -- all gateway routing
+ -- protocols
+ egp(5),
+ ggp(6),
+
+
+
+
+
+ hello(7),
+ rip(8),
+ is-is(9),
+ es-is(10),
+ ciscoIgrp(11),
+ bbnSpfIgp(12),
+ ospf(13),
+ bgp(14)
+ }
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The routing mechanism via which this route was
+ learned. Inclusion of values for gateway routing
+ protocols is not intended to imply that hosts
+ should support those protocols."
+ ::= { ipRouteEntry 9 }
+
+ ipRouteAge OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The number of seconds since this route was last
+ updated or otherwise determined to be correct.
+ Note that no semantics of `too old' can be implied
+ except through knowledge of the routing protocol
+ by which the route was learned."
+ ::= { ipRouteEntry 10 }
+
+ ipRouteMask OBJECT-TYPE
+ SYNTAX IpAddress
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "Indicate the mask to be logical-ANDed with the
+ destination address before being compared to the
+ value in the ipRouteDest field. For those systems
+ that do not support arbitrary subnet masks, an
+ agent constructs the value of the ipRouteMask by
+ determining whether the value of the correspondent
+ ipRouteDest field belong to a class-A, B, or C
+ network, and then using one of:
+
+ mask network
+ 255.0.0.0 class-A
+ 255.255.0.0 class-B
+ 255.255.255.0 class-C
+
+
+
+
+
+ If the value of the ipRouteDest is 0.0.0.0 (a
+ default route), then the mask value is also
+ 0.0.0.0. It should be noted that all IP routing
+ subsystems implicitly use this mechanism."
+ ::= { ipRouteEntry 11 }
+
+ ipRouteMetric5 OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "An alternate routing metric for this route. The
+ semantics of this metric are determined by the
+ routing-protocol specified in the route's
+ ipRouteProto value. If this metric is not used,
+ its value should be set to -1."
+ ::= { ipRouteEntry 12 }
+
+ ipRouteInfo OBJECT-TYPE
+ SYNTAX OBJECT IDENTIFIER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "A reference to MIB definitions specific to the
+ particular routing protocol which is responsible
+ for this route, as determined by the value
+ specified in the route's ipRouteProto value. If
+ this information is not present, its value should
+ be set to the OBJECT IDENTIFIER { 0 0 }, which is
+ a syntatically valid object identifier, and any
+ conformant implementation of ASN.1 and BER must be
+ able to generate and recognize this value."
+ ::= { ipRouteEntry 13 }
+
+
+ -- the IP Address Translation table
+
+ -- The IP address translation table contain the IpAddress to
+ -- `physical' address equivalences. Some interfaces do not
+ -- use translation tables for determining address
+ -- equivalences (e.g., DDN-X.25 has an algorithmic method);
+ -- if all interfaces are of this type, then the Address
+ -- Translation table is empty, i.e., has zero entries.
+
+ ipNetToMediaTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF IpNetToMediaEntry
+ ACCESS not-accessible
+ STATUS mandatory
+
+
+
+
+
+ DESCRIPTION
+ "The IP Address Translation table used for mapping
+ from IP addresses to physical addresses."
+ ::= { ip 22 }
+
+ ipNetToMediaEntry OBJECT-TYPE
+ SYNTAX IpNetToMediaEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "Each entry contains one IpAddress to `physical'
+ address equivalence."
+ INDEX { ipNetToMediaIfIndex,
+ ipNetToMediaNetAddress }
+ ::= { ipNetToMediaTable 1 }
+
+ IpNetToMediaEntry ::=
+ SEQUENCE {
+ ipNetToMediaIfIndex
+ INTEGER,
+ ipNetToMediaPhysAddress
+ PhysAddress,
+ ipNetToMediaNetAddress
+ IpAddress,
+ ipNetToMediaType
+ INTEGER
+ }
+
+ ipNetToMediaIfIndex OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The interface on which this entry's equivalence
+ is effective. The interface identified by a
+ particular value of this index is the same
+ interface as identified by the same value of
+ ifIndex."
+ ::= { ipNetToMediaEntry 1 }
+
+ ipNetToMediaPhysAddress OBJECT-TYPE
+ SYNTAX PhysAddress
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The media-dependent `physical' address."
+ ::= { ipNetToMediaEntry 2 }
+
+
+
+
+
+
+ ipNetToMediaNetAddress OBJECT-TYPE
+ SYNTAX IpAddress
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The IpAddress corresponding to the media-
+ dependent `physical' address."
+ ::= { ipNetToMediaEntry 3 }
+
+ ipNetToMediaType OBJECT-TYPE
+ SYNTAX INTEGER {
+ other(1), -- none of the following
+ invalid(2), -- an invalidated mapping
+ dynamic(3),
+ static(4)
+ }
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The type of mapping.
+
+ Setting this object to the value invalid(2) has
+ the effect of invalidating the corresponding entry
+ in the ipNetToMediaTable. That is, it effectively
+ dissasociates the interface identified with said
+ entry from the mapping identified with said entry.
+ It is an implementation-specific matter as to
+ whether the agent removes an invalidated entry
+ from the table. Accordingly, management stations
+ must be prepared to receive tabular information
+ from agents that corresponds to entries not
+ currently in use. Proper interpretation of such
+ entries requires examination of the relevant
+ ipNetToMediaType object."
+ ::= { ipNetToMediaEntry 4 }
+
+
+ -- additional IP objects
+
+ ipRoutingDiscards OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of routing entries which were chosen
+ to be discarded even though they are valid. One
+ possible reason for discarding such an entry could
+ be to free-up buffer space for other routing
+
+
+
+
+
+ entries."
+ ::= { ip 23 }
+
+
+ -- the ICMP group
+
+ -- Implementation of the ICMP group is mandatory for all
+ -- systems.
+
+ icmpInMsgs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of ICMP messages which the
+ entity received. Note that this counter includes
+ all those counted by icmpInErrors."
+ ::= { icmp 1 }
+
+ icmpInErrors OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP messages which the entity
+ received but determined as having ICMP-specific
+ errors (bad ICMP checksums, bad length, etc.)."
+ ::= { icmp 2 }
+
+ icmpInDestUnreachs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Destination Unreachable
+ messages received."
+ ::= { icmp 3 }
+
+ icmpInTimeExcds OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Time Exceeded messages
+ received."
+ ::= { icmp 4 }
+
+
+
+
+
+
+
+ icmpInParmProbs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Parameter Problem messages
+ received."
+ ::= { icmp 5 }
+
+ icmpInSrcQuenchs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Source Quench messages
+ received."
+ ::= { icmp 6 }
+
+ icmpInRedirects OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Redirect messages received."
+ ::= { icmp 7 }
+
+ icmpInEchos OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Echo (request) messages
+ received."
+ ::= { icmp 8 }
+
+ icmpInEchoReps OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Echo Reply messages received."
+ ::= { icmp 9 }
+
+ icmpInTimestamps OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+
+
+
+
+
+ "The number of ICMP Timestamp (request) messages
+ received."
+ ::= { icmp 10 }
+
+ icmpInTimestampReps OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Timestamp Reply messages
+ received."
+ ::= { icmp 11 }
+
+ icmpInAddrMasks OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Address Mask Request messages
+ received."
+ ::= { icmp 12 }
+
+ icmpInAddrMaskReps OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Address Mask Reply messages
+ received."
+ ::= { icmp 13 }
+
+ icmpOutMsgs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of ICMP messages which this
+ entity attempted to send. Note that this counter
+ includes all those counted by icmpOutErrors."
+ ::= { icmp 14 }
+
+ icmpOutErrors OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP messages which this entity did
+ not send due to problems discovered within ICMP
+
+
+
+
+
+ such as a lack of buffers. This value should not
+ include errors discovered outside the ICMP layer
+ such as the inability of IP to route the resultant
+ datagram. In some implementations there may be no
+ types of error which contribute to this counter's
+ value."
+ ::= { icmp 15 }
+
+ icmpOutDestUnreachs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Destination Unreachable
+ messages sent."
+ ::= { icmp 16 }
+
+ icmpOutTimeExcds OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Time Exceeded messages sent."
+ ::= { icmp 17 }
+
+ icmpOutParmProbs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Parameter Problem messages
+ sent."
+ ::= { icmp 18 }
+
+ icmpOutSrcQuenchs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Source Quench messages sent."
+ ::= { icmp 19 }
+
+ icmpOutRedirects OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Redirect messages sent. For a
+
+
+
+
+
+ host, this object will always be zero, since hosts
+ do not send redirects."
+ ::= { icmp 20 }
+
+ icmpOutEchos OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Echo (request) messages sent."
+ ::= { icmp 21 }
+
+ icmpOutEchoReps OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Echo Reply messages sent."
+ ::= { icmp 22 }
+
+ icmpOutTimestamps OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Timestamp (request) messages
+ sent."
+ ::= { icmp 23 }
+
+ icmpOutTimestampReps OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Timestamp Reply messages
+ sent."
+ ::= { icmp 24 }
+
+ icmpOutAddrMasks OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Address Mask Request messages
+ sent."
+ ::= { icmp 25 }
+
+
+
+
+
+
+
+ icmpOutAddrMaskReps OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ICMP Address Mask Reply messages
+ sent."
+ ::= { icmp 26 }
+
+
+ -- the TCP group
+
+ -- Implementation of the TCP group is mandatory for all
+ -- systems that implement the TCP.
+
+ -- Note that instances of object types that represent
+ -- information about a particular TCP connection are
+ -- transient; they persist only as long as the connection
+ -- in question.
+
+ tcpRtoAlgorithm OBJECT-TYPE
+ SYNTAX INTEGER {
+ other(1), -- none of the following
+
+ constant(2), -- a constant rto
+ rsre(3), -- MIL-STD-1778, Appendix B
+ vanj(4) -- Van Jacobson's algorithm [10]
+ }
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The algorithm used to determine the timeout value
+ used for retransmitting unacknowledged octets."
+ ::= { tcp 1 }
+
+ tcpRtoMin OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The minimum value permitted by a TCP
+ implementation for the retransmission timeout,
+ measured in milliseconds. More refined semantics
+ for objects of this type depend upon the algorithm
+ used to determine the retransmission timeout. In
+ particular, when the timeout algorithm is rsre(3),
+ an object of this type has the semantics of the
+ LBOUND quantity described in RFC 793."
+
+
+
+
+
+ ::= { tcp 2 }
+
+
+ tcpRtoMax OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The maximum value permitted by a TCP
+ implementation for the retransmission timeout,
+ measured in milliseconds. More refined semantics
+ for objects of this type depend upon the algorithm
+ used to determine the retransmission timeout. In
+ particular, when the timeout algorithm is rsre(3),
+ an object of this type has the semantics of the
+ UBOUND quantity described in RFC 793."
+ ::= { tcp 3 }
+
+ tcpMaxConn OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The limit on the total number of TCP connections
+ the entity can support. In entities where the
+ maximum number of connections is dynamic, this
+ object should contain the value -1."
+ ::= { tcp 4 }
+
+ tcpActiveOpens OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of times TCP connections have made a
+ direct transition to the SYN-SENT state from the
+ CLOSED state."
+ ::= { tcp 5 }
+
+ tcpPassiveOpens OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of times TCP connections have made a
+ direct transition to the SYN-RCVD state from the
+ LISTEN state."
+ ::= { tcp 6 }
+
+
+
+
+
+ tcpAttemptFails OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of times TCP connections have made a
+ direct transition to the CLOSED state from either
+ the SYN-SENT state or the SYN-RCVD state, plus the
+ number of times TCP connections have made a direct
+ transition to the LISTEN state from the SYN-RCVD
+ state."
+ ::= { tcp 7 }
+
+ tcpEstabResets OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of times TCP connections have made a
+ direct transition to the CLOSED state from either
+ the ESTABLISHED state or the CLOSE-WAIT state."
+ ::= { tcp 8 }
+
+ tcpCurrEstab OBJECT-TYPE
+ SYNTAX Gauge
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of TCP connections for which the
+ current state is either ESTABLISHED or CLOSE-
+ WAIT."
+ ::= { tcp 9 }
+
+ tcpInSegs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of segments received, including
+ those received in error. This count includes
+ segments received on currently established
+ connections."
+ ::= { tcp 10 }
+
+ tcpOutSegs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+
+
+
+
+
+ DESCRIPTION
+ "The total number of segments sent, including
+ those on current connections but excluding those
+ containing only retransmitted octets."
+ ::= { tcp 11 }
+
+ tcpRetransSegs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of segments retransmitted - that
+ is, the number of TCP segments transmitted
+ containing one or more previously transmitted
+ octets."
+ ::= { tcp 12 }
+
+
+ -- the TCP Connection table
+
+ -- The TCP connection table contains information about this
+ -- entity's existing TCP connections.
+
+ tcpConnTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF TcpConnEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A table containing TCP connection-specific
+ information."
+ ::= { tcp 13 }
+
+ tcpConnEntry OBJECT-TYPE
+ SYNTAX TcpConnEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "Information about a particular current TCP
+ connection. An object of this type is transient,
+ in that it ceases to exist when (or soon after)
+ the connection makes the transition to the CLOSED
+ state."
+ INDEX { tcpConnLocalAddress,
+ tcpConnLocalPort,
+ tcpConnRemAddress,
+ tcpConnRemPort }
+ ::= { tcpConnTable 1 }
+
+
+
+
+
+
+ TcpConnEntry ::=
+ SEQUENCE {
+ tcpConnState
+ INTEGER,
+ tcpConnLocalAddress
+ IpAddress,
+ tcpConnLocalPort
+ INTEGER (0..65535),
+ tcpConnRemAddress
+ IpAddress,
+ tcpConnRemPort
+ INTEGER (0..65535)
+ }
+
+ tcpConnState OBJECT-TYPE
+ SYNTAX INTEGER {
+ closed(1),
+ listen(2),
+ synSent(3),
+ synReceived(4),
+ established(5),
+ finWait1(6),
+ finWait2(7),
+ closeWait(8),
+ lastAck(9),
+ closing(10),
+ timeWait(11),
+ deleteTCB(12)
+ }
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The state of this TCP connection.
+
+ The only value which may be set by a management
+ station is deleteTCB(12). Accordingly, it is
+ appropriate for an agent to return a `badValue'
+ response if a management station attempts to set
+ this object to any other value.
+
+ If a management station sets this object to the
+ value deleteTCB(12), then this has the effect of
+ deleting the TCB (as defined in RFC 793) of the
+ corresponding connection on the managed node,
+ resulting in immediate termination of the
+ connection.
+
+ As an implementation-specific option, a RST
+
+
+
+
+
+ segment may be sent from the managed node to the
+ other TCP endpoint (note however that RST segments
+ are not sent reliably)."
+ ::= { tcpConnEntry 1 }
+
+ tcpConnLocalAddress OBJECT-TYPE
+ SYNTAX IpAddress
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The local IP address for this TCP connection. In
+ the case of a connection in the listen state which
+ is willing to accept connections for any IP
+ interface associated with the node, the value
+ 0.0.0.0 is used."
+ ::= { tcpConnEntry 2 }
+
+ tcpConnLocalPort OBJECT-TYPE
+ SYNTAX INTEGER (0..65535)
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The local port number for this TCP connection."
+ ::= { tcpConnEntry 3 }
+
+ tcpConnRemAddress OBJECT-TYPE
+ SYNTAX IpAddress
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The remote IP address for this TCP connection."
+ ::= { tcpConnEntry 4 }
+
+ tcpConnRemPort OBJECT-TYPE
+ SYNTAX INTEGER (0..65535)
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The remote port number for this TCP connection."
+ ::= { tcpConnEntry 5 }
+
+
+ -- additional TCP objects
+
+ tcpInErrs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+
+
+
+
+
+ DESCRIPTION
+ "The total number of segments received in error
+ (e.g., bad TCP checksums)."
+ ::= { tcp 14 }
+
+ tcpOutRsts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of TCP segments sent containing the
+ RST flag."
+ ::= { tcp 15 }
+
+
+ -- the UDP group
+
+ -- Implementation of the UDP group is mandatory for all
+ -- systems which implement the UDP.
+
+ udpInDatagrams OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of UDP datagrams delivered to
+ UDP users."
+ ::= { udp 1 }
+
+ udpNoPorts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of received UDP datagrams for
+ which there was no application at the destination
+ port."
+ ::= { udp 2 }
+
+ udpInErrors OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of received UDP datagrams that could
+ not be delivered for reasons other than the lack
+ of an application at the destination port."
+ ::= { udp 3 }
+
+
+
+
+
+ udpOutDatagrams OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of UDP datagrams sent from this
+ entity."
+ ::= { udp 4 }
+
+
+ -- the UDP Listener table
+
+ -- The UDP listener table contains information about this
+ -- entity's UDP end-points on which a local application is
+ -- currently accepting datagrams.
+
+ udpTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF UdpEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A table containing UDP listener information."
+ ::= { udp 5 }
+
+ udpEntry OBJECT-TYPE
+ SYNTAX UdpEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "Information about a particular current UDP
+ listener."
+ INDEX { udpLocalAddress, udpLocalPort }
+ ::= { udpTable 1 }
+
+ UdpEntry ::=
+ SEQUENCE {
+ udpLocalAddress
+ IpAddress,
+ udpLocalPort
+ INTEGER (0..65535)
+ }
+
+ udpLocalAddress OBJECT-TYPE
+ SYNTAX IpAddress
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The local IP address for this UDP listener. In
+
+
+
+
+
+ the case of a UDP listener which is willing to
+ accept datagrams for any IP interface associated
+ with the node, the value 0.0.0.0 is used."
+ ::= { udpEntry 1 }
+
+ udpLocalPort OBJECT-TYPE
+ SYNTAX INTEGER (0..65535)
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The local port number for this UDP listener."
+ ::= { udpEntry 2 }
+
+
+ -- the EGP group
+
+ -- Implementation of the EGP group is mandatory for all
+ -- systems which implement the EGP.
+
+ egpInMsgs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of EGP messages received without
+ error."
+ ::= { egp 1 }
+
+ egpInErrors OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of EGP messages received that proved
+ to be in error."
+ ::= { egp 2 }
+
+ egpOutMsgs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of locally generated EGP
+ messages."
+ ::= { egp 3 }
+
+ egpOutErrors OBJECT-TYPE
+ SYNTAX Counter
+
+
+
+
+
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of locally generated EGP messages not
+ sent due to resource limitations within an EGP
+ entity."
+ ::= { egp 4 }
+
+
+ -- the EGP Neighbor table
+
+ -- The EGP neighbor table contains information about this
+ -- entity's EGP neighbors.
+
+ egpNeighTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF EgpNeighEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "The EGP neighbor table."
+ ::= { egp 5 }
+
+ egpNeighEntry OBJECT-TYPE
+ SYNTAX EgpNeighEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "Information about this entity's relationship with
+ a particular EGP neighbor."
+ INDEX { egpNeighAddr }
+ ::= { egpNeighTable 1 }
+
+ EgpNeighEntry ::=
+ SEQUENCE {
+ egpNeighState
+ INTEGER,
+ egpNeighAddr
+ IpAddress,
+ egpNeighAs
+ INTEGER,
+ egpNeighInMsgs
+ Counter,
+ egpNeighInErrs
+ Counter,
+ egpNeighOutMsgs
+ Counter,
+ egpNeighOutErrs
+ Counter,
+
+
+
+
+
+ egpNeighInErrMsgs
+ Counter,
+ egpNeighOutErrMsgs
+ Counter,
+ egpNeighStateUps
+ Counter,
+ egpNeighStateDowns
+ Counter,
+ egpNeighIntervalHello
+ INTEGER,
+ egpNeighIntervalPoll
+ INTEGER,
+ egpNeighMode
+ INTEGER,
+ egpNeighEventTrigger
+ INTEGER
+ }
+
+ egpNeighState OBJECT-TYPE
+ SYNTAX INTEGER {
+ idle(1),
+ acquisition(2),
+ down(3),
+ up(4),
+ cease(5)
+ }
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The EGP state of the local system with respect to
+ this entry's EGP neighbor. Each EGP state is
+ represented by a value that is one greater than
+ the numerical value associated with said state in
+ RFC 904."
+ ::= { egpNeighEntry 1 }
+
+ egpNeighAddr OBJECT-TYPE
+ SYNTAX IpAddress
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The IP address of this entry's EGP neighbor."
+ ::= { egpNeighEntry 2 }
+
+ egpNeighAs OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+
+
+
+
+
+ DESCRIPTION
+ "The autonomous system of this EGP peer. Zero
+ should be specified if the autonomous system
+ number of the neighbor is not yet known."
+ ::= { egpNeighEntry 3 }
+
+ egpNeighInMsgs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of EGP messages received without error
+ from this EGP peer."
+ ::= { egpNeighEntry 4 }
+
+ egpNeighInErrs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of EGP messages received from this EGP
+ peer that proved to be in error (e.g., bad EGP
+ checksum)."
+ ::= { egpNeighEntry 5 }
+
+ egpNeighOutMsgs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of locally generated EGP messages to
+ this EGP peer."
+ ::= { egpNeighEntry 6 }
+
+ egpNeighOutErrs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of locally generated EGP messages not
+ sent to this EGP peer due to resource limitations
+ within an EGP entity."
+ ::= { egpNeighEntry 7 }
+
+ egpNeighInErrMsgs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+
+
+
+
+
+ DESCRIPTION
+ "The number of EGP-defined error messages received
+ from this EGP peer."
+ ::= { egpNeighEntry 8 }
+
+ egpNeighOutErrMsgs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of EGP-defined error messages sent to
+ this EGP peer."
+ ::= { egpNeighEntry 9 }
+
+ egpNeighStateUps OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of EGP state transitions to the UP
+ state with this EGP peer."
+ ::= { egpNeighEntry 10 }
+
+ egpNeighStateDowns OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of EGP state transitions from the UP
+ state to any other state with this EGP peer."
+ ::= { egpNeighEntry 11 }
+
+ egpNeighIntervalHello OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The interval between EGP Hello command
+ retransmissions (in hundredths of a second). This
+ represents the t1 timer as defined in RFC 904."
+ ::= { egpNeighEntry 12 }
+
+ egpNeighIntervalPoll OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The interval between EGP poll command
+
+
+
+
+
+ retransmissions (in hundredths of a second). This
+ represents the t3 timer as defined in RFC 904."
+ ::= { egpNeighEntry 13 }
+
+ egpNeighMode OBJECT-TYPE
+ SYNTAX INTEGER { active(1), passive(2) }
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The polling mode of this EGP entity, either
+ passive or active."
+ ::= { egpNeighEntry 14 }
+
+ egpNeighEventTrigger OBJECT-TYPE
+ SYNTAX INTEGER { start(1), stop(2) }
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "A control variable used to trigger operator-
+ initiated Start and Stop events. When read, this
+ variable always returns the most recent value that
+ egpNeighEventTrigger was set to. If it has not
+ been set since the last initialization of the
+ network management subsystem on the node, it
+ returns a value of `stop'.
+
+ When set, this variable causes a Start or Stop
+ event on the specified neighbor, as specified on
+ pages 8-10 of RFC 904. Briefly, a Start event
+ causes an Idle peer to begin neighbor acquisition
+ and a non-Idle peer to reinitiate neighbor
+ acquisition. A stop event causes a non-Idle peer
+ to return to the Idle state until a Start event
+ occurs, either via egpNeighEventTrigger or
+ otherwise."
+ ::= { egpNeighEntry 15 }
+
+
+ -- additional EGP objects
+
+ egpAs OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The autonomous system number of this EGP entity."
+ ::= { egp 6 }
+
+
+
+
+
+
+ -- the Transmission group
+
+ -- Based on the transmission media underlying each interface
+ -- on a system, the corresponding portion of the Transmission
+ -- group is mandatory for that system.
+
+ -- When Internet-standard definitions for managing
+ -- transmission media are defined, the transmission group is
+ -- used to provide a prefix for the names of those objects.
+
+ -- Typically, such definitions reside in the experimental
+ -- portion of the MIB until they are "proven", then as a
+ -- part of the Internet standardization process, the
+ -- definitions are accordingly elevated and a new object
+ -- identifier, under the transmission group is defined. By
+ -- convention, the name assigned is:
+ --
+ -- type OBJECT IDENTIFIER ::= { transmission number }
+ --
+ -- where "type" is the symbolic value used for the media in
+ -- the ifType column of the ifTable object, and "number" is
+ -- the actual integer value corresponding to the symbol.
+
+
+ -- the SNMP group
+
+ -- Implementation of the SNMP group is mandatory for all
+ -- systems which support an SNMP protocol entity. Some of
+ -- the objects defined below will be zero-valued in those
+ -- SNMP implementations that are optimized to support only
+ -- those functions specific to either a management agent or
+ -- a management station. In particular, it should be
+ -- observed that the objects below refer to an SNMP entity,
+ -- and there may be several SNMP entities residing on a
+ -- managed node (e.g., if the node is hosting acting as
+ -- a management station).
+
+ snmpInPkts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of Messages delivered to the
+ SNMP entity from the transport service."
+ ::= { snmp 1 }
+
+ snmpOutPkts OBJECT-TYPE
+ SYNTAX Counter
+
+
+
+
+
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Messages which were
+ passed from the SNMP protocol entity to the
+ transport service."
+ ::= { snmp 2 }
+
+ snmpInBadVersions OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Messages which were
+ delivered to the SNMP protocol entity and were for
+ an unsupported SNMP version."
+ ::= { snmp 3 }
+
+ snmpInBadCommunityNames OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Messages delivered to
+ the SNMP protocol entity which used a SNMP
+ community name not known to said entity."
+ ::= { snmp 4 }
+
+ snmpInBadCommunityUses OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Messages delivered to
+ the SNMP protocol entity which represented an SNMP
+ operation which was not allowed by the SNMP
+ community named in the Message."
+ ::= { snmp 5 }
+
+ snmpInASNParseErrs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of ASN.1 or BER errors
+ encountered by the SNMP protocol entity when
+ decoding received SNMP Messages."
+ ::= { snmp 6 }
+
+
+
+
+
+ -- { snmp 7 } is not used
+
+ snmpInTooBigs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP PDUs which were
+ delivered to the SNMP protocol entity and for
+ which the value of the error-status field is
+ `tooBig'."
+ ::= { snmp 8 }
+
+ snmpInNoSuchNames OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP PDUs which were
+ delivered to the SNMP protocol entity and for
+ which the value of the error-status field is
+ `noSuchName'."
+ ::= { snmp 9 }
+
+ snmpInBadValues OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP PDUs which were
+ delivered to the SNMP protocol entity and for
+ which the value of the error-status field is
+ `badValue'."
+ ::= { snmp 10 }
+
+ snmpInReadOnlys OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number valid SNMP PDUs which were
+ delivered to the SNMP protocol entity and for
+ which the value of the error-status field is
+ `readOnly'. It should be noted that it is a
+ protocol error to generate an SNMP PDU which
+ contains the value `readOnly' in the error-status
+ field, as such this object is provided as a means
+ of detecting incorrect implementations of the
+
+
+
+
+
+ SNMP."
+ ::= { snmp 11 }
+
+ snmpInGenErrs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP PDUs which were
+ delivered to the SNMP protocol entity and for
+ which the value of the error-status field is
+ `genErr'."
+ ::= { snmp 12 }
+
+ snmpInTotalReqVars OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of MIB objects which have been
+ retrieved successfully by the SNMP protocol entity
+ as the result of receiving valid SNMP Get-Request
+ and Get-Next PDUs."
+ ::= { snmp 13 }
+
+ snmpInTotalSetVars OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of MIB objects which have been
+ altered successfully by the SNMP protocol entity
+ as the result of receiving valid SNMP Set-Request
+ PDUs."
+ ::= { snmp 14 }
+
+ snmpInGetRequests OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Get-Request PDUs which
+ have been accepted and processed by the SNMP
+ protocol entity."
+ ::= { snmp 15 }
+
+ snmpInGetNexts OBJECT-TYPE
+ SYNTAX Counter
+
+
+
+
+
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Get-Next PDUs which have
+ been accepted and processed by the SNMP protocol
+ entity."
+ ::= { snmp 16 }
+
+ snmpInSetRequests OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Set-Request PDUs which
+ have been accepted and processed by the SNMP
+ protocol entity."
+ ::= { snmp 17 }
+
+ snmpInGetResponses OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Get-Response PDUs which
+ have been accepted and processed by the SNMP
+ protocol entity."
+ ::= { snmp 18 }
+
+ snmpInTraps OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Trap PDUs which have
+ been accepted and processed by the SNMP protocol
+ entity."
+ ::= { snmp 19 }
+
+ snmpOutTooBigs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP PDUs which were
+ generated by the SNMP protocol entity and for
+ which the value of the error-status field is
+ `tooBig.'"
+ ::= { snmp 20 }
+
+
+
+
+
+ snmpOutNoSuchNames OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP PDUs which were
+ generated by the SNMP protocol entity and for
+ which the value of the error-status is
+ `noSuchName'."
+ ::= { snmp 21 }
+
+ snmpOutBadValues OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP PDUs which were
+ generated by the SNMP protocol entity and for
+ which the value of the error-status field is
+ `badValue'."
+ ::= { snmp 22 }
+
+ -- { snmp 23 } is not used
+
+ snmpOutGenErrs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP PDUs which were
+ generated by the SNMP protocol entity and for
+ which the value of the error-status field is
+ `genErr'."
+ ::= { snmp 24 }
+
+ snmpOutGetRequests OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Get-Request PDUs which
+ have been generated by the SNMP protocol entity."
+ ::= { snmp 25 }
+
+ snmpOutGetNexts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+
+
+
+
+
+ DESCRIPTION
+ "The total number of SNMP Get-Next PDUs which have
+ been generated by the SNMP protocol entity."
+ ::= { snmp 26 }
+
+ snmpOutSetRequests OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Set-Request PDUs which
+ have been generated by the SNMP protocol entity."
+ ::= { snmp 27 }
+
+ snmpOutGetResponses OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Get-Response PDUs which
+ have been generated by the SNMP protocol entity."
+ ::= { snmp 28 }
+
+ snmpOutTraps OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Trap PDUs which have
+ been generated by the SNMP protocol entity."
+ ::= { snmp 29 }
+
+ snmpEnableAuthenTraps OBJECT-TYPE
+ SYNTAX INTEGER { enabled(1), disabled(2) }
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "Indicates whether the SNMP agent process is
+ permitted to generate authentication-failure
+ traps. The value of this object overrides any
+ configuration information; as such, it provides a
+ means whereby all authentication-failure traps may
+ be disabled.
+
+ Note that it is strongly recommended that this
+ object be stored in non-volatile memory so that it
+ remains constant between re-initializations of the
+ network management system."
+
+
+
+
+
+ ::= { snmp 30 }
+
+ END
+
diff --git a/lib/snmp/test/test-mibs/RFC1271-MIB.mib b/lib/snmp/test/test-mibs/RFC1271-MIB.mib
new file mode 100644
index 0000000000..25778dede8
--- /dev/null
+++ b/lib/snmp/test/test-mibs/RFC1271-MIB.mib
@@ -0,0 +1,3492 @@
+ RFC1271-MIB DEFINITIONS ::= BEGIN
+
+ IMPORTS
+ Counter FROM RFC1155-SMI
+ mib-2,DisplayString FROM RFC1213-MIB
+ OBJECT-TYPE FROM RFC-1212;
+
+ -- This MIB module uses the extended OBJECT-TYPE macro as
+ -- defined in [9].
+
+
+ -- Remote Network Monitoring MIB
+
+ rmon OBJECT IDENTIFIER ::= { mib-2 16 }
+
+
+ -- textual conventions
+
+ OwnerString ::= DisplayString
+ -- This data type is used to model an administratively
+ -- assigned name of the owner of a resource. This
+ -- information is taken from the NVT ASCII character set.
+ -- It is suggested that this name contain one or more
+ -- of the following:
+ -- IP address, management station name, network manager's
+ -- name, location, or phone number.
+ -- In some cases the agent itself will be the owner of
+ -- an entry. In these cases, this string shall be set
+ -- to a string starting with 'monitor'.
+
+
+ --
+ -- SNMP access control is articulated entirely in terms of
+ -- the contents of MIB views; access to a particular SNMP
+ -- object instance depends only upon its presence or
+ -- absence in a particular MIB view and never upon its
+ -- value or the value of related object instances. Thus,
+ -- objects of this type afford resolution of resource
+ -- contention only among cooperating managers; they
+ -- realize no access control function with respect
+ -- to uncooperative parties.
+ --
+ -- By convention, objects with this syntax are declared
+ -- as having
+ --
+ -- SIZE (0..127)
+
+
+ EntryStatus ::= INTEGER
+ { valid(1),
+ createRequest(2),
+ underCreation(3),
+ invalid(4)
+ }
+
+ -- The status of a table entry.
+ --
+ -- Setting this object to the value invalid(4) has the
+ -- effect of invalidating the corresponding entry.
+ -- That is, it effectively disassociates the mapping
+ -- identified with said entry.
+ -- It is an implementation-specific matter as to whether
+ -- the agent removes an invalidated entry from the table.
+ -- Accordingly, management stations must be prepared to
+ -- receive tabular information from agents that corresponds
+ -- to entries currently not in use. Proper
+ -- interpretation of such entries requires examination
+ -- of the relevant EntryStatus object.
+ --
+ -- An existing instance of this object cannot be set to
+ -- createRequest(2). This object may only be set to
+ -- createRequest(2) when this instance is created. When
+ -- this object is created, the agent may wish to create
+ -- supplemental object instances to complete a conceptual
+ -- row in this table. Immediately after completing the
+ -- create operation, the agent must set this object to
+ -- underCreation(3).
+ --
+ -- Entries shall exist in the underCreation(3) state until
+
+
+ -- the management station is finished configuring the
+ -- entry and sets this object to valid(1) or aborts,
+ -- setting this object to invalid(4). If the agent
+ -- determines that an entry has been in the
+ -- underCreation(3) state for an abnormally long time,
+ -- it may decide that the management station has
+ -- crashed. If the agent makes this decision,
+ -- it may set this object to invalid(4) to reclaim the
+ -- entry. A prudent agent will understand that the
+ -- management station may need to wait for human input
+ -- and will allow for that possibility in its
+ -- determination of this abnormally long period.
+
+
+ statistics OBJECT IDENTIFIER ::= { rmon 1 }
+ history OBJECT IDENTIFIER ::= { rmon 2 }
+ alarm OBJECT IDENTIFIER ::= { rmon 3 }
+ hosts OBJECT IDENTIFIER ::= { rmon 4 }
+ hostTopN OBJECT IDENTIFIER ::= { rmon 5 }
+ matrix OBJECT IDENTIFIER ::= { rmon 6 }
+ filter OBJECT IDENTIFIER ::= { rmon 7 }
+ capture OBJECT IDENTIFIER ::= { rmon 8 }
+ event OBJECT IDENTIFIER ::= { rmon 9 }
+
+
+ -- The Statistics Group
+ --
+ -- Implementation of the Statistics group is optional.
+ --
+ -- The statistics group contains statistics measured by the
+ -- probe for each monitored interface on this device. These
+ -- statistics take the form of free running counters that
+ -- start from zero when a valid entry is created.
+ --
+ -- This group currently has statistics defined only for
+ -- Ethernet interfaces. Each etherStatsEntry contains
+ -- statistics for one Ethernet interface. The probe must
+ -- create one etherStats entry for each monitored Ethernet
+ -- interface on the device.
+
+ etherStatsTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF EtherStatsEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A list of Ethernet statistics entries."
+ ::= { statistics 1 }
+
+
+
+ etherStatsEntry OBJECT-TYPE
+ SYNTAX EtherStatsEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A collection of statistics kept for a particular
+ Ethernet interface."
+ INDEX { etherStatsIndex }
+ ::= { etherStatsTable 1 }
+
+ EtherStatsEntry ::= SEQUENCE {
+ etherStatsIndex INTEGER (1..65535),
+ etherStatsDataSource OBJECT IDENTIFIER,
+ etherStatsDropEvents Counter,
+ etherStatsOctets Counter,
+ etherStatsPkts Counter,
+ etherStatsBroadcastPkts Counter,
+ etherStatsMulticastPkts Counter,
+ etherStatsCRCAlignErrors Counter,
+ etherStatsUndersizePkts Counter,
+ etherStatsOversizePkts Counter,
+ etherStatsFragments Counter,
+ etherStatsJabbers Counter,
+ etherStatsCollisions Counter,
+ etherStatsPkts64Octets Counter,
+ etherStatsPkts65to127Octets Counter,
+ etherStatsPkts128to255Octets Counter,
+ etherStatsPkts256to511Octets Counter,
+ etherStatsPkts512to1023Octets Counter,
+ etherStatsPkts1024to1518Octets Counter,
+ etherStatsOwner OwnerString,
+ etherStatsStatus INTEGER
+ }
+
+ etherStatsIndex OBJECT-TYPE
+ SYNTAX INTEGER (1..65535)
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The value of this object uniquely identifies this
+ etherStats entry."
+ ::= { etherStatsEntry 1 }
+
+ etherStatsDataSource OBJECT-TYPE
+ SYNTAX OBJECT IDENTIFIER
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+
+
+ "This object identifies the source of the data that
+ this etherStats entry is configured to analyze. This
+ source can be any ethernet interface on this device.
+ In order to identify a particular interface, this
+ object shall identify the instance of the ifIndex
+ object, defined in [4,6], for the desired interface.
+ For example, if an entry were to receive data from
+ interface #1, this object would be set to ifIndex.1.
+
+ The statistics in this group reflect all packets
+ on the local network segment attached to the
+ identified interface.
+
+ This object may not be modified if the associated
+ etherStatsStatus object is equal to valid(1)."
+ ::= { etherStatsEntry 2 }
+
+ etherStatsDropEvents OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of events in which packets
+ were dropped by the probe due to lack of resources.
+ Note that this number is not necessarily the number of
+ packets dropped; it is just the number of times this
+ condition has been detected."
+ ::= { etherStatsEntry 3 }
+
+ etherStatsOctets OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of octets of data (including
+ those in bad packets) received on the
+ network (excluding framing bits but including
+ FCS octets)."
+ ::= { etherStatsEntry 4 }
+
+ etherStatsPkts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of packets (including error packets)
+ received."
+ ::= { etherStatsEntry 5 }
+
+
+ etherStatsBroadcastPkts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of good packets received that were
+ directed to the broadcast address."
+ ::= { etherStatsEntry 6 }
+
+ etherStatsMulticastPkts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of good packets received that were
+ directed to a multicast address. Note that this
+ number does not include packets directed to the
+ broadcast address."
+ ::= { etherStatsEntry 7 }
+
+ etherStatsCRCAlignErrors OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of packets received that
+ had a length (excluding framing bits, but
+ including FCS octets) of between 64 and 1518
+ octets, inclusive, but were not an integral number
+ of octets in length or had a bad Frame Check
+ Sequence (FCS)."
+ ::= { etherStatsEntry 8 }
+
+ etherStatsUndersizePkts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of packets received that were
+ less than 64 octets long (excluding framing bits,
+ but including FCS octets) and were otherwise well
+ formed."
+ ::= { etherStatsEntry 9 }
+
+ etherStatsOversizePkts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+
+
+ DESCRIPTION
+ "The total number of packets received that were
+ longer than 1518 octets (excluding framing bits,
+ but including FCS octets) and were otherwise
+ well formed."
+ ::= { etherStatsEntry 10 }
+
+ etherStatsFragments OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of packets received that were not an
+ integral number of octets in length or that had a bad
+ Frame Check Sequence (FCS), and were less than 64
+ octets in length (excluding framing bits but
+ including FCS octets)."
+ ::= { etherStatsEntry 11 }
+
+ etherStatsJabbers OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of packets received that were
+ longer than 1518 octets (excluding framing bits,
+ but including FCS octets), and were not an
+ integral number of octets in length or had
+ a bad Frame Check Sequence (FCS)."
+ ::= { etherStatsEntry 12 }
+
+ etherStatsCollisions OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The best estimate of the total number of collisions
+ on this Ethernet segment."
+ ::= { etherStatsEntry 13 }
+
+ etherStatsPkts64Octets OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of packets (including error
+ packets) received that were 64 octets in length
+ (excluding framing bits but including FCS octets)."
+
+
+ ::= { etherStatsEntry 14 }
+
+ etherStatsPkts65to127Octets OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of packets (including error
+ packets) received that were between
+ 65 and 127 octets in length inclusive
+ (excluding framing bits but including FCS octets)."
+ ::= { etherStatsEntry 15 }
+
+ etherStatsPkts128to255Octets OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of packets (including error
+ packets) received that were between
+ 128 and 255 octets in length inclusive
+ (excluding framing bits but including FCS octets)."
+ ::= { etherStatsEntry 16 }
+
+ etherStatsPkts256to511Octets OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of packets (including error
+ packets) received that were between
+ 256 and 511 octets in length inclusive
+ (excluding framing bits but including FCS octets)."
+ ::= { etherStatsEntry 17 }
+
+ etherStatsPkts512to1023Octets OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of packets (including error
+ packets) received that were between
+ 512 and 1023 octets in length inclusive
+ (excluding framing bits but including FCS octets)."
+ ::= { etherStatsEntry 18 }
+
+
+
+
+
+ etherStatsPkts1024to1518Octets OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of packets (including error
+ packets) received that were between
+ 1024 and 1518 octets in length inclusive
+ (excluding framing bits but including FCS octets)."
+ ::= { etherStatsEntry 19 }
+
+ etherStatsOwner OBJECT-TYPE
+ SYNTAX OwnerString
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The entity that configured this entry and is
+ therefore using the resources assigned to it."
+ ::= { etherStatsEntry 20 }
+
+ etherStatsStatus OBJECT-TYPE
+ SYNTAX EntryStatus
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The status of this etherStats entry."
+ ::= { etherStatsEntry 21 }
+
+
+ -- The History Group
+
+ -- Implementation of the History group is optional.
+ --
+ -- The history group records periodic statistical samples from
+ -- a network and stores them for later retrieval. The
+ -- historyControl table stores configuration entries that each
+ -- define an interface, polling period, and other parameters.
+ -- Once samples are taken, their data is stored in an entry
+ -- in a media-specific table. Each such entry defines one
+ -- sample, and is associated with the historyControlEntry that
+ -- caused the sample to be taken. Currently the only media-
+ -- specific table defined is the etherHistoryTable, for
+ -- Ethernet networks.
+ --
+ -- If the probe keeps track of the time of day, it should
+ -- start the first sample of the history at a time such that
+ -- when the next hour of the day begins, a sample is
+ -- started at that instant. This tends to make more
+
+
+ -- user-friendly reports, and enables comparison of reports
+ -- from different probes that have relatively accurate time
+ -- of day.
+ --
+ -- The monitor is encouraged to add two history control entries
+ -- per monitored interface upon initialization that describe
+ -- a short term and a long term polling period. Suggested
+ -- parameters are 30 seconds for the short term polling
+ -- period and 30 minutes for the long term period.
+
+ historyControlTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF HistoryControlEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A list of history control entries."
+ ::= { history 1 }
+
+ historyControlEntry OBJECT-TYPE
+ SYNTAX HistoryControlEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A list of parameters that set up a periodic
+ sampling of statistics."
+ INDEX { historyControlIndex }
+ ::= { historyControlTable 1 }
+
+ HistoryControlEntry ::= SEQUENCE {
+ historyControlIndex INTEGER (1..65535),
+ historyControlDataSource OBJECT IDENTIFIER,
+ historyControlBucketsRequested INTEGER (1..65535),
+ historyControlBucketsGranted INTEGER (1..65535),
+ historyControlInterval INTEGER (1..3600),
+ historyControlOwner OwnerString,
+ historyControlStatus INTEGER
+ }
+
+ historyControlIndex OBJECT-TYPE
+ SYNTAX INTEGER (1..65535)
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "An index that uniquely identifies an entry in the
+ historyControl table. Each such entry defines a
+ set of samples at a particular interval for an
+ interface on the device."
+ ::= { historyControlEntry 1 }
+
+
+ historyControlDataSource OBJECT-TYPE
+ SYNTAX OBJECT IDENTIFIER
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "This object identifies the source of the data for
+ which historical data was collected and
+ placed in a media-specific table on behalf of this
+ historyControlEntry. This source can be any
+ interface on this device. In order to identify
+ a particular interface, this object shall identify
+ the instance of the ifIndex object, defined
+ in [4,6], for the desired interface. For example,
+ if an entry were to receive data from interface #1,
+ this object would be set to ifIndex.1.
+
+ The statistics in this group reflect all packets
+ on the local network segment attached to the
+ identified interface.
+
+ This object may not be modified if the associated
+ historyControlStatus object is equal to valid(1)."
+ ::= { historyControlEntry 2 }
+
+ historyControlBucketsRequested OBJECT-TYPE
+ SYNTAX INTEGER (1..65535)
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The requested number of discrete time intervals
+ over which data is to be saved in the part of the
+ media-specific table associated with this
+ historyControl entry.
+
+ When this object is created or modified, the probe
+ should set historyControlBucketsGranted as closely to
+ this object as is possible for the particular probe
+ implementation and available resources."
+ DEFVAL { 50 }
+ ::= { historyControlEntry 3 }
+
+ historyControlBucketsGranted OBJECT-TYPE
+ SYNTAX INTEGER (1..65535)
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of discrete sampling intervals
+ over which data shall be saved in the part of
+
+
+ the media-specific table associated with this
+ historyControl entry.
+
+ When the associated historyControlBucketsRequested
+ object is created or modified, the probe
+ should set this object as closely to the requested
+ value as is possible for the particular
+ probe implementation and available resources. The
+ probe must not lower this value except as a result
+ of a modification to the associated
+ historyControlBucketsRequested object.
+
+ There will be times when the actual number of
+ buckets associated with this entry is less than
+ the value of this object. In this case, at the
+ end of each sampling interval, a new bucket will
+ be added to the media-specific table.
+
+ When the number of buckets reaches the value of
+ this object and a new bucket is to be added to the
+ media-specific table, the oldest bucket associated
+ with this historyControlEntry shall be deleted by
+ the agent so that the new bucket can be added.
+
+ When the value of this object changes to a value less
+ than the current value, entries are deleted
+ from the media-specific table associated with this
+ historyControlEntry. Enough of the oldest of these
+ entries shall be deleted by the agent so that their
+ number remains less than or equal to the new value of
+ this object.
+
+ When the value of this object changes to a value
+ greater than the current value, the number of
+ associated media-specific entries may be allowed
+ to grow."
+ ::= { historyControlEntry 4 }
+
+ historyControlInterval OBJECT-TYPE
+ SYNTAX INTEGER (1..3600)
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The interval in seconds over which the data is
+ sampled for each bucket in the part of the
+ media-specific table associated with this
+ historyControl entry. This interval can
+ be set to any number of seconds between 1 and
+
+
+ 3600 (1 hour).
+
+ Because the counters in a bucket may overflow at their
+ maximum value with no indication, a prudent manager
+ will take into account the possibility of overflow
+ in any of the associated counters. It is important
+ to consider the minimum time in which any counter
+ could overflow on a particular media type and set
+ the historyControlInterval object to a value less
+ than this interval. This is typically most
+ important for the 'octets' counter in any
+ media-specific table. For example, on an Ethernet
+ network, the etherHistoryOctets counter could overflow
+ in about one hour at the Ethernet's maximum
+ utilization.
+
+ This object may not be modified if the associated
+ historyControlStatus object is equal to valid(1)."
+ DEFVAL { 1800 }
+ ::= { historyControlEntry 5 }
+
+ historyControlOwner OBJECT-TYPE
+ SYNTAX OwnerString
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The entity that configured this entry and is therefore
+ using the resources assigned to it."
+ ::= { historyControlEntry 6 }
+
+ historyControlStatus OBJECT-TYPE
+ SYNTAX EntryStatus
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The status of this historyControl entry.
+
+ Each instance of the media-specific table associated
+ with this historyControlEntry will be deleted by the
+ agent if this historyControlEntry is not equal to
+ valid(1)."
+ ::= { historyControlEntry 7 }
+
+
+ -- Ether History table
+
+ etherHistoryTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF EtherHistoryEntry
+
+
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A list of Ethernet history entries."
+ ::= { history 2 }
+
+ etherHistoryEntry OBJECT-TYPE
+ SYNTAX EtherHistoryEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "An historical sample of Ethernet statistics on a
+ particular Ethernet interface. This sample is
+ associated with the historyControlEntry which set
+ up the parameters for a regular collection of these
+ samples."
+ INDEX { etherHistoryIndex , etherHistorySampleIndex }
+ ::= { etherHistoryTable 1 }
+
+ EtherHistoryEntry ::= SEQUENCE {
+ etherHistoryIndex INTEGER (1..65535),
+ etherHistorySampleIndex INTEGER,
+ etherHistoryIntervalStart TimeTicks,
+ etherHistoryDropEvents Counter,
+ etherHistoryOctets Counter,
+ etherHistoryPkts Counter,
+ etherHistoryBroadcastPkts Counter,
+ etherHistoryMulticastPkts Counter,
+ etherHistoryCRCAlignErrors Counter,
+ etherHistoryUndersizePkts Counter,
+ etherHistoryOversizePkts Counter,
+ etherHistoryFragments Counter,
+ etherHistoryJabbers Counter,
+ etherHistoryCollisions Counter,
+ etherHistoryUtilization INTEGER (0..10000)
+ }
+
+ etherHistoryIndex OBJECT-TYPE
+ SYNTAX INTEGER (1..65535)
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The history of which this entry is a part. The
+ history identified by a particular value of this
+ index is the same history as identified
+ by the same value of historyControlIndex."
+ ::= { etherHistoryEntry 1 }
+
+
+
+ etherHistorySampleIndex OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "An index that uniquely identifies the particular
+ sample this entry represents among all samples
+ associated with the same historyControlEntry.
+ This index starts at 1 and increases by one
+ as each new sample is taken."
+ ::= { etherHistoryEntry 2 }
+
+ etherHistoryIntervalStart OBJECT-TYPE
+ SYNTAX TimeTicks
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The value of sysUpTime at the start of the interval
+ over which this sample was measured. If the probe
+ keeps track of the time of day, it should start
+ the first sample of the history at a time such that
+ when the next hour of the day begins, a sample is
+ started at that instant. Note that following this
+ rule may require the probe to delay collecting the
+ first sample of the history, as each sample must be
+ of the same interval. Also note that the sample which
+ is currently being collected is not accessible in this
+ table until the end of its interval."
+ ::= { etherHistoryEntry 3 }
+
+ etherHistoryDropEvents OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of events in which packets
+ were dropped by the probe due to lack of resources
+ during this interval. Note that this number is not
+ necessarily the number of packets dropped, it is just
+ the number of times this condition has been detected."
+ ::= { etherHistoryEntry 4 }
+
+ etherHistoryOctets OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of octets of data (including
+
+
+ those in bad packets) received on the
+ network (excluding framing bits but including
+ FCS octets)."
+ ::= { etherHistoryEntry 5 }
+
+ etherHistoryPkts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of packets (including error packets)
+ received during this sampling interval."
+ ::= { etherHistoryEntry 6 }
+
+ etherHistoryBroadcastPkts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of good packets received during this
+ sampling interval that were directed to the
+ broadcast address."
+ ::= { etherHistoryEntry 7 }
+
+ etherHistoryMulticastPkts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of good packets received during this
+ sampling interval that were directed to a
+ multicast address. Note that this number does not
+ include packets addressed to the broadcast address."
+ ::= { etherHistoryEntry 8 }
+
+ etherHistoryCRCAlignErrors OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of packets received during this
+ sampling interval that had a length (excluding
+ framing bits but including FCS octets) between
+ 64 and 1518 octets, inclusive, but were not an
+ integral number of octets in length or had a
+ bad Frame Check Sequence (FCS)."
+ ::= { etherHistoryEntry 9 }
+
+
+
+ etherHistoryUndersizePkts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of packets received during this
+ interval that were less than 64 octets long
+ (excluding framing bits but including FCS
+ octets) and were otherwise well formed."
+ ::= { etherHistoryEntry 10 }
+
+ etherHistoryOversizePkts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of packets received during this
+ interval that were longer than 1518 octets
+ (excluding framing bits but including FCS
+ octets) but were otherwise well formed."
+ ::= { etherHistoryEntry 11 }
+
+ etherHistoryFragments OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of packets received during this
+ sampling interval that were not an integral
+ number of octets in length or that
+ had a bad Frame Check Sequence (FCS), and
+ were less than 64 octets in length (excluding
+ framing bits but including FCS octets)."
+ ::= { etherHistoryEntry 12 }
+
+ etherHistoryJabbers OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of packets received during this
+ interval that were longer than 1518 octets
+ (excluding framing bits but including FCS octets),
+ and were not an integral number of octets in
+ length or had a bad Frame Check Sequence (FCS)."
+ ::= { etherHistoryEntry 13 }
+
+
+
+
+ etherHistoryCollisions OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The best estimate of the total number of collisions
+ on this Ethernet segment during this interval."
+ ::= { etherHistoryEntry 14 }
+
+ etherHistoryUtilization OBJECT-TYPE
+ SYNTAX INTEGER (0..10000)
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The best estimate of the mean physical layer
+ network utilization on this interface during this
+ interval, in hundredths of a percent."
+ ::= { etherHistoryEntry 15 }
+
+
+ -- The Alarm Group
+
+ -- Implementation of the Alarm group is optional.
+ --
+ -- The Alarm Group requires the implementation of the Event
+ -- group.
+ --
+ -- The Alarm group periodically takes statistical samples from
+ -- variables in the probe and compares them to thresholds
+ -- that have been configured. The alarm table stores
+ -- configuration entries that each define a variable,
+ -- polling period, and threshold parameters. If a sample is
+ -- found to cross the threshold values, an event is
+ -- generated. Only variables that resolve to an ASN.1
+ -- primitive type of INTEGER (INTEGER, Counter,
+ -- Gauge, or TimeTicks) may be monitored in this way.
+ --
+ -- This function has a hysteresis mechanism to limit the
+ -- generation of events. This mechanism generates one event
+ -- as a threshold is crossed in the appropriate direction.
+ -- No more events are generated for that threshold until the
+ -- opposite threshold is crossed.
+ --
+ -- In the case of a sampling a deltaValue, a probe may
+ -- implement this mechanism with more precision if it takes
+ -- a delta sample twice per period, each time comparing the
+ -- sum of the latest two samples to the threshold. This
+ -- allows the detection of threshold crossings
+
+
+ -- that span the sampling boundary. Note that this does not
+ -- require any special configuration of the threshold value.
+ -- It is suggested that probes implement this more precise
+ -- algorithm.
+
+ alarmTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF AlarmEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A list of alarm entries."
+ ::= { alarm 1 }
+
+ alarmEntry OBJECT-TYPE
+ SYNTAX AlarmEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A list of parameters that set up a periodic checking
+ for alarm conditions."
+ INDEX { alarmIndex }
+ ::= { alarmTable 1 }
+
+ AlarmEntry ::= SEQUENCE {
+ alarmIndex INTEGER (1..65535),
+ alarmInterval INTEGER,
+ alarmVariable OBJECT IDENTIFIER,
+ alarmSampleType INTEGER,
+ alarmValue INTEGER,
+ alarmStartupAlarm INTEGER,
+ alarmRisingThreshold INTEGER,
+ alarmFallingThreshold INTEGER,
+ alarmRisingEventIndex INTEGER (1..65535),
+ alarmFallingEventIndex INTEGER (1..65535),
+ alarmOwner OwnerString,
+ alarmStatus INTEGER
+ }
+
+ alarmIndex OBJECT-TYPE
+ SYNTAX INTEGER (1..65535)
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "An index that uniquely identifies an entry in the
+ alarm table. Each such entry defines a
+ diagnostic sample at a particular interval
+ for an object on the device."
+ ::= { alarmEntry 1 }
+
+
+ alarmInterval OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The interval in seconds over which the data is
+ sampled and compared with the rising and falling
+ thresholds. When setting this variable, care
+ should be given to ensure that the variable being
+ monitored will not exceed 2^31 - 1 and roll
+ over the alarmValue object during the interval.
+
+ This object may not be modified if the associated
+ alarmStatus object is equal to valid(1)."
+ ::= { alarmEntry 2 }
+
+ alarmVariable OBJECT-TYPE
+ SYNTAX OBJECT IDENTIFIER
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The object identifier of the particular variable to
+ be sampled. Only variables that resolve to an ASN.1
+ primitive type of INTEGER (INTEGER, Counter, Gauge,
+ or TimeTicks) may be sampled.
+
+ Because SNMP access control is articulated entirely
+ in terms of the contents of MIB views, no access
+ control mechanism exists that can restrict the value of
+ this object to identify only those objects that exist
+ in a particular MIB view. Because there is thus no
+ acceptable means of restricting the read access that
+ could be obtained through the alarm mechanism, the
+ probe must only grant write access to this object in
+ those views that have read access to all objects on
+ the probe.
+
+ During a set operation, if the supplied variable
+ name is not available in the selected MIB view, a
+ badValue error must be returned. If at any time
+ the variable name of an established alarmEntry is
+ no longer available in the selected MIB view, the
+ probe must change the status of this alarmEntry
+ to invalid(4).
+
+ This object may not be modified if the associated
+ alarmStatus object is equal to valid(1)."
+ ::= { alarmEntry 3 }
+
+
+ alarmSampleType OBJECT-TYPE
+ SYNTAX INTEGER {
+ absoluteValue(1),
+ deltaValue(2)
+ }
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The method of sampling the selected variable and
+ calculating the value to be compared against the
+ thresholds. If the value of this object is
+ absoluteValue(1), the value of the selected variable
+ will be compared directly with the thresholds at the
+ end of the sampling interval. If the value of this
+ object is deltaValue(2), the value of the selected
+ variable at the last sample will be subtracted from
+ the current value, and the difference compared with
+ the thresholds.
+
+ This object may not be modified if the associated
+ alarmStatus object is equal to valid(1)."
+ ::= { alarmEntry 4 }
+
+ alarmValue OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The value of the statistic during the last sampling
+ period. The value during the current sampling period
+ is not made available until the period is completed."
+ ::= { alarmEntry 5 }
+
+ alarmStartupAlarm OBJECT-TYPE
+ SYNTAX INTEGER {
+ risingAlarm(1),
+ fallingAlarm(2),
+ risingOrFallingAlarm(3)
+ }
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The alarm that may be sent when this entry is first
+ set to valid. If the first sample after this entry
+ becomes valid is greater than or equal to the
+ risingThreshold and alarmStartupAlarm is equal to
+ risingAlarm(1) or risingOrFallingAlarm(3), then a
+ single rising alarm will be generated. If the first
+
+
+ sample after this entry becomes valid is less than
+ or equal to the fallingThreshold and
+ alarmStartupAlarm is equal to fallingAlarm(2) or
+ risingOrFallingAlarm(3), then a single falling
+ alarm will be generated.
+
+ This object may not be modified if the associated
+ alarmStatus object is equal to valid(1)."
+ ::= { alarmEntry 6 }
+
+ alarmRisingThreshold OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "A threshold for the sampled statistic. When the
+ current sampled value is greater than or equal to
+ this threshold, and the value at the last sampling
+ interval was less than this threshold, a single
+ event will be generated.
+ A single event will also be generated if the first
+ sample after this entry becomes valid is greater
+ than or equal to this threshold and the associated
+ alarmStartupAlarm is equal to risingAlarm(1) or
+ risingOrFallingAlarm(3).
+
+ After a rising event is generated, another such event
+ will not be generated until the sampled value
+ falls below this threshold and reaches the
+ alarmFallingThreshold.
+
+ This object may not be modified if the associated
+ alarmStatus object is equal to valid(1)."
+ ::= { alarmEntry 7 }
+
+ alarmFallingThreshold OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "A threshold for the sampled statistic. When the
+ current sampled value is less than or equal to
+ this threshold, and the value at the last sampling
+ interval was greater than this threshold, a single
+ event will be generated.
+ A single event will also be generated if the first
+ sample after this entry becomes valid is less than or
+ equal to this threshold and the associated
+
+
+ alarmStartupAlarm is equal to fallingAlarm(2) or
+ risingOrFallingAlarm(3).
+
+ After a falling event is generated, another such event
+ will not be generated until the sampled value
+ rises above this threshold and reaches the
+ alarmRisingThreshold.
+
+ This object may not be modified if the associated
+ alarmStatus object is equal to valid(1)."
+ ::= { alarmEntry 8 }
+
+ alarmRisingEventIndex OBJECT-TYPE
+ SYNTAX INTEGER (0..65535)
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The index of the eventEntry that is
+ used when a rising threshold is crossed. The
+ eventEntry identified by a particular value of
+ this index is the same as identified by the same value
+ of the eventIndex object. If there is no
+ corresponding entry in the eventTable, then
+ no association exists. In particular, if this value
+ is zero, no associated event will be generated, as
+ zero is not a valid event index.
+
+ This object may not be modified if the associated
+ alarmStatus object is equal to valid(1)."
+ ::= { alarmEntry 9 }
+
+ alarmFallingEventIndex OBJECT-TYPE
+ SYNTAX INTEGER (0..65535)
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The index of the eventEntry that is
+ used when a falling threshold is crossed. The
+ eventEntry identified by a particular value of
+ this index is the same as identified by the same value
+ of the eventIndex object. If there is no
+ corresponding entry in the eventTable, then
+ no association exists. In particular, if this value
+ is zero, no associated event will be generated, as
+ zero is not a valid event index.
+
+ This object may not be modified if the associated
+ alarmStatus object is equal to valid(1)."
+
+
+ ::= { alarmEntry 10 }
+
+ alarmOwner OBJECT-TYPE
+ SYNTAX OwnerString
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The entity that configured this entry and is
+ therefore using the resources assigned to it."
+ ::= { alarmEntry 11 }
+
+ alarmStatus OBJECT-TYPE
+ SYNTAX EntryStatus
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The status of this alarm entry."
+ ::= { alarmEntry 12 }
+
+
+ -- The Host Group
+
+ -- Implementation of the Host group is optional.
+ --
+ -- The host group discovers new hosts on the network by
+ -- keeping a list of source and destination MAC Addresses seen
+ -- in good packets. For each of these addresses, the host
+ -- group keeps a set of statistics. The hostControlTable
+ -- controls which interfaces this function is performed on,
+ -- and contains some information about the process. On
+ -- behalf of each hostControlEntry, data is collected on an
+ -- interface and placed both the hostTable and the
+ -- hostTimeTable. If the monitoring device finds itself
+ -- short of resources, it may delete entries as needed. It
+ -- is suggested that the device delete the least recently
+ -- used entries first.
+
+ -- The hostTable contains entries for each address
+ -- discovered on a particular interface. Each entry
+ -- contains statistical data about that host. This table
+ -- is indexed by the MAC address of the host, through
+ -- which a random access may be achieved.
+
+ -- The hostTimeTable contains data in the same format as the
+ -- hostTable, and must contain the same set of hosts, but is
+ -- indexed using hostTimeCreationOrder rather than hostAddress.
+ -- The hostTimeCreationOrder is an integer which reflects
+ -- the relative order in which a particular entry was
+
+
+ -- discovered and thus inserted into the table. As this
+ -- order, and thus index, is among those entries currently
+ -- in the table, the index for a particular entry may change
+ -- if an (earlier) entry is deleted. Thus the association
+ -- between hostTimeCreationOrder and hostTimeEntry may be
+ -- broken at any time.
+
+ -- The hostTimeTable has two important uses. The first is the
+ -- fast download of this potentially large table. Because the
+ -- index of this table runs from 1 to the size of the table,
+ -- inclusive, its values are predictable. This allows very
+ -- efficient packing of variables into SNMP PDU's and allows
+ -- a table transfer to have multiple packets outstanding.
+ -- These benefits increase transfer rates tremendously.
+
+ -- The second use of the hostTimeTable is the efficient
+ -- discovery by the management station of new entries added
+ -- to the table. After the management station has
+ -- downloaded the entire table, it knows that new entries
+ -- will be added immediately after the end of the current
+ -- table. It can thus detect new entries there
+ -- and retrieve them easily.
+
+ -- Because the association between hostTimeCreationOrder and
+ -- hostTimeEntry may be broken at any time, the management
+ -- station must monitor the related hostControlLastDeleteTime
+ -- object. When the management station thus detects a deletion,
+ -- it must assume that any such associations have been broken,
+ -- and invalidate any it has stored locally. This includes
+ -- restarting any download of the hostTimeTable that may have
+ -- been in progress, as well as rediscovering the end of the
+ -- hostTimeTable so that it may detect new entries. If the
+ -- management station does not detect the broken association,
+ -- it may continue to refer to a particular host by its
+ -- creationOrder while unwittingly retrieving the data
+ -- associated with another host entirely. If this happens
+ -- while downloading the host table, the management station
+ -- may fail to download all of the entries in the table.
+
+
+ hostControlTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF HostControlEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A list of host table control entries."
+ ::= { hosts 1 }
+
+
+
+ hostControlEntry OBJECT-TYPE
+ SYNTAX HostControlEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A list of parameters that set up the discovery of
+ hosts on a particular interface and the collection
+ of statistics about these hosts."
+ INDEX { hostControlIndex }
+ ::= { hostControlTable 1 }
+
+ HostControlEntry ::= SEQUENCE {
+ hostControlIndex INTEGER (1..65535),
+ hostControlDataSource OBJECT IDENTIFIER,
+ hostControlTableSize INTEGER,
+ hostControlLastDeleteTime TimeTicks,
+ hostControlOwner OwnerString,
+ hostControlStatus INTEGER
+ }
+
+ hostControlIndex OBJECT-TYPE
+ SYNTAX INTEGER (1..65535)
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "An index that uniquely identifies an entry in the
+ hostControl table. Each such entry defines
+ a function that discovers hosts on a particular
+ interface and places statistics about them in the
+ hostTable and the hostTimeTable on behalf of this
+ hostControlEntry."
+ ::= { hostControlEntry 1 }
+
+ hostControlDataSource OBJECT-TYPE
+ SYNTAX OBJECT IDENTIFIER
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "This object identifies the source of the data for
+ this instance of the host function. This source
+ can be any interface on this device. In order
+ to identify a particular interface, this object shall
+ identify the instance of the ifIndex object, defined
+ in [4,6], for the desired interface. For example,
+ if an entry were to receive data from interface #1,
+ this object would be set to ifIndex.1.
+
+ The statistics in this group reflect all packets
+
+
+ on the local network segment attached to the
+ identified interface.
+
+ This object may not be modified if the associated
+ hostControlStatus object is equal to valid(1)."
+ ::= { hostControlEntry 2 }
+
+ hostControlTableSize OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of hostEntries in the hostTable and the
+ hostTimeTable associated with this hostControlEntry."
+ ::= { hostControlEntry 3 }
+
+ hostControlLastDeleteTime OBJECT-TYPE
+ SYNTAX TimeTicks
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The value of sysUpTime when the last entry
+ was deleted from the portion of the hostTable
+ associated with this hostControlEntry. If no
+ deletions have occurred, this value shall be zero."
+ ::= { hostControlEntry 4 }
+
+ hostControlOwner OBJECT-TYPE
+ SYNTAX OwnerString
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The entity that configured this entry and is
+ therefore using the resources assigned to it."
+ ::= { hostControlEntry 5 }
+
+ hostControlStatus OBJECT-TYPE
+ SYNTAX EntryStatus
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The status of this hostControl entry.
+
+ If this object is not equal to valid(1), all
+ associated entries in the hostTable,
+ hostTimeTable, and the hostTopNTable shall be
+ deleted by the agent."
+ ::= { hostControlEntry 6 }
+
+
+ hostTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF HostEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A list of host entries."
+ ::= { hosts 2 }
+
+ hostEntry OBJECT-TYPE
+ SYNTAX HostEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A collection of statistics for a particular host
+ that has been discovered on an interface of this
+ device."
+ INDEX { hostIndex, hostAddress }
+ ::= { hostTable 1 }
+
+ HostEntry ::= SEQUENCE {
+ hostAddress OCTET STRING,
+ hostCreationOrder INTEGER (1..65535),
+ hostIndex INTEGER (1..65535),
+ hostInPkts Counter,
+ hostOutPkts Counter,
+ hostInOctets Counter,
+ hostOutOctets Counter,
+ hostOutErrors Counter,
+ hostOutBroadcastPkts Counter,
+ hostOutMulticastPkts Counter
+ }
+
+ hostAddress OBJECT-TYPE
+ SYNTAX OCTET STRING
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The physical address of this host."
+ ::= { hostEntry 1 }
+
+ hostCreationOrder OBJECT-TYPE
+ SYNTAX INTEGER (1..65535)
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "An index that defines the relative ordering of
+ the creation time of hosts captured for a
+ particular hostControlEntry. This index shall
+
+
+ be between 1 and N, where N is the value of
+ the associated hostControlTableSize. The ordering
+ of the indexes is based on the order of each entry's
+ insertion into the table, in which entries added
+ earlier have a lower index value than entries added
+ later.
+
+ It is important to note that the order for a
+ particular entry may change as an (earlier) entry
+ is deleted from the table. Because this order may
+ change, management stations should make use of the
+ hostControlLastDeleteTime variable in the
+ hostControlEntry associated with the relevant
+ portion of the hostTable. By observing
+ this variable, the management station may detect
+ the circumstances where a previous association
+ between a value of hostCreationOrder
+ and a hostEntry may no longer hold."
+ ::= { hostEntry 2 }
+
+ hostIndex OBJECT-TYPE
+ SYNTAX INTEGER (1..65535)
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The set of collected host statistics of which
+ this entry is a part. The set of hosts
+ identified by a particular value of this
+ index is associated with the hostControlEntry
+ as identified by the same value of hostControlIndex."
+ ::= { hostEntry 3 }
+
+ hostInPkts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of packets without errors transmitted to
+ this address since it was added to the hostTable."
+ ::= { hostEntry 4 }
+
+ hostOutPkts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of packets including errors transmitted
+ by this address since it was added to the hostTable."
+
+
+ ::= { hostEntry 5 }
+
+ hostInOctets OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of octets transmitted to this address
+ since it was added to the hostTable (excluding
+ framing bits but including FCS octets), except for
+ those octets in packets that contained errors."
+ ::= { hostEntry 6 }
+
+ hostOutOctets OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of octets transmitted by this address
+ since it was added to the hostTable (excluding
+ framing bits but including FCS octets), including
+ those octets in packets that contained errors."
+ ::= { hostEntry 7 }
+
+ hostOutErrors OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of error packets transmitted by this
+ address since this host was added to the hostTable."
+ ::= { hostEntry 8 }
+
+ hostOutBroadcastPkts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of good packets transmitted by this
+ address that were directed to the broadcast address
+ since this host was added to the hostTable."
+ ::= { hostEntry 9 }
+
+ hostOutMulticastPkts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+
+
+ "The number of good packets transmitted by this
+ address that were directed to a multicast address
+ since this host was added to the hostTable.
+ Note that this number does not include packets
+ directed to the broadcast address."
+ ::= { hostEntry 10 }
+
+
+ -- host Time Table
+
+ hostTimeTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF HostTimeEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A list of time-ordered host table entries."
+ ::= { hosts 3 }
+
+ hostTimeEntry OBJECT-TYPE
+ SYNTAX HostTimeEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A collection of statistics for a particular host
+ that has been discovered on an interface of this
+ device. This collection includes the relative
+ ordering of the creation time of this object."
+ INDEX { hostTimeIndex, hostTimeCreationOrder }
+ ::= { hostTimeTable 1 }
+
+ HostTimeEntry ::= SEQUENCE {
+ hostTimeAddress OCTET STRING,
+ hostTimeCreationOrder INTEGER (1..65535),
+ hostTimeIndex INTEGER (1..65535),
+ hostTimeInPkts Counter,
+ hostTimeOutPkts Counter,
+ hostTimeInOctets Counter,
+ hostTimeOutOctets Counter,
+ hostTimeOutErrors Counter,
+ hostTimeOutBroadcastPkts Counter,
+ hostTimeOutMulticastPkts Counter
+ }
+
+ hostTimeAddress OBJECT-TYPE
+ SYNTAX OCTET STRING
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+
+
+ "The physical address of this host."
+ ::= { hostTimeEntry 1 }
+
+ hostTimeCreationOrder OBJECT-TYPE
+ SYNTAX INTEGER (1..65535)
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "An index that uniquely identifies an entry in
+ the hostTime table among those entries associated
+ with the same hostControlEntry. This index shall
+ be between 1 and N, where N is the value of
+ the associated hostControlTableSize. The ordering
+ of the indexes is based on the order of each entry's
+ insertion into the table, in which entries added
+ earlier have a lower index value than entries added
+ later. Thus the management station has the ability
+ to learn of new entries added to this table without
+ downloading the entire table.
+
+ It is important to note that the index for a
+ particular entry may change as an (earlier) entry
+ is deleted from the table. Because this order may
+ change, management stations should make use of the
+ hostControlLastDeleteTime variable in the
+ hostControlEntry associated with the relevant
+ portion of the hostTimeTable. By observing
+ this variable, the management station may detect
+ the circumstances where a download of the table
+ may have missed entries, and where a previous
+ association between a value of hostTimeCreationOrder
+ and a hostTimeEntry may no longer hold."
+ ::= { hostTimeEntry 2 }
+
+ hostTimeIndex OBJECT-TYPE
+ SYNTAX INTEGER (1..65535)
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The set of collected host statistics of which
+ this entry is a part. The set of hosts
+ identified by a particular value of this
+ index is associated with the hostControlEntry
+ as identified by the same value of hostControlIndex."
+ ::= { hostTimeEntry 3 }
+
+
+
+
+
+ hostTimeInPkts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of packets without errors transmitted to
+ this address since it was added to the hostTimeTable."
+ ::= { hostTimeEntry 4 }
+
+ hostTimeOutPkts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of packets including errors transmitted
+ by this address since it was added to the
+ hostTimeTable."
+ ::= { hostTimeEntry 5 }
+
+ hostTimeInOctets OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of octets transmitted to this address
+ since it was added to the hostTimeTable (excluding
+ framing bits but including FCS octets), except for
+ those octets in packets that contained errors."
+ ::= { hostTimeEntry 6 }
+
+ hostTimeOutOctets OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of octets transmitted by this address since
+ it was added to the hostTimeTable (excluding framing
+ bits but including FCS octets), including those
+ octets in packets that contained errors."
+ ::= { hostTimeEntry 7 }
+
+ hostTimeOutErrors OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of error packets transmitted by this
+ address since this host was added to the
+
+
+ hostTimeTable."
+ ::= { hostTimeEntry 8 }
+
+ hostTimeOutBroadcastPkts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of good packets transmitted by this
+ address that were directed to the broadcast address
+ since this host was added to the hostTimeTable."
+ ::= { hostTimeEntry 9 }
+
+ hostTimeOutMulticastPkts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of good packets transmitted by this
+ address that were directed to a multicast address
+ since this host was added to the hostTimeTable.
+ Note that this number does not include packets
+ directed to the broadcast address."
+ ::= { hostTimeEntry 10 }
+
+
+ -- The Host Top "N" Group
+
+ -- Implementation of the Host Top N group is optional.
+ --
+ -- The Host Top N group requires the implementation of the
+ -- host group.
+ --
+ -- The Host Top N group is used to prepare reports that
+ -- describe the hosts that top a list ordered by one of
+ -- their statistics. The available statistics are samples
+ -- of one of their base statistics, over an interval
+ -- specified by the management station. Thus, these
+ -- statistics are rate based. The management
+ -- station also selects how many such hosts are reported.
+
+ -- The hostTopNControlTable is used to initiate the generation
+ -- of such a report. The management station may select the
+ -- parameters of such a report, such as which interface,
+ -- which statistic, how many hosts, and the start and stop
+ -- times of the sampling. When the report is prepared,
+ -- entries are created in the hostTopNTable associated with
+ -- the relevant hostTopNControlEntry. These entries are
+
+
+ -- static for each report after it has been prepared.
+
+ hostTopNControlTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF HostTopNControlEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A list of top N host control entries."
+ ::= { hostTopN 1 }
+
+ hostTopNControlEntry OBJECT-TYPE
+ SYNTAX HostTopNControlEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A set of parameters that control the creation of a
+ report of the top N hosts according to several
+ metrics."
+ INDEX { hostTopNControlIndex }
+ ::= { hostTopNControlTable 1 }
+
+ HostTopNControlEntry ::= SEQUENCE {
+ hostTopNControlIndex INTEGER (1..65535),
+ hostTopNHostIndex INTEGER (1..65535),
+ hostTopNRateBase INTEGER,
+ hostTopNTimeRemaining INTEGER,
+ hostTopNDuration INTEGER,
+ hostTopNRequestedSize INTEGER,
+ hostTopNGrantedSize INTEGER,
+ hostTopNStartTime TimeTicks,
+ hostTopNOwner OwnerString,
+ hostTopNStatus INTEGER
+ }
+
+ hostTopNControlIndex OBJECT-TYPE
+ SYNTAX INTEGER (1..65535)
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "An index that uniquely identifies an entry
+ in the hostTopNControl table. Each such
+ entry defines one top N report prepared for
+ one interface."
+ ::= { hostTopNControlEntry 1 }
+
+ hostTopNHostIndex OBJECT-TYPE
+ SYNTAX INTEGER (1..65535)
+ ACCESS read-write
+
+
+ STATUS mandatory
+ DESCRIPTION
+ "The host table for which a top N report will be
+ prepared on behalf of this entry. The host table
+ identified by a particular value of this index is
+ associated with the same host table as identified
+ by the same value of hostIndex.
+
+ This object may not be modified if the associated
+ hostTopNStatus object is equal to valid(1)."
+ ::= { hostTopNControlEntry 2 }
+
+ hostTopNRateBase OBJECT-TYPE
+ SYNTAX INTEGER {
+ hostTopNInPkts(1),
+ hostTopNOutPkts(2),
+ hostTopNInOctets(3),
+ hostTopNOutOctets(4),
+ hostTopNOutErrors(5),
+ hostTopNOutBroadcastPkts(6),
+ hostTopNOutMulticastPkts(7)
+ }
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The variable for each host that the hostTopNRate
+ variable is based upon.
+
+ This object may not be modified if the associated
+ hostTopNStatus object is equal to valid(1)."
+ ::= { hostTopNControlEntry 3 }
+
+ hostTopNTimeRemaining OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The number of seconds left in the report currently
+ being collected. When this object is modified by
+ the management station, a new collection is started,
+ possibly aborting a currently running report. The
+ new value is used as the requested duration of this
+ report, which is loaded into the associated
+ hostTopNDuration object.
+
+ When this object is set to a non-zero value, any
+ associated hostTopNEntries shall be made
+ inaccessible by the monitor. While the value of this
+
+
+ object is non-zero, it decrements by one per second
+ until it reaches zero. During this time, all
+ associated hostTopNEntries shall remain
+ inaccessible. At the time that this object
+ decrements to zero, the report is made
+ accessible in the hostTopNTable. Thus, the hostTopN
+ table needs to be created only at the end of the
+ collection interval."
+ DEFVAL { 0 }
+ ::= { hostTopNControlEntry 4 }
+
+ hostTopNDuration OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of seconds that this report has collected
+ during the last sampling interval, or if this
+ report is currently being collected, the number
+ of seconds that this report is being collected
+ during this sampling interval.
+
+ When the associated hostTopNTimeRemaining object is
+ set, this object shall be set by the probe to the
+ same value and shall not be modified until the next
+ time the hostTopNTimeRemaining is set.
+
+ This value shall be zero if no reports have been
+ requested for this hostTopNControlEntry."
+ DEFVAL { 0 }
+ ::= { hostTopNControlEntry 5 }
+
+ hostTopNRequestedSize OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The maximum number of hosts requested for the top N
+ table.
+
+ When this object is created or modified, the probe
+ should set hostTopNGrantedSize as closely to this
+ object as is possible for the particular probe
+ implementation and available resources."
+ DEFVAL { 10 }
+ ::= { hostTopNControlEntry 6 }
+
+
+
+
+ hostTopNGrantedSize OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The maximum number of hosts in the top N table.
+
+ When the associated hostTopNRequestedSize object is
+ created or modified, the probe should set this
+ object as closely to the requested value as is
+ possible for the particular implementation and
+ available resources. The probe must not lower this
+ value except as a result of a set to the associated
+ hostTopNRequestedSize object.
+
+ Hosts with the highest value of hostTopNRate shall be
+ placed in this table in decreasing order of this rate
+ until there is no more room or until there are no more
+ hosts."
+ ::= { hostTopNControlEntry 7 }
+
+ hostTopNStartTime OBJECT-TYPE
+ SYNTAX TimeTicks
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The value of sysUpTime when this top N report was
+ last started. In other words, this is the time that
+ the associated hostTopNTimeRemaining object was
+ modified to start the requested report."
+ ::= { hostTopNControlEntry 8 }
+
+ hostTopNOwner OBJECT-TYPE
+ SYNTAX OwnerString
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The entity that configured this entry and is
+ therefore using the resources assigned to it."
+ ::= { hostTopNControlEntry 9 }
+
+ hostTopNStatus OBJECT-TYPE
+ SYNTAX EntryStatus
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The status of this hostTopNControl entry.
+
+
+
+ If this object is not equal to valid(1), all
+ associated hostTopNEntries shall be deleted by
+ the agent."
+ ::= { hostTopNControlEntry 10 }
+
+ hostTopNTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF HostTopNEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A list of top N host entries."
+ ::= { hostTopN 2 }
+
+ hostTopNEntry OBJECT-TYPE
+ SYNTAX HostTopNEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A set of statistics for a host that is part of a
+ top N report."
+ INDEX { hostTopNReport, hostTopNIndex }
+ ::= { hostTopNTable 1 }
+
+ HostTopNEntry ::= SEQUENCE {
+ hostTopNReport INTEGER (1..65535),
+ hostTopNIndex INTEGER (1..65535),
+ hostTopNAddress OCTET STRING,
+ hostTopNRate INTEGER
+ }
+
+ hostTopNReport OBJECT-TYPE
+ SYNTAX INTEGER (1..65535)
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "This object identifies the top N report of which
+ this entry is a part. The set of hosts
+ identified by a particular value of this
+ object is part of the same report as identified
+ by the same value of the hostTopNControlIndex object."
+ ::= { hostTopNEntry 1 }
+
+ hostTopNIndex OBJECT-TYPE
+ SYNTAX INTEGER (1..65535)
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "An index that uniquely identifies an entry in
+
+
+ the hostTopN table among those in the same report.
+ This index is between 1 and N, where N is the
+ number of entries in this table. Increasing values
+ of hostTopNIndex shall be assigned to entries with
+ decreasing values of hostTopNRate until index N
+ is assigned to the entry with the lowest value of
+ hostTopNRate or there are no more hostTopNEntries."
+ ::= { hostTopNEntry 2 }
+
+ hostTopNAddress OBJECT-TYPE
+ SYNTAX OCTET STRING
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The physical address of this host."
+ ::= { hostTopNEntry 3 }
+
+ hostTopNRate OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The amount of change in the selected variable
+ during this sampling interval. The selected
+ variable is this host's instance of the object
+ selected by hostTopNRateBase."
+ ::= { hostTopNEntry 4 }
+
+
+ -- The Matrix Group
+
+ -- Implementation of the Matrix group is optional.
+ --
+ -- The Matrix group consists of the matrixControlTable,
+ -- matrixSDTable and the matrixDSTable. These tables
+ -- store statistics for a particular conversation between
+ -- two addresses. As the device detects a new conversation,
+ -- including those to a non-unicast address, it creates a
+ -- new entry in both of the matrix tables.
+ -- It must only create new entries based on information
+ -- received in good packets. If the monitoring device finds
+ -- itself short of resources, it may delete entries as needed.
+ -- It is suggested that the device delete the least recently
+ -- used entries first.
+
+ matrixControlTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF MatrixControlEntry
+ ACCESS not-accessible
+
+
+ STATUS mandatory
+ DESCRIPTION
+ "A list of information entries for the
+ traffic matrix on each interface."
+ ::= { matrix 1 }
+
+ matrixControlEntry OBJECT-TYPE
+ SYNTAX MatrixControlEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "Information about a traffic matrix on a
+ particular interface."
+ INDEX { matrixControlIndex }
+ ::= { matrixControlTable 1 }
+
+ MatrixControlEntry ::= SEQUENCE {
+ matrixControlIndex INTEGER (1..65535),
+ matrixControlDataSource OBJECT IDENTIFIER,
+ matrixControlTableSize INTEGER,
+ matrixControlLastDeleteTime TimeTicks,
+ matrixControlOwner OwnerString,
+ matrixControlStatus INTEGER
+ }
+
+ matrixControlIndex OBJECT-TYPE
+ SYNTAX INTEGER (1..65535)
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "An index that uniquely identifies an entry in the
+ matrixControl table. Each such entry defines
+ a function that discovers conversations on a particular
+ interface and places statistics about them in the
+ matrixSDTable and the matrixDSTable on behalf of this
+ matrixControlEntry."
+ ::= { matrixControlEntry 1 }
+
+ matrixControlDataSource OBJECT-TYPE
+ SYNTAX OBJECT IDENTIFIER
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "This object identifies the source of
+ the data from which this entry creates a traffic matrix.
+ This source can be any interface on this device. In
+ order to identify a particular interface, this object
+ shall identify the instance of the ifIndex object,
+
+
+ defined in [4,6], for the desired interface. For
+ example, if an entry were to receive data from
+ interface #1, this object would be set to ifIndex.1.
+
+ The statistics in this group reflect all packets
+ on the local network segment attached to the
+ identified interface.
+
+ This object may not be modified if the associated
+ matrixControlStatus object is equal to valid(1)."
+ ::= { matrixControlEntry 2 }
+
+ matrixControlTableSize OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of matrixSDEntries in the matrixSDTable
+ for this interface. This must also be the value of
+ the number of entries in the matrixDSTable for this
+ interface."
+ ::= { matrixControlEntry 3 }
+
+ matrixControlLastDeleteTime OBJECT-TYPE
+ SYNTAX TimeTicks
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The value of sysUpTime when the last entry
+ was deleted from the portion of the matrixSDTable
+ or matrixDSTable associated with this
+ matrixControlEntry.
+ If no deletions have occurred, this value shall be
+ zero."
+ ::= { matrixControlEntry 4 }
+
+ matrixControlOwner OBJECT-TYPE
+ SYNTAX OwnerString
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The entity that configured this entry and is
+ therefore using the resources assigned to it."
+ ::= { matrixControlEntry 5 }
+
+ matrixControlStatus OBJECT-TYPE
+ SYNTAX EntryStatus
+ ACCESS read-write
+
+
+ STATUS mandatory
+ DESCRIPTION
+ "The status of this matrixControl entry.
+
+ If this object is not equal to valid(1), all
+ associated entries in the matrixSDTable and the
+ matrixDSTable shall be deleted by the agent."
+ ::= { matrixControlEntry 6 }
+
+ matrixSDTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF MatrixSDEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A list of traffic matrix entries indexed by
+ source and destination MAC address."
+ ::= { matrix 2 }
+
+ matrixSDEntry OBJECT-TYPE
+ SYNTAX MatrixSDEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A collection of statistics for communications between
+ two addresses on a particular interface."
+ INDEX { matrixSDIndex,
+ matrixSDSourceAddress, matrixSDDestAddress }
+ ::= { matrixSDTable 1 }
+
+ MatrixSDEntry ::= SEQUENCE {
+ matrixSDSourceAddress OCTET STRING,
+ matrixSDDestAddress OCTET STRING,
+ matrixSDIndex INTEGER (1..65535),
+ matrixSDPkts Counter,
+ matrixSDOctets Counter,
+ matrixSDErrors Counter
+ }
+
+ matrixSDSourceAddress OBJECT-TYPE
+ SYNTAX OCTET STRING
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The source physical address."
+ ::= { matrixSDEntry 1 }
+
+
+
+
+
+ matrixSDDestAddress OBJECT-TYPE
+ SYNTAX OCTET STRING
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The destination physical address."
+ ::= { matrixSDEntry 2 }
+
+ matrixSDIndex OBJECT-TYPE
+ SYNTAX INTEGER (1..65535)
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The set of collected matrix statistics of which
+ this entry is a part. The set of matrix statistics
+ identified by a particular value of this index
+ is associated with the same matrixControlEntry
+ as identified by the same value of matrixControlIndex."
+ ::= { matrixSDEntry 3 }
+
+ matrixSDPkts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of packets transmitted from the source
+ address to the destination address (this number
+ includes error packets)."
+ ::= { matrixSDEntry 4 }
+
+ matrixSDOctets OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of octets (excluding framing bits but
+ including FCS octets) contained in all packets
+ transmitted from the source address to the
+ destination address."
+ ::= { matrixSDEntry 5 }
+
+ matrixSDErrors OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of error packets transmitted from
+ the source address to the destination address."
+
+
+ ::= { matrixSDEntry 6 }
+
+
+ -- Traffic matrix tables from destination to source
+
+ matrixDSTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF MatrixDSEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A list of traffic matrix entries indexed by
+ destination and source MAC address."
+ ::= { matrix 3 }
+
+ matrixDSEntry OBJECT-TYPE
+ SYNTAX MatrixDSEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A collection of statistics for communications between
+ two address on a particular interface."
+ INDEX { matrixDSIndex,
+ matrixDSDestAddress, matrixDSSourceAddress }
+ ::= { matrixDSTable 1 }
+
+ MatrixDSEntry ::= SEQUENCE {
+ matrixDSSourceAddress OCTET STRING,
+ matrixDSDestAddress OCTET STRING,
+ matrixDSIndex INTEGER (1..65535),
+ matrixDSPkts Counter,
+ matrixDSOctets Counter,
+ matrixDSErrors Counter
+ }
+
+ matrixDSSourceAddress OBJECT-TYPE
+ SYNTAX OCTET STRING
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The source physical address."
+ ::= { matrixDSEntry 1 }
+
+ matrixDSDestAddress OBJECT-TYPE
+ SYNTAX OCTET STRING
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The destination physical address."
+
+
+ ::= { matrixDSEntry 2 }
+
+ matrixDSIndex OBJECT-TYPE
+ SYNTAX INTEGER (1..65535)
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The set of collected matrix statistics of which
+ this entry is a part. The set of matrix statistics
+ identified by a particular value of this index
+ is associated with the same matrixControlEntry
+ as identified by the same value of matrixControlIndex."
+ ::= { matrixDSEntry 3 }
+
+ matrixDSPkts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of packets transmitted from the source
+ address to the destination address (this number
+ includes error packets)."
+ ::= { matrixDSEntry 4 }
+
+ matrixDSOctets OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of octets (excluding framing bits
+ but including FCS octets) contained in all packets
+ transmitted from the source address to the
+ destination address."
+ ::= { matrixDSEntry 5 }
+
+ matrixDSErrors OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of error packets transmitted from
+ the source address to the destination address."
+ ::= { matrixDSEntry 6 }
+
+
+ -- The Filter Group
+
+ -- Implementation of the Filter group is optional.
+
+
+ --
+ -- The Filter group allows packets to be captured with an
+ -- arbitrary filter expression. A logical data and
+ -- event stream or "channel" is formed by the packets
+ -- that match the filter expression.
+ --
+ -- This filter mechanism allows the creation of an arbitrary
+ -- logical expression with which to filter packets. Each
+ -- filter associated with a channel is OR'ed with the others.
+ -- Within a filter, any bits checked in the data and status are
+ -- AND'ed with respect to other bits in the same filter. The
+ -- NotMask also allows for checking for inequality. Finally,
+ -- the channelAcceptType object allows for inversion of the
+ -- whole equation.
+ --
+ -- The channel can be turned on or off, and can also
+ -- generate events when packets pass through it.
+
+ filterTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF FilterEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A list of packet filter entries."
+ ::= { filter 1 }
+
+ filterEntry OBJECT-TYPE
+ SYNTAX FilterEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A set of parameters for a packet filter applied on a
+ particular interface."
+ INDEX { filterIndex }
+ ::= { filterTable 1 }
+
+ FilterEntry ::= SEQUENCE {
+ filterIndex INTEGER (1..65535),
+ filterChannelIndex INTEGER (1..65535),
+ filterPktDataOffset INTEGER,
+ filterPktData OCTET STRING,
+ filterPktDataMask OCTET STRING,
+ filterPktDataNotMask OCTET STRING,
+ filterPktStatus INTEGER,
+ filterPktStatusMask INTEGER,
+ filterPktStatusNotMask INTEGER,
+ filterOwner OwnerString,
+ filterStatus INTEGER
+
+
+ }
+
+ filterIndex OBJECT-TYPE
+ SYNTAX INTEGER (1..65535)
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "An index that uniquely identifies an entry
+ in the filter table. Each such entry defines
+ one filter that is to be applied to every packet
+ received on an interface."
+ ::= { filterEntry 1 }
+
+ filterChannelIndex OBJECT-TYPE
+ SYNTAX INTEGER (1..65535)
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "This object identifies the channel of which this
+ filter is a part. The filters identified by a
+ particular value of this object are associated
+ with the same channel as identified by the same
+ value of the channelIndex object."
+ ::= { filterEntry 2 }
+
+ filterPktDataOffset OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The offset from the beginning of each packet where
+ a match of packet data will be attempted. This offset
+ is measured from the point in the physical layer
+ packet after the framing bits, if any. For example,
+ in an Ethernet frame, this point is at the beginning
+ of the destination MAC address.
+
+ This object may not be modified if the associated
+ filterStatus object is equal to valid(1)."
+ DEFVAL { 0 }
+ ::= { filterEntry 3 }
+
+ filterPktData OBJECT-TYPE
+ SYNTAX OCTET STRING
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The data that is to be matched with the input packet.
+
+
+ For each packet received, this filter and the
+ accompanying filterPktDataMask and
+ filterPktDataNotMask will be adjusted for the
+ offset. The only bits relevant to this
+ match algorithm are those that have the corresponding
+ filterPktDataMask bit equal to one. The following
+ three rules are then applied to every packet:
+
+ (1) If the packet is too short and does not have data
+ corresponding to part of the filterPktData, the
+ packet will fail this data match.
+
+ (2) For each relevant bit from the packet with the
+ corresponding filterPktDataNotMask bit set to
+ zero, if the bit from the packet is not equal to
+ the corresponding bit from the filterPktData,
+ then the packet will fail this data match.
+
+ (3) If for every relevant bit from the packet with the
+ corresponding filterPktDataNotMask bit set to one,
+ the bit from the packet is equal to the
+ corresponding bit from the filterPktData, then
+ the packet will fail this data match.
+
+ Any packets that have not failed any of the three
+ matches above have passed this data match.
+
+ This object may not be modified if the associated
+ filterStatus object is equal to valid(1)."
+ ::= { filterEntry 4 }
+
+ filterPktDataMask OBJECT-TYPE
+ SYNTAX OCTET STRING
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The mask that is applied to the match process.
+ After adjusting this mask for the offset, only those
+ bits in the received packet that correspond to bits
+ set in this mask are relevant for further processing
+ by the match algorithm. The offset is applied to
+ filterPktDataMask in the same way it is applied to
+ the filter. For the purposes of the matching
+ algorithm, if the associated filterPktData object
+ is longer than this mask, this mask is conceptually
+ extended with '1' bits until it reaches the
+ length of the filterPktData object.
+
+
+
+ This object may not be modified if the associated
+ filterStatus object is equal to valid(1)."
+ ::= { filterEntry 5 }
+
+ filterPktDataNotMask OBJECT-TYPE
+ SYNTAX OCTET STRING
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The inversion mask that is applied to the match
+ process. After adjusting this mask for the offset,
+ those relevant bits in the received packet that
+ correspond to bits cleared in this mask must all
+ be equal to their corresponding bits in the
+ filterPktData object for the packet to be accepted.
+ In addition, at least one of those relevant
+ bits in the received packet that correspond to bits
+ set in this mask must be different to its
+ corresponding bit in the filterPktData object.
+
+ For the purposes of the matching algorithm, if
+ the associated filterPktData object is longer than
+ this mask, this mask is conceptually extended with
+ '0' bits until it reaches the length of the
+ filterPktData object.
+
+ This object may not be modified if the associated
+ filterStatus object is equal to valid(1)."
+ ::= { filterEntry 6 }
+
+ filterPktStatus OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The status that is to be matched with the input
+ packet. The only bits relevant to this match
+ algorithm are those that have the corresponding
+ filterPktStatusMask bit equal to one.
+
+ The following two rules are then applied to every
+ packet:
+
+ (1) For each relevant bit from the packet status
+ with the corresponding filterPktStatusNotMask
+ bit set to zero, if the bit from the packet
+ status is not equal to the corresponding bit
+ from the filterPktStatus, then the packet will
+
+
+ fail this status match.
+
+ (2) If for every relevant bit from the packet status
+ with the corresponding filterPktStatusNotMask
+ bit set to one, the bit from the packet status
+ is equal to the corresponding bit from the
+ filterPktStatus, then the packet will fail
+ this status match.
+
+ Any packets that have not failed either of the two
+ matches above have passed this status match.
+
+ The value of the packet status is a sum. This sum
+ initially takes the value zero. Then, for each
+ error, E, that has been discovered in this packet,
+ 2 raised to a value representing E is added to the sum.
+ The errors and the bits that represent them are
+ dependent on the media type of the interface that
+ this channel is receiving packets from.
+
+ The errors defined for a packet captured off of an
+ Ethernet interface are as follows:
+
+ bit # Error
+ 0 Packet is longer than 1518 octets
+ 1 Packet is shorter than 64 octets
+ 2 Packet experienced a CRC or Alignment
+ error
+
+ For example, an Ethernet fragment would have a
+ value of 6 (2^1 + 2^2).
+
+ As this MIB is expanded to new media types, this
+ object will have other media-specific errors defined.
+
+ For the purposes of this status matching algorithm, if
+ the packet status is longer than this
+ object, filterPktStatus this object is conceptually
+ extended with '0' bits until it reaches the size of
+ the packet status.
+
+ This object may not be modified if the associated
+ filterStatus object is equal to valid(1)."
+ ::= { filterEntry 7 }
+
+ filterPktStatusMask OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-write
+
+
+ STATUS mandatory
+ DESCRIPTION
+ "The mask that is applied to the status match process.
+ Only those bits in the received packet that correspond
+ to bits set in this mask are relevant for further
+ processing by the status match algorithm. For the
+ purposes of the matching algorithm, if the
+ associated filterPktStatus object is longer than
+ this mask, this mask is conceptually extended with
+ '1' bits until it reaches the size of the
+ filterPktStatus. In addition, if a packet status is
+ longer than this mask, this mask is conceptually
+ extended with '0' bits until it reaches the size of
+ the packet status.
+
+ This object may not be modified if the associated
+ filterStatus object is equal to valid(1)."
+ ::= { filterEntry 8 }
+
+ filterPktStatusNotMask OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The inversion mask that is applied to the status match
+ process. Those relevant bits in the received packet
+ status that correspond to bits cleared in this mask
+ must all be equal to their corresponding bits in the
+ filterPktStatus object for the packet to be accepted.
+ In addition, at least one of those relevant bits in the
+ received packet status that correspond to bits set in
+ this mask must be different to its corresponding bit
+ in the filterPktStatus object for the packet to be
+ accepted.
+
+ For the purposes of the matching algorithm, if the
+ associated filterPktStatus object or a packet status
+ is longer than this mask, this mask is conceptually
+ extended with '0' bits until it reaches the longer of
+ the lengths of the filterPktStatus object and the
+ packet status.
+
+ This object may not be modified if the associated
+ filterStatus object is equal to valid(1)."
+ ::= { filterEntry 9 }
+
+ filterOwner OBJECT-TYPE
+ SYNTAX OwnerString
+
+
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The entity that configured this entry and is
+ therefore using the resources assigned to it."
+ ::= { filterEntry 10 }
+
+ filterStatus OBJECT-TYPE
+ SYNTAX EntryStatus
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The status of this filter entry."
+ ::= { filterEntry 11 }
+
+ channelTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF ChannelEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A list of packet channel entries."
+ ::= { filter 2 }
+
+ channelEntry OBJECT-TYPE
+ SYNTAX ChannelEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A set of parameters for a packet channel applied on a
+ particular interface."
+ INDEX { channelIndex }
+ ::= { channelTable 1 }
+
+ ChannelEntry ::= SEQUENCE {
+ channelIndex INTEGER (1..65535),
+ channelIfIndex INTEGER (1..65535),
+ channelAcceptType INTEGER,
+ channelDataControl INTEGER,
+ channelTurnOnEventIndex INTEGER (0..65535),
+ channelTurnOffEventIndex INTEGER (0..65535),
+ channelEventIndex INTEGER (0..65535),
+ channelEventStatus INTEGER,
+ channelMatches Counter,
+ channelDescription DisplayString (SIZE (0..127)),
+ channelOwner OwnerString,
+ channelStatus INTEGER
+ }
+
+
+
+ channelIndex OBJECT-TYPE
+ SYNTAX INTEGER (1..65535)
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "An index that uniquely identifies an entry
+ in the channel table. Each such
+ entry defines one channel, a logical data
+ and event stream."
+ ::= { channelEntry 1 }
+
+ channelIfIndex OBJECT-TYPE
+ SYNTAX INTEGER (1..65535)
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The value of this object uniquely identifies the
+ interface on this remote network monitoring device
+ to which the associated filters are applied to allow
+ data into this channel. The interface identified by
+ a particular value of this object is the same
+ interface as identified by the same value of the
+ ifIndex object, defined in [4,6]. The filters in
+ this group are applied to all packets on the local
+ network segment attached to the identified
+ interface.
+
+ This object may not be modified if the associated
+ channelStatus object is equal to valid(1)."
+ ::= { channelEntry 2 }
+
+ channelAcceptType OBJECT-TYPE
+ SYNTAX INTEGER {
+ acceptMatched(1),
+ acceptFailed(2)
+ }
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "This object controls the action of the filters
+ associated with this channel. If this object is equal
+ to acceptMatched(1), packets will be accepted to this
+ channel if they are accepted by both the packet data
+ and packet status matches of an associated filter. If
+ this object is equal to acceptFailed(2), packets will
+ be accepted to this channel only if they fail either
+ the packet data match or the packet status match of
+ each of the associated filters.
+
+
+ This object may not be modified if the associated
+ channelStatus object is equal to valid(1)."
+ ::= { channelEntry 3 }
+
+ channelDataControl OBJECT-TYPE
+ SYNTAX INTEGER {
+ on(1),
+ off(2)
+ }
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "This object controls the flow of data through this
+ channel. If this object is on(1), data, status and
+ events flow through this channel. If this object is
+ off(2), data, status and events will not flow through
+ this channel."
+ DEFVAL { off }
+ ::= { channelEntry 4 }
+
+ channelTurnOnEventIndex OBJECT-TYPE
+ SYNTAX INTEGER (0..65535)
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The value of this object identifies the event
+ that is configured to turn the associated
+ channelDataControl from off to on when the event is
+ generated. The event identified by a particular value
+ of this object is the same event as identified by the
+ same value of the eventIndex object. If there is no
+ corresponding entry in the eventTable, then no
+ association exists. In fact, if no event is intended
+ for this channel, channelTurnOnEventIndex must be
+ set to zero, a non-existent event index.
+
+ This object may not be modified if the associated
+ channelStatus object is equal to valid(1)."
+ ::= { channelEntry 5 }
+
+ channelTurnOffEventIndex OBJECT-TYPE
+ SYNTAX INTEGER (0..65535)
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The value of this object identifies the event
+ that is configured to turn the associated
+ channelDataControl from on to off when the event is
+
+
+ generated. The event identified by a particular value
+ of this object is the same event as identified by the
+ same value of the eventIndex object. If there is no
+ corresponding entry in the eventTable, then no
+ association exists. In fact, if no event is intended
+ for this channel, channelTurnOffEventIndex must be
+ set to zero, a non-existent event index.
+
+ This object may not be modified if the associated
+ channelStatus object is equal to valid(1)."
+ ::= { channelEntry 6 }
+
+ channelEventIndex OBJECT-TYPE
+ SYNTAX INTEGER (0..65535)
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The value of this object identifies the event
+ that is configured to be generated when the
+ associated channelDataControl is on and a packet
+ is matched. The event identified by a particular value
+ of this object is the same event as identified by the
+ same value of the eventIndex object. If there is no
+ corresponding entry in the eventTable, then no
+ association exists. In fact, if no event is intended
+ for this channel, channelEventIndex must be
+ set to zero, a non-existent event index.
+
+ This object may not be modified if the associated
+ channelStatus object is equal to valid(1)."
+ ::= { channelEntry 7 }
+
+ channelEventStatus OBJECT-TYPE
+ SYNTAX INTEGER {
+ eventReady(1),
+ eventFired(2),
+ eventAlwaysReady(3)
+ }
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The event status of this channel.
+
+ If this channel is configured to generate events
+ when packets are matched, a means of controlling
+ the flow of those events is often needed. When
+ this object is equal to eventReady(1), a single
+ event may be generated, after which this object
+
+
+ will be set by the probe to eventFired(2). While
+ in the eventFired(2) state, no events will be
+ generated until the object is modified to
+ eventReady(1) (or eventAlwaysReady(3)). The
+ management station can thus easily respond to a
+ notification of an event by re-enabling this object.
+
+ If the management station wishes to disable this
+ flow control and allow events to be generated
+ at will, this object may be set to
+ eventAlwaysReady(3). Disabling the flow control
+ is discouraged as it can result in high network
+ traffic or other performance problems."
+ DEFVAL { eventReady }
+ ::= { channelEntry 8 }
+
+ channelMatches OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of times this channel has matched a packet.
+ Note that this object is updated even when
+ channelDataControl is set to off."
+ ::= { channelEntry 9 }
+
+ channelDescription OBJECT-TYPE
+ SYNTAX DisplayString (SIZE (0..127))
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "A comment describing this channel."
+ ::= { channelEntry 10 }
+
+ channelOwner OBJECT-TYPE
+ SYNTAX OwnerString
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The entity that configured this entry and is therefore
+ using the resources assigned to it."
+ ::= { channelEntry 11 }
+
+ channelStatus OBJECT-TYPE
+ SYNTAX EntryStatus
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+
+
+ "The status of this channel entry."
+ ::= { channelEntry 12 }
+
+
+ -- The Packet Capture Group
+
+ -- Implementation of the Packet Capture group is optional.
+ --
+ -- The Packet Capture Group requires implementation of the
+ -- Filter Group.
+ --
+ -- The Packet Capture group allows packets to be captured
+ -- upon a filter match. The bufferControlTable controls
+ -- the captured packets output from a channel that is
+ -- associated with it. The captured packets are placed
+ -- in entries in the captureBufferTable. These entries are
+ -- associated with the bufferControlEntry on whose behalf they
+ -- were stored.
+
+ bufferControlTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF BufferControlEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A list of buffers control entries."
+ ::= { capture 1 }
+
+ bufferControlEntry OBJECT-TYPE
+ SYNTAX BufferControlEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A set of parameters that control the collection of
+ a stream of packets that have matched filters."
+ INDEX { bufferControlIndex }
+ ::= { bufferControlTable 1 }
+
+ BufferControlEntry ::= SEQUENCE {
+ bufferControlIndex INTEGER (1..65535),
+ bufferControlChannelIndex INTEGER (1..65535),
+ bufferControlFullStatus INTEGER,
+ bufferControlFullAction INTEGER,
+ bufferControlCaptureSliceSize INTEGER,
+ bufferControlDownloadSliceSize INTEGER,
+ bufferControlDownloadOffset INTEGER,
+ bufferControlMaxOctetsRequested INTEGER,
+ bufferControlMaxOctetsGranted INTEGER,
+ bufferControlCapturedPackets INTEGER,
+
+
+ bufferControlTurnOnTime TimeTicks,
+ bufferControlOwner OwnerString,
+ bufferControlStatus INTEGER
+ }
+
+ bufferControlIndex OBJECT-TYPE
+ SYNTAX INTEGER (1..65535)
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "An index that uniquely identifies an entry
+ in the bufferControl table. The value of this
+ index shall never be zero. Each such
+ entry defines one set of packets that is
+ captured and controlled by one or more filters."
+ ::= { bufferControlEntry 1 }
+
+ bufferControlChannelIndex OBJECT-TYPE
+ SYNTAX INTEGER (1..65535)
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "An index that identifies the channel that is the
+ source of packets for this bufferControl table.
+ The channel identified by a particular value of this
+ index is the same as identified by the same value of
+ the channelIndex object.
+
+ This object may not be modified if the associated
+ bufferControlStatus object is equal to valid(1)."
+ ::= { bufferControlEntry 2 }
+
+ bufferControlFullStatus OBJECT-TYPE
+ SYNTAX INTEGER {
+ spaceAvailable(1),
+ full(2)
+ }
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "This object shows whether the buffer has room to
+ accept new packets or if it is full.
+
+ If the status is spaceAvailable(1), the buffer is
+ accepting new packets normally. If the status is
+ full(2) and the associated bufferControlFullAction
+ object is wrapWhenFull, the buffer is accepting new
+ packets by deleting enough of the oldest packets
+
+
+ to make room for new ones as they arrive. Otherwise,
+ if the status is full(2) and the
+ bufferControlFullAction object is lockWhenFull,
+ then the buffer has stopped collecting packets.
+
+ When this object is set to full(2) the probe must
+ not later set it to spaceAvailable(1) except in the
+ case of a significant gain in resources such as
+ an increase of bufferControlOctetsGranted. In
+ particular, the wrap-mode action of deleting old
+ packets to make room for newly arrived packets
+ must not affect the value of this object."
+ ::= { bufferControlEntry 3 }
+
+ bufferControlFullAction OBJECT-TYPE
+ SYNTAX INTEGER {
+ lockWhenFull(1),
+ wrapWhenFull(2) -- FIFO
+ }
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "Controls the action of the buffer when it
+ reaches the full status. When in the lockWhenFull(1)
+ state a packet is added to the buffer that
+ fills the buffer, the bufferControlFullStatus will
+ be set to full(2) and this buffer will stop capturing
+ packets."
+ ::= { bufferControlEntry 4 }
+
+ bufferControlCaptureSliceSize OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The maximum number of octets of each packet
+ that will be saved in this capture buffer.
+ For example, if a 1500 octet packet is received by
+ the probe and this object is set to 500, then only
+ 500 octets of the packet will be stored in the
+ associated capture buffer. If this variable is set
+ to 0, the capture buffer will save as many octets
+ as is possible.
+
+ This object may not be modified if the associated
+ bufferControlStatus object is equal to valid(1)."
+ DEFVAL { 100 }
+ ::= { bufferControlEntry 5 }
+
+
+ bufferControlDownloadSliceSize OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The maximum number of octets of each packet
+ in this capture buffer that will be returned in
+ an SNMP retrieval of that packet. For example,
+ if 500 octets of a packet have been stored in the
+ associated capture buffer, the associated
+ bufferControlDownloadOffset is 0, and this
+ object is set to 100, then the captureBufferPacket
+ object that contains the packet will contain only
+ the first 100 octets of the packet.
+
+ A prudent manager will take into account possible
+ interoperability or fragmentation problems that may
+ occur if the download slice size is set too large.
+ In particular, conformant SNMP implementations are not
+ required to accept messages whose length exceeds 484
+ octets, although they are encouraged to support larger
+ datagrams whenever feasible."
+ DEFVAL { 100 }
+ ::= { bufferControlEntry 6 }
+
+ bufferControlDownloadOffset OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The offset of the first octet of each packet
+ in this capture buffer that will be returned in
+ an SNMP retrieval of that packet. For example,
+ if 500 octets of a packet have been stored in the
+ associated capture buffer and this object is set to
+ 100, then the captureBufferPacket object that
+ contains the packet will contain bytes starting
+ 100 octets into the packet."
+ DEFVAL { 0 }
+ ::= { bufferControlEntry 7 }
+
+ bufferControlMaxOctetsRequested OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The requested maximum number of octets to be
+ saved in this captureBuffer, including any
+
+
+ implementation-specific overhead. If this variable
+ is set to -1, the capture buffer will save as many
+ octets as is possible.
+
+ When this object is created or modified, the probe
+ should set bufferControlMaxOctetsGranted as closely
+ to this object as is possible for the particular probe
+ implementation and available resources. However, if
+ the object has the special value of -1, the probe
+ must set bufferControlMaxOctetsGranted to -1."
+ DEFVAL { -1 }
+ ::= { bufferControlEntry 8 }
+
+ bufferControlMaxOctetsGranted OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The maximum number of octets that can be
+ saved in this captureBuffer, including overhead.
+ If this variable is -1, the capture buffer will save
+ as many octets as possible.
+
+ When the bufferControlMaxOctetsRequested object is
+ created or modified, the probe should set this object
+ as closely to the requested value as is possible for
+ the particular probe implementation and available
+ resources. However, if the request object has the
+ special value of -1, the probe must set this object
+ to -1. The probe must not lower this value except
+ as a result of a modification to the associated
+ bufferControlMaxOctetsRequested object.
+
+ When this maximum number of octets is reached
+ and a new packet is to be added to this
+ capture buffer and the corresponding
+ bufferControlFullAction is set to wrapWhenFull(2),
+ enough of the oldest packets associated with this
+ capture buffer shall be deleted by the agent so
+ that the new packet can be added. If the
+ corresponding bufferControlFullAction is set to
+ lockWhenFull(1), the new packet shall be discarded.
+ In either case, the probe must set
+ bufferControlFullStatus to full(2).
+
+ When the value of this object changes to a value less
+ than the current value, entries are deleted from
+ the captureBufferTable associated with this
+
+
+ bufferControlEntry. Enough of the
+ oldest of these captureBufferEntries shall be
+ deleted by the agent so that the number of octets
+ used remains less than or equal to the new value of
+ this object.
+
+ When the value of this object changes to a value greater
+ than the current value, the number of associated
+ captureBufferEntries may be allowed to grow."
+ ::= { bufferControlEntry 9 }
+
+ bufferControlCapturedPackets OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of packets currently in this captureBuffer."
+ ::= { bufferControlEntry 10 }
+
+ bufferControlTurnOnTime OBJECT-TYPE
+ SYNTAX TimeTicks
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The value of sysUpTime when this capture buffer was
+ first turned on."
+ ::= { bufferControlEntry 11 }
+
+ bufferControlOwner OBJECT-TYPE
+ SYNTAX OwnerString
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The entity that configured this entry and is therefore
+ using the resources assigned to it."
+ ::= { bufferControlEntry 12 }
+
+ bufferControlStatus OBJECT-TYPE
+ SYNTAX EntryStatus
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The status of this buffer Control Entry."
+ ::= { bufferControlEntry 13 }
+
+ captureBufferTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF CaptureBufferEntry
+ ACCESS not-accessible
+
+
+ STATUS mandatory
+ DESCRIPTION
+ "A list of packets captured off of a channel."
+ ::= { capture 2 }
+
+ captureBufferEntry OBJECT-TYPE
+ SYNTAX CaptureBufferEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A packet captured off of an attached network."
+ INDEX { captureBufferControlIndex, captureBufferIndex }
+ ::= { captureBufferTable 1 }
+
+ CaptureBufferEntry ::= SEQUENCE {
+ captureBufferControlIndex INTEGER (1..65535),
+ captureBufferIndex INTEGER,
+ captureBufferPacketID INTEGER,
+ captureBufferPacketData OCTET STRING,
+ captureBufferPacketLength INTEGER,
+ captureBufferPacketTime INTEGER,
+ captureBufferPacketStatus INTEGER
+ }
+
+ captureBufferControlIndex OBJECT-TYPE
+ SYNTAX INTEGER (1..65535)
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The index of the bufferControlEntry with which
+ this packet is associated."
+ ::= { captureBufferEntry 1 }
+
+ captureBufferIndex OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "An index that uniquely identifies an entry
+ in the captureBuffer table associated with a
+ particular bufferControlEntry. This index will
+ start at 1 and increase by one for each new packet
+ added with the same captureBufferControlIndex."
+ ::= { captureBufferEntry 2 }
+
+ captureBufferPacketID OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+
+
+ STATUS mandatory
+ DESCRIPTION
+ "An index that describes the order of packets
+ that are received on a particular interface.
+ The packetID of a packet captured on an
+ interface is defined to be greater than the
+ packetID's of all packets captured previously on
+ the same interface. As the captureBufferPacketID
+ object has a maximum positive value of 2^31 - 1,
+ any captureBufferPacketID object shall have the
+ value of the associated packet's packetID mod 2^31."
+ ::= { captureBufferEntry 3 }
+
+ captureBufferPacketData OBJECT-TYPE
+ SYNTAX OCTET STRING
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The data inside the packet, starting at the beginning
+ of the packet plus any offset specified in the
+ associated bufferControlDownloadOffset, including any
+ link level headers. The length of the data in this
+ object is the minimum of the length of the captured
+ packet minus the offset, the length of the associated
+ bufferControlCaptureSliceSize minus the offset, and the
+ associated bufferControlDownloadSliceSize. If this
+ minimum is less than zero, this object shall have a
+ length of zero."
+ ::= { captureBufferEntry 4 }
+
+ captureBufferPacketLength OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The actual length (off the wire) of the packet stored
+ in this entry, including FCS octets."
+ ::= { captureBufferEntry 5 }
+
+ captureBufferPacketTime OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of milliseconds that had passed since
+ this capture buffer was first turned on when this
+ packet was captured."
+ ::= { captureBufferEntry 6 }
+
+
+ captureBufferPacketStatus OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "A value which indicates the error status of this
+ packet.
+
+ The value of this object is defined in the same way as
+ filterPacketStatus. The value is a sum. This sum
+ initially takes the value zero. Then, for each
+ error, E, that has been discovered in this packet,
+ 2 raised to a value representing E is added to the sum.
+
+ The errors defined for a packet captured off of an
+ Ethernet interface are as follows:
+
+ bit # Error
+ 0 Packet is longer than 1518 octets
+ 1 Packet is shorter than 64 octets
+ 2 Packet experienced a CRC or Alignment
+ error
+ 3 First packet in this capture buffer after
+ it was detected that some packets were
+ not processed correctly.
+
+ For example, an Ethernet fragment would have a
+ value of 6 (2^1 + 2^2).
+
+ As this MIB is expanded to new media types, this object
+ will have other media-specific errors defined."
+ ::= { captureBufferEntry 7 }
+
+
+ -- The Event Group
+
+ -- Implementation of the Event group is optional.
+ --
+ -- The Event group controls the generation and notification
+ -- of events from this device. Each entry in the eventTable
+ -- describes the parameters of the event that can be triggered.
+ -- Each event entry is fired by an associated condition located
+ -- elsewhere in the MIB. An event entry may also be associated
+ -- with a function elsewhere in the MIB that will be executed
+ -- when the event is generated. For example, a channel may
+ -- be turned on or off by the firing of an event.
+ --
+ -- Each eventEntry may optionally specify that a log entry
+
+
+ -- be created on its behalf whenever the event occurs.
+ -- Each entry may also specify that notification should
+ -- occur by way of SNMP trap messages. In this case, the
+ -- community for the trap message is given in the associated
+ -- eventCommunity object. The enterprise and specific trap
+ -- fields of the trap are determined by the condition that
+ -- triggered the event. Three traps are defined in a companion
+ -- document: risingAlarm, fallingAlarm, and packetMatch.
+ -- If the eventTable is triggered by a condition specified
+ -- elsewhere, the enterprise and specific trap fields
+ -- must be specified for traps generated for that condition.
+
+ eventTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF EventEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A list of events to be generated."
+ ::= { event 1 }
+
+ eventEntry OBJECT-TYPE
+ SYNTAX EventEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A set of parameters that describe an event to be
+ generated when certain conditions are met."
+ INDEX { eventIndex }
+ ::= { eventTable 1 }
+
+ EventEntry ::= SEQUENCE {
+ eventIndex INTEGER (1..65535),
+ eventDescription DisplayString (SIZE (0..127)),
+ eventType INTEGER,
+ eventCommunity OCTET STRING (SIZE (0..127)),
+ eventLastTimeSent TimeTicks,
+ eventOwner OwnerString,
+ eventStatus INTEGER
+ }
+
+ eventIndex OBJECT-TYPE
+ SYNTAX INTEGER (1..65535)
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "An index that uniquely identifies an entry in the
+ event table. Each such entry defines one event that
+ is to be generated when the appropriate conditions
+
+
+ occur."
+ ::= { eventEntry 1 }
+
+ eventDescription OBJECT-TYPE
+ SYNTAX DisplayString (SIZE (0..127))
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "A comment describing this event entry."
+ ::= { eventEntry 2 }
+
+ eventType OBJECT-TYPE
+ SYNTAX INTEGER {
+ none(1),
+ log(2),
+ snmp-trap(3), -- send an SNMP trap
+ log-and-trap(4)
+ }
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The type of notification that the probe will make
+ about this event. In the case of log, an entry is
+ made in the log table for each event. In the case of
+ snmp-trap, an SNMP trap is sent to one or more
+ management stations."
+ ::= { eventEntry 3 }
+
+ eventCommunity OBJECT-TYPE
+ SYNTAX OCTET STRING (SIZE (0..127))
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "If an SNMP trap is to be sent, it will be sent to
+ the SNMP community specified by this octet string.
+ In the future this table will be extended to include
+ the party security mechanism. This object shall be
+ set to a string of length zero if it is intended that
+ that mechanism be used to specify the destination of
+ the trap."
+ ::= { eventEntry 4 }
+
+ eventLastTimeSent OBJECT-TYPE
+ SYNTAX TimeTicks
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The value of sysUpTime at the time this event
+
+
+ entry last generated an event. If this entry has
+ not generated any events, this value will be
+ zero."
+ ::= { eventEntry 5 }
+
+ eventOwner OBJECT-TYPE
+ SYNTAX OwnerString
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The entity that configured this entry and is therefore
+ using the resources assigned to it.
+
+ If this object contains a string starting with 'monitor'
+ and has associated entries in the log table, all
+ connected management stations should retrieve those
+ log entries, as they may have significance to all
+ management stations connected to this device"
+ ::= { eventEntry 6 }
+
+ eventStatus OBJECT-TYPE
+ SYNTAX EntryStatus
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The status of this event entry.
+
+ If this object is not equal to valid(1), all associated
+ log entries shall be deleted by the agent."
+ ::= { eventEntry 7 }
+
+ --
+ logTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF LogEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A list of events that have been logged."
+ ::= { event 2 }
+
+ logEntry OBJECT-TYPE
+ SYNTAX LogEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A set of data describing an event that has been
+ logged."
+ INDEX { logEventIndex, logIndex }
+
+
+ ::= { logTable 1 }
+
+ LogEntry ::= SEQUENCE {
+ logEventIndex INTEGER (1..65535),
+ logIndex INTEGER,
+ logTime TimeTicks,
+ logDescription DisplayString (SIZE (0..255))
+ }
+
+ logEventIndex OBJECT-TYPE
+ SYNTAX INTEGER (1..65535)
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The event entry that generated this log
+ entry. The log identified by a particular
+ value of this index is associated with the same
+ eventEntry as identified by the same value
+ of eventIndex."
+ ::= { logEntry 1 }
+
+ logIndex OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "An index that uniquely identifies an entry
+ in the log table amongst those generated by the
+ same eventEntries. These indexes are
+ assigned beginning with 1 and increase by one
+ with each new log entry. The association
+ between values of logIndex and logEntries
+ is fixed for the lifetime of each logEntry.
+ The agent may choose to delete the oldest
+ instances of logEntry as required because of
+ lack of memory. It is an implementation-specific
+ matter as to when this deletion may occur."
+ ::= { logEntry 2 }
+
+ logTime OBJECT-TYPE
+ SYNTAX TimeTicks
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The value of sysUpTime when this log entry was
+ created."
+ ::= { logEntry 3 }
+
+
+
+ logDescription OBJECT-TYPE
+ SYNTAX DisplayString (SIZE (0..255))
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "An implementation dependent description of the
+ event that activated this log entry."
+ ::= { logEntry 4 }
+
+ END
+
diff --git a/lib/snmp/test/test-mibs/RMON-MIB.mib b/lib/snmp/test/test-mibs/RMON-MIB.mib
new file mode 100644
index 0000000000..0824dbde1d
--- /dev/null
+++ b/lib/snmp/test/test-mibs/RMON-MIB.mib
@@ -0,0 +1,3826 @@
+ RMON-MIB DEFINITIONS ::= BEGIN
+
+ IMPORTS
+ Counter FROM RFC1155-SMI
+ mib-2,DisplayString FROM RFC1213-MIB
+ OBJECT-TYPE FROM RFC-1212
+ TRAP-TYPE FROM RFC-1215;
+
+ -- Remote Network Monitoring MIB
+
+ rmon OBJECT IDENTIFIER ::= { mib-2 16 }
+
+
+ -- textual conventions
+
+ OwnerString ::= DisplayString
+ -- This data type is used to model an administratively
+ -- assigned name of the owner of a resource. This
+ -- information is taken from the NVT ASCII character
+ -- set. It is suggested that this name contain one or
+
+
+ -- more of the following: IP address, management station
+ -- name, network manager's name, location, or phone
+ -- number.
+ -- In some cases the agent itself will be the owner of
+ -- an entry. In these cases, this string shall be set
+ -- to a string starting with 'monitor'.
+ --
+ -- SNMP access control is articulated entirely in terms
+ -- of the contents of MIB views; access to a particular
+ -- SNMP object instance depends only upon its presence
+ -- or absence in a particular MIB view and never upon
+ -- its value or the value of related object instances.
+ -- Thus, objects of this type afford resolution of
+ -- resource contention only among cooperating managers;
+ -- they realize no access control function with respect
+ -- to uncooperative parties.
+ --
+ -- By convention, objects with this syntax are declared as
+ -- having
+ --
+ -- SIZE (0..127)
+
+ EntryStatus ::= INTEGER
+ { valid(1),
+ createRequest(2),
+ underCreation(3),
+ invalid(4)
+ }
+ -- The status of a table entry.
+ --
+ -- Setting this object to the value invalid(4) has the
+ -- effect of invalidating the corresponding entry.
+ -- That is, it effectively disassociates the mapping
+ -- identified with said entry.
+ -- It is an implementation-specific matter as to whether
+ -- the agent removes an invalidated entry from the table.
+ -- Accordingly, management stations must be prepared to
+ -- receive tabular information from agents that
+ -- corresponds to entries currently not in use. Proper
+ -- interpretation of such entries requires examination
+ -- of the relevant EntryStatus object.
+ --
+ -- An existing instance of this object cannot be set to
+ -- createRequest(2). This object may only be set to
+ -- createRequest(2) when this instance is created. When
+ -- this object is created, the agent may wish to create
+ -- supplemental object instances with default values
+ -- to complete a conceptual row in this table. Because
+
+
+ -- the creation of these default objects is entirely at
+ -- the option of the agent, the manager must not assume
+ -- that any will be created, but may make use of any that
+ -- are created. Immediately after completing the create
+ -- operation, the agent must set this object to
+ -- underCreation(3).
+ --
+ -- When in the underCreation(3) state, an entry is
+ -- allowed to exist in a possibly incomplete, possibly
+ -- inconsistent state, usually to allow it to be
+ -- modified in mutiple PDUs. When in this state, an
+ -- entry is not fully active. Entries shall exist in
+ -- the underCreation(3) state until the management
+ -- station is finished configuring the entry and sets
+ -- this object to valid(1) or aborts, setting this
+ -- object to invalid(4). If the agent determines that
+ -- an entry has been in the underCreation(3) state for
+ -- an abnormally long time, it may decide that the
+ -- management station has crashed. If the agent makes
+ -- this decision, it may set this object to invalid(4)
+ -- to reclaim the entry. A prudent agent will
+ -- understand that the management station may need to
+ -- wait for human input and will allow for that
+ -- possibility in its determination of this abnormally
+ -- long period.
+ --
+ -- An entry in the valid(1) state is fully configured and
+ -- consistent and fully represents the configuration or
+ -- operation such a row is intended to represent. For
+ -- example, it could be a statistical function that is
+ -- configured and active, or a filter that is available
+ -- in the list of filters processed by the packet capture
+ -- process.
+ --
+ -- A manager is restricted to changing the state of an
+ -- entry in the following ways:
+ --
+ -- create under
+ -- To: valid Request Creation invalid
+ -- From:
+ -- valid OK NO OK OK
+ -- createRequest N/A N/A N/A N/A
+ -- underCreation OK NO OK OK
+ -- invalid NO NO NO OK
+ -- nonExistent NO OK NO OK
+ --
+ -- In the table above, it is not applicable to move the
+ -- state from the createRequest state to any other
+
+
+ -- state because the manager will never find the
+ -- variable in that state. The nonExistent state is
+ -- not a value of the enumeration, rather it means that
+ -- the entryStatus variable does not exist at all.
+ --
+ -- An agent may allow an entryStatus variable to change
+ -- state in additional ways, so long as the semantics
+ -- of the states are followed. This allowance is made
+ -- to ease the implementation of the agent and is made
+ -- despite the fact that managers should never
+ -- excercise these additional state transitions.
+
+
+ statistics OBJECT IDENTIFIER ::= { rmon 1 }
+ history OBJECT IDENTIFIER ::= { rmon 2 }
+ alarm OBJECT IDENTIFIER ::= { rmon 3 }
+ hosts OBJECT IDENTIFIER ::= { rmon 4 }
+ hostTopN OBJECT IDENTIFIER ::= { rmon 5 }
+ matrix OBJECT IDENTIFIER ::= { rmon 6 }
+ filter OBJECT IDENTIFIER ::= { rmon 7 }
+ capture OBJECT IDENTIFIER ::= { rmon 8 }
+ event OBJECT IDENTIFIER ::= { rmon 9 }
+
+
+ -- The Ethernet Statistics Group
+ --
+ -- Implementation of the Ethernet Statistics group is
+ -- optional.
+ --
+ -- The ethernet statistics group contains statistics
+ -- measured by the probe for each monitored interface on
+ -- this device. These statistics take the form of free
+ -- running counters that start from zero when a valid entry
+ -- is created.
+ --
+ -- This group currently has statistics defined only for
+ -- Ethernet interfaces. Each etherStatsEntry contains
+ -- statistics for one Ethernet interface. The probe must
+ -- create one etherStats entry for each monitored Ethernet
+ -- interface on the device.
+
+ etherStatsTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF EtherStatsEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A list of Ethernet statistics entries."
+ ::= { statistics 1 }
+
+
+ etherStatsEntry OBJECT-TYPE
+ SYNTAX EtherStatsEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A collection of statistics kept for a particular
+ Ethernet interface. As an example, an instance of the
+ etherStatsPkts object might be named etherStatsPkts.1"
+ INDEX { etherStatsIndex }
+ ::= { etherStatsTable 1 }
+
+ EtherStatsEntry ::= SEQUENCE {
+ etherStatsIndex INTEGER (1..65535),
+ etherStatsDataSource OBJECT IDENTIFIER,
+ etherStatsDropEvents Counter,
+ etherStatsOctets Counter,
+ etherStatsPkts Counter,
+ etherStatsBroadcastPkts Counter,
+ etherStatsMulticastPkts Counter,
+ etherStatsCRCAlignErrors Counter,
+ etherStatsUndersizePkts Counter,
+ etherStatsOversizePkts Counter,
+ etherStatsFragments Counter,
+ etherStatsJabbers Counter,
+ etherStatsCollisions Counter,
+ etherStatsPkts64Octets Counter,
+ etherStatsPkts65to127Octets Counter,
+ etherStatsPkts128to255Octets Counter,
+ etherStatsPkts256to511Octets Counter,
+ etherStatsPkts512to1023Octets Counter,
+ etherStatsPkts1024to1518Octets Counter,
+ etherStatsOwner OwnerString,
+ etherStatsStatus EntryStatus
+ }
+
+ etherStatsIndex OBJECT-TYPE
+ SYNTAX INTEGER (1..65535)
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The value of this object uniquely identifies this
+ etherStats entry."
+ ::= { etherStatsEntry 1 }
+
+ etherStatsDataSource OBJECT-TYPE
+ SYNTAX OBJECT IDENTIFIER
+ ACCESS read-write
+ STATUS mandatory
+
+
+ DESCRIPTION
+ "This object identifies the source of the data that
+ this etherStats entry is configured to analyze. This
+ source can be any ethernet interface on this device.
+ In order to identify a particular interface, this
+ object shall identify the instance of the ifIndex
+ object, defined in RFC 1213 and RFC 1573 [4,6], for
+ the desired interface. For example, if an entry
+ were to receive data from interface #1, this object
+ would be set to ifIndex.1.
+
+ The statistics in this group reflect all packets
+ on the local network segment attached to the
+ identified interface.
+
+ An agent may or may not be able to tell if
+ fundamental changes to the media of the interface
+ have occurred and necessitate an invalidation of
+ this entry. For example, a hot-pluggable ethernet
+ card could be pulled out and replaced by a
+ token-ring card. In such a case, if the agent has
+ such knowledge of the change, it is recommended that
+ it invalidate this entry.
+
+ This object may not be modified if the associated
+ etherStatsStatus object is equal to valid(1)."
+ ::= { etherStatsEntry 2 }
+
+ etherStatsDropEvents OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of events in which packets
+ were dropped by the probe due to lack of resources.
+ Note that this number is not necessarily the number of
+ packets dropped; it is just the number of times this
+ condition has been detected."
+ ::= { etherStatsEntry 3 }
+
+ etherStatsOctets OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of octets of data (including
+ those in bad packets) received on the
+ network (excluding framing bits but including
+
+
+ FCS octets).
+
+ This object can be used as a reasonable estimate of
+ ethernet utilization. If greater precision is
+ desired, the etherStatsPkts and etherStatsOctets
+ objects should be sampled before and after a common
+ interval. The differences in the sampled values are
+ Pkts and Octets, respectively, and the number of
+ seconds in the interval is Interval. These values
+ are used to calculate the Utilization as follows:
+
+ Pkts * (9.6 + 6.4) + (Octets * .8)
+ Utilization = -------------------------------------
+ Interval * 10,000
+
+ The result of this equation is the value Utilization
+ which is the percent utilization of the ethernet
+ segment on a scale of 0 to 100 percent."
+ ::= { etherStatsEntry 4 }
+
+ etherStatsPkts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of packets (including bad packets,
+ broadcast packets, and multicast packets) received."
+ ::= { etherStatsEntry 5 }
+
+ etherStatsBroadcastPkts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of good packets received that were
+ directed to the broadcast address. Note that this
+ does not include multicast packets."
+ ::= { etherStatsEntry 6 }
+
+ etherStatsMulticastPkts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of good packets received that were
+ directed to a multicast address. Note that this
+ number does not include packets directed to the
+ broadcast address."
+
+
+ ::= { etherStatsEntry 7 }
+
+ etherStatsCRCAlignErrors OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of packets received that
+ had a length (excluding framing bits, but
+ including FCS octets) of between 64 and 1518
+ octets, inclusive, but but had either a bad
+ Frame Check Sequence (FCS) with an integral
+ number of octets (FCS Error) or a bad FCS with
+ a non-integral number of octets (Alignment Error)."
+ ::= { etherStatsEntry 8 }
+
+ etherStatsUndersizePkts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of packets received that were
+ less than 64 octets long (excluding framing bits,
+ but including FCS octets) and were otherwise well
+ formed."
+ ::= { etherStatsEntry 9 }
+
+ etherStatsOversizePkts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of packets received that were
+ longer than 1518 octets (excluding framing bits,
+ but including FCS octets) and were otherwise
+ well formed."
+ ::= { etherStatsEntry 10 }
+
+ etherStatsFragments OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of packets received that were less
+ than 64 octets in length (excluding framing bits but
+ including FCS octets) and had either a bad Frame
+ Check Sequence (FCS) with an integral number of
+ octets (FCS Error) or a bad FCS with a non-integral
+
+
+ number of octets (Alignment Error).
+
+ Note that it is entirely normal for
+ etherStatsFragments to increment. This is because
+ it counts both runts (which are normal occurrences
+ due to collisions) and noise hits."
+ ::= { etherStatsEntry 11 }
+
+ etherStatsJabbers OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of packets received that were
+ longer than 1518 octets (excluding framing bits,
+ but including FCS octets), and had either a bad
+ Frame Check Sequence (FCS) with an integral number
+ of octets (FCS Error) or a bad FCS with a
+ non-integral number of octets (Alignment Error).
+
+ Note that this definition of jabber is different
+ than the definition in IEEE-802.3 section 8.2.1.5
+ (10BASE5) and section 10.3.1.4 (10BASE2). These
+ documents define jabber as the condition where any
+ packet exceeds 20 ms. The allowed range to detect
+ jabber is between 20 ms and 150 ms."
+ ::= { etherStatsEntry 12 }
+
+ etherStatsCollisions OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The best estimate of the total number of collisions
+ on this Ethernet segment.
+
+ The value returned will depend on the location of
+ the RMON probe. Section 8.2.1.3 (10BASE-5) and
+ section 10.3.1.3 (10BASE-2) of IEEE standard 802.3
+ states that a station must detect a collision, in
+ the receive mode, if three or more stations are
+ transmitting simultaneously. A repeater port must
+ detect a collision when two or more stations are
+ transmitting simultaneously. Thus a probe placed on
+ a repeater port could record more collisions than a
+ probe connected to a station on the same segment
+ would.
+
+
+
+ Probe location plays a much smaller role when
+ considering 10BASE-T. 14.2.1.4 (10BASE-T) of IEEE
+ standard 802.3 defines a collision as the
+ simultaneous presence of signals on the DO and RD
+ circuits (transmitting and receiving at the same
+ time). A 10BASE-T station can only detect
+ collisions when it is transmitting. Thus probes
+ placed on a station and a repeater, should report
+ the same number of collisions.
+
+ Note also that an RMON probe inside a repeater
+ should ideally report collisions between the
+ repeater and one or more other hosts (transmit
+ collisions as defined by IEEE 802.3k) plus receiver
+ collisions observed on any coax segments to which
+ the repeater is connected."
+ ::= { etherStatsEntry 13 }
+
+ etherStatsPkts64Octets OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of packets (including bad
+ packets) received that were 64 octets in length
+ (excluding framing bits but including FCS octets)."
+ ::= { etherStatsEntry 14 }
+
+ etherStatsPkts65to127Octets OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of packets (including bad
+ packets) received that were between
+ 65 and 127 octets in length inclusive
+ (excluding framing bits but including FCS octets)."
+ ::= { etherStatsEntry 15 }
+
+ etherStatsPkts128to255Octets OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of packets (including bad
+ packets) received that were between
+ 128 and 255 octets in length inclusive
+ (excluding framing bits but including FCS octets)."
+
+
+ ::= { etherStatsEntry 16 }
+
+ etherStatsPkts256to511Octets OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of packets (including bad
+ packets) received that were between
+ 256 and 511 octets in length inclusive
+ (excluding framing bits but including FCS octets)."
+ ::= { etherStatsEntry 17 }
+
+ etherStatsPkts512to1023Octets OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of packets (including bad
+ packets) received that were between
+ 512 and 1023 octets in length inclusive
+ (excluding framing bits but including FCS octets)."
+ ::= { etherStatsEntry 18 }
+
+ etherStatsPkts1024to1518Octets OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of packets (including bad
+ packets) received that were between
+ 1024 and 1518 octets in length inclusive
+ (excluding framing bits but including FCS octets)."
+ ::= { etherStatsEntry 19 }
+
+ etherStatsOwner OBJECT-TYPE
+ SYNTAX OwnerString
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The entity that configured this entry and is
+ therefore using the resources assigned to it."
+ ::= { etherStatsEntry 20 }
+
+ etherStatsStatus OBJECT-TYPE
+ SYNTAX EntryStatus
+ ACCESS read-write
+ STATUS mandatory
+
+
+ DESCRIPTION
+ "The status of this etherStats entry."
+ ::= { etherStatsEntry 21 }
+
+
+ -- The History Control Group
+
+ -- Implementation of the History Control group is optional.
+ --
+ -- The history control group controls the periodic statistical
+ -- sampling of data from various types of networks. The
+ -- historyControlTable stores configuration entries that each
+ -- define an interface, polling period, and other parameters.
+ -- Once samples are taken, their data is stored in an entry
+ -- in a media-specific table. Each such entry defines one
+ -- sample, and is associated with the historyControlEntry that
+ -- caused the sample to be taken. Each counter in the
+ -- etherHistoryEntry counts the same event as its
+ -- similarly-named counterpart in the etherStatsEntry,
+ -- except that each value here is a cumulative sum during a
+ -- sampling period.
+ --
+ -- If the probe keeps track of the time of day, it should
+ -- start the first sample of the history at a time such that
+ -- when the next hour of the day begins, a sample is
+ -- started at that instant. This tends to make more
+ -- user-friendly reports, and enables comparison of reports
+ -- from different probes that have relatively accurate time
+ -- of day.
+ --
+ -- The probe is encouraged to add two history control entries
+ -- per monitored interface upon initialization that describe
+ -- a short term and a long term polling period. Suggested
+ -- parameters are 30 seconds for the short term polling period
+ -- and 30 minutes for the long term period.
+
+ historyControlTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF HistoryControlEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A list of history control entries."
+ ::= { history 1 }
+
+ historyControlEntry OBJECT-TYPE
+ SYNTAX HistoryControlEntry
+ ACCESS not-accessible
+ STATUS mandatory
+
+
+ DESCRIPTION
+ "A list of parameters that set up a periodic sampling
+ of statistics. As an example, an instance of the
+ historyControlInterval object might be named
+ historyControlInterval.2"
+ INDEX { historyControlIndex }
+ ::= { historyControlTable 1 }
+
+ HistoryControlEntry ::= SEQUENCE {
+ historyControlIndex INTEGER (1..65535),
+ historyControlDataSource OBJECT IDENTIFIER,
+ historyControlBucketsRequested INTEGER (1..65535),
+ historyControlBucketsGranted INTEGER (1..65535),
+ historyControlInterval INTEGER (1..3600),
+ historyControlOwner OwnerString,
+ historyControlStatus EntryStatus
+ }
+
+ historyControlIndex OBJECT-TYPE
+ SYNTAX INTEGER (1..65535)
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "An index that uniquely identifies an entry in the
+ historyControl table. Each such entry defines a
+ set of samples at a particular interval for an
+ interface on the device."
+ ::= { historyControlEntry 1 }
+
+ historyControlDataSource OBJECT-TYPE
+ SYNTAX OBJECT IDENTIFIER
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "This object identifies the source of the data for
+ which historical data was collected and
+ placed in a media-specific table on behalf of this
+ historyControlEntry. This source can be any
+ interface on this device. In order to identify
+ a particular interface, this object shall identify
+ the instance of the ifIndex object, defined
+ in RFC 1213 and RFC 1573 [4,6], for the desired
+ interface. For example, if an entry were to receive
+ data from interface #1, this object would be set
+ to ifIndex.1.
+
+ The statistics in this group reflect all packets
+ on the local network segment attached to the
+
+
+ identified interface.
+
+ An agent may or may not be able to tell if fundamental
+ changes to the media of the interface have occurred
+ and necessitate an invalidation of this entry. For
+ example, a hot-pluggable ethernet card could be
+ pulled out and replaced by a token-ring card. In
+ such a case, if the agent has such knowledge of the
+ change, it is recommended that it invalidate this
+ entry.
+
+ This object may not be modified if the associated
+ historyControlStatus object is equal to valid(1)."
+ ::= { historyControlEntry 2 }
+
+ historyControlBucketsRequested OBJECT-TYPE
+ SYNTAX INTEGER (1..65535)
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The requested number of discrete time intervals
+ over which data is to be saved in the part of the
+ media-specific table associated with this
+ historyControlEntry.
+
+ When this object is created or modified, the probe
+ should set historyControlBucketsGranted as closely to
+ this object as is possible for the particular probe
+ implementation and available resources."
+ DEFVAL { 50 }
+ ::= { historyControlEntry 3 }
+
+ historyControlBucketsGranted OBJECT-TYPE
+ SYNTAX INTEGER (1..65535)
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of discrete sampling intervals
+ over which data shall be saved in the part of
+ the media-specific table associated with this
+ historyControlEntry.
+
+ When the associated historyControlBucketsRequested
+ object is created or modified, the probe
+ should set this object as closely to the requested
+ value as is possible for the particular
+ probe implementation and available resources. The
+ probe must not lower this value except as a result
+
+
+ of a modification to the associated
+ historyControlBucketsRequested object.
+
+ There will be times when the actual number of
+ buckets associated with this entry is less than
+ the value of this object. In this case, at the
+ end of each sampling interval, a new bucket will
+ be added to the media-specific table.
+
+ When the number of buckets reaches the value of
+ this object and a new bucket is to be added to the
+ media-specific table, the oldest bucket associated
+ with this historyControlEntry shall be deleted by
+ the agent so that the new bucket can be added.
+
+ When the value of this object changes to a value less
+ than the current value, entries are deleted
+ from the media-specific table associated with this
+ historyControlEntry. Enough of the oldest of these
+ entries shall be deleted by the agent so that their
+ number remains less than or equal to the new value of
+ this object.
+
+ When the value of this object changes to a value
+ greater than the current value, the number of
+ associated media- specific entries may be allowed to
+ grow."
+ ::= { historyControlEntry 4 }
+
+ historyControlInterval OBJECT-TYPE
+ SYNTAX INTEGER (1..3600)
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The interval in seconds over which the data is
+ sampled for each bucket in the part of the
+ media-specific table associated with this
+ historyControlEntry. This interval can
+ be set to any number of seconds between 1 and
+ 3600 (1 hour).
+
+ Because the counters in a bucket may overflow at their
+ maximum value with no indication, a prudent manager
+ will take into account the possibility of overflow
+ in any of the associated counters. It is important
+ to consider the minimum time in which any counter
+ could overflow on a particular media type and set
+ the historyControlInterval object to a value less
+
+
+ than this interval. This is typically most
+ important for the 'octets' counter in any
+ media-specific table. For example, on an Ethernet
+ network, the etherHistoryOctets counter could
+ overflow in about one hour at the Ethernet's maximum
+ utilization.
+
+ This object may not be modified if the associated
+ historyControlStatus object is equal to valid(1)."
+ DEFVAL { 1800 }
+ ::= { historyControlEntry 5 }
+
+ historyControlOwner OBJECT-TYPE
+ SYNTAX OwnerString
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The entity that configured this entry and is
+ therefore using the resources assigned to it."
+ ::= { historyControlEntry 6 }
+
+ historyControlStatus OBJECT-TYPE
+ SYNTAX EntryStatus
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The status of this historyControl entry.
+
+ Each instance of the media-specific table associated
+ with this historyControlEntry will be deleted by the
+ agent if this historyControlEntry is not equal to
+ valid(1)."
+ ::= { historyControlEntry 7 }
+
+
+ -- The Ethernet History Group
+
+ -- Implementation of the Ethernet History group is optional.
+ --
+ -- The Ethernet History group records periodic
+ -- statistical samples from a network and stores them
+ -- for later retrieval. Once samples are taken, their
+ -- data is stored in an entry in a media-specific
+ -- table. Each such entry defines one sample, and is
+ -- associated with the historyControlEntry that caused
+ -- the sample to be taken. This group defines the
+ -- etherHistoryTable, for Ethernet networks.
+ --
+
+
+ etherHistoryTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF EtherHistoryEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A list of Ethernet history entries."
+ ::= { history 2 }
+
+ etherHistoryEntry OBJECT-TYPE
+ SYNTAX EtherHistoryEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "An historical sample of Ethernet statistics on a
+ particular Ethernet interface. This sample is
+ associated with the historyControlEntry which set up
+ the parameters for a regular collection of these
+ samples. As an example, an instance of the
+ etherHistoryPkts object might be named
+ etherHistoryPkts.2.89"
+ INDEX { etherHistoryIndex , etherHistorySampleIndex }
+ ::= { etherHistoryTable 1 }
+
+ EtherHistoryEntry ::= SEQUENCE {
+ etherHistoryIndex INTEGER (1..65535),
+ etherHistorySampleIndex INTEGER (1..2147483647),
+ etherHistoryIntervalStart TimeTicks,
+ etherHistoryDropEvents Counter,
+ etherHistoryOctets Counter,
+ etherHistoryPkts Counter,
+ etherHistoryBroadcastPkts Counter,
+ etherHistoryMulticastPkts Counter,
+ etherHistoryCRCAlignErrors Counter,
+ etherHistoryUndersizePkts Counter,
+ etherHistoryOversizePkts Counter,
+ etherHistoryFragments Counter,
+ etherHistoryJabbers Counter,
+ etherHistoryCollisions Counter,
+ etherHistoryUtilization INTEGER (0..10000)
+ }
+
+ etherHistoryIndex OBJECT-TYPE
+ SYNTAX INTEGER (1..65535)
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The history of which this entry is a part. The
+ history identified by a particular value of this
+
+
+ index is the same history as identified
+ by the same value of historyControlIndex."
+ ::= { etherHistoryEntry 1 }
+
+ etherHistorySampleIndex OBJECT-TYPE
+ SYNTAX INTEGER (1..2147483647)
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "An index that uniquely identifies the particular
+ sample this entry represents among all samples
+ associated with the same historyControlEntry.
+ This index starts at 1 and increases by one
+ as each new sample is taken."
+ ::= { etherHistoryEntry 2 }
+
+ etherHistoryIntervalStart OBJECT-TYPE
+ SYNTAX TimeTicks
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The value of sysUpTime at the start of the interval
+ over which this sample was measured. If the probe
+ keeps track of the time of day, it should start
+ the first sample of the history at a time such that
+ when the next hour of the day begins, a sample is
+ started at that instant. Note that following this
+ rule may require the probe to delay collecting the
+ first sample of the history, as each sample must be
+ of the same interval. Also note that the sample which
+ is currently being collected is not accessible in this
+ table until the end of its interval."
+ ::= { etherHistoryEntry 3 }
+
+ etherHistoryDropEvents OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of events in which packets
+ were dropped by the probe due to lack of resources
+ during this sampling interval. Note that this number
+ is not necessarily the number of packets dropped, it
+ is just the number of times this condition has been
+ detected."
+ ::= { etherHistoryEntry 4 }
+
+ etherHistoryOctets OBJECT-TYPE
+
+
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of octets of data (including
+ those in bad packets) received on the
+ network (excluding framing bits but including
+ FCS octets)."
+ ::= { etherHistoryEntry 5 }
+
+ etherHistoryPkts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of packets (including bad packets)
+ received during this sampling interval."
+ ::= { etherHistoryEntry 6 }
+
+ etherHistoryBroadcastPkts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of good packets received during this
+ sampling interval that were directed to the
+ broadcast address."
+ ::= { etherHistoryEntry 7 }
+
+ etherHistoryMulticastPkts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of good packets received during this
+ sampling interval that were directed to a
+ multicast address. Note that this number does not
+ include packets addressed to the broadcast address."
+ ::= { etherHistoryEntry 8 }
+
+ etherHistoryCRCAlignErrors OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of packets received during this sampling
+ interval that had a length (excluding framing bits
+ but including FCS octets) between 64 and 1518
+
+
+ octets, inclusive, but had either a bad Frame Check
+ Sequence (FCS) with an integral number of octets
+ (FCS Error) or a bad FCS with a non-integral number
+ of octets (Alignment Error)."
+ ::= { etherHistoryEntry 9 }
+
+ etherHistoryUndersizePkts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of packets received during this
+ sampling interval that were less than 64 octets
+ long (excluding framing bits but including FCS
+ octets) and were otherwise well formed."
+ ::= { etherHistoryEntry 10 }
+
+ etherHistoryOversizePkts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of packets received during this
+ sampling interval that were longer than 1518
+ octets (excluding framing bits but including
+ FCS octets) but were otherwise well formed."
+ ::= { etherHistoryEntry 11 }
+
+ etherHistoryFragments OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of packets received during this
+ sampling interval that were less than 64 octets in
+ length (excluding framing bits but including FCS
+ octets) had either a bad Frame Check Sequence (FCS)
+ with an integral number of octets (FCS Error) or a bad
+ FCS with a non-integral number of octets (Alignment
+ Error).
+
+ Note that it is entirely normal for
+ etherHistoryFragments to increment. This is because
+ it counts both runts (which are normal occurrences
+ due to collisions) and noise hits."
+ ::= { etherHistoryEntry 12 }
+
+ etherHistoryJabbers OBJECT-TYPE
+
+
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of packets received during this
+ sampling interval that were longer than 1518 octets
+ (excluding framing bits but including FCS octets),
+ and had either a bad Frame Check Sequence (FCS)
+ with an integral number of octets (FCS Error) or
+ a bad FCS with a non-integral number of octets
+ (Alignment Error).
+
+ Note that this definition of jabber is different
+ than the definition in IEEE-802.3 section 8.2.1.5
+ (10BASE5) and section 10.3.1.4 (10BASE2). These
+ documents define jabber as the condition where any
+ packet exceeds 20 ms. The allowed range to detect
+ jabber is between 20 ms and 150 ms."
+ ::= { etherHistoryEntry 13 }
+
+ etherHistoryCollisions OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The best estimate of the total number of collisions
+ on this Ethernet segment during this sampling
+ interval.
+
+ The value returned will depend on the location of
+ the RMON probe. Section 8.2.1.3 (10BASE-5) and
+ section 10.3.1.3 (10BASE-2) of IEEE standard 802.3
+ states that a station must detect a collision, in
+ the receive mode, if three or more stations are
+ transmitting simultaneously. A repeater port must
+ detect a collision when two or more stations are
+ transmitting simultaneously. Thus a probe placed on
+ a repeater port could record more collisions than a
+ probe connected to a station on the same segment
+ would.
+
+ Probe location plays a much smaller role when
+ considering 10BASE-T. 14.2.1.4 (10BASE-T) of IEEE
+ standard 802.3 defines a collision as the
+ simultaneous presence of signals on the DO and RD
+ circuits (transmitting and receiving at the same
+ time). A 10BASE-T station can only detect
+ collisions when it is transmitting. Thus probes
+
+
+ placed on a station and a repeater, should report
+ the same number of collisions.
+
+ Note also that an RMON probe inside a repeater
+ should ideally report collisions between the
+ repeater and one or more other hosts (transmit
+ collisions as defined by IEEE 802.3k) plus receiver
+ collisions observed on any coax segments to which
+ the repeater is connected."
+ ::= { etherHistoryEntry 14 }
+
+ etherHistoryUtilization OBJECT-TYPE
+ SYNTAX INTEGER (0..10000)
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The best estimate of the mean physical layer
+ network utilization on this interface during this
+ sampling interval, in hundredths of a percent."
+ ::= { etherHistoryEntry 15 }
+
+
+ -- The Alarm Group
+
+ -- Implementation of the Alarm group is optional.
+ --
+ -- The Alarm Group requires the implementation of the Event
+ -- group.
+ --
+ -- The Alarm group periodically takes
+ -- statistical samples from variables in the probe and
+ -- compares them to thresholds that have been
+ -- configured. The alarm table stores configuration
+ -- entries that each define a variable, polling period,
+ -- and threshold parameters. If a sample is found to
+ -- cross the threshold values, an event is generated.
+ -- Only variables that resolve to an ASN.1 primitive
+ -- type of INTEGER (INTEGER, Counter, Gauge, or
+ -- TimeTicks) may be monitored in this way.
+ --
+ -- This function has a hysteresis mechanism to limit
+ -- the generation of events. This mechanism generates
+ -- one event as a threshold is crossed in the
+ -- appropriate direction. No more events are generated
+ -- for that threshold until the opposite threshold is
+ -- crossed.
+ --
+ -- In the case of a sampling a deltaValue, a probe may
+
+
+ -- implement this mechanism with more precision if it
+ -- takes a delta sample twice per period, each time
+ -- comparing the sum of the latest two samples to the
+ -- threshold. This allows the detection of threshold
+ -- crossings that span the sampling boundary. Note
+ -- that this does not require any special configuration
+ -- of the threshold value. It is suggested that probes
+ -- implement this more precise algorithm.
+
+ alarmTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF AlarmEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A list of alarm entries."
+ ::= { alarm 1 }
+
+ alarmEntry OBJECT-TYPE
+ SYNTAX AlarmEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A list of parameters that set up a periodic checking
+ for alarm conditions. For example, an instance of the
+ alarmValue object might be named alarmValue.8"
+ INDEX { alarmIndex }
+ ::= { alarmTable 1 }
+
+ AlarmEntry ::= SEQUENCE {
+ alarmIndex INTEGER (1..65535),
+ alarmInterval INTEGER,
+ alarmVariable OBJECT IDENTIFIER,
+ alarmSampleType INTEGER,
+ alarmValue INTEGER,
+ alarmStartupAlarm INTEGER,
+ alarmRisingThreshold INTEGER,
+ alarmFallingThreshold INTEGER,
+ alarmRisingEventIndex INTEGER (0..65535),
+ alarmFallingEventIndex INTEGER (0..65535),
+ alarmOwner OwnerString,
+ alarmStatus EntryStatus
+ }
+
+ alarmIndex OBJECT-TYPE
+ SYNTAX INTEGER (1..65535)
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+
+
+ "An index that uniquely identifies an entry in the
+ alarm table. Each such entry defines a
+ diagnostic sample at a particular interval
+ for an object on the device."
+ ::= { alarmEntry 1 }
+
+ alarmInterval OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The interval in seconds over which the data is
+ sampled and compared with the rising and falling
+ thresholds. When setting this variable, care
+ should be taken in the case of deltaValue
+ sampling - the interval should be set short enough
+ that the sampled variable is very unlikely to
+ increase or decrease by more than 2^31 - 1 during
+ a single sampling interval.
+
+ This object may not be modified if the associated
+ alarmStatus object is equal to valid(1)."
+ ::= { alarmEntry 2 }
+
+ alarmVariable OBJECT-TYPE
+ SYNTAX OBJECT IDENTIFIER
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The object identifier of the particular variable to
+ be sampled. Only variables that resolve to an ASN.1
+ primitive type of INTEGER (INTEGER, Counter, Gauge,
+ or TimeTicks) may be sampled.
+
+ Because SNMP access control is articulated entirely
+ in terms of the contents of MIB views, no access
+ control mechanism exists that can restrict the value
+ of this object to identify only those objects that
+ exist in a particular MIB view. Because there is
+ thus no acceptable means of restricting the read
+ access that could be obtained through the alarm
+ mechanism, the probe must only grant write access to
+ this object in those views that have read access to
+ all objects on the probe.
+
+ During a set operation, if the supplied variable
+ name is not available in the selected MIB view, a
+ badValue error must be returned. If at any time the
+
+
+ variable name of an established alarmEntry is no
+ longer available in the selected MIB view, the probe
+ must change the status of this alarmEntry to
+ invalid(4).
+
+ This object may not be modified if the associated
+ alarmStatus object is equal to valid(1)."
+ ::= { alarmEntry 3 }
+
+ alarmSampleType OBJECT-TYPE
+ SYNTAX INTEGER {
+ absoluteValue(1),
+ deltaValue(2)
+ }
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The method of sampling the selected variable and
+ calculating the value to be compared against the
+ thresholds. If the value of this object is
+ absoluteValue(1), the value of the selected variable
+ will be compared directly with the thresholds at the
+ end of the sampling interval. If the value of this
+ object is deltaValue(2), the value of the selected
+ variable at the last sample will be subtracted from
+ the current value, and the difference compared with
+ the thresholds.
+
+ This object may not be modified if the associated
+ alarmStatus object is equal to valid(1)."
+ ::= { alarmEntry 4 }
+
+ alarmValue OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The value of the statistic during the last sampling
+ period. For example, if the sample type is
+ deltaValue, this value will be the difference
+ between the samples at the beginning and end of the
+ period. If the sample type is absoluteValue, this
+ value will be the sampled value at the end of the
+ period.
+
+ This is the value that is compared with the rising and
+ falling thresholds.
+
+
+
+ The value during the current sampling period is not
+ made available until the period is completed and will
+ remain available until the next period completes."
+ ::= { alarmEntry 5 }
+
+ alarmStartupAlarm OBJECT-TYPE
+ SYNTAX INTEGER {
+ risingAlarm(1),
+ fallingAlarm(2),
+ risingOrFallingAlarm(3)
+ }
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The alarm that may be sent when this entry is first
+ set to valid. If the first sample after this entry
+ becomes valid is greater than or equal to the
+ risingThreshold and alarmStartupAlarm is equal to
+ risingAlarm(1) or risingOrFallingAlarm(3), then a
+ single rising alarm will be generated. If the first
+ sample after this entry becomes valid is less than
+ or equal to the fallingThreshold and
+ alarmStartupAlarm is equal to fallingAlarm(2) or
+ risingOrFallingAlarm(3), then a single falling alarm
+ will be generated.
+
+ This object may not be modified if the associated
+ alarmStatus object is equal to valid(1)."
+ ::= { alarmEntry 6 }
+
+ alarmRisingThreshold OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "A threshold for the sampled statistic. When the
+ current sampled value is greater than or equal to
+ this threshold, and the value at the last sampling
+ interval was less than this threshold, a single
+ event will be generated. A single event will also
+ be generated if the first sample after this entry
+ becomes valid is greater than or equal to this
+ threshold and the associated alarmStartupAlarm is
+ equal to risingAlarm(1) or risingOrFallingAlarm(3).
+
+ After a rising event is generated, another such event
+ will not be generated until the sampled value
+ falls below this threshold and reaches the
+
+
+ alarmFallingThreshold.
+
+ This object may not be modified if the associated
+ alarmStatus object is equal to valid(1)."
+ ::= { alarmEntry 7 }
+
+ alarmFallingThreshold OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "A threshold for the sampled statistic. When the
+ current sampled value is less than or equal to this
+ threshold, and the value at the last sampling
+ interval was greater than this threshold, a single
+ event will be generated. A single event will also
+ be generated if the first sample after this entry
+ becomes valid is less than or equal to this
+ threshold and the associated alarmStartupAlarm is
+ equal to fallingAlarm(2) or risingOrFallingAlarm(3).
+
+ After a falling event is generated, another such event
+ will not be generated until the sampled value
+ rises above this threshold and reaches the
+ alarmRisingThreshold.
+
+ This object may not be modified if the associated
+ alarmStatus object is equal to valid(1)."
+ ::= { alarmEntry 8 }
+
+ alarmRisingEventIndex OBJECT-TYPE
+ SYNTAX INTEGER (0..65535)
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The index of the eventEntry that is
+ used when a rising threshold is crossed. The
+ eventEntry identified by a particular value of
+ this index is the same as identified by the same value
+ of the eventIndex object. If there is no
+ corresponding entry in the eventTable, then
+ no association exists. In particular, if this value
+ is zero, no associated event will be generated, as
+ zero is not a valid event index.
+
+ This object may not be modified if the associated
+ alarmStatus object is equal to valid(1)."
+ ::= { alarmEntry 9 }
+
+
+ alarmFallingEventIndex OBJECT-TYPE
+ SYNTAX INTEGER (0..65535)
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The index of the eventEntry that is
+ used when a falling threshold is crossed. The
+ eventEntry identified by a particular value of
+ this index is the same as identified by the same value
+ of the eventIndex object. If there is no
+ corresponding entry in the eventTable, then
+ no association exists. In particular, if this value
+ is zero, no associated event will be generated, as
+ zero is not a valid event index.
+
+ This object may not be modified if the associated
+ alarmStatus object is equal to valid(1)."
+ ::= { alarmEntry 10 }
+
+ alarmOwner OBJECT-TYPE
+ SYNTAX OwnerString
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The entity that configured this entry and is
+ therefore using the resources assigned to it."
+ ::= { alarmEntry 11 }
+
+ alarmStatus OBJECT-TYPE
+ SYNTAX EntryStatus
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The status of this alarm entry."
+ ::= { alarmEntry 12 }
+
+
+ -- The Host Group
+
+ -- Implementation of the Host group is optional.
+ --
+ -- The host group discovers new hosts on the network by
+ -- keeping a list of source and destination MAC Addresses seen
+ -- in good packets. For each of these addresses, the host
+ -- group keeps a set of statistics. The hostControlTable
+ -- controls which interfaces this function is performed on,
+ -- and contains some information about the process. On
+ -- behalf of each hostControlEntry, data is collected on an
+
+
+ -- interface and placed in both the hostTable and the
+ -- hostTimeTable. If the monitoring device finds itself
+ -- short of resources, it may delete entries as needed. It
+ -- is suggested that the device delete the least recently
+ -- used entries first.
+
+ -- The hostTable contains entries for each address
+ -- discovered on a particular interface. Each entry
+ -- contains statistical data about that host. This table is
+ -- indexed by the MAC address of the host, through which a
+ -- random access may be achieved.
+
+ -- The hostTimeTable contains data in the same format as the
+ -- hostTable, and must contain the same set of hosts, but is
+ -- indexed using hostTimeCreationOrder rather than
+ -- hostAddress.
+ -- The hostTimeCreationOrder is an integer which reflects
+ -- the relative order in which a particular entry was
+ -- discovered and thus inserted into the table. As this
+ -- order, and thus the index, is among those entries
+ -- currently in the table, the index for a particular entry
+ -- may change if an (earlier) entry is deleted. Thus the
+ -- association between hostTimeCreationOrder and
+ -- hostTimeEntry may be broken at any time.
+
+ -- The hostTimeTable has two important uses. The first is the
+ -- fast download of this potentially large table. Because the
+ -- index of this table runs from 1 to the size of the table,
+ -- inclusive, its values are predictable. This allows very
+ -- efficient packing of variables into SNMP PDU's and allows
+ -- a table transfer to have multiple packets outstanding.
+ -- These benefits increase transfer rates tremendously.
+
+ -- The second use of the hostTimeTable is the efficient
+ -- discovery by the management station of new entries added
+ -- to the table. After the management station has downloaded
+ -- the entire table, it knows that new entries will be added
+ -- immediately after the end of the current table. It can
+ -- thus detect new entries there and retrieve them easily.
+
+ -- Because the association between hostTimeCreationOrder and
+ -- hostTimeEntry may be broken at any time, the management
+ -- station must monitor the related hostControlLastDeleteTime
+ -- object. When the management station thus detects a
+ -- deletion, it must assume that any such associations have
+ --- been broken, and invalidate any it has stored locally.
+ -- This includes restarting any download of the
+ -- hostTimeTable that may have been in progress, as well as
+
+
+ -- rediscovering the end of the hostTimeTable so that it may
+ -- detect new entries. If the management station does not
+ -- detect the broken association, it may continue to refer
+ -- to a particular host by its creationOrder while
+ -- unwittingly retrieving the data associated with another
+ -- host entirely. If this happens while downloading the
+ -- host table, the management station may fail to download
+ -- all of the entries in the table.
+
+ hostControlTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF HostControlEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A list of host table control entries."
+ ::= { hosts 1 }
+
+ hostControlEntry OBJECT-TYPE
+ SYNTAX HostControlEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A list of parameters that set up the discovery of
+ hosts on a particular interface and the collection
+ of statistics about these hosts. For example, an
+ instance of the hostControlTableSize object might be
+ named hostControlTableSize.1"
+ INDEX { hostControlIndex }
+ ::= { hostControlTable 1 }
+
+ HostControlEntry ::= SEQUENCE {
+ hostControlIndex INTEGER (1..65535),
+ hostControlDataSource OBJECT IDENTIFIER,
+ hostControlTableSize INTEGER,
+ hostControlLastDeleteTime TimeTicks,
+ hostControlOwner OwnerString,
+ hostControlStatus EntryStatus
+ }
+
+ hostControlIndex OBJECT-TYPE
+ SYNTAX INTEGER (1..65535)
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "An index that uniquely identifies an entry in the
+ hostControl table. Each such entry defines
+ a function that discovers hosts on a particular
+ interface and places statistics about them in the
+
+
+ hostTable and the hostTimeTable on behalf of this
+ hostControlEntry."
+ ::= { hostControlEntry 1 }
+
+ hostControlDataSource OBJECT-TYPE
+ SYNTAX OBJECT IDENTIFIER
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "This object identifies the source of the data for
+ this instance of the host function. This source
+ can be any interface on this device. In order
+ to identify a particular interface, this object shall
+ identify the instance of the ifIndex object, defined
+ in RFC 1213 and RFC 1573 [4,6], for the desired
+ interface. For example, if an entry were to receive
+ data from interface #1, this object would be set to
+ ifIndex.1.
+
+ The statistics in this group reflect all packets
+ on the local network segment attached to the
+ identified interface.
+
+ An agent may or may not be able to tell if
+ fundamental changes to the media of the interface
+ have occurred and necessitate an invalidation of
+ this entry. For example, a hot-pluggable ethernet
+ card could be pulled out and replaced by a
+ token-ring card. In such a case, if the agent has
+ such knowledge of the change, it is recommended that
+ it invalidate this entry.
+
+ This object may not be modified if the associated
+ hostControlStatus object is equal to valid(1)."
+ ::= { hostControlEntry 2 }
+
+ hostControlTableSize OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of hostEntries in the hostTable and the
+ hostTimeTable associated with this hostControlEntry."
+ ::= { hostControlEntry 3 }
+
+ hostControlLastDeleteTime OBJECT-TYPE
+ SYNTAX TimeTicks
+ ACCESS read-only
+
+
+ STATUS mandatory
+ DESCRIPTION
+ "The value of sysUpTime when the last entry
+ was deleted from the portion of the hostTable
+ associated with this hostControlEntry. If no
+ deletions have occurred, this value shall be zero."
+ ::= { hostControlEntry 4 }
+
+ hostControlOwner OBJECT-TYPE
+ SYNTAX OwnerString
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The entity that configured this entry and is
+ therefore using the resources assigned to it."
+ ::= { hostControlEntry 5 }
+
+ hostControlStatus OBJECT-TYPE
+ SYNTAX EntryStatus
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The status of this hostControl entry.
+
+ If this object is not equal to valid(1), all
+ associated entries in the hostTable, hostTimeTable,
+ and the hostTopNTable shall be deleted by the
+ agent."
+ ::= { hostControlEntry 6 }
+
+ hostTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF HostEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A list of host entries."
+ ::= { hosts 2 }
+
+ hostEntry OBJECT-TYPE
+ SYNTAX HostEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A collection of statistics for a particular host
+ that has been discovered on an interface of this
+ device. For example, an instance of the
+ hostOutBroadcastPkts object might be named
+ hostOutBroadcastPkts.1.6.8.0.32.27.3.176"
+
+
+ INDEX { hostIndex, hostAddress }
+ ::= { hostTable 1 }
+
+ HostEntry ::= SEQUENCE {
+ hostAddress OCTET STRING,
+ hostCreationOrder INTEGER (1..65535),
+ hostIndex INTEGER (1..65535),
+ hostInPkts Counter,
+ hostOutPkts Counter,
+ hostInOctets Counter,
+ hostOutOctets Counter,
+ hostOutErrors Counter,
+ hostOutBroadcastPkts Counter,
+ hostOutMulticastPkts Counter
+ }
+
+ hostAddress OBJECT-TYPE
+ SYNTAX OCTET STRING
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The physical address of this host."
+ ::= { hostEntry 1 }
+
+ hostCreationOrder OBJECT-TYPE
+ SYNTAX INTEGER (1..65535)
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "An index that defines the relative ordering of
+ the creation time of hosts captured for a
+ particular hostControlEntry. This index shall
+ be between 1 and N, where N is the value of
+ the associated hostControlTableSize. The ordering
+ of the indexes is based on the order of each entry's
+ insertion into the table, in which entries added
+ earlier have a lower index value than entries added
+ later.
+
+ It is important to note that the order for a
+ particular entry may change as an (earlier) entry
+ is deleted from the table. Because this order may
+ change, management stations should make use of the
+ hostControlLastDeleteTime variable in the
+ hostControlEntry associated with the relevant
+ portion of the hostTable. By observing
+ this variable, the management station may detect
+ the circumstances where a previous association
+
+
+ between a value of hostCreationOrder
+ and a hostEntry may no longer hold."
+ ::= { hostEntry 2 }
+
+ hostIndex OBJECT-TYPE
+ SYNTAX INTEGER (1..65535)
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The set of collected host statistics of which
+ this entry is a part. The set of hosts
+ identified by a particular value of this
+ index is associated with the hostControlEntry
+ as identified by the same value of hostControlIndex."
+ ::= { hostEntry 3 }
+
+ hostInPkts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of good packets transmitted to this
+ address since it was added to the hostTable."
+ ::= { hostEntry 4 }
+
+ hostOutPkts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of packets, including bad packets,
+ transmitted by this address since it was added
+ to the hostTable."
+ ::= { hostEntry 5 }
+
+ hostInOctets OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of octets transmitted to this address
+ since it was added to the hostTable (excluding
+ framing bits but including FCS octets), except for
+ those octets in bad packets."
+ ::= { hostEntry 6 }
+
+ hostOutOctets OBJECT-TYPE
+ SYNTAX Counter
+
+
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of octets transmitted by this address
+ since it was added to the hostTable (excluding
+ framing bits but including FCS octets), including
+ those octets in bad packets."
+ ::= { hostEntry 7 }
+
+ hostOutErrors OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of bad packets transmitted by this address
+ since this host was added to the hostTable."
+ ::= { hostEntry 8 }
+
+ hostOutBroadcastPkts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of good packets transmitted by this
+ address that were directed to the broadcast address
+ since this host was added to the hostTable."
+ ::= { hostEntry 9 }
+
+ hostOutMulticastPkts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of good packets transmitted by this
+ address that were directed to a multicast address
+ since this host was added to the hostTable.
+ Note that this number does not include packets
+ directed to the broadcast address."
+ ::= { hostEntry 10 }
+
+ -- host Time Table
+
+ hostTimeTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF HostTimeEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A list of time-ordered host table entries."
+
+
+ ::= { hosts 3 }
+
+ hostTimeEntry OBJECT-TYPE
+ SYNTAX HostTimeEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A collection of statistics for a particular host
+ that has been discovered on an interface of this
+ device. This collection includes the relative
+ ordering of the creation time of this object. For
+ example, an instance of the hostTimeOutBroadcastPkts
+ object might be named
+ hostTimeOutBroadcastPkts.1.687"
+ INDEX { hostTimeIndex, hostTimeCreationOrder }
+ ::= { hostTimeTable 1 }
+
+ HostTimeEntry ::= SEQUENCE {
+ hostTimeAddress OCTET STRING,
+ hostTimeCreationOrder INTEGER (1..65535),
+ hostTimeIndex INTEGER (1..65535),
+ hostTimeInPkts Counter,
+ hostTimeOutPkts Counter,
+ hostTimeInOctets Counter,
+ hostTimeOutOctets Counter,
+ hostTimeOutErrors Counter,
+ hostTimeOutBroadcastPkts Counter,
+ hostTimeOutMulticastPkts Counter
+ }
+
+ hostTimeAddress OBJECT-TYPE
+ SYNTAX OCTET STRING
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The physical address of this host."
+ ::= { hostTimeEntry 1 }
+
+ hostTimeCreationOrder OBJECT-TYPE
+ SYNTAX INTEGER (1..65535)
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "An index that uniquely identifies an entry in
+ the hostTime table among those entries associated
+ with the same hostControlEntry. This index shall
+ be between 1 and N, where N is the value of
+ the associated hostControlTableSize. The ordering
+
+
+ of the indexes is based on the order of each entry's
+ insertion into the table, in which entries added
+ earlier have a lower index value than entries added
+ later. Thus the management station has the ability to
+ learn of new entries added to this table without
+ downloading the entire table.
+
+ It is important to note that the index for a
+ particular entry may change as an (earlier) entry
+ is deleted from the table. Because this order may
+ change, management stations should make use of the
+ hostControlLastDeleteTime variable in the
+ hostControlEntry associated with the relevant
+ portion of the hostTimeTable. By observing
+ this variable, the management station may detect
+ the circumstances where a download of the table
+ may have missed entries, and where a previous
+ association between a value of hostTimeCreationOrder
+ and a hostTimeEntry may no longer hold."
+ ::= { hostTimeEntry 2 }
+
+ hostTimeIndex OBJECT-TYPE
+ SYNTAX INTEGER (1..65535)
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The set of collected host statistics of which
+ this entry is a part. The set of hosts
+ identified by a particular value of this
+ index is associated with the hostControlEntry
+ as identified by the same value of hostControlIndex."
+ ::= { hostTimeEntry 3 }
+
+ hostTimeInPkts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of good packets transmitted to this
+ address since it was added to the hostTimeTable."
+ ::= { hostTimeEntry 4 }
+
+ hostTimeOutPkts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of god packets transmitted by this
+
+
+ address since it was added to the hostTimeTable."
+ ::= { hostTimeEntry 5 }
+
+ hostTimeInOctets OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of octets transmitted to this address
+ since it was added to the hostTimeTable (excluding
+ framing bits but including FCS octets), except for
+ those octets in bad packets."
+ ::= { hostTimeEntry 6 }
+
+ hostTimeOutOctets OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of octets transmitted by this address
+ since it was added to the hostTimeTable (excluding
+ framing bits but including FCS octets), including
+ those octets in bad packets."
+ ::= { hostTimeEntry 7 }
+
+ hostTimeOutErrors OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of bad packets transmitted by this address
+ since this host was added to the hostTimeTable."
+ ::= { hostTimeEntry 8 }
+
+ hostTimeOutBroadcastPkts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of good packets transmitted by this
+ address that were directed to the broadcast address
+ since this host was added to the hostTimeTable."
+ ::= { hostTimeEntry 9 }
+
+ hostTimeOutMulticastPkts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+
+
+ DESCRIPTION
+ "The number of good packets transmitted by this
+ address that were directed to a multicast address
+ since this host was added to the hostTimeTable.
+ Note that this number does not include packets
+ directed to the broadcast address."
+ ::= { hostTimeEntry 10 }
+
+
+ -- The Host Top "N" Group
+
+ -- Implementation of the Host Top N group is optional.
+ --
+ -- The Host Top N group requires the implementation of the
+ -- host group.
+ --
+ -- The Host Top N group is used to prepare reports that
+ -- describe the hosts that top a list ordered by one of
+ -- their statistics.
+ -- The available statistics are samples of one of their
+ -- base statistics, over an interval specified by the
+ -- management station. Thus, these statistics are rate
+ -- based. The management station also selects how many such
+ -- hosts are reported.
+
+ -- The hostTopNControlTable is used to initiate the
+ -- generation of such a report. The management station
+ -- may select the parameters of such a report, such as
+ -- which interface, which statistic, how many hosts,
+ -- and the start and stop times of the sampling. When
+ -- the report is prepared, entries are created in the
+ -- hostTopNTable associated with the relevant
+ -- hostTopNControlEntry. These entries are static for
+ -- each report after it has been prepared.
+
+ hostTopNControlTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF HostTopNControlEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A list of top N host control entries."
+ ::= { hostTopN 1 }
+
+ hostTopNControlEntry OBJECT-TYPE
+ SYNTAX HostTopNControlEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+
+
+ "A set of parameters that control the creation of a
+ report of the top N hosts according to several
+ metrics. For example, an instance of the
+ hostTopNDuration object might be named
+ hostTopNDuration.3"
+ INDEX { hostTopNControlIndex }
+ ::= { hostTopNControlTable 1 }
+
+ HostTopNControlEntry ::= SEQUENCE {
+ hostTopNControlIndex INTEGER (1..65535),
+ hostTopNHostIndex INTEGER (1..65535),
+ hostTopNRateBase INTEGER,
+ hostTopNTimeRemaining INTEGER,
+ hostTopNDuration INTEGER,
+ hostTopNRequestedSize INTEGER,
+ hostTopNGrantedSize INTEGER,
+ hostTopNStartTime TimeTicks,
+ hostTopNOwner OwnerString,
+ hostTopNStatus EntryStatus
+ }
+
+ hostTopNControlIndex OBJECT-TYPE
+ SYNTAX INTEGER (1..65535)
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "An index that uniquely identifies an entry
+ in the hostTopNControl table. Each such
+ entry defines one top N report prepared for
+ one interface."
+ ::= { hostTopNControlEntry 1 }
+
+ hostTopNHostIndex OBJECT-TYPE
+ SYNTAX INTEGER (1..65535)
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The host table for which a top N report will be
+ prepared on behalf of this entry. The host table
+ identified by a particular value of this index is
+ associated with the same host table as identified by
+ the same value of hostIndex.
+
+ This object may not be modified if the associated
+ hostTopNStatus object is equal to valid(1)."
+ ::= { hostTopNControlEntry 2 }
+
+ hostTopNRateBase OBJECT-TYPE
+
+
+ SYNTAX INTEGER {
+ hostTopNInPkts(1),
+ hostTopNOutPkts(2),
+ hostTopNInOctets(3),
+ hostTopNOutOctets(4),
+ hostTopNOutErrors(5),
+ hostTopNOutBroadcastPkts(6),
+ hostTopNOutMulticastPkts(7)
+ }
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The variable for each host that the hostTopNRate
+ variable is based upon.
+
+ This object may not be modified if the associated
+ hostTopNStatus object is equal to valid(1)."
+ ::= { hostTopNControlEntry 3 }
+
+ hostTopNTimeRemaining OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The number of seconds left in the report currently
+ being collected. When this object is modified by
+ the management station, a new collection is started,
+ possibly aborting a currently running report. The
+ new value is used as the requested duration of this
+ report, which is loaded into the associated
+ hostTopNDuration object.
+
+ When this object is set to a non-zero value, any
+ associated hostTopNEntries shall be made
+ inaccessible by the monitor. While the value of
+ this object is non-zero, it decrements by one per
+ second until it reaches zero. During this time, all
+ associated hostTopNEntries shall remain
+ inaccessible. At the time that this object
+ decrements to zero, the report is made accessible in
+ the hostTopNTable. Thus, the hostTopN table needs
+ to be created only at the end of the collection
+ interval."
+ DEFVAL { 0 }
+ ::= { hostTopNControlEntry 4 }
+
+ hostTopNDuration OBJECT-TYPE
+ SYNTAX INTEGER
+
+
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of seconds that this report has collected
+ during the last sampling interval, or if this
+ report is currently being collected, the number
+ of seconds that this report is being collected
+ during this sampling interval.
+
+ When the associated hostTopNTimeRemaining object is
+ set, this object shall be set by the probe to the
+ same value and shall not be modified until the next
+ time the hostTopNTimeRemaining is set.
+
+ This value shall be zero if no reports have been
+ requested for this hostTopNControlEntry."
+ DEFVAL { 0 }
+ ::= { hostTopNControlEntry 5 }
+
+ hostTopNRequestedSize OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The maximum number of hosts requested for the top N
+ table.
+
+ When this object is created or modified, the probe
+ should set hostTopNGrantedSize as closely to this
+ object as is possible for the particular probe
+ implementation and available resources."
+ DEFVAL { 10 }
+ ::= { hostTopNControlEntry 6 }
+
+ hostTopNGrantedSize OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The maximum number of hosts in the top N table.
+
+ When the associated hostTopNRequestedSize object is
+ created or modified, the probe should set this
+ object as closely to the requested value as is
+ possible for the particular implementation and
+ available resources. The probe must not lower this
+ value except as a result of a set to the associated
+ hostTopNRequestedSize object.
+
+
+ Hosts with the highest value of hostTopNRate shall be
+ placed in this table in decreasing order of this rate
+ until there is no more room or until there are no more
+ hosts."
+ ::= { hostTopNControlEntry 7 }
+
+ hostTopNStartTime OBJECT-TYPE
+ SYNTAX TimeTicks
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The value of sysUpTime when this top N report was
+ last started. In other words, this is the time that
+ the associated hostTopNTimeRemaining object was
+ modified to start the requested report."
+ ::= { hostTopNControlEntry 8 }
+
+ hostTopNOwner OBJECT-TYPE
+ SYNTAX OwnerString
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The entity that configured this entry and is
+ therefore using the resources assigned to it."
+ ::= { hostTopNControlEntry 9 }
+
+ hostTopNStatus OBJECT-TYPE
+ SYNTAX EntryStatus
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The status of this hostTopNControl entry.
+
+ If this object is not equal to valid(1), all
+ associated hostTopNEntries shall be deleted by the
+ agent."
+ ::= { hostTopNControlEntry 10 }
+
+ hostTopNTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF HostTopNEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A list of top N host entries."
+ ::= { hostTopN 2 }
+
+ hostTopNEntry OBJECT-TYPE
+ SYNTAX HostTopNEntry
+
+
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A set of statistics for a host that is part of a
+ top N report. For example, an instance of the
+ hostTopNRate object might be named
+ hostTopNRate.3.10"
+ INDEX { hostTopNReport, hostTopNIndex }
+ ::= { hostTopNTable 1 }
+
+ HostTopNEntry ::= SEQUENCE {
+ hostTopNReport INTEGER (1..65535),
+ hostTopNIndex INTEGER (1..65535),
+ hostTopNAddress OCTET STRING,
+ hostTopNRate INTEGER
+ }
+
+ hostTopNReport OBJECT-TYPE
+ SYNTAX INTEGER (1..65535)
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "This object identifies the top N report of which
+ this entry is a part. The set of hosts
+ identified by a particular value of this
+ object is part of the same report as identified
+ by the same value of the hostTopNControlIndex object."
+ ::= { hostTopNEntry 1 }
+
+ hostTopNIndex OBJECT-TYPE
+ SYNTAX INTEGER (1..65535)
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "An index that uniquely identifies an entry in
+ the hostTopN table among those in the same report.
+ This index is between 1 and N, where N is the
+ number of entries in this table. Increasing values
+ of hostTopNIndex shall be assigned to entries with
+ decreasing values of hostTopNRate until index N
+ is assigned to the entry with the lowest value of
+ hostTopNRate or there are no more hostTopNEntries."
+ ::= { hostTopNEntry 2 }
+
+ hostTopNAddress OBJECT-TYPE
+ SYNTAX OCTET STRING
+ ACCESS read-only
+ STATUS mandatory
+
+
+ DESCRIPTION
+ "The physical address of this host."
+ ::= { hostTopNEntry 3 }
+
+ hostTopNRate OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The amount of change in the selected variable
+ during this sampling interval. The selected
+ variable is this host's instance of the object
+ selected by hostTopNRateBase."
+ ::= { hostTopNEntry 4 }
+
+
+ -- The Matrix Group
+
+ -- Implementation of the Matrix group is optional.
+ --
+ -- The Matrix group consists of the matrixControlTable,
+ -- matrixSDTable and the matrixDSTable. These tables
+ -- store statistics for a particular conversation
+ -- between two addresses. As the device detects a new
+ -- conversation, including those to a non-unicast
+ -- address, it creates a new entry in both of the
+ -- matrix tables. It must only create new entries
+ -- based on information received in good packets. If
+ -- the monitoring device finds itself short of
+ -- resources, it may delete entries as needed. It is
+ -- suggested that the device delete the least recently
+ -- used entries first.
+
+ matrixControlTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF MatrixControlEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A list of information entries for the
+ traffic matrix on each interface."
+ ::= { matrix 1 }
+
+ matrixControlEntry OBJECT-TYPE
+ SYNTAX MatrixControlEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "Information about a traffic matrix on a particular
+
+
+ interface. For example, an instance of the
+ matrixControlLastDeleteTime object might be named
+ matrixControlLastDeleteTime.1"
+ INDEX { matrixControlIndex }
+ ::= { matrixControlTable 1 }
+
+ MatrixControlEntry ::= SEQUENCE {
+ matrixControlIndex INTEGER (1..65535),
+ matrixControlDataSource OBJECT IDENTIFIER,
+ matrixControlTableSize INTEGER,
+ matrixControlLastDeleteTime TimeTicks,
+ matrixControlOwner OwnerString,
+ matrixControlStatus EntryStatus
+ }
+
+ matrixControlIndex OBJECT-TYPE
+ SYNTAX INTEGER (1..65535)
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "An index that uniquely identifies an entry in the
+ matrixControl table. Each such entry defines
+ a function that discovers conversations on a
+ particular interface and places statistics about
+ them in the matrixSDTable and the matrixDSTable on
+ behalf of this matrixControlEntry."
+ ::= { matrixControlEntry 1 }
+
+ matrixControlDataSource OBJECT-TYPE
+ SYNTAX OBJECT IDENTIFIER
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "This object identifies the source of
+ the data from which this entry creates a traffic
+ matrix. This source can be any interface on this
+ device. In order to identify a particular
+ interface, this object shall identify the instance
+ of the ifIndex object, defined in RFC 1213 and RFC
+ 1573 [4,6], for the desired interface. For example,
+ if an entry were to receive data from interface #1,
+ this object would be set to ifIndex.1.
+
+ The statistics in this group reflect all packets
+ on the local network segment attached to the
+ identified interface.
+
+ An agent may or may not be able to tell if
+
+
+ fundamental changes to the media of the interface
+ have occurred and necessitate an invalidation of
+ this entry. For example, a hot-pluggable ethernet
+ card could be pulled out and replaced by a
+ token-ring card. In such a case, if the agent has
+ such knowledge of the change, it is recommended that
+ it invalidate this entry.
+
+ This object may not be modified if the associated
+ matrixControlStatus object is equal to valid(1)."
+ ::= { matrixControlEntry 2 }
+
+ matrixControlTableSize OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of matrixSDEntries in the matrixSDTable
+ for this interface. This must also be the value of
+ the number of entries in the matrixDSTable for this
+ interface."
+ ::= { matrixControlEntry 3 }
+
+ matrixControlLastDeleteTime OBJECT-TYPE
+ SYNTAX TimeTicks
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The value of sysUpTime when the last entry
+ was deleted from the portion of the matrixSDTable
+ or matrixDSTable associated with this
+ matrixControlEntry. If no deletions have occurred,
+ this value shall be zero."
+ ::= { matrixControlEntry 4 }
+
+ matrixControlOwner OBJECT-TYPE
+ SYNTAX OwnerString
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The entity that configured this entry and is
+ therefore using the resources assigned to it."
+ ::= { matrixControlEntry 5 }
+
+ matrixControlStatus OBJECT-TYPE
+ SYNTAX EntryStatus
+ ACCESS read-write
+ STATUS mandatory
+
+
+ DESCRIPTION
+ "The status of this matrixControl entry.
+
+ If this object is not equal to valid(1), all
+ associated entries in the matrixSDTable and the
+ matrixDSTable shall be deleted by the agent."
+ ::= { matrixControlEntry 6 }
+
+ matrixSDTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF MatrixSDEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A list of traffic matrix entries indexed by
+ source and destination MAC address."
+ ::= { matrix 2 }
+
+ matrixSDEntry OBJECT-TYPE
+ SYNTAX MatrixSDEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A collection of statistics for communications between
+ two addresses on a particular interface. For example,
+ an instance of the matrixSDPkts object might be named
+ matrixSDPkts.1.6.8.0.32.27.3.176.6.8.0.32.10.8.113"
+ INDEX { matrixSDIndex,
+ matrixSDSourceAddress, matrixSDDestAddress }
+ ::= { matrixSDTable 1 }
+
+ MatrixSDEntry ::= SEQUENCE {
+ matrixSDSourceAddress OCTET STRING,
+ matrixSDDestAddress OCTET STRING,
+ matrixSDIndex INTEGER (1..65535),
+ matrixSDPkts Counter,
+ matrixSDOctets Counter,
+ matrixSDErrors Counter
+ }
+
+ matrixSDSourceAddress OBJECT-TYPE
+ SYNTAX OCTET STRING
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The source physical address."
+ ::= { matrixSDEntry 1 }
+
+ matrixSDDestAddress OBJECT-TYPE
+
+
+ SYNTAX OCTET STRING
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The destination physical address."
+ ::= { matrixSDEntry 2 }
+
+ matrixSDIndex OBJECT-TYPE
+ SYNTAX INTEGER (1..65535)
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The set of collected matrix statistics of which
+ this entry is a part. The set of matrix statistics
+ identified by a particular value of this index
+ is associated with the same matrixControlEntry
+ as identified by the same value of
+ matrixControlIndex."
+ ::= { matrixSDEntry 3 }
+
+ matrixSDPkts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of packets transmitted from the source
+ address to the destination address (this number
+ includes bad packets)."
+ ::= { matrixSDEntry 4 }
+
+ matrixSDOctets OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of octets (excluding framing bits but
+ including FCS octets) contained in all packets
+ transmitted from the source address to the
+ destination address."
+ ::= { matrixSDEntry 5 }
+
+ matrixSDErrors OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of bad packets transmitted from
+ the source address to the destination address."
+
+
+ ::= { matrixSDEntry 6 }
+
+
+ -- Traffic matrix tables from destination to source
+
+ matrixDSTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF MatrixDSEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A list of traffic matrix entries indexed by
+ destination and source MAC address."
+ ::= { matrix 3 }
+
+ matrixDSEntry OBJECT-TYPE
+ SYNTAX MatrixDSEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A collection of statistics for communications between
+ two addresses on a particular interface. For example,
+ an instance of the matrixSDPkts object might be named
+ matrixSDPkts.1.6.8.0.32.10.8.113.6.8.0.32.27.3.176"
+ INDEX { matrixDSIndex,
+ matrixDSDestAddress, matrixDSSourceAddress }
+ ::= { matrixDSTable 1 }
+
+ MatrixDSEntry ::= SEQUENCE {
+ matrixDSSourceAddress OCTET STRING,
+ matrixDSDestAddress OCTET STRING,
+ matrixDSIndex INTEGER (1..65535),
+ matrixDSPkts Counter,
+ matrixDSOctets Counter,
+ matrixDSErrors Counter
+ }
+
+ matrixDSSourceAddress OBJECT-TYPE
+ SYNTAX OCTET STRING
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The source physical address."
+ ::= { matrixDSEntry 1 }
+
+ matrixDSDestAddress OBJECT-TYPE
+ SYNTAX OCTET STRING
+ ACCESS read-only
+ STATUS mandatory
+
+
+ DESCRIPTION
+ "The destination physical address."
+ ::= { matrixDSEntry 2 }
+
+ matrixDSIndex OBJECT-TYPE
+ SYNTAX INTEGER (1..65535)
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The set of collected matrix statistics of which
+ this entry is a part. The set of matrix statistics
+ identified by a particular value of this index
+ is associated with the same matrixControlEntry
+ as identified by the same value of
+ matrixControlIndex."
+ ::= { matrixDSEntry 3 }
+
+ matrixDSPkts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of packets transmitted from the source
+ address to the destination address (this number
+ includes bad packets)."
+ ::= { matrixDSEntry 4 }
+
+ matrixDSOctets OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of octets (excluding framing bits
+ but including FCS octets) contained in all packets
+ transmitted from the source address to the
+ destination address."
+ ::= { matrixDSEntry 5 }
+
+ matrixDSErrors OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of bad packets transmitted from
+ the source address to the destination address."
+ ::= { matrixDSEntry 6 }
+
+
+
+
+ -- The Filter Group
+
+ -- Implementation of the Filter group is optional.
+ --
+ -- The Filter group allows packets to be captured with an
+ -- arbitrary filter expression. A logical data and
+ -- event stream or "channel" is formed by the packets
+ -- that match the filter expression.
+ --
+ -- This filter mechanism allows the creation of an arbitrary
+ -- logical expression with which to filter packets. Each
+ -- filter associated with a channel is OR'ed with the others.
+ -- Within a filter, any bits checked in the data and status
+ -- are AND'ed with respect to other bits in the same filter.
+ -- The NotMask also allows for checking for inequality.
+ -- Finally, the channelAcceptType object allows for
+ -- inversion of the whole equation.
+ --
+ -- If a management station wishes to receive a trap to alert
+ -- it that new packets have been captured and are available
+ -- for download, it is recommended that it set up an alarm
+ -- entry that monitors the value of the relevant
+ -- channelMatches instance.
+ --
+ -- The channel can be turned on or off, and can also
+ -- generate events when packets pass through it.
+
+ filterTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF FilterEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A list of packet filter entries."
+ ::= { filter 1 }
+
+ filterEntry OBJECT-TYPE
+ SYNTAX FilterEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A set of parameters for a packet filter applied on a
+ particular interface. As an example, an instance of
+ the filterPktData object might be named
+ filterPktData.12"
+ INDEX { filterIndex }
+ ::= { filterTable 1 }
+
+
+
+
+ FilterEntry ::= SEQUENCE {
+ filterIndex INTEGER (1..65535),
+ filterChannelIndex INTEGER (1..65535),
+ filterPktDataOffset INTEGER,
+ filterPktData OCTET STRING,
+ filterPktDataMask OCTET STRING,
+ filterPktDataNotMask OCTET STRING,
+ filterPktStatus INTEGER,
+ filterPktStatusMask INTEGER,
+ filterPktStatusNotMask INTEGER,
+ filterOwner OwnerString,
+ filterStatus EntryStatus
+ }
+
+ filterIndex OBJECT-TYPE
+ SYNTAX INTEGER (1..65535)
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "An index that uniquely identifies an entry
+ in the filter table. Each such entry defines
+ one filter that is to be applied to every packet
+ received on an interface."
+ ::= { filterEntry 1 }
+
+ filterChannelIndex OBJECT-TYPE
+ SYNTAX INTEGER (1..65535)
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "This object identifies the channel of which this
+ filter is a part. The filters identified by a
+ particular value of this object are associated with
+ the same channel as identified by the same value of
+ the channelIndex object."
+ ::= { filterEntry 2 }
+
+ filterPktDataOffset OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The offset from the beginning of each packet where
+ a match of packet data will be attempted. This offset
+ is measured from the point in the physical layer
+ packet after the framing bits, if any. For example,
+ in an Ethernet frame, this point is at the beginning
+ of the destination MAC address.
+
+
+ This object may not be modified if the associated
+ filterStatus object is equal to valid(1)."
+ DEFVAL { 0 }
+ ::= { filterEntry 3 }
+
+ filterPktData OBJECT-TYPE
+ SYNTAX OCTET STRING
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The data that is to be matched with the input
+ packet. For each packet received, this filter and
+ the accompanying filterPktDataMask and
+ filterPktDataNotMask will be adjusted for the
+ offset. The only bits relevant to this match
+ algorithm are those that have the corresponding
+ filterPktDataMask bit equal to one. The following
+ three rules are then applied to every packet:
+
+ (1) If the packet is too short and does not have data
+ corresponding to part of the filterPktData, the
+ packet will fail this data match.
+
+ (2) For each relevant bit from the packet with the
+ corresponding filterPktDataNotMask bit set to
+ zero, if the bit from the packet is not equal to
+ the corresponding bit from the filterPktData,
+ then the packet will fail this data match.
+
+ (3) If for every relevant bit from the packet with the
+ corresponding filterPktDataNotMask bit set to one,
+ the bit from the packet is equal to the
+ corresponding bit from the filterPktData, then
+ the packet will fail this data match.
+
+ Any packets that have not failed any of the three
+ matches above have passed this data match. In
+ particular, a zero length filter will match any
+ packet.
+
+ This object may not be modified if the associated
+ filterStatus object is equal to valid(1)."
+ ::= { filterEntry 4 }
+
+ filterPktDataMask OBJECT-TYPE
+ SYNTAX OCTET STRING
+ ACCESS read-write
+ STATUS mandatory
+
+
+ DESCRIPTION
+ "The mask that is applied to the match process.
+ After adjusting this mask for the offset, only those
+ bits in the received packet that correspond to bits
+ set in this mask are relevant for further processing
+ by the match algorithm. The offset is applied to
+ filterPktDataMask in the same way it is applied to the
+ filter. For the purposes of the matching algorithm,
+ if the associated filterPktData object is longer
+ than this mask, this mask is conceptually extended
+ with '1' bits until it reaches the length of the
+ filterPktData object.
+
+ This object may not be modified if the associated
+ filterStatus object is equal to valid(1)."
+ ::= { filterEntry 5 }
+
+ filterPktDataNotMask OBJECT-TYPE
+ SYNTAX OCTET STRING
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The inversion mask that is applied to the match
+ process. After adjusting this mask for the offset,
+ those relevant bits in the received packet that
+ correspond to bits cleared in this mask must all be
+ equal to their corresponding bits in the
+ filterPktData object for the packet to be accepted.
+ In addition, at least one of those relevant bits in
+ the received packet that correspond to bits set in
+ this mask must be different to its corresponding bit
+ in the filterPktData object.
+
+ For the purposes of the matching algorithm, if the
+ associated filterPktData object is longer than this
+ mask, this mask is conceptually extended with '0'
+ bits until it reaches the length of the
+ filterPktData object.
+
+ This object may not be modified if the associated
+ filterStatus object is equal to valid(1)."
+ ::= { filterEntry 6 }
+
+ filterPktStatus OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+
+
+ "The status that is to be matched with the input
+ packet. The only bits relevant to this match
+ algorithm are those that have the corresponding
+ filterPktStatusMask bit equal to one. The following
+ two rules are then applied to every packet:
+
+ (1) For each relevant bit from the packet status
+ with the corresponding filterPktStatusNotMask bit
+ set to zero, if the bit from the packet status is
+ not equal to the corresponding bit from the
+ filterPktStatus, then the packet will fail this
+ status match.
+
+ (2) If for every relevant bit from the packet status
+ with the corresponding filterPktStatusNotMask bit
+ set to one, the bit from the packet status is
+ equal to the corresponding bit from the
+ filterPktStatus, then the packet will fail this
+ status match.
+
+ Any packets that have not failed either of the two
+ matches above have passed this status match. In
+ particular, a zero length status filter will match any
+ packet's status.
+
+ The value of the packet status is a sum. This sum
+ initially takes the value zero. Then, for each
+ error, E, that has been discovered in this packet,
+ 2 raised to a value representing E is added to the
+ sum. The errors and the bits that represent them are
+ dependent on the media type of the interface that
+ this channel is receiving packets from.
+
+ The errors defined for a packet captured off of an
+ Ethernet interface are as follows:
+
+ bit # Error
+ 0 Packet is longer than 1518 octets
+ 1 Packet is shorter than 64 octets
+ 2 Packet experienced a CRC or Alignment
+ error
+
+ For example, an Ethernet fragment would have a
+ value of 6 (2^1 + 2^2).
+
+ As this MIB is expanded to new media types, this
+ object will have other media-specific errors
+ defined.
+
+
+ For the purposes of this status matching algorithm,
+ if the packet status is longer than this
+ filterPktStatus object, this object is conceptually
+ extended with '0' bits until it reaches the size of
+ the packet status.
+
+ This object may not be modified if the associated
+ filterStatus object is equal to valid(1)."
+ ::= { filterEntry 7 }
+
+ filterPktStatusMask OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The mask that is applied to the status match
+ process. Only those bits in the received packet
+ that correspond to bits set in this mask are
+ relevant for further processing by the status match
+ algorithm. For the purposes of the matching
+ algorithm, if the associated filterPktStatus object
+ is longer than this mask, this mask is conceptually
+ extended with '1' bits until it reaches the size of
+ the filterPktStatus. In addition, if a packet
+ status is longer than this mask, this mask is
+ conceptually extended with '0' bits until it reaches
+ the size of the packet status.
+
+ This object may not be modified if the associated
+ filterStatus object is equal to valid(1)."
+ ::= { filterEntry 8 }
+
+ filterPktStatusNotMask OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The inversion mask that is applied to the status
+ match process. Those relevant bits in the received
+ packet status that correspond to bits cleared in
+ this mask must all be equal to their corresponding
+ bits in the filterPktStatus object for the packet to
+ be accepted. In addition, at least one of those
+ relevant bits in the received packet status that
+ correspond to bits set in this mask must be
+ different to its corresponding bit in the
+ filterPktStatus object for the packet to be
+ accepted.
+
+
+ For the purposes of the matching algorithm, if the
+ associated filterPktStatus object or a packet status
+ is longer than this mask, this mask is conceptually
+ extended with '0' bits until it reaches the longer
+ of the lengths of the filterPktStatus object and the
+ packet status.
+
+ This object may not be modified if the associated
+ filterStatus object is equal to valid(1)."
+ ::= { filterEntry 9 }
+
+ filterOwner OBJECT-TYPE
+ SYNTAX OwnerString
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The entity that configured this entry and is
+ therefore using the resources assigned to it."
+ ::= { filterEntry 10 }
+
+ filterStatus OBJECT-TYPE
+ SYNTAX EntryStatus
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The status of this filter entry."
+ ::= { filterEntry 11 }
+
+ channelTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF ChannelEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A list of packet channel entries."
+ ::= { filter 2 }
+
+ channelEntry OBJECT-TYPE
+ SYNTAX ChannelEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A set of parameters for a packet channel applied on a
+ particular interface. As an example, an instance of
+ the channelMatches object might be named
+ channelMatches.3"
+ INDEX { channelIndex }
+ ::= { channelTable 1 }
+
+
+
+ ChannelEntry ::= SEQUENCE {
+ channelIndex INTEGER (1..65535),
+ channelIfIndex INTEGER (1..65535),
+ channelAcceptType INTEGER,
+ channelDataControl INTEGER,
+ channelTurnOnEventIndex INTEGER (0..65535),
+ channelTurnOffEventIndex INTEGER (0..65535),
+ channelEventIndex INTEGER (0..65535),
+ channelEventStatus INTEGER,
+ channelMatches Counter,
+ channelDescription DisplayString (SIZE (0..127)),
+ channelOwner OwnerString,
+ channelStatus EntryStatus
+ }
+
+ channelIndex OBJECT-TYPE
+ SYNTAX INTEGER (1..65535)
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "An index that uniquely identifies an entry in the
+ channel table. Each such entry defines one channel,
+ a logical data and event stream.
+
+ It is suggested that before creating a channel, an
+ application should scan all instances of the
+ filterChannelIndex object to make sure that there
+ are no pre-existing filters that would be
+ inadvertently be linked to the channel."
+ ::= { channelEntry 1 }
+
+ channelIfIndex OBJECT-TYPE
+ SYNTAX INTEGER (1..65535)
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The value of this object uniquely identifies the
+ interface on this remote network monitoring device
+ to which the associated filters are applied to allow
+ data into this channel. The interface identified by
+ a particular value of this object is the same
+ interface as identified by the same value of the
+ ifIndex object, defined in RFC 1213 and RFC 1573
+ [4,6].
+
+ The filters in this group are applied to all packets
+ on the local network segment attached to the
+ identified interface.
+
+
+ An agent may or may not be able to tell if
+ fundamental changes to the media of the interface
+ have occurred and necessitate an invalidation of
+ this entry. For example, a hot-pluggable ethernet
+ card could be pulled out and replaced by a
+ token-ring card. In such a case, if the agent has
+ such knowledge of the change, it is recommended that
+ it invalidate this entry.
+
+ This object may not be modified if the associated
+ channelStatus object is equal to valid(1)."
+ ::= { channelEntry 2 }
+
+ channelAcceptType OBJECT-TYPE
+ SYNTAX INTEGER {
+ acceptMatched(1),
+ acceptFailed(2)
+ }
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "This object controls the action of the filters
+ associated with this channel. If this object is equal
+ to acceptMatched(1), packets will be accepted to this
+ channel if they are accepted by both the packet data
+ and packet status matches of an associated filter. If
+ this object is equal to acceptFailed(2), packets will
+ be accepted to this channel only if they fail either
+ the packet data match or the packet status match of
+ each of the associated filters.
+
+ In particular, a channel with no associated filters
+ will match no packets if set to acceptMatched(1)
+ case and will match all packets in the
+ acceptFailed(2) case.
+
+ This object may not be modified if the associated
+ channelStatus object is equal to valid(1)."
+ ::= { channelEntry 3 }
+
+ channelDataControl OBJECT-TYPE
+ SYNTAX INTEGER {
+ on(1),
+ off(2)
+ }
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+
+
+ "This object controls the flow of data through this
+ channel. If this object is on(1), data, status and
+ events flow through this channel. If this object is
+ off(2), data, status and events will not flow
+ through this channel."
+ DEFVAL { off }
+ ::= { channelEntry 4 }
+
+ channelTurnOnEventIndex OBJECT-TYPE
+ SYNTAX INTEGER (0..65535)
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The value of this object identifies the event
+ that is configured to turn the associated
+ channelDataControl from off to on when the event is
+ generated. The event identified by a particular value
+ of this object is the same event as identified by the
+ same value of the eventIndex object. If there is no
+ corresponding entry in the eventTable, then no
+ association exists. In fact, if no event is intended
+ for this channel, channelTurnOnEventIndex must be
+ set to zero, a non-existent event index.
+
+ This object may not be modified if the associated
+ channelStatus object is equal to valid(1)."
+ ::= { channelEntry 5 }
+
+ channelTurnOffEventIndex OBJECT-TYPE
+ SYNTAX INTEGER (0..65535)
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The value of this object identifies the event
+ that is configured to turn the associated
+ channelDataControl from on to off when the event is
+ generated. The event identified by a particular value
+ of this object is the same event as identified by the
+ same value of the eventIndex object. If there is no
+ corresponding entry in the eventTable, then no
+ association exists. In fact, if no event is intended
+ for this channel, channelTurnOffEventIndex must be
+ set to zero, a non-existent event index.
+
+ This object may not be modified if the associated
+ channelStatus object is equal to valid(1)."
+ ::= { channelEntry 6 }
+
+
+
+ channelEventIndex OBJECT-TYPE
+ SYNTAX INTEGER (0..65535)
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The value of this object identifies the event
+ that is configured to be generated when the
+ associated channelDataControl is on and a packet
+ is matched. The event identified by a particular
+ value of this object is the same event as identified
+ by the same value of the eventIndex object. If
+ there is no corresponding entry in the eventTable,
+ then no association exists. In fact, if no event is
+ intended for this channel, channelEventIndex must be
+ set to zero, a non-existent event index.
+
+ This object may not be modified if the associated
+ channelStatus object is equal to valid(1)."
+ ::= { channelEntry 7 }
+
+ channelEventStatus OBJECT-TYPE
+ SYNTAX INTEGER {
+ eventReady(1),
+ eventFired(2),
+ eventAlwaysReady(3)
+ }
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The event status of this channel.
+
+ If this channel is configured to generate events
+ when packets are matched, a means of controlling
+ the flow of those events is often needed. When
+ this object is equal to eventReady(1), a single
+ event may be generated, after which this object
+ will be set by the probe to eventFired(2). While
+ in the eventFired(2) state, no events will be
+ generated until the object is modified to
+ eventReady(1) (or eventAlwaysReady(3)). The
+ management station can thus easily respond to a
+ notification of an event by re-enabling this object.
+
+ If the management station wishes to disable this
+ flow control and allow events to be generated
+ at will, this object may be set to
+ eventAlwaysReady(3). Disabling the flow control
+ is discouraged as it can result in high network
+
+
+ traffic or other performance problems."
+ DEFVAL { eventReady }
+ ::= { channelEntry 8 }
+
+ channelMatches OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of times this channel has matched a
+ packet. Note that this object is updated even when
+ channelDataControl is set to off."
+ ::= { channelEntry 9 }
+
+ channelDescription OBJECT-TYPE
+ SYNTAX DisplayString (SIZE (0..127))
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "A comment describing this channel."
+ ::= { channelEntry 10 }
+
+ channelOwner OBJECT-TYPE
+ SYNTAX OwnerString
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The entity that configured this entry and is
+ therefore using the resources assigned to it."
+ ::= { channelEntry 11 }
+
+ channelStatus OBJECT-TYPE
+ SYNTAX EntryStatus
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The status of this channel entry."
+ ::= { channelEntry 12 }
+
+
+ -- The Packet Capture Group
+
+ -- Implementation of the Packet Capture group is optional.
+ --
+ -- The Packet Capture Group requires implementation of the
+ -- Filter Group.
+ --
+ -- The Packet Capture group allows packets to be captured
+
+
+ -- upon a filter match. The bufferControlTable controls
+ -- the captured packets output from a channel that is
+ -- associated with it. The captured packets are placed
+ -- in entries in the captureBufferTable. These entries are
+ -- associated with the bufferControlEntry on whose behalf they
+ -- were stored.
+
+ bufferControlTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF BufferControlEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A list of buffers control entries."
+ ::= { capture 1 }
+
+ bufferControlEntry OBJECT-TYPE
+ SYNTAX BufferControlEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A set of parameters that control the collection of
+ a stream of packets that have matched filters. As
+ an example, an instance of the
+ bufferControlCaptureSliceSize object might be named
+ bufferControlCaptureSliceSize.3"
+ INDEX { bufferControlIndex }
+ ::= { bufferControlTable 1 }
+
+ BufferControlEntry ::= SEQUENCE {
+ bufferControlIndex INTEGER (1..65535),
+ bufferControlChannelIndex INTEGER (1..65535),
+ bufferControlFullStatus INTEGER,
+ bufferControlFullAction INTEGER,
+ bufferControlCaptureSliceSize INTEGER,
+ bufferControlDownloadSliceSize INTEGER,
+ bufferControlDownloadOffset INTEGER,
+ bufferControlMaxOctetsRequested INTEGER,
+ bufferControlMaxOctetsGranted INTEGER,
+ bufferControlCapturedPackets INTEGER,
+ bufferControlTurnOnTime TimeTicks,
+ bufferControlOwner OwnerString,
+ bufferControlStatus EntryStatus
+ }
+
+ bufferControlIndex OBJECT-TYPE
+ SYNTAX INTEGER (1..65535)
+ ACCESS read-only
+ STATUS mandatory
+
+
+ DESCRIPTION
+ "An index that uniquely identifies an entry
+ in the bufferControl table. The value of this
+ index shall never be zero. Each such
+ entry defines one set of packets that is
+ captured and controlled by one or more filters."
+ ::= { bufferControlEntry 1 }
+
+ bufferControlChannelIndex OBJECT-TYPE
+ SYNTAX INTEGER (1..65535)
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "An index that identifies the channel that is the
+ source of packets for this bufferControl table.
+ The channel identified by a particular value of this
+ index is the same as identified by the same value of
+ the channelIndex object.
+
+ This object may not be modified if the associated
+ bufferControlStatus object is equal to valid(1)."
+ ::= { bufferControlEntry 2 }
+
+ bufferControlFullStatus OBJECT-TYPE
+ SYNTAX INTEGER {
+ spaceAvailable(1),
+ full(2)
+ }
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "This object shows whether the buffer has room to
+ accept new packets or if it is full.
+
+ If the status is spaceAvailable(1), the buffer is
+ accepting new packets normally. If the status is
+ full(2) and the associated bufferControlFullAction
+ object is wrapWhenFull, the buffer is accepting new
+ packets by deleting enough of the oldest packets
+ to make room for new ones as they arrive. Otherwise,
+ if the status is full(2) and the
+ bufferControlFullAction object is lockWhenFull,
+ then the buffer has stopped collecting packets.
+
+ When this object is set to full(2) the probe must
+ not later set it to spaceAvailable(1) except in the
+ case of a significant gain in resources such as
+ an increase of bufferControlOctetsGranted. In
+
+
+ particular, the wrap-mode action of deleting old
+ packets to make room for newly arrived packets
+ must not affect the value of this object."
+ ::= { bufferControlEntry 3 }
+
+ bufferControlFullAction OBJECT-TYPE
+ SYNTAX INTEGER {
+ lockWhenFull(1),
+ wrapWhenFull(2) -- FIFO
+ }
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "Controls the action of the buffer when it
+ reaches the full status. When in the lockWhenFull(1)
+ state and a packet is added to the buffer that
+ fills the buffer, the bufferControlFullStatus will
+ be set to full(2) and this buffer will stop capturing
+ packets."
+ ::= { bufferControlEntry 4 }
+
+ bufferControlCaptureSliceSize OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The maximum number of octets of each packet
+ that will be saved in this capture buffer.
+ For example, if a 1500 octet packet is received by
+ the probe and this object is set to 500, then only
+ 500 octets of the packet will be stored in the
+ associated capture buffer. If this variable is set
+ to 0, the capture buffer will save as many octets
+ as is possible.
+
+ This object may not be modified if the associated
+ bufferControlStatus object is equal to valid(1)."
+ DEFVAL { 100 }
+ ::= { bufferControlEntry 5 }
+
+ bufferControlDownloadSliceSize OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The maximum number of octets of each packet
+ in this capture buffer that will be returned in
+ an SNMP retrieval of that packet. For example,
+
+
+ if 500 octets of a packet have been stored in the
+ associated capture buffer, the associated
+ bufferControlDownloadOffset is 0, and this
+ object is set to 100, then the captureBufferPacket
+ object that contains the packet will contain only
+ the first 100 octets of the packet.
+
+ A prudent manager will take into account possible
+ interoperability or fragmentation problems that may
+ occur if the download slice size is set too large.
+ In particular, conformant SNMP implementations are not
+ required to accept messages whose length exceeds 484
+ octets, although they are encouraged to support larger
+ datagrams whenever feasible."
+ DEFVAL { 100 }
+ ::= { bufferControlEntry 6 }
+
+ bufferControlDownloadOffset OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The offset of the first octet of each packet
+ in this capture buffer that will be returned in
+ an SNMP retrieval of that packet. For example,
+ if 500 octets of a packet have been stored in the
+ associated capture buffer and this object is set to
+ 100, then the captureBufferPacket object that
+ contains the packet will contain bytes starting
+ 100 octets into the packet."
+ DEFVAL { 0 }
+ ::= { bufferControlEntry 7 }
+
+ bufferControlMaxOctetsRequested OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The requested maximum number of octets to be
+ saved in this captureBuffer, including any
+ implementation-specific overhead. If this variable
+ is set to -1, the capture buffer will save as many
+ octets as is possible.
+
+ When this object is created or modified, the probe
+ should set bufferControlMaxOctetsGranted as closely
+ to this object as is possible for the particular probe
+ implementation and available resources. However, if
+
+
+ the object has the special value of -1, the probe
+ must set bufferControlMaxOctetsGranted to -1."
+ DEFVAL { -1 }
+ ::= { bufferControlEntry 8 }
+
+ bufferControlMaxOctetsGranted OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The maximum number of octets that can be
+ saved in this captureBuffer, including overhead.
+ If this variable is -1, the capture buffer will save
+ as many octets as possible.
+
+ When the bufferControlMaxOctetsRequested object is
+ created or modified, the probe should set this object
+ as closely to the requested value as is possible for
+ the particular probe implementation and available
+ resources.
+ However, if the request object has the special value
+ of -1, the probe must set this object to -1.
+ The probe must not lower this value except as a result
+ of a modification to the associated
+ bufferControlMaxOctetsRequested object.
+
+ When this maximum number of octets is reached
+ and a new packet is to be added to this
+ capture buffer and the corresponding
+ bufferControlFullAction is set to wrapWhenFull(2),
+ enough of the oldest packets associated with this
+ capture buffer shall be deleted by the agent so
+ that the new packet can be added. If the
+ corresponding bufferControlFullAction is set to
+ lockWhenFull(1), the new packet shall be discarded.
+ In either case, the probe must set
+ bufferControlFullStatus to full(2).
+
+ When the value of this object changes to a value less
+ than the current value, entries are deleted from
+ the captureBufferTable associated with this
+ bufferControlEntry. Enough of the
+ oldest of these captureBufferEntries shall be
+ deleted by the agent so that the number of octets
+ used remains less than or equal to the new value of
+ this object.
+
+ When the value of this object changes to a value
+
+
+ greater than the current value, the number of
+ associated captureBufferEntries may be allowed to
+ grow."
+ ::= { bufferControlEntry 9 }
+
+ bufferControlCapturedPackets OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of packets currently in this
+ captureBuffer."
+ ::= { bufferControlEntry 10 }
+
+ bufferControlTurnOnTime OBJECT-TYPE
+ SYNTAX TimeTicks
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The value of sysUpTime when this capture buffer was
+ first turned on."
+ ::= { bufferControlEntry 11 }
+
+ bufferControlOwner OBJECT-TYPE
+ SYNTAX OwnerString
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The entity that configured this entry and is
+ therefore using the resources assigned to it."
+ ::= { bufferControlEntry 12 }
+
+ bufferControlStatus OBJECT-TYPE
+ SYNTAX EntryStatus
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The status of this buffer Control Entry."
+ ::= { bufferControlEntry 13 }
+
+ captureBufferTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF CaptureBufferEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A list of packets captured off of a channel."
+ ::= { capture 2 }
+
+
+
+ captureBufferEntry OBJECT-TYPE
+ SYNTAX CaptureBufferEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A packet captured off of an attached network. As an
+ example, an instance of the captureBufferPacketData
+ object might be named captureBufferPacketData.3.1783"
+ INDEX { captureBufferControlIndex, captureBufferIndex }
+ ::= { captureBufferTable 1 }
+
+ CaptureBufferEntry ::= SEQUENCE {
+ captureBufferControlIndex INTEGER (1..65535),
+ captureBufferIndex INTEGER (1..2147483647),
+ captureBufferPacketID INTEGER,
+ captureBufferPacketData OCTET STRING,
+ captureBufferPacketLength INTEGER,
+ captureBufferPacketTime INTEGER,
+ captureBufferPacketStatus INTEGER
+ }
+
+ captureBufferControlIndex OBJECT-TYPE
+ SYNTAX INTEGER (1..65535)
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The index of the bufferControlEntry with which
+ this packet is associated."
+ ::= { captureBufferEntry 1 }
+
+ captureBufferIndex OBJECT-TYPE
+ SYNTAX INTEGER (1..2147483647)
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "An index that uniquely identifies an entry
+ in the captureBuffer table associated with a
+ particular bufferControlEntry. This index will
+ start at 1 and increase by one for each new packet
+ added with the same captureBufferControlIndex.
+
+ Should this value reach 2147483647, the next packet
+ added with the same captureBufferControlIndex shall
+ cause this value to wrap around to 1."
+ ::= { captureBufferEntry 2 }
+
+ captureBufferPacketID OBJECT-TYPE
+ SYNTAX INTEGER
+
+
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "An index that describes the order of packets
+ that are received on a particular interface.
+ The packetID of a packet captured on an
+ interface is defined to be greater than the
+ packetID's of all packets captured previously on
+ the same interface. As the captureBufferPacketID
+ object has a maximum positive value of 2^31 - 1,
+ any captureBufferPacketID object shall have the
+ value of the associated packet's packetID mod 2^31."
+ ::= { captureBufferEntry 3 }
+
+ captureBufferPacketData OBJECT-TYPE
+ SYNTAX OCTET STRING
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The data inside the packet, starting at the
+ beginning of the packet plus any offset specified in
+ the associated bufferControlDownloadOffset,
+ including any link level headers. The length of the
+ data in this object is the minimum of the length of
+ the captured packet minus the offset, the length of
+ the associated bufferControlCaptureSliceSize minus
+ the offset, and the associated
+ bufferControlDownloadSliceSize. If this minimum is
+ less than zero, this object shall have a length of
+ zero."
+ ::= { captureBufferEntry 4 }
+
+ captureBufferPacketLength OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The actual length (off the wire) of the packet stored
+ in this entry, including FCS octets."
+ ::= { captureBufferEntry 5 }
+
+ captureBufferPacketTime OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of milliseconds that had passed since
+ this capture buffer was first turned on when this
+
+
+ packet was captured."
+ ::= { captureBufferEntry 6 }
+
+ captureBufferPacketStatus OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "A value which indicates the error status of this
+ packet.
+
+ The value of this object is defined in the same way as
+ filterPktStatus. The value is a sum. This sum
+ initially takes the value zero. Then, for each
+ error, E, that has been discovered in this packet,
+ 2 raised to a value representing E is added to the
+ sum.
+
+ The errors defined for a packet captured off of an
+ Ethernet interface are as follows:
+
+ bit # Error
+ 0 Packet is longer than 1518 octets
+ 1 Packet is shorter than 64 octets
+ 2 Packet experienced a CRC or Alignment
+ error
+ 3 First packet in this capture buffer after
+ it was detected that some packets were
+ not processed correctly.
+ 4 Packet's order in buffer is only
+ approximate (May only be set for packets
+ sent from the probe)
+
+ For example, an Ethernet fragment would have a
+ value of 6 (2^1 + 2^2).
+
+ As this MIB is expanded to new media types, this
+ object will have other media-specific errors defined."
+ ::= { captureBufferEntry 7 }
+
+
+ -- The Event Group
+
+ -- Implementation of the Event group is optional.
+ --
+ -- The Event group controls the generation and notification
+ -- of events from this device. Each entry in the eventTable
+ -- describes the parameters of the event that can be
+
+
+ -- triggered. Each event entry is fired by an associated
+ -- condition located elsewhere in the MIB. An event entry
+ -- may also be associated- with a function elsewhere in the
+ -- MIB that will be executed when the event is generated. For
+ -- example, a channel may be turned on or off by the firing
+ -- of an event.
+ --
+ -- Each eventEntry may optionally specify that a log entry
+ -- be created on its behalf whenever the event occurs.
+ -- Each entry may also specify that notification should
+ -- occur by way of SNMP trap messages. In this case, the
+ -- community for the trap message is given in the associated
+ -- eventCommunity object. The enterprise and specific trap
+ -- fields of the trap are determined by the condition that
+ -- triggered the event. Two traps are defined: risingAlarm
+ -- and fallingAlarm. If the eventTable is triggered by a
+ -- condition specified elsewhere, the enterprise and
+ -- specific trap fields must be specified for traps
+ -- generated for that condition.
+
+ eventTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF EventEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A list of events to be generated."
+ ::= { event 1 }
+
+ eventEntry OBJECT-TYPE
+ SYNTAX EventEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A set of parameters that describe an event to be
+ generated when certain conditions are met. As an
+ example, an instance of the eventLastTimeSent object
+ might be named eventLastTimeSent.6"
+ INDEX { eventIndex }
+ ::= { eventTable 1 }
+
+ EventEntry ::= SEQUENCE {
+ eventIndex INTEGER (1..65535),
+ eventDescription DisplayString (SIZE (0..127)),
+ eventType INTEGER,
+ eventCommunity OCTET STRING (SIZE (0..127)),
+ eventLastTimeSent TimeTicks,
+ eventOwner OwnerString,
+ eventStatus EntryStatus
+
+
+ }
+
+ eventIndex OBJECT-TYPE
+ SYNTAX INTEGER (1..65535)
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "An index that uniquely identifies an entry in the
+ event table. Each such entry defines one event that
+ is to be generated when the appropriate conditions
+ occur."
+ ::= { eventEntry 1 }
+
+ eventDescription OBJECT-TYPE
+ SYNTAX DisplayString (SIZE (0..127))
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "A comment describing this event entry."
+ ::= { eventEntry 2 }
+
+ eventType OBJECT-TYPE
+ SYNTAX INTEGER {
+ none(1),
+ log(2),
+ snmp-trap(3), -- send an SNMP trap
+ log-and-trap(4)
+ }
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The type of notification that the probe will make
+ about this event. In the case of log, an entry is
+ made in the log table for each event. In the case of
+ snmp-trap, an SNMP trap is sent to one or more
+ management stations."
+ ::= { eventEntry 3 }
+
+ eventCommunity OBJECT-TYPE
+ SYNTAX OCTET STRING (SIZE (0..127))
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "If an SNMP trap is to be sent, it will be sent to
+ the SNMP community specified by this octet string.
+ In the future this table will be extended to include
+ the party security mechanism. This object shall be
+ set to a string of length zero if it is intended that
+
+
+ that mechanism be used to specify the destination of
+ the trap."
+ ::= { eventEntry 4 }
+
+ eventLastTimeSent OBJECT-TYPE
+ SYNTAX TimeTicks
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The value of sysUpTime at the time this event
+ entry last generated an event. If this entry has
+ not generated any events, this value will be
+ zero."
+ ::= { eventEntry 5 }
+
+ eventOwner OBJECT-TYPE
+ SYNTAX OwnerString
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The entity that configured this entry and is
+ therefore using the resources assigned to it.
+
+ If this object contains a string starting with
+ 'monitor' and has associated entries in the log
+ table, all connected management stations should
+ retrieve those log entries, as they may have
+ significance to all management stations connected to
+ this device"
+ ::= { eventEntry 6 }
+
+ eventStatus OBJECT-TYPE
+ SYNTAX EntryStatus
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The status of this event entry.
+
+ If this object is not equal to valid(1), all
+ associated log entries shall be deleted by the
+ agent."
+ ::= { eventEntry 7 }
+
+ --
+ logTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF LogEntry
+ ACCESS not-accessible
+ STATUS mandatory
+
+
+ DESCRIPTION
+ "A list of events that have been logged."
+ ::= { event 2 }
+
+ logEntry OBJECT-TYPE
+ SYNTAX LogEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A set of data describing an event that has been
+ logged. For example, an instance of the
+ logDescription object might be named
+ logDescription.6.47"
+ INDEX { logEventIndex, logIndex }
+ ::= { logTable 1 }
+
+ LogEntry ::= SEQUENCE {
+ logEventIndex INTEGER (1..65535),
+ logIndex INTEGER (1..2147483647),
+ logTime TimeTicks,
+ logDescription DisplayString (SIZE (0..255))
+ }
+
+ logEventIndex OBJECT-TYPE
+ SYNTAX INTEGER (1..65535)
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The event entry that generated this log
+ entry. The log identified by a particular
+ value of this index is associated with the same
+ eventEntry as identified by the same value
+ of eventIndex."
+ ::= { logEntry 1 }
+
+ logIndex OBJECT-TYPE
+ SYNTAX INTEGER (1..2147483647)
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "An index that uniquely identifies an entry
+ in the log table amongst those generated by the
+ same eventEntries. These indexes are
+ assigned beginning with 1 and increase by one
+ with each new log entry. The association
+ between values of logIndex and logEntries
+ is fixed for the lifetime of each logEntry.
+ The agent may choose to delete the oldest
+
+
+ instances of logEntry as required because of
+ lack of memory. It is an implementation-specific
+ matter as to when this deletion may occur."
+ ::= { logEntry 2 }
+
+ logTime OBJECT-TYPE
+ SYNTAX TimeTicks
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The value of sysUpTime when this log entry was
+ created."
+ ::= { logEntry 3 }
+
+ logDescription OBJECT-TYPE
+ SYNTAX DisplayString (SIZE (0..255))
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "An implementation dependent description of the
+ event that activated this log entry."
+ ::= { logEntry 4 }
+
+ -- These definitions use the TRAP-TYPE macro as
+ -- defined in RFC 1215 [10]
+
+ -- Remote Network Monitoring Traps
+
+ risingAlarm TRAP-TYPE
+ ENTERPRISE rmon
+ VARIABLES { alarmIndex, alarmVariable, alarmSampleType,
+ alarmValue, alarmRisingThreshold }
+ DESCRIPTION
+ "The SNMP trap that is generated when an alarm
+ entry crosses its rising threshold and generates
+ an event that is configured for sending SNMP
+ traps."
+ ::= 1
+
+ fallingAlarm TRAP-TYPE
+ ENTERPRISE rmon
+ VARIABLES { alarmIndex, alarmVariable, alarmSampleType,
+ alarmValue, alarmFallingThreshold }
+ DESCRIPTION
+ "The SNMP trap that is generated when an alarm
+ entry crosses its falling threshold and generates
+ an event that is configured for sending SNMP
+ traps."
+
+
+ ::= 2
+
+ END
+
diff --git a/lib/snmp/test/test-mibs/RMON2-MIB.mib b/lib/snmp/test/test-mibs/RMON2-MIB.mib
new file mode 100644
index 0000000000..827bb38ff9
--- /dev/null
+++ b/lib/snmp/test/test-mibs/RMON2-MIB.mib
@@ -0,0 +1,5450 @@
+RMON2-MIB DEFINITIONS ::= BEGIN
+IMPORTS
+ MODULE-IDENTITY, OBJECT-TYPE, Counter32, Integer32,
+ Gauge32, IpAddress, TimeTicks FROM SNMPv2-SMI
+ TEXTUAL-CONVENTION, RowStatus, DisplayString, TimeStamp
+ FROM SNMPv2-TC
+ MODULE-COMPLIANCE, OBJECT-GROUP FROM SNMPv2-CONF
+ mib-2, ifIndex FROM RFC1213-MIB
+ OwnerString, statistics, history, hosts,
+ matrix, filter, etherStatsEntry, historyControlEntry,
+ hostControlEntry, matrixControlEntry, filterEntry,
+ channelEntry FROM RMON-MIB
+ tokenRing, tokenRingMLStatsEntry, tokenRingPStatsEntry,
+ ringStationControlEntry, sourceRoutingStatsEntry
+ FROM TOKEN-RING-RMON-MIB;
+-- Remote Network Monitoring MIB
+
+rmon MODULE-IDENTITY
+ LAST-UPDATED "9605270000Z"
+ ORGANIZATION "IETF RMON MIB Working Group"
+ CONTACT-INFO
+ "Steve Waldbusser (WG Editor)
+ Postal: International Network Services
+ 650 Castro Street, Suite 260
+ Mountain View, CA 94041
+ Phone: +1 415 254 4251
+
+
+ Andy Bierman (WG Chair)
+ Phone: +1 805 648 2028
+ DESCRIPTION
+ "The MIB module for managing remote monitoring
+ device implementations. This MIB module
+ augments the original RMON MIB as specified in
+ RFC 1757."
+ ::= { mib-2 16 }
+
+-- { rmon 1 } through { rmon 10 } are defined in RMON and
+-- the Token Ring RMON MIB [RFC 1513]
+
+ protocolDir OBJECT IDENTIFIER ::= { rmon 11 }
+ protocolDist OBJECT IDENTIFIER ::= { rmon 12 }
+ addressMap OBJECT IDENTIFIER ::= { rmon 13 }
+ nlHost OBJECT IDENTIFIER ::= { rmon 14 }
+ nlMatrix OBJECT IDENTIFIER ::= { rmon 15 }
+ alHost OBJECT IDENTIFIER ::= { rmon 16 }
+ alMatrix OBJECT IDENTIFIER ::= { rmon 17 }
+ usrHistory OBJECT IDENTIFIER ::= { rmon 18 }
+ probeConfig OBJECT IDENTIFIER ::= { rmon 19 }
+ rmonConformance OBJECT IDENTIFIER ::= { rmon 20 }
+
+-- Textual Conventions
+
+ZeroBasedCounter32 ::= TEXTUAL-CONVENTION
+ STATUS current
+ DESCRIPTION
+ "This TC describes an object which counts events with the
+ following semantics: objects of this type will be set to
+ zero(0) on creation and will thereafter count appropriate
+ events, wrapping back to zero(0) when the value 2^32 is
+ reached.
+
+ Provided that an application discovers the new object within
+ the minimum time to wrap it can use the initial value as a
+ delta since it last polled the table of which this object is
+ part. It is important for a management station to be aware of
+ this minimum time and the actual time between polls, and to
+ discard data if the actual time is too long or there is no
+ defined minimum time.
+
+ Typically this TC is used in tables where the INDEX space is
+ constantly changing and/or the TimeFilter mechanism is in use."
+ SYNTAX Gauge32
+
+LastCreateTime ::= TEXTUAL-CONVENTION
+ STATUS current
+ DESCRIPTION
+ "This TC describes an object that stores the last time its
+ entry was created.
+
+ This can be used for polling applications to determine that an
+ entry has been deleted and re-created between polls, causing
+ an otherwise undetectable discontinuity in the data."
+ SYNTAX TimeStamp
+
+TimeFilter ::= TEXTUAL-CONVENTION
+ STATUS current
+ DESCRIPTION
+
+
+
+ "To be used for the index to a table. Allows an application
+ to download only those rows changed since a particular time.
+ A row is considered changed if the value of any object in the
+ row changes or if the row is created or deleted.
+
+ When sysUpTime is equal to zero, this table shall be empty.
+
+ One entry exists for each past value of sysUpTime, except that
+ the whole table is purged should sysUpTime wrap.
+
+ As this basic row is updated new conceptual rows are created
+ (which still share the now updated object values with all
+ other instances). The number of instances which are created
+ is determined by the value of sysUpTime at which the basic row
+ was last updated. One instance will exist for each value of
+ sysUpTime at the last update time for the row. A new
+ timeMark instance is created for each new sysUpTime value.
+ Each new conceptual row will be associated with the timeMark
+ instance which was created at the value of sysUpTime with
+ which the conceptual row is to be associated.
+
+ By definition all conceptual rows were updated at or after
+ time zero and so at least one conceptual row (associated with
+ timeMark.0) must exist for each underlying (basic) row.
+
+ See the appendix for further discussion of this variable.
+
+ Consider the following fooTable:
+
+ fooTable ...
+ INDEX { fooTimeMark, fooIndex }
+
+ FooEntry {
+ fooTimeMark TimeFilter
+ fooIndex INTEGER,
+ fooCounts Counter
+ }
+
+ Should there be two basic rows in this table (fooIndex == 1,
+ fooIndex == 2) and row 1 was updated most recently at time 6,
+ while row 2 was updated most recently at time 8, and both rows
+ had been updated on several earlier occasions such that the
+ current values were 5 and 9 respectively then the following
+ fooCounts instances would exist.
+
+ fooCounts.0.1 5
+ fooCounts.0.2 9
+ fooCounts.1.1 5
+
+ fooCounts.1.2 9
+ fooCounts.2.1 5
+ fooCounts.2.2 9
+ fooCounts.3.1 5
+ fooCounts.3.2 9
+ fooCounts.4.1 5
+ fooCounts.4.2 9
+ fooCounts.5.1 5
+ fooCounts.5.2 9
+ fooCounts.6.1 5
+ fooCounts.6.2 9
+ fooCounts.7.2 9 -- note that row 1 doesn't exist for
+ fooCounts.8.2 9 -- times 7 and 8"
+ SYNTAX TimeTicks
+
+DataSource ::= TEXTUAL-CONVENTION
+ STATUS current
+ DESCRIPTION
+ "Identifies the source of the data that the associated
+ function is configured to analyze. This source can be any
+ interface on this device.
+
+ In order to identify a particular interface, this
+ object shall identify the instance of the ifIndex
+ object, defined in [3,5], for the desired interface.
+
+ For example, if an entry were to receive data from
+ interface #1, this object would be set to ifIndex.1."
+ SYNTAX OBJECT IDENTIFIER
+--
+-- Protocol Directory Group
+--
+-- Lists the inventory of protocols the probe has the capability of
+-- monitoring and allows the addition, deletion, and configuration of
+-- entries in this list.
+
+protocolDirLastChange OBJECT-TYPE
+ SYNTAX TimeStamp
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The value of sysUpTime at the time the protocol directory
+ was last modified, either through insertions or deletions,
+ or through modifications of either the
+ protocolDirAddressMapConfig, protocolDirHostConfig, or
+ protocolDirMatrixConfig."
+ ::= { protocolDir 1 }
+
+protocolDirTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF ProtocolDirEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "This table lists the protocols that this agent has the
+ capability to decode and count. There is one entry in this
+ table for each such protocol. These protocols represent
+ different network layer, transport layer, and higher-layer
+ protocols. The agent should boot up with this table
+ preconfigured with those protocols that it knows about and
+ wishes to monitor. Implementations are strongly encouraged to
+ support protocols higher than the network layer (at least for
+ the protocol distribution group), even for implementations
+ that don't support the application layer groups."
+ ::= { protocolDir 2 }
+
+protocolDirEntry OBJECT-TYPE
+ SYNTAX ProtocolDirEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A conceptual row in the protocolDirTable.
+
+ An example of the indexing of this entry is
+ protocolDirLocalIndex.8.0.0.0.1.0.0.8.0.2.0.0, which is the
+ encoding of a length of 8, followed by 8 subids encoding the
+ protocolDirID of 1.2048, followed by a length of 2 and the
+ 2 subids encoding zero-valued parameters."
+ INDEX { protocolDirID, protocolDirParameters }
+ ::= { protocolDirTable 1 }
+
+ProtocolDirEntry ::= SEQUENCE {
+ protocolDirID OCTET STRING,
+ protocolDirParameters OCTET STRING,
+ protocolDirLocalIndex Integer32,
+ protocolDirDescr DisplayString,
+ protocolDirType BITS,
+ protocolDirAddressMapConfig INTEGER,
+ protocolDirHostConfig INTEGER,
+ protocolDirMatrixConfig INTEGER,
+ protocolDirOwner OwnerString,
+ protocolDirStatus RowStatus
+}
+
+protocolDirID OBJECT-TYPE
+ SYNTAX OCTET STRING
+ MAX-ACCESS not-accessible
+
+ STATUS current
+ DESCRIPTION
+ "A unique identifier for a particular protocol. Standard
+ identifiers will be defined in a manner such that they
+ can often be used as specifications for new protocols - i.e.
+ a tree-structured assignment mechanism that matches the
+ protocol encapsulation `tree' and which has algorithmic
+ assignment mechanisms for certain subtrees. See RFC XXX for
+ more details.
+
+ Despite the algorithmic mechanism, the probe will only place
+ entries in here for those protocols it chooses to collect. In
+ other words, it need not populate this table with all of the
+ possible ethernet protocol types, nor need it create them on
+ the fly when it sees them. Whether or not it does these
+ things is a matter of product definition (cost/benefit,
+ usability), and is up to the designer of the product.
+
+ If an entry is written to this table with a protocolDirID that
+ the agent doesn't understand, either directly or
+ algorithmically, the SET request will be rejected with an
+ inconsistentName or badValue (for SNMPv1) error."
+ ::= { protocolDirEntry 1 }
+
+protocolDirParameters OBJECT-TYPE
+ SYNTAX OCTET STRING
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A set of parameters for the associated protocolDirID.
+ See the associated RMON2 Protocol Identifiers document
+ for a description of the possible parameters. There
+ will be one octet in this string for each sub-identifier in
+ the protocolDirID, and the parameters will appear here in the
+ same order as the associated sub-identifiers appear in the
+ protocolDirID.
+
+ Every node in the protocolDirID tree has a different, optional
+ set of parameters defined (that is, the definition of
+ parameters for a node is optional). The proper parameter
+ value for each node is included in this string. Note that the
+ inclusion of a parameter value in this string for each node is
+ not optional - what is optional is that a node may have no
+ parameters defined, in which case the parameter field for that
+ node will be zero."
+ ::= { protocolDirEntry 2 }
+
+protocolDirLocalIndex OBJECT-TYPE
+
+
+ SYNTAX Integer32 (1..2147483647)
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The locally arbitrary, but unique identifier associated
+ with this protocolDir entry.
+
+ The value for each supported protocol must remain constant at
+ least from one re-initialization of the entity's network
+ management system to the next re-initialization, except that
+ if a protocol is deleted and re-created, it must be re-created
+ with a new value that has not been used since the last
+ re-initialization.
+
+ The specific value is meaningful only within a given SNMP
+ entity. A protocolDirLocalIndex must not be re-used until the
+ next agent-restart in the event the protocol directory entry
+ is deleted."
+ ::= { protocolDirEntry 3 }
+
+protocolDirDescr OBJECT-TYPE
+ SYNTAX DisplayString (SIZE (1..64))
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "A textual description of the protocol encapsulation.
+ A probe may choose to describe only a subset of the
+ entire encapsulation (e.g. only the highest layer).
+
+ This object is intended for human consumption only.
+
+ This object may not be modified if the associated
+ protocolDirStatus object is equal to active(1)."
+ ::= { protocolDirEntry 4 }
+
+protocolDirType OBJECT-TYPE
+ SYNTAX BITS {
+ extensible(0),
+ addressRecognitionCapable(1)
+ }
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "This object describes 2 attributes of this protocol
+ directory entry.
+
+ The presence or absence of the `extensible' bit describes
+ whether or not this protocol directory entry can be extended
+
+
+ by the user by creating protocol directory entries which are
+ children of this protocol.
+
+ An example of an entry that will often allow extensibility is
+ `ip.udp'. The probe may automatically populate some children
+ of this node such as `ip.udp.snmp' and `ip.udp.dns'.
+ A probe administrator or user may also populate additional
+ children via remote SNMP requests that create entries in this
+ table. When a child node is added for a protocol for which the
+ probe has no built in support, extending a parent node (for
+ which the probe does have built in support),
+ that child node is not extendible. This is termed `limited
+ extensibility'.
+
+ When a child node is added through this extensibility
+ mechanism, the values of protocolDirLocalIndex and
+ protocolDirType shall be assigned by the agent.
+
+ The other objects in the entry will be assigned by the
+ manager who is creating the new entry.
+
+ This object also describes whether or not this agent can
+ recognize addresses for this protocol, should it be a network
+ level protocol. That is, while a probe may be able to
+ recognize packets of a particular network layer protocol and
+ count them, it takes additional logic to be able to recognize
+ the addresses in this protocol and to populate network layer
+ or application layer tables with the addresses in this
+ protocol. If this bit is set, the agent will recognize
+ network layer addresses for this protoocl and populate the
+ network and application layer host and matrix tables with
+ these protocols.
+
+ Note that when an entry is created, the agent will supply
+ values for the bits that match the capabilities of the agent
+ with respect to this protocol. Note that since row creations
+ usually exercise the limited extensibility feature, these
+ bits will usually be set to zero."
+ ::= { protocolDirEntry 5 }
+
+protocolDirAddressMapConfig OBJECT-TYPE
+ SYNTAX INTEGER {
+ notSupported(1),
+ supportedOff(2),
+ supportedOn(3)
+ }
+ MAX-ACCESS read-create
+ STATUS current
+
+
+ DESCRIPTION
+ "This object describes and configures the probe's support for
+ address mapping for this protocol. When the probe creates
+ entries in this table for all protocols that it understands,
+ it will set the entry to notSupported(1) if it doesn't have
+ the capability to perform address mapping for the protocol or
+ if this protocol is not a network-layer protocol. When
+ an entry is created in this table by a management operation as
+ part of the limited extensibility feature, the probe must set
+ this value to notSupported(1), because limited extensibility
+ of the protocolDirTable does not extend to interpreting
+ addresses of the extended protocols.
+
+ If the value of this object is notSupported(1), the probe
+ will not perform address mapping for this protocol and
+ shall not allow this object to be changed to any other value.
+ If the value of this object is supportedOn(3), the probe
+ supports address mapping for this protocol and is configured
+ to perform address mapping for this protocol for all
+ addressMappingControlEntries and all interfaces.
+ If the value of this object is supportedOff(2), the probe
+ supports address mapping for this protocol but is configured
+ to not perform address mapping for this protocol for any
+ addressMappingControlEntries and all interfaces.
+ Whenever this value changes from supportedOn(3) to
+ supportedOff(2), the probe shall delete all related entries in
+ the addressMappingTable."
+ ::= { protocolDirEntry 6 }
+
+protocolDirHostConfig OBJECT-TYPE
+ SYNTAX INTEGER {
+ notSupported(1),
+ supportedOff(2),
+ supportedOn(3)
+ }
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "This object describes and configures the probe's support for
+ the network layer and application layer host tables for this
+ protocol. When the probe creates entries in this table for
+ all protocols that it understands, it will set the entry to
+ notSupported(1) if it doesn't have the capability to track the
+ nlHostTable for this protocol or if the alHostTable is
+ implemented but doesn't have the capability to track this
+ protocol. Note that if the alHostTable is implemented, the
+ probe may only support a protocol if it is supported in both
+ the nlHostTable and the alHostTable.
+
+
+
+ If the associated protocolDirType object has the
+ addressRecognitionCapable bit set, then this is a network
+ layer protocol for which the probe recognizes addresses, and
+ thus the probe will populate the nlHostTable and alHostTable
+ with addresses it discovers for this protocol.
+
+ If the value of this object is notSupported(1), the probe
+ will not track the nlHostTable or alHostTable for this
+ protocol and shall not allow this object to be changed to any
+ other value. If the value of this object is supportedOn(3),
+ the probe supports tracking of the nlHostTable and alHostTable
+ for this protocol and is configured to track both tables
+ for this protocol for all control entries and all interfaces.
+ If the value of this object is supportedOff(2), the probe
+ supports tracking of the nlHostTable and alHostTable for this
+ protocol but is configured to not track these tables
+ for any control entries or interfaces.
+ Whenever this value changes from supportedOn(3) to
+ supportedOff(2), the probe shall delete all related entries in
+ the nlHostTable and alHostTable.
+
+ Note that since each alHostEntry references 2 protocol
+ directory entries, one for the network address and one for the
+ type of the highest protocol recognized, that an entry will
+ only be created in that table if this value is supportedOn(3)
+ for both protocols."
+ ::= { protocolDirEntry 7 }
+
+protocolDirMatrixConfig OBJECT-TYPE
+ SYNTAX INTEGER {
+ notSupported(1),
+ supportedOff(2),
+ supportedOn(3)
+ }
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "This object describes and configures the probe's support for
+ the network layer and application layer matrix tables for this
+ protocol. When the probe creates entries in this table for
+ all protocols that it understands, it will set the entry to
+ notSupported(1) if it doesn't have the capability to track the
+ nlMatrixTables for this protocol or if the alMatrixTables are
+ implemented but don't have the capability to track this
+ protocol. Note that if the alMatrix tables are implemented,
+ the probe may only support a protocol if it is supported in
+ the the both of the nlMatrixTables and both of the
+ alMatrixTables.
+
+ If the associated protocolDirType object has the
+ addressRecognitionCapable bit set, then this is a network
+ layer protocol for which the probe recognizes addresses, and
+ thus the probe will populate both of the nlMatrixTables and
+ both of the alMatrixTables with addresses it discovers for
+ this protocol.
+
+ If the value of this object is notSupported(1), the probe
+ will not track either of the nlMatrixTables or the
+ alMatrixTables for this protocol and shall not allow this
+ object to be changed to any other value. If the value of this
+ object is supportedOn(3), the probe supports tracking of both
+ of the nlMatrixTables and (if implemented) both of the
+ alMatrixTables for this protocol and is configured to track
+ these tables for this protocol for all control entries and all
+ interfaces. If the value of this object is supportedOff(2),
+ the probe supports tracking of both of the nlMatrixTables and
+ (if implemented) both of the alMatrixTables for this protocol
+ but is configured to not track these tables for this
+ protocol for any control entries or interfaces.
+ Whenever this value changes from supportedOn(3) to
+ supportedOff(2), the probe shall delete all related entries in
+ the nlMatrixTables and the alMatrixTables.
+
+ Note that since each alMatrixEntry references 2 protocol
+ directory entries, one for the network address and one for the
+ type of the highest protocol recognized, that an entry will
+ only be created in that table if this value is supportedOn(3)
+ for both protocols."
+ ::= { protocolDirEntry 8 }
+
+protocolDirOwner OBJECT-TYPE
+ SYNTAX OwnerString
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "The entity that configured this entry and is
+ therefore using the resources assigned to it."
+ ::= { protocolDirEntry 9 }
+
+protocolDirStatus OBJECT-TYPE
+ SYNTAX RowStatus
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "The status of this protocol directory entry.
+
+ An entry may not exist in the active state unless all
+
+
+ objects in the entry have an appropriate value.
+
+ If this object is not equal to active(1), all associated
+ entries in the nlHostTable, nlMatrixSDTable, nlMatrixDSTable,
+ alHostTable, alMatrixSDTable, and alMatrixDSTable shall be
+ deleted."
+ ::= { protocolDirEntry 10 }
+
+--
+-- Protocol Distribution Group (protocolDist)
+--
+-- Collects the relative amounts of octets and packets for the
+-- different protocols detected on a network segment.
+-- protocolDistControlTable,
+-- protocolDistStatsTable
+
+protocolDistControlTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF ProtocolDistControlEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "Controls the setup of protocol type distribution statistics
+ tables.
+
+ Implementations are encouraged to add an entry per monitored
+ interface upon initialization so that a default collection
+ of protocol statistics is available.
+
+ Rationale:
+ This table controls collection of very basic statistics
+ for any or all of the protocols detected on a given interface.
+ An NMS can use this table to quickly determine bandwidth
+ allocation utilized by different protocols.
+
+ A media-specific statistics collection could also
+ be configured (e.g. etherStats, trPStats) to easily obtain
+ total frame, octet, and droppedEvents for the same
+ interface."
+ ::= { protocolDist 1 }
+
+protocolDistControlEntry OBJECT-TYPE
+ SYNTAX ProtocolDistControlEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A conceptual row in the protocolDistControlTable.
+
+ An example of the indexing of this entry is
+
+
+ protocolDistControlDroppedFrames.7"
+ INDEX { protocolDistControlIndex }
+ ::= { protocolDistControlTable 1 }
+
+ProtocolDistControlEntry ::= SEQUENCE {
+ protocolDistControlIndex Integer32,
+ protocolDistControlDataSource DataSource,
+ protocolDistControlDroppedFrames Counter32,
+ protocolDistControlCreateTime LastCreateTime,
+ protocolDistControlOwner OwnerString,
+ protocolDistControlStatus RowStatus
+}
+
+protocolDistControlIndex OBJECT-TYPE
+ SYNTAX Integer32 (1..65535)
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A unique index for this protocolDistControlEntry."
+ ::= { protocolDistControlEntry 1 }
+
+protocolDistControlDataSource OBJECT-TYPE
+ SYNTAX DataSource
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "The source of data for the this protocol distribution.
+
+ The statistics in this group reflect all packets
+ on the local network segment attached to the
+ identified interface.
+
+ This object may not be modified if the associated
+ protocolDistControlStatus object is equal to active(1)."
+ ::= { protocolDistControlEntry 2 }
+
+protocolDistControlDroppedFrames OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The total number of frames which were received by the probe
+ and therefore not accounted for in the *StatsDropEvents, but
+ for which the probe chose not to count for this entry for
+ whatever reason. Most often, this event occurs when the probe
+ is out of some resources and decides to shed load from this
+ collection.
+
+ This count does not include packets that were not counted
+ because they had MAC-layer errors.
+
+ Note that, unlike the dropEvents counter, this number is the
+ exact number of frames dropped."
+ ::= { protocolDistControlEntry 3 }
+
+protocolDistControlCreateTime OBJECT-TYPE
+ SYNTAX LastCreateTime
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The value of sysUpTime when this control entry was last
+ activated. This can be used by the management station to
+ ensure that the table has not been deleted and recreated
+ between polls."
+ ::= { protocolDistControlEntry 4 }
+
+protocolDistControlOwner OBJECT-TYPE
+ SYNTAX OwnerString
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "The entity that configured this entry and is
+ therefore using the resources assigned to it."
+ ::= { protocolDistControlEntry 5 }
+
+protocolDistControlStatus OBJECT-TYPE
+ SYNTAX RowStatus
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "The status of this row.
+
+ An entry may not exist in the active state unless all
+ objects in the entry have an appropriate value.
+
+ If this object is not equal to active(1), all associated
+ entries in the protocolDistStatsTable shall be deleted."
+ ::= { protocolDistControlEntry 6 }
+
+-- per interface protocol distribution statistics table
+protocolDistStatsTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF ProtocolDistStatsEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "An entry is made in this table for every protocol in the
+
+
+ protocolDirTable which has been seen in at least one packet.
+ Counters are updated in this table for every protocol type
+ that is encountered when parsing a packet, but no counters are
+ updated for packets with MAC-layer errors.
+
+ Note that if a protocolDirEntry is deleted, all associated
+ entries in this table are removed."
+ ::= { protocolDist 2 }
+
+protocolDistStatsEntry OBJECT-TYPE
+ SYNTAX ProtocolDistStatsEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A conceptual row in the protocolDistStatsTable.
+
+ The index is composed of the protocolDistControlIndex of the
+ associated protocolDistControlEntry followed by the
+ protocolDirLocalIndex of the associated protocol that this
+ entry represents. In other words, the index identifies the
+ protocol distribution an entry is a part of as well as the
+ particular protocol that it represents.
+
+ An example of the indexing of this entry is
+ protocolDistStatsPkts.1.18"
+ INDEX { protocolDistControlIndex, protocolDirLocalIndex }
+ ::= { protocolDistStatsTable 1 }
+
+ProtocolDistStatsEntry ::= SEQUENCE {
+ protocolDistStatsPkts ZeroBasedCounter32,
+ protocolDistStatsOctets ZeroBasedCounter32
+}
+
+protocolDistStatsPkts OBJECT-TYPE
+ SYNTAX ZeroBasedCounter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of packets without errors received of this
+ protocol type. Note that this is the number of link-layer
+ packets, so if a single network-layer packet is fragmented
+ into several link-layer frames, this counter is incremented
+ several times."
+ ::= { protocolDistStatsEntry 1 }
+
+protocolDistStatsOctets OBJECT-TYPE
+ SYNTAX ZeroBasedCounter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of octets in packets received of this protocol
+ type since it was added to the protocolDistStatsTable
+ (excluding framing bits but including FCS octets), except for
+ those octets in packets that contained errors.
+
+ Note this doesn't count just those octets in the particular
+ protocol frames, but includes the entire packet that contained
+ the protocol."
+ ::= { protocolDistStatsEntry 2 }
+
+--
+-- Address Map Group (addressMap)
+--
+-- Lists MAC address to network address bindings discovered by the
+-- probe and what interface they were last seen on.
+-- addressMapControlTable
+-- addressMapTable
+
+addressMapInserts OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of times an address mapping entry has been
+ inserted into the addressMapTable. If an entry is inserted,
+ then deleted, and then inserted, this counter will be
+ incremented by 2.
+
+ Note that the table size can be determined by subtracting
+ addressMapDeletes from addressMapInserts."
+ ::= { addressMap 1 }
+
+addressMapDeletes OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of times an address mapping entry has been
+ deleted from the addressMapTable (for any reason). If
+ an entry is deleted, then inserted, and then deleted, this
+ counter will be incremented by 2.
+
+ Note that the table size can be determined by subtracting
+ addressMapDeletes from addressMapInserts."
+ ::= { addressMap 2 }
+
+
+
+
+addressMapMaxDesiredEntries OBJECT-TYPE
+ SYNTAX Integer32 (-1..2147483647)
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The maximum number of entries that are desired in the
+ addressMapTable. The probe will not create more than
+ this number of entries in the table, but may choose to create
+ fewer entries in this table for any reason including the lack
+ of resources.
+
+ If this object is set to a value less than the current number
+ of entries, enough entries are chosen in an
+ implementation-dependent manner and deleted so that the number
+ of entries in the table equals the value of this object.
+
+ If this value is set to -1, the probe may create any number
+ of entries in this table.
+
+ This object may be used to control how resources are allocated
+ on the probe for the various RMON functions."
+ ::= { addressMap 3 }
+
+addressMapControlTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF AddressMapControlEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A table to control the collection of network layer address to
+ physical address to interface mappings.
+
+ Note that this is not like the typical RMON
+ controlTable and dataTable in which each entry creates
+ its own data table. Each entry in this table enables the
+ discovery of addresses on a new interface and the placement
+ of address mappings into the central addressMapTable.
+
+ Implementations are encouraged to add an entry per monitored
+ interface upon initialization so that a default collection
+ of address mappings is available."
+ ::= { addressMap 4 }
+
+addressMapControlEntry OBJECT-TYPE
+ SYNTAX AddressMapControlEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A conceptual row in the addressMapControlTable.
+
+
+ An example of the indexing of this entry is
+ addressMapControlDroppedFrames.1"
+ INDEX { addressMapControlIndex }
+ ::= { addressMapControlTable 1 }
+
+AddressMapControlEntry ::= SEQUENCE {
+ addressMapControlIndex Integer32,
+ addressMapControlDataSource DataSource,
+ addressMapControlDroppedFrames Counter32,
+ addressMapControlOwner OwnerString,
+ addressMapControlStatus RowStatus
+}
+
+addressMapControlIndex OBJECT-TYPE
+ SYNTAX Integer32 (1..65535)
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A unique index for this entry in the addressMapControlTable."
+ ::= { addressMapControlEntry 1 }
+
+addressMapControlDataSource OBJECT-TYPE
+ SYNTAX DataSource
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "The source of data for this addressMapControlEntry."
+ ::= { addressMapControlEntry 2 }
+
+addressMapControlDroppedFrames OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The total number of frames which were received by the probe
+ and therefore not accounted for in the *StatsDropEvents, but
+ for which the probe chose not to count for this entry for
+ whatever reason. Most often, this event occurs when the probe
+ is out of some resources and decides to shed load from this
+ collection.
+
+ This count does not include packets that were not counted
+ because they had MAC-layer errors.
+
+ Note that, unlike the dropEvents counter, this number is the
+ exact number of frames dropped."
+ ::= { addressMapControlEntry 3 }
+
+
+
+
+addressMapControlOwner OBJECT-TYPE
+ SYNTAX OwnerString
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "The entity that configured this entry and is
+ therefore using the resources assigned to it."
+ ::= { addressMapControlEntry 4 }
+
+addressMapControlStatus OBJECT-TYPE
+ SYNTAX RowStatus
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "The status of this addressMap control entry.
+
+ An entry may not exist in the active state unless all
+ objects in the entry have an appropriate value.
+
+ If this object is not equal to active(1), all associated
+ entries in the addressMapTable shall be deleted."
+ ::= { addressMapControlEntry 5 }
+
+addressMapTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF AddressMapEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A table of network layer address to physical address to
+ interface mappings.
+
+ The probe will add entries to this table based on the source
+ MAC and network addresses seen in packets without MAC-level
+ errors. The probe will populate this table for all protocols
+ in the protocol directory table whose value of
+ protocolDirAddressMapConfig is equal to supportedOn(3), and
+ will delete any entries whose protocolDirEntry is deleted or
+ has a protocolDirAddressMapConfig value of supportedOff(2)."
+ ::= { addressMap 5 }
+
+addressMapEntry OBJECT-TYPE
+ SYNTAX AddressMapEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A conceptual row in the addressMapTable.
+ The protocolDirLocalIndex in the index identifies the network
+ layer protocol of the addressMapNetworkAddress.
+
+
+ An example of the indexing of this entry is
+ addressMapSource.783495.18.4.128.2.6.6.11.1.3.6.1.2.1.2.2.1.1.1"
+ INDEX { addressMapTimeMark, protocolDirLocalIndex,
+ addressMapNetworkAddress, addressMapSource }
+ ::= { addressMapTable 1 }
+
+AddressMapEntry ::= SEQUENCE {
+ addressMapTimeMark TimeFilter,
+ addressMapNetworkAddress OCTET STRING,
+ addressMapSource OBJECT IDENTIFIER,
+ addressMapPhysicalAddress OCTET STRING,
+ addressMapLastChange TimeStamp
+}
+
+addressMapTimeMark OBJECT-TYPE
+ SYNTAX TimeFilter
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A TimeFilter for this entry. See the TimeFilter textual
+ convention to see how this works."
+ ::= { addressMapEntry 1 }
+
+addressMapNetworkAddress OBJECT-TYPE
+ SYNTAX OCTET STRING
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "The network address for this relation.
+
+ This is represented as an octet string with
+ specific semantics and length as identified
+ by the protocolDirLocalIndex component of the
+ index.
+
+ For example, if the protocolDirLocalIndex indicates an
+ encapsulation of ip, this object is encoded as a length
+ octet of 4, followed by the 4 octets of the ip address,
+ in network byte order."
+ ::= { addressMapEntry 2 }
+
+addressMapSource OBJECT-TYPE
+ SYNTAX OBJECT IDENTIFIER
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "The interface or port on which the associated network
+ address was most recently seen.
+
+
+
+ If this address mapping was discovered on an interface, this
+ object shall identify the instance of the ifIndex
+ object, defined in [3,5], for the desired interface.
+ For example, if an entry were to receive data from
+ interface #1, this object would be set to ifIndex.1.
+
+ If this address mapping was discovered on a port, this
+ object shall identify the instance of the rptrGroupPortIndex
+ object, defined in [RFC1516], for the desired port.
+ For example, if an entry were to receive data from
+ group #1, port #1, this object would be set to
+ rptrGroupPortIndex.1.1.
+
+ Note that while the dataSource associated with this entry
+ may only point to index objects, this object may at times
+ point to repeater port objects. This situation occurs when
+ the dataSource points to an interface which is a locally
+ attached repeater and the agent has additional information
+ about the source port of traffic seen on that repeater."
+ ::= { addressMapEntry 3 }
+
+addressMapPhysicalAddress OBJECT-TYPE
+ SYNTAX OCTET STRING
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The last source physical address on which the associated
+ network address was seen. If the protocol of the associated
+ network address was encapsulated inside of a network-level or
+ higher protocol, this will be the address of the next-lower
+ protocol with the addressRecognitionCapable bit enabled and
+ will be formatted as specified for that protocol."
+ ::= { addressMapEntry 4 }
+
+addressMapLastChange OBJECT-TYPE
+ SYNTAX TimeStamp
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The value of sysUpTime at the time this entry was last
+ created or the values of the physical address changed.
+
+ This can be used to help detect duplicate address problems, in
+ which case this object will be updated frequently."
+ ::= { addressMapEntry 5 }
+
+--
+-- Network Layer Host Group
+
+
+
+--
+-- Counts the amount of traffic sent from and to each network address
+-- discovered by the probe.
+-- Note that while the hlHostControlTable also has objects that
+-- control an optional alHostTable, implementation of the alHostTable is
+-- not required to fully implement this group.
+
+hlHostControlTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF HlHostControlEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A list of higher layer (i.e. non-MAC) host table control entries.
+
+ These entries will enable the collection of the network and
+ application level host tables indexed by network addresses.
+ Both the network and application level host tables are
+ controlled by this table is so that they will both be created
+ and deleted at the same time, further increasing the ease with
+ which they can be implemented as a single datastore (note that
+ if an implementation stores application layer host records in
+ memory, it can derive network layer host records from them).
+
+ Entries in the nlHostTable will be created on behalf of each
+ entry in this table. Additionally, if this probe implements
+ the alHostTable, entries in the alHostTable will be created on
+ behalf of each entry in this table.
+
+ Implementations are encouraged to add an entry per monitored
+ interface upon initialization so that a default collection
+ of host statistics is available."
+ ::= { nlHost 1 }
+
+hlHostControlEntry OBJECT-TYPE
+ SYNTAX HlHostControlEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A conceptual row in the hlHostControlTable.
+
+ An example of the indexing of this entry is
+ hlHostControlNlDroppedFrames.1"
+ INDEX { hlHostControlIndex }
+ ::= { hlHostControlTable 1 }
+
+HlHostControlEntry ::= SEQUENCE {
+ hlHostControlIndex Integer32,
+ hlHostControlDataSource DataSource,
+
+
+ hlHostControlNlDroppedFrames Counter32,
+ hlHostControlNlInserts Counter32,
+ hlHostControlNlDeletes Counter32,
+ hlHostControlNlMaxDesiredEntries Integer32,
+ hlHostControlAlDroppedFrames Counter32,
+ hlHostControlAlInserts Counter32,
+ hlHostControlAlDeletes Counter32,
+ hlHostControlAlMaxDesiredEntries Integer32,
+ hlHostControlOwner OwnerString,
+ hlHostControlStatus RowStatus
+}
+
+hlHostControlIndex OBJECT-TYPE
+ SYNTAX Integer32 (1..65535)
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "An index that uniquely identifies an entry in the
+ hlHostControlTable. Each such entry defines
+ a function that discovers hosts on a particular
+ interface and places statistics about them in the
+ nlHostTable, and optionally in the alHostTable, on
+ behalf of this hlHostControlEntry."
+ ::= { hlHostControlEntry 1 }
+
+hlHostControlDataSource OBJECT-TYPE
+ SYNTAX DataSource
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "The source of data for the associated host tables.
+
+ The statistics in this group reflect all packets
+ on the local network segment attached to the
+ identified interface.
+
+ This object may not be modified if the associated
+ hlHostControlStatus object is equal to active(1)."
+ ::= { hlHostControlEntry 2 }
+
+hlHostControlNlDroppedFrames OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The total number of frames which were received by the probe
+ and therefore not accounted for in the *StatsDropEvents, but
+ for which the probe chose not to count for the associated
+
+ nlHost entries for whatever reason. Most often, this event
+ occurs when the probe is out of some resources and decides to
+ shed load from this collection.
+
+ This count does not include packets that were not counted
+ because they had MAC-layer errors.
+
+ Note that if the nlHostTable is inactive because no protocols
+ are enabled in the protocol directory, this value should be 0.
+
+ Note that, unlike the dropEvents counter, this number is the
+ exact number of frames dropped."
+ ::= { hlHostControlEntry 3 }
+
+hlHostControlNlInserts OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of times an nlHost entry has been
+ inserted into the nlHost table. If an entry is inserted, then
+ deleted, and then inserted, this counter will be incremented
+ by 2.
+
+ To allow for efficient implementation strategies, agents may
+ delay updating this object for short periods of time. For
+ example, an implementation strategy may allow internal
+ data structures to differ from those visible via SNMP for
+ short periods of time. This counter may reflect the internal
+ data structures for those short periods of time.
+
+ Note that the table size can be determined by subtracting
+ hlHostControlNlDeletes from hlHostControlNlInserts."
+ ::= { hlHostControlEntry 4 }
+
+hlHostControlNlDeletes OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of times an nlHost entry has been
+ deleted from the nlHost table (for any reason). If an entry
+ is deleted, then inserted, and then deleted, this counter will
+ be incremented by 2.
+
+ To allow for efficient implementation strategies, agents may
+ delay updating this object for short periods of time. For
+ example, an implementation strategy may allow internal
+
+
+ data structures to differ from those visible via SNMP for
+ short periods of time. This counter may reflect the internal
+ data structures for those short periods of time.
+
+ Note that the table size can be determined by subtracting
+ hlHostControlNlDeletes from hlHostControlNlInserts."
+ ::= { hlHostControlEntry 5 }
+
+hlHostControlNlMaxDesiredEntries OBJECT-TYPE
+ SYNTAX Integer32 (-1..2147483647)
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "The maximum number of entries that are desired in the
+ nlHostTable on behalf of this control entry. The probe will
+ not create more than this number of associated entries in the
+ table, but may choose to create fewer entries in this table
+ for any reason including the lack of resources.
+
+ If this object is set to a value less than the current number
+ of entries, enough entries are chosen in an
+ implementation-dependent manner and deleted so that the number
+ of entries in the table equals the value of this object.
+
+ If this value is set to -1, the probe may create any number
+ of entries in this table. If the associated
+ hlHostControlStatus object is equal to `active', this
+ object may not be modified.
+
+ This object may be used to control how resources are allocated
+ on the probe for the various RMON functions."
+ ::= { hlHostControlEntry 6 }
+
+hlHostControlAlDroppedFrames OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The total number of frames which were received by the probe
+ and therefore not accounted for in the *StatsDropEvents, but
+ for which the probe chose not to count for the associated
+ alHost entries for whatever reason. Most often, this event
+ occurs when the probe is out of some resources and decides to
+ shed load from this collection.
+
+ This count does not include packets that were not counted
+ because they had MAC-layer errors.
+
+ Note that if the alHostTable is not implemented or is inactive
+ because no protocols are enabled in the protocol directory,
+ this value should be 0.
+
+ Note that, unlike the dropEvents counter, this number is the
+ exact number of frames dropped."
+ ::= { hlHostControlEntry 7 }
+
+hlHostControlAlInserts OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of times an alHost entry has been
+ inserted into the alHost table. If an entry is inserted, then
+ deleted, and then inserted, this counter will be incremented
+ by 2.
+
+ To allow for efficient implementation strategies, agents may
+ delay updating this object for short periods of time. For
+ example, an implementation strategy may allow internal
+ data structures to differ from those visible via SNMP for
+ short periods of time. This counter may reflect the internal
+ data structures for those short periods of time.
+
+ Note that the table size can be determined by subtracting
+ hlHostControlAlDeletes from hlHostControlAlInserts."
+ ::= { hlHostControlEntry 8 }
+
+hlHostControlAlDeletes OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of times an alHost entry has been
+ deleted from the alHost table (for any reason). If an entry
+ is deleted, then inserted, and then deleted, this counter will
+ be incremented by 2.
+
+ To allow for efficient implementation strategies, agents may
+ delay updating this object for short periods of time. For
+ example, an implementation strategy may allow internal
+ data structures to differ from those visible via SNMP for
+ short periods of time. This counter may reflect the internal
+ data structures for those short periods of time.
+
+ Note that the table size can be determined by subtracting
+ hlHostControlAlDeletes from hlHostControlAlInserts."
+
+
+
+ ::= { hlHostControlEntry 9 }
+
+hlHostControlAlMaxDesiredEntries OBJECT-TYPE
+ SYNTAX Integer32 (-1..2147483647)
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "The maximum number of entries that are desired in the alHost
+ table on behalf of this control entry. The probe will not
+ create more than this number of associated entries in the
+ table, but may choose to create fewer entries in this table
+ for any reason including the lack of resources.
+
+ If this object is set to a value less than the current number
+ of entries, enough entries are chosen in an
+ implementation-dependent manner and deleted so that the number
+ of entries in the table equals the value of this object.
+
+ If this value is set to -1, the probe may create any number
+ of entries in this table. If the associated
+ hlHostControlStatus object is equal to `active', this
+ object may not be modified.
+
+ This object may be used to control how resources are allocated
+ on the probe for the various RMON functions."
+ ::= { hlHostControlEntry 10 }
+
+hlHostControlOwner OBJECT-TYPE
+ SYNTAX OwnerString
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "The entity that configured this entry and is
+ therefore using the resources assigned to it."
+ ::= { hlHostControlEntry 11 }
+
+hlHostControlStatus OBJECT-TYPE
+ SYNTAX RowStatus
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "The status of this hlHostControlEntry.
+
+ An entry may not exist in the active state unless all
+ objects in the entry have an appropriate value.
+
+ If this object is not equal to active(1), all associated
+ entries in the nlHostTable and alHostTable shall be deleted."
+ ::= { hlHostControlEntry 12 }
+
+nlHostTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF NlHostEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A collection of statistics for a particular network layer
+ address that has been discovered on an interface of this
+ device.
+
+ The probe will populate this table for all network layer
+ protocols in the protocol directory table whose value of
+ protocolDirHostConfig is equal to supportedOn(3), and
+ will delete any entries whose protocolDirEntry is deleted or
+ has a protocolDirHostConfig value of supportedOff(2).
+
+ The probe will add to this table all addresses seen
+ as the source or destination address in all packets with no
+ MAC errors, and will increment octet and packet counts in the
+ table for all packets with no MAC errors."
+::= { nlHost 2 }
+
+nlHostEntry OBJECT-TYPE
+ SYNTAX NlHostEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A conceptual row in the nlHostTable.
+
+ The hlHostControlIndex value in the index identifies the
+ hlHostControlEntry on whose behalf this entry was created.
+ The protocolDirLocalIndex value in the index identifies the
+ network layer protocol of the nlHostAddress.
+
+ An example of the indexing of this entry is
+ nlHostOutPkts.1.783495.18.4.128.2.6.6."
+ INDEX { hlHostControlIndex, nlHostTimeMark,
+ protocolDirLocalIndex, nlHostAddress }
+ ::= { nlHostTable 1 }
+
+NlHostEntry ::= SEQUENCE {
+ nlHostTimeMark TimeFilter,
+ nlHostAddress OCTET STRING,
+ nlHostInPkts ZeroBasedCounter32,
+ nlHostOutPkts ZeroBasedCounter32,
+ nlHostInOctets ZeroBasedCounter32,
+ nlHostOutOctets ZeroBasedCounter32,
+
+
+ nlHostOutMacNonUnicastPkts ZeroBasedCounter32,
+ nlHostCreateTime LastCreateTime
+}
+
+nlHostTimeMark OBJECT-TYPE
+ SYNTAX TimeFilter
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A TimeFilter for this entry. See the TimeFilter textual
+ convention to see how this works."
+ ::= { nlHostEntry 1 }
+
+nlHostAddress OBJECT-TYPE
+ SYNTAX OCTET STRING
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "The network address for this nlHostEntry.
+
+ This is represented as an octet string with
+ specific semantics and length as identified
+ by the protocolDirLocalIndex component of the index.
+
+ For example, if the protocolDirLocalIndex indicates an
+ encapsulation of ip, this object is encoded as a length
+ octet of 4, followed by the 4 octets of the ip address,
+ in network byte order."
+ ::= { nlHostEntry 2 }
+
+nlHostInPkts OBJECT-TYPE
+ SYNTAX ZeroBasedCounter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of packets without errors transmitted to
+ this address since it was added to the nlHostTable. Note that
+ this is the number of link-layer packets, so if a single
+ network-layer packet is fragmented into several link-layer
+ frames, this counter is incremented several times."
+ ::= { nlHostEntry 3 }
+
+nlHostOutPkts OBJECT-TYPE
+ SYNTAX ZeroBasedCounter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of packets without errors transmitted by
+
+
+ this address since it was added to the nlHostTable. Note that
+ this is the number of link-layer packets, so if a single
+ network-layer packet is fragmented into several link-layer
+ frames, this counter is incremented several times."
+ ::= { nlHostEntry 4 }
+
+nlHostInOctets OBJECT-TYPE
+ SYNTAX ZeroBasedCounter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of octets transmitted to this address
+ since it was added to the nlHostTable (excluding
+ framing bits but including FCS octets), excluding
+ those octets in packets that contained errors.
+
+ Note this doesn't count just those octets in the particular
+ protocol frames, but includes the entire packet that contained
+ the protocol."
+ ::= { nlHostEntry 5 }
+
+nlHostOutOctets OBJECT-TYPE
+ SYNTAX ZeroBasedCounter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of octets transmitted by this address
+ since it was added to the nlHostTable (excluding
+ framing bits but including FCS octets), excluding
+ those octets in packets that contained errors.
+
+ Note this doesn't count just those octets in the particular
+ protocol frames, but includes the entire packet that contained
+ the protocol."
+ ::= { nlHostEntry 6 }
+
+nlHostOutMacNonUnicastPkts OBJECT-TYPE
+ SYNTAX ZeroBasedCounter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of packets without errors transmitted by this
+ address that were directed to any MAC broadcast addresses
+ or to any MAC multicast addresses since this host was
+ added to the nlHostTable. Note that this is the number of
+ link-layer packets, so if a single network-layer packet is
+ fragmented into several link-layer frames, this counter is
+ incremented several times."
+
+
+
+ ::= { nlHostEntry 7 }
+
+nlHostCreateTime OBJECT-TYPE
+ SYNTAX LastCreateTime
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The value of sysUpTime when this entry was last activated.
+ This can be used by the management station to ensure that the
+ entry has not been deleted and recreated between polls."
+ ::= { nlHostEntry 8 }
+
+--
+-- Network Layer Matrix Group
+--
+-- Counts the amount of traffic sent between each pair of network
+-- addresses discovered by the probe.
+-- Note that while the hlMatrixControlTable also has objects that
+-- control optional alMatrixTables, implementation of the
+-- alMatrixTables is not required to fully implement this group.
+
+hlMatrixControlTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF HlMatrixControlEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A list of higher layer (i.e. non-MAC) matrix control entries.
+
+ These entries will enable the collection of the network and
+ application level matrix tables containing conversation
+ statistics indexed by pairs of network addresses.
+ Both the network and application level matrix tables are
+ controlled by this table is so that they will both be created
+ and deleted at the same time, further increasing the ease with
+ which they can be implemented as a single datastore (note that
+ if an implementation stores application layer matrix records
+ in memory, it can derive network layer matrix records from
+ them).
+
+ Entries in the nlMatrixSDTable and nlMatrixDSTable will be
+ created on behalf of each entry in this table. Additionally,
+ if this probe implements the alMatrix tables, entries in the
+ alMatrix tables will be created on behalf of each entry in
+ this table."
+ ::= { nlMatrix 1 }
+
+hlMatrixControlEntry OBJECT-TYPE
+ SYNTAX HlMatrixControlEntry
+
+
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A conceptual row in the hlMatrixControlTable.
+
+ An example of indexing of this entry is
+ hlMatrixControlNlDroppedFrames.1"
+ INDEX { hlMatrixControlIndex }
+ ::= { hlMatrixControlTable 1 }
+
+HlMatrixControlEntry ::= SEQUENCE {
+ hlMatrixControlIndex Integer32,
+ hlMatrixControlDataSource DataSource,
+ hlMatrixControlNlDroppedFrames Counter32,
+ hlMatrixControlNlInserts Counter32,
+ hlMatrixControlNlDeletes Counter32,
+ hlMatrixControlNlMaxDesiredEntries Integer32,
+ hlMatrixControlAlDroppedFrames Counter32,
+ hlMatrixControlAlInserts Counter32,
+ hlMatrixControlAlDeletes Counter32,
+ hlMatrixControlAlMaxDesiredEntries Integer32,
+ hlMatrixControlOwner OwnerString,
+ hlMatrixControlStatus RowStatus
+}
+
+hlMatrixControlIndex OBJECT-TYPE
+ SYNTAX Integer32 (1..65535)
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "An index that uniquely identifies an entry in the
+ hlMatrixControlTable. Each such entry defines
+ a function that discovers conversations on a particular
+ interface and places statistics about them in the
+ nlMatrixSDTable and the nlMatrixDSTable, and optionally the
+ alMatrixSDTable and alMatrixDSTable, on behalf of this
+ hlMatrixControlEntry."
+ ::= { hlMatrixControlEntry 1 }
+
+hlMatrixControlDataSource OBJECT-TYPE
+ SYNTAX DataSource
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "The source of the data for the associated matrix tables.
+
+ The statistics in this group reflect all packets
+ on the local network segment attached to the
+
+
+ identified interface.
+
+ This object may not be modified if the associated
+ hlMatrixControlStatus object is equal to active(1)."
+ ::= { hlMatrixControlEntry 2 }
+
+hlMatrixControlNlDroppedFrames OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The total number of frames which were received by the probe
+ and therefore not accounted for in the *StatsDropEvents, but
+ for which the probe chose not to count for this entry for
+ whatever reason. Most often, this event occurs when the probe
+ is out of some resources and decides to shed load from this
+ collection.
+
+ This count does not include packets that were not counted
+ because they had MAC-layer errors.
+
+ Note that if the nlMatrixTables are inactive because no
+ protocols are enabled in the protocol directory, this value
+ should be 0.
+
+ Note that, unlike the dropEvents counter, this number is the
+ exact number of frames dropped."
+ ::= { hlMatrixControlEntry 3 }
+
+hlMatrixControlNlInserts OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of times an nlMatrix entry has been
+ inserted into the nlMatrix tables. If an entry is inserted,
+ then deleted, and then inserted, this counter will be
+ incremented by 2. The addition of a conversation into both
+ the nlMatrixSDTable and nlMatrixDSTable shall be counted as
+ two insertions (even though every addition into one table must
+ be accompanied by an insertion into the other).
+
+ To allow for efficient implementation strategies, agents may
+ delay updating this object for short periods of time. For
+ example, an implementation strategy may allow internal
+ data structures to differ from those visible via SNMP for
+ short periods of time. This counter may reflect the internal
+ data structures for those short periods of time.
+
+
+ Note that the sum of then nlMatrixSDTable and nlMatrixDSTable
+ sizes can be determined by subtracting
+ hlMatrixControlNlDeletes from hlMatrixControlNlInserts."
+ ::= { hlMatrixControlEntry 4 }
+
+hlMatrixControlNlDeletes OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of times an nlMatrix entry has been
+ deleted from the nlMatrix tables (for any reason). If an
+ entry is deleted, then inserted, and then deleted, this
+ counter will be incremented by 2. The deletion of a
+ conversation from both the nlMatrixSDTable and nlMatrixDSTable
+ shall be counted as two deletions (even though every deletion
+ from one table must be accompanied by a deletion from the
+ other).
+
+ To allow for efficient implementation strategies, agents may
+ delay updating this object for short periods of time. For
+ example, an implementation strategy may allow internal
+ data structures to differ from those visible via SNMP for
+ short periods of time. This counter may reflect the internal
+ data structures for those short periods of time.
+
+ Note that the table size can be determined by subtracting
+ hlMatrixControlNlDeletes from hlMatrixControlNlInserts."
+ ::= { hlMatrixControlEntry 5 }
+
+hlMatrixControlNlMaxDesiredEntries OBJECT-TYPE
+ SYNTAX Integer32 (-1..2147483647)
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "The maximum number of entries that are desired in the
+ nlMatrix tables on behalf of this control entry. The probe
+ will not create more than this number of associated entries in
+ the table, but may choose to create fewer entries in this
+ table for any reason including the lack of resources.
+
+ If this object is set to a value less than the current number
+ of entries, enough entries are chosen in an
+ implementation-dependent manner and deleted so that the number
+ of entries in the table equals the value of this object.
+
+ If this value is set to -1, the probe may create any number
+ of entries in this table. If the associated
+
+
+
+
+ hlMatrixControlStatus object is equal to `active', this
+ object may not be modified.
+
+ This object may be used to control how resources are allocated
+ on the probe for the various RMON functions."
+ ::= { hlMatrixControlEntry 6 }
+
+hlMatrixControlAlDroppedFrames OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The total number of frames which were received by the probe
+ and therefore not accounted for in the *StatsDropEvents, but
+ for which the probe chose not to count for this entry for
+ whatever reason. Most often, this event occurs when the probe
+ is out of some resources and decides to shed load from this
+ collection.
+
+ This count does not include packets that were not counted
+ because they had MAC-layer errors.
+
+ Note that if the alMatrixTables are not implemented or are
+ inactive because no protocols are enabled in the protocol
+ directory, this value should be 0.
+
+ Note that, unlike the dropEvents counter, this number is the
+ exact number of frames dropped."
+ ::= { hlMatrixControlEntry 7 }
+
+hlMatrixControlAlInserts OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of times an alMatrix entry has been
+ inserted into the alMatrix tables. If an entry is inserted,
+ then deleted, and then inserted, this counter will be
+ incremented by 2. The addition of a conversation into both
+ the alMatrixSDTable and alMatrixDSTable shall be counted as
+ two insertions (even though every addition into one table must
+ be accompanied by an insertion into the other).
+
+ To allow for efficient implementation strategies, agents may
+ delay updating this object for short periods of time. For
+ example, an implementation strategy may allow internal
+ data structures to differ from those visible via SNMP for
+ short periods of time. This counter may reflect the internal
+
+ data structures for those short periods of time.
+
+ Note that the table size can be determined by subtracting
+ hlMatrixControlAlDeletes from hlMatrixControlAlInserts."
+ ::= { hlMatrixControlEntry 8 }
+
+hlMatrixControlAlDeletes OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of times an alMatrix entry has been
+ deleted from the alMatrix tables. If an entry is deleted,
+ then inserted, and then deleted, this counter will be
+ incremented by 2. The deletion of a conversation from both
+ the alMatrixSDTable and alMatrixDSTable shall be counted as
+ two deletions (even though every deletion from one table must
+ be accompanied by a deletion from the other).
+
+ To allow for efficient implementation strategies, agents may
+ delay updating this object for short periods of time. For
+ example, an implementation strategy may allow internal
+ data structures to differ from those visible via SNMP for
+ short periods of time. This counter may reflect the internal
+ data structures for those short periods of time.
+
+ Note that the table size can be determined by subtracting
+ hlMatrixControlAlDeletes from hlMatrixControlAlInserts."
+ ::= { hlMatrixControlEntry 9 }
+
+hlMatrixControlAlMaxDesiredEntries OBJECT-TYPE
+ SYNTAX Integer32 (-1..2147483647)
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "The maximum number of entries that are desired in the
+ alMatrix tables on behalf of this control entry. The probe
+ will not create more than this number of associated entries in
+ the table, but may choose to create fewer entries in this
+ table for any reason including the lack of resources.
+
+ If this object is set to a value less than the current number
+ of entries, enough entries are chosen in an
+ implementation-dependent manner and deleted so that the number
+ of entries in the table equals the value of this object.
+
+ If this value is set to -1, the probe may create any number
+ of entries in this table. If the associated
+
+
+ hlMatrixControlStatus object is equal to `active', this
+ object may not be modified.
+
+ This object may be used to control how resources are allocated
+ on the probe for the various RMON functions."
+ ::= { hlMatrixControlEntry 10 }
+
+hlMatrixControlOwner OBJECT-TYPE
+ SYNTAX OwnerString
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "The entity that configured this entry and is
+ therefore using the resources assigned to it."
+ ::= { hlMatrixControlEntry 11 }
+
+hlMatrixControlStatus OBJECT-TYPE
+ SYNTAX RowStatus
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "The status of this hlMatrixControlEntry.
+
+ An entry may not exist in the active state unless all
+ objects in the entry have an appropriate value.
+
+ If this object is not equal to active(1), all
+ associated entries in the nlMatrixSDTable,
+ nlMatrixDSTable, alMatrixSDTable, and the alMatrixDSTable
+ shall be deleted by the agent."
+ ::= { hlMatrixControlEntry 12 }
+
+nlMatrixSDTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF NlMatrixSDEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A list of traffic matrix entries which collect statistics for
+ conversations between two network-level addresses. This table
+ is indexed first by the source address and then by the
+ destination address to make it convenient to collect all
+ conversations from a particular address.
+
+ The probe will populate this table for all network layer
+ protocols in the protocol directory table whose value of
+ protocolDirMatrixConfig is equal to supportedOn(3), and
+ will delete any entries whose protocolDirEntry is deleted or
+ has a protocolDirMatrixConfig value of supportedOff(2).
+
+ The probe will add to this table all pairs of addresses
+ seen in all packets with no MAC errors, and will increment
+ octet and packet counts in the table for all packets with no
+ MAC errors.
+
+ Further, this table will only contain entries that have a
+ corresponding entry in the nlMatrixDSTable with the same
+ source address and destination address."
+ ::= { nlMatrix 2 }
+
+nlMatrixSDEntry OBJECT-TYPE
+ SYNTAX NlMatrixSDEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A conceptual row in the nlMatrixSDTable.
+
+ The hlMatrixControlIndex value in the index identifies the
+ hlMatrixControlEntry on whose behalf this entry was created.
+ The protocolDirLocalIndex value in the index identifies the
+ network layer protocol of the nlMatrixSDSourceAddress and
+ nlMatrixSDDestAddress.
+
+ An example of the indexing of this table is
+ nlMatrixSDPkts.1.783495.18.4.128.2.6.6.4.128.2.6.7"
+ INDEX { hlMatrixControlIndex, nlMatrixSDTimeMark,
+ protocolDirLocalIndex,
+ nlMatrixSDSourceAddress, nlMatrixSDDestAddress }
+ ::= { nlMatrixSDTable 1 }
+
+NlMatrixSDEntry ::= SEQUENCE {
+ nlMatrixSDTimeMark TimeFilter,
+ nlMatrixSDSourceAddress OCTET STRING,
+ nlMatrixSDDestAddress OCTET STRING,
+ nlMatrixSDPkts ZeroBasedCounter32,
+ nlMatrixSDOctets ZeroBasedCounter32,
+ nlMatrixSDCreateTime LastCreateTime
+}
+
+nlMatrixSDTimeMark OBJECT-TYPE
+ SYNTAX TimeFilter
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A TimeFilter for this entry. See the TimeFilter textual
+ convention to see how this works."
+ ::= { nlMatrixSDEntry 1 }
+
+
+
+nlMatrixSDSourceAddress OBJECT-TYPE
+ SYNTAX OCTET STRING
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "The network source address for this nlMatrixSDEntry.
+
+ This is represented as an octet string with
+ specific semantics and length as identified
+ by the protocolDirLocalIndex component of the index.
+
+ For example, if the protocolDirLocalIndex indicates an
+ encapsulation of ip, this object is encoded as a length
+ octet of 4, followed by the 4 octets of the ip address,
+ in network byte order."
+ ::= { nlMatrixSDEntry 2 }
+
+nlMatrixSDDestAddress OBJECT-TYPE
+ SYNTAX OCTET STRING
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "The network destination address for this
+ nlMatrixSDEntry.
+
+ This is represented as an octet string with
+ specific semantics and length as identified
+ by the protocolDirLocalIndex component of the index.
+
+ For example, if the protocolDirLocalIndex indicates an
+ encapsulation of ip, this object is encoded as a length
+ octet of 4, followed by the 4 octets of the ip address,
+ in network byte order."
+ ::= { nlMatrixSDEntry 3 }
+
+nlMatrixSDPkts OBJECT-TYPE
+ SYNTAX ZeroBasedCounter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of packets without errors transmitted from the
+ source address to the destination address since this entry was
+ added to the nlMatrixSDTable. Note that this is the number of
+ link-layer packets, so if a single network-layer packet is
+ fragmented into several link-layer frames, this counter is
+ incremented several times."
+ ::= { nlMatrixSDEntry 4 }
+
+
+
+nlMatrixSDOctets OBJECT-TYPE
+ SYNTAX ZeroBasedCounter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of octets transmitted from the source address to
+ the destination address since this entry was added to the
+ nlMatrixSDTable (excluding framing bits but
+ including FCS octets), excluding those octets in packets that
+ contained errors.
+
+ Note this doesn't count just those octets in the particular
+ protocol frames, but includes the entire packet that contained
+ the protocol."
+ ::= { nlMatrixSDEntry 5 }
+
+nlMatrixSDCreateTime OBJECT-TYPE
+ SYNTAX LastCreateTime
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The value of sysUpTime when this entry was last activated.
+ This can be used by the management station to ensure that the
+ entry has not been deleted and recreated between polls."
+ ::= { nlMatrixSDEntry 6 }
+
+
+-- Traffic matrix tables from destination to source
+
+nlMatrixDSTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF NlMatrixDSEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A list of traffic matrix entries which collect statistics for
+ conversations between two network-level addresses. This table
+ is indexed first by the destination address and then by the
+ source address to make it convenient to collect all
+ conversations to a particular address.
+
+ The probe will populate this table for all network layer
+ protocols in the protocol directory table whose value of
+ protocolDirMatrixConfig is equal to supportedOn(3), and
+ will delete any entries whose protocolDirEntry is deleted or
+ has a protocolDirMatrixConfig value of supportedOff(2).
+
+ The probe will add to this table all pairs of addresses
+ seen in all packets with no MAC errors, and will increment
+
+
+ octet and packet counts in the table for all packets with no
+ MAC errors.
+
+ Further, this table will only contain entries that have a
+ corresponding entry in the nlMatrixSDTable with the same
+ source address and destination address."
+ ::= { nlMatrix 3 }
+
+nlMatrixDSEntry OBJECT-TYPE
+ SYNTAX NlMatrixDSEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A conceptual row in the nlMatrixDSTable.
+
+ The hlMatrixControlIndex value in the index identifies the
+ hlMatrixControlEntry on whose behalf this entry was created.
+ The protocolDirLocalIndex value in the index identifies the
+ network layer protocol of the nlMatrixDSSourceAddress and
+ nlMatrixDSDestAddress.
+
+ An example of the indexing of this table is
+ nlMatrixDSPkts.1.783495.18.4.128.2.6.7.4.128.2.6.6"
+ INDEX { hlMatrixControlIndex, nlMatrixDSTimeMark,
+ protocolDirLocalIndex,
+ nlMatrixDSDestAddress, nlMatrixDSSourceAddress }
+ ::= { nlMatrixDSTable 1 }
+
+NlMatrixDSEntry ::= SEQUENCE {
+ nlMatrixDSTimeMark TimeFilter,
+ nlMatrixDSSourceAddress OCTET STRING,
+ nlMatrixDSDestAddress OCTET STRING,
+ nlMatrixDSPkts ZeroBasedCounter32,
+ nlMatrixDSOctets ZeroBasedCounter32,
+ nlMatrixDSCreateTime LastCreateTime
+}
+
+nlMatrixDSTimeMark OBJECT-TYPE
+ SYNTAX TimeFilter
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A TimeFilter for this entry. See the TimeFilter textual
+ convention to see how this works."
+ ::= { nlMatrixDSEntry 1 }
+
+nlMatrixDSSourceAddress OBJECT-TYPE
+ SYNTAX OCTET STRING
+
+
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "The network source address for this nlMatrixDSEntry.
+
+ This is represented as an octet string with
+ specific semantics and length as identified
+ by the protocolDirLocalIndex component of the index.
+
+ For example, if the protocolDirLocalIndex indicates an
+ encapsulation of ip, this object is encoded as a length
+ octet of 4, followed by the 4 octets of the ip address,
+ in network byte order."
+ ::= { nlMatrixDSEntry 2 }
+
+nlMatrixDSDestAddress OBJECT-TYPE
+ SYNTAX OCTET STRING
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "The network destination address for this
+ nlMatrixDSEntry.
+
+ This is represented as an octet string with
+ specific semantics and length as identified
+ by the protocolDirLocalIndex component of the index.
+
+ For example, if the protocolDirLocalIndex indicates an
+ encapsulation of ip, this object is encoded as a length
+ octet of 4, followed by the 4 octets of the ip address,
+ in network byte order."
+ ::= { nlMatrixDSEntry 3 }
+
+nlMatrixDSPkts OBJECT-TYPE
+ SYNTAX ZeroBasedCounter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of packets without errors transmitted from the
+ source address to the destination address since this entry was
+ added to the nlMatrixDSTable. Note that this is the number of
+ link-layer packets, so if a single network-layer packet is
+ fragmented into several link-layer frames, this counter is
+ incremented several times."
+ ::= { nlMatrixDSEntry 4 }
+
+nlMatrixDSOctets OBJECT-TYPE
+ SYNTAX ZeroBasedCounter32
+
+
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of octets transmitted from the source address
+ to the destination address since this entry was added to the
+ nlMatrixDSTable (excluding framing bits but
+ including FCS octets), excluding those octets in packets that
+ contained errors.
+
+ Note this doesn't count just those octets in the particular
+ protocol frames, but includes the entire packet that contained
+ the protocol."
+ ::= { nlMatrixDSEntry 5 }
+
+nlMatrixDSCreateTime OBJECT-TYPE
+ SYNTAX LastCreateTime
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The value of sysUpTime when this entry was last activated.
+ This can be used by the management station to ensure that the
+ entry has not been deleted and recreated between polls."
+ ::= { nlMatrixDSEntry 6 }
+
+nlMatrixTopNControlTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF NlMatrixTopNControlEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A set of parameters that control the creation of a
+ report of the top N matrix entries according to
+ a selected metric."
+ ::= { nlMatrix 4 }
+
+nlMatrixTopNControlEntry OBJECT-TYPE
+ SYNTAX NlMatrixTopNControlEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A conceptual row in the nlMatrixTopNControlTable.
+
+ An example of the indexing of this table is
+ nlMatrixTopNControlDuration.3"
+ INDEX { nlMatrixTopNControlIndex }
+ ::= { nlMatrixTopNControlTable 1 }
+
+NlMatrixTopNControlEntry ::= SEQUENCE {
+ nlMatrixTopNControlIndex Integer32,
+
+
+ nlMatrixTopNControlMatrixIndex Integer32,
+ nlMatrixTopNControlRateBase INTEGER,
+ nlMatrixTopNControlTimeRemaining Integer32,
+ nlMatrixTopNControlGeneratedReports Counter32,
+ nlMatrixTopNControlDuration Integer32,
+ nlMatrixTopNControlRequestedSize Integer32,
+ nlMatrixTopNControlGrantedSize Integer32,
+ nlMatrixTopNControlStartTime TimeStamp,
+ nlMatrixTopNControlOwner OwnerString,
+ nlMatrixTopNControlStatus RowStatus
+}
+
+nlMatrixTopNControlIndex OBJECT-TYPE
+ SYNTAX Integer32 (1..65535)
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "An index that uniquely identifies an entry
+ in the nlMatrixTopNControlTable. Each such
+ entry defines one top N report prepared for
+ one interface."
+ ::= { nlMatrixTopNControlEntry 1 }
+
+nlMatrixTopNControlMatrixIndex OBJECT-TYPE
+ SYNTAX Integer32 (1..65535)
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "The nlMatrix[SD/DS] table for which a top N report will be
+ prepared on behalf of this entry. The nlMatrix[SD/DS] table
+ is identified by the value of the hlMatrixControlIndex
+ for that table - that value is used here to identify the
+ particular table.
+
+ This object may not be modified if the associated
+ nlMatrixTopNControlStatus object is equal to active(1)."
+ ::= { nlMatrixTopNControlEntry 2 }
+
+nlMatrixTopNControlRateBase OBJECT-TYPE
+ SYNTAX INTEGER {
+ nlMatrixTopNPkts(1),
+ nlMatrixTopNOctets(2)
+ }
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "The variable for each nlMatrix[SD/DS] entry that the
+ nlMatrixTopNEntries are sorted by.
+
+
+ This object may not be modified if the associated
+ nlMatrixTopNControlStatus object is equal to active(1)."
+ ::= { nlMatrixTopNControlEntry 3 }
+
+nlMatrixTopNControlTimeRemaining OBJECT-TYPE
+ SYNTAX Integer32 (0..2147483647)
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "The number of seconds left in the report currently
+ being collected. When this object is modified by
+ the management station, a new collection is started,
+ possibly aborting a currently running report. The
+ new value is used as the requested duration of this
+ report, and is immediately loaded into the associated
+ nlMatrixTopNControlDuration object.
+ When the report finishes, the probe will automatically
+ start another collection with the same initial value
+ of nlMatrixTopNControlTimeRemaining. Thus the management
+ station may simply read the resulting reports repeatedly,
+ checking the startTime and duration each time to ensure that a
+ report was not missed or that the report parameters were not
+ changed.
+
+ While the value of this object is non-zero, it decrements
+ by one per second until it reaches zero. At the time
+ that this object decrements to zero, the report is made
+ accessible in the nlMatrixTopNTable, overwriting any report
+ that may be there.
+
+ When this object is modified by the management station, any
+ associated entries in the nlMatrixTopNTable shall be deleted.
+
+ (Note that this is a different algorithm than the one used in
+ the hostTopNTable)."
+ DEFVAL { 1800 }
+ ::= { nlMatrixTopNControlEntry 4 }
+
+nlMatrixTopNControlGeneratedReports OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of reports that have been generated by this entry."
+ ::= { nlMatrixTopNControlEntry 5 }
+
+nlMatrixTopNControlDuration OBJECT-TYPE
+ SYNTAX Integer32
+
+
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of seconds that this report has collected
+ during the last sampling interval.
+
+ When the associated nlMatrixTopNControlTimeRemaining object is
+ set, this object shall be set by the probe to the
+ same value and shall not be modified until the next
+ time the nlMatrixTopNControlTimeRemaining is set.
+ This value shall be zero if no reports have been
+ requested for this nlMatrixTopNControlEntry."
+ ::= { nlMatrixTopNControlEntry 6 }
+
+nlMatrixTopNControlRequestedSize OBJECT-TYPE
+ SYNTAX Integer32 (0..2147483647)
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "The maximum number of matrix entries requested for this report.
+
+ When this object is created or modified, the probe
+ should set nlMatrixTopNControlGrantedSize as closely to this
+ object as is possible for the particular probe
+ implementation and available resources."
+ DEFVAL { 150 }
+ ::= { nlMatrixTopNControlEntry 7 }
+
+nlMatrixTopNControlGrantedSize OBJECT-TYPE
+ SYNTAX Integer32 (0..2147483647)
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The maximum number of matrix entries in this report.
+
+ When the associated nlMatrixTopNControlRequestedSize object is
+ created or modified, the probe should set this
+ object as closely to the requested value as is
+ possible for the particular implementation and
+ available resources. The probe must not lower this
+ value except as a result of a set to the associated
+ nlMatrixTopNControlRequestedSize object.
+
+ If the value of nlMatrixTopNControlRateBase is equal to
+ nlMatrixTopNPkts, when the next topN report is generated,
+ matrix entries with the highest value of nlMatrixTopNPktRate
+ shall be placed in this table in decreasing order of this rate
+ until there is no more room or until there are no more
+
+
+ matrix entries.
+
+ If the value of nlMatrixTopNControlRateBase is equal to
+ nlMatrixTopNOctets, when the next topN report is generated,
+ matrix entries with the highest value of nlMatrixTopNOctetRate
+ shall be placed in this table in decreasing order of this rate
+ until there is no more room or until there are no more
+ matrix entries.
+
+ It is an implementation-specific matter how entries with the
+ same value of nlMatrixTopNPktRate or nlMatrixTopNOctetRate are
+ sorted. It is also an implementation-specific matter as to
+ whether or not zero-valued entries are available."
+ ::= { nlMatrixTopNControlEntry 8 }
+
+nlMatrixTopNControlStartTime OBJECT-TYPE
+ SYNTAX TimeStamp
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The value of sysUpTime when this top N report was
+ last started. In other words, this is the time that
+ the associated nlMatrixTopNControlTimeRemaining object was
+ modified to start the requested report or the time
+ the report was last automatically (re)started.
+
+ This object may be used by the management station to
+ determine if a report was missed or not."
+ ::= { nlMatrixTopNControlEntry 9 }
+
+nlMatrixTopNControlOwner OBJECT-TYPE
+ SYNTAX OwnerString
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "The entity that configured this entry and is
+ therefore using the resources assigned to it."
+ ::= { nlMatrixTopNControlEntry 10 }
+
+nlMatrixTopNControlStatus OBJECT-TYPE
+ SYNTAX RowStatus
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "The status of this nlMatrixTopNControlEntry.
+
+ An entry may not exist in the active state unless all
+ objects in the entry have an appropriate value.
+
+
+ If this object is not equal to active(1), all
+ associated entries in the nlMatrixTopNTable shall be deleted
+ by the agent."
+ ::= { nlMatrixTopNControlEntry 11 }
+
+nlMatrixTopNTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF NlMatrixTopNEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A set of statistics for those network layer matrix entries
+ that have counted the highest number of octets or packets."
+ ::= { nlMatrix 5 }
+
+nlMatrixTopNEntry OBJECT-TYPE
+ SYNTAX NlMatrixTopNEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A conceptual row in the nlMatrixTopNTable.
+
+ The nlMatrixTopNControlIndex value in the index identifies the
+ nlMatrixTopNControlEntry on whose behalf this entry was
+ created.
+
+ An example of the indexing of this table is
+ nlMatrixTopNPktRate.3.10"
+ INDEX { nlMatrixTopNControlIndex, nlMatrixTopNIndex }
+ ::= { nlMatrixTopNTable 1 }
+
+NlMatrixTopNEntry ::= SEQUENCE {
+ nlMatrixTopNIndex Integer32,
+ nlMatrixTopNProtocolDirLocalIndex Integer32,
+ nlMatrixTopNSourceAddress OCTET STRING,
+ nlMatrixTopNDestAddress OCTET STRING,
+ nlMatrixTopNPktRate Gauge32,
+ nlMatrixTopNReversePktRate Gauge32,
+ nlMatrixTopNOctetRate Gauge32,
+ nlMatrixTopNReverseOctetRate Gauge32
+}
+
+nlMatrixTopNIndex OBJECT-TYPE
+ SYNTAX Integer32 (1..65535)
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "An index that uniquely identifies an entry in
+ the nlMatrixTopNTable among those in the same report.
+
+
+ This index is between 1 and N, where N is the
+ number of entries in this report.
+
+ If the value of nlMatrixTopNControlRateBase is equal to
+ nlMatrixTopNPkts, increasing values of nlMatrixTopNIndex shall
+ be assigned to entries with decreasing values of
+ nlMatrixTopNPktRate until index N is assigned or there are no
+ more nlMatrixTopNEntries.
+
+ If the value of nlMatrixTopNControlRateBase is equal to
+ nlMatrixTopNOctets, increasing values of nlMatrixTopNIndex
+ shall be assigned to entries with decreasing values of
+ nlMatrixTopNOctetRate until index N is assigned or there are
+ no more nlMatrixTopNEntries."
+ ::= { nlMatrixTopNEntry 1 }
+
+nlMatrixTopNProtocolDirLocalIndex OBJECT-TYPE
+ SYNTAX Integer32 (1..2147483647)
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The protocolDirLocalIndex of the network layer protocol of
+ this entry's network address."
+ ::= { nlMatrixTopNEntry 2 }
+
+nlMatrixTopNSourceAddress OBJECT-TYPE
+ SYNTAX OCTET STRING
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The network layer address of the source host in this
+ conversation.
+
+ This is represented as an octet string with
+ specific semantics and length as identified
+ by the associated nlMatrixTopNProtocolDirLocalIndex.
+
+ For example, if the protocolDirLocalIndex indicates an
+ encapsulation of ip, this object is encoded as a length
+ octet of 4, followed by the 4 octets of the ip address,
+ in network byte order."
+ ::= { nlMatrixTopNEntry 3 }
+
+nlMatrixTopNDestAddress OBJECT-TYPE
+ SYNTAX OCTET STRING
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+
+
+ "The network layer address of the destination host in this
+ conversation.
+
+ This is represented as an octet string with
+ specific semantics and length as identified
+ by the associated nlMatrixTopNProtocolDirLocalIndex.
+
+ For example, if the nlMatrixTopNProtocolDirLocalIndex
+ indicates an encapsulation of ip, this object is encoded as a
+ length octet of 4, followed by the 4 octets of the ip address,
+ in network byte order."
+ ::= { nlMatrixTopNEntry 4 }
+
+nlMatrixTopNPktRate OBJECT-TYPE
+ SYNTAX Gauge32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of packets seen from the source host
+ to the destination host during this sampling interval, counted
+ using the rules for counting the nlMatrixSDPkts object.
+ If the value of nlMatrixTopNControlRateBase is
+ nlMatrixTopNPkts, this variable will be used to sort this
+ report."
+ ::= { nlMatrixTopNEntry 5 }
+
+nlMatrixTopNReversePktRate OBJECT-TYPE
+ SYNTAX Gauge32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of packets seen from the destination host to the
+ source host during this sampling interval, counted
+ using the rules for counting the nlMatrixSDPkts object (note
+ that the corresponding nlMatrixSDPkts object selected is the
+ one whose source address is equal to nlMatrixTopNDestAddress
+ and whose destination address is equal to
+ nlMatrixTopNSourceAddress.)
+
+ Note that if the value of nlMatrixTopNControlRateBase is equal
+ to nlMatrixTopNPkts, the sort of topN entries is based
+ entirely on nlMatrixTopNPktRate, and not on the value of this
+ object."
+ ::= { nlMatrixTopNEntry 6 }
+
+nlMatrixTopNOctetRate OBJECT-TYPE
+ SYNTAX Gauge32
+ MAX-ACCESS read-only
+
+
+ STATUS current
+ DESCRIPTION
+ "The number of octets seen from the source host
+ to the destination host during this sampling interval, counted
+ using the rules for counting the nlMatrixSDOctets object. If
+ the value of nlMatrixTopNControlRateBase is
+ nlMatrixTopNOctets, this variable will be used to sort this
+ report."
+ ::= { nlMatrixTopNEntry 7 }
+
+nlMatrixTopNReverseOctetRate OBJECT-TYPE
+ SYNTAX Gauge32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of octets seen from the destination host to the
+ source host during this sampling interval, counted
+ using the rules for counting the nlMatrixDSOctets object (note
+ that the corresponding nlMatrixSDOctets object selected is the
+ one whose source address is equal to nlMatrixTopNDestAddress
+ and whose destination address is equal to
+ nlMatrixTopNSourceAddress.)
+
+ Note that if the value of nlMatrixTopNControlRateBase is equal
+ to nlMatrixTopNOctets, the sort of topN entries is based
+ entirely on nlMatrixTopNOctetRate, and not on the value of
+ this object."
+ ::= { nlMatrixTopNEntry 8 }
+
+-- Application Layer Functions
+--
+-- The application layer host, matrix, and matrixTopN functions report
+-- on protocol usage at the network layer or higher. Note that the
+-- use of the term application layer does not imply that only
+-- application-layer protocols are counted, rather it means that
+-- protocols up to and including the application layer are supported.
+
+--
+-- Application Layer Host Group
+--
+-- Counts the amount of traffic, by protocol, sent from and to each
+-- network address discovered by the probe.
+-- Implementation of this group requires implementation of the Network
+-- Layer Host Group.
+
+alHostTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF AlHostEntry
+ MAX-ACCESS not-accessible
+
+
+ STATUS current
+ DESCRIPTION
+ "A collection of statistics for a particular protocol from a
+ particular network address that has been discovered on an
+ interface of this device.
+
+ The probe will populate this table for all protocols in the
+ protocol directory table whose value of
+ protocolDirHostConfig is equal to supportedOn(3), and
+ will delete any entries whose protocolDirEntry is deleted or
+ has a protocolDirHostConfig value of supportedOff(2).
+
+ The probe will add to this table all addresses
+ seen as the source or destination address in all packets with
+ no MAC errors, and will increment octet and packet counts in
+ the table for all packets with no MAC errors. Further,
+ entries will only be added to this table if their address
+ exists in the nlHostTable and will be deleted from this table
+ if their address is deleted from the nlHostTable."
+ ::= { alHost 1 }
+
+alHostEntry OBJECT-TYPE
+ SYNTAX AlHostEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A conceptual row in the alHostTable.
+
+ The hlHostControlIndex value in the index identifies the
+ hlHostControlEntry on whose behalf this entry was created.
+ The first protocolDirLocalIndex value in the index identifies
+ the network layer protocol of the address.
+ The nlHostAddress value in the index identifies the network
+ layer address of this entry.
+ The second protocolDirLocalIndex value in the index identifies
+ the protocol that is counted by this entry.
+
+ An example of the indexing in this entry is
+ alHostOutPkts.1.783495.18.4.128.2.6.6.34"
+ INDEX { hlHostControlIndex, alHostTimeMark,
+ protocolDirLocalIndex, nlHostAddress,
+ protocolDirLocalIndex } -- OTP-1427
+ ::= { alHostTable 1 }
+
+AlHostEntry ::= SEQUENCE {
+ alHostTimeMark TimeFilter,
+ alHostInPkts ZeroBasedCounter32,
+ alHostOutPkts ZeroBasedCounter32,
+
+
+ alHostInOctets ZeroBasedCounter32,
+ alHostOutOctets ZeroBasedCounter32,
+ alHostCreateTime LastCreateTime
+}
+
+alHostTimeMark OBJECT-TYPE
+ SYNTAX TimeFilter
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A TimeFilter for this entry. See the TimeFilter textual
+ convention to see how this works."
+ ::= { alHostEntry 1 }
+
+alHostInPkts OBJECT-TYPE
+ SYNTAX ZeroBasedCounter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of packets of this protocol type without errors
+ transmitted to this address since it was added to the
+ alHostTable. Note that this is the number of link-layer
+ packets, so if a single network-layer packet is fragmented
+ into several link-layer frames, this counter is incremented
+ several times."
+ ::= { alHostEntry 2 }
+
+alHostOutPkts OBJECT-TYPE
+ SYNTAX ZeroBasedCounter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of packets of this protocol type without errors
+ transmitted by this address since it was added to the
+ alHostTable. Note that this is the number of link-layer
+ packets, so if a single network-layer packet is fragmented
+ into several link-layer frames, this counter is incremented
+ several times."
+ ::= { alHostEntry 3 }
+
+alHostInOctets OBJECT-TYPE
+ SYNTAX ZeroBasedCounter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of octets transmitted to this address
+ of this protocol type since it was added to the
+ alHostTable (excluding framing bits but including
+
+
+ FCS octets), excluding those octets in packets that
+ contained errors.
+
+ Note this doesn't count just those octets in the particular
+ protocol frames, but includes the entire packet that contained
+ the protocol."
+ ::= { alHostEntry 4 }
+
+alHostOutOctets OBJECT-TYPE
+ SYNTAX ZeroBasedCounter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of octets transmitted by this address
+ of this protocol type since it was added to the
+ alHostTable (excluding framing bits but including
+ FCS octets), excluding those octets in packets that
+ contained errors.
+
+ Note this doesn't count just those octets in the particular
+ protocol frames, but includes the entire packet that contained
+ the protocol."
+ ::= { alHostEntry 5 }
+
+alHostCreateTime OBJECT-TYPE
+ SYNTAX LastCreateTime
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The value of sysUpTime when this entry was last activated.
+ This can be used by the management station to ensure that the
+ entry has not been deleted and recreated between polls."
+ ::= { alHostEntry 6 }
+
+--
+-- Application Layer Matrix Group
+--
+-- Counts the amount of traffic, by protocol, sent between each pair
+-- of network addresses discovered by the probe.
+-- Implementation of this group requires implementation of the Network
+-- Layer Matrix Group.
+
+alMatrixSDTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF AlMatrixSDEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A list of application traffic matrix entries which collect
+
+
+ statistics for conversations of a particular protocol between
+ two network-level addresses. This table is indexed first by
+ the source address and then by the destination address to make
+ it convenient to collect all statistics from a particular
+ address.
+
+ The probe will populate this table for all protocols in the
+ protocol directory table whose value of
+ protocolDirMatrixConfig is equal to supportedOn(3), and
+ will delete any entries whose protocolDirEntry is deleted or
+ has a protocolDirMatrixConfig value of supportedOff(2).
+
+ The probe will add to this table all pairs of addresses for
+ all protocols seen in all packets with no MAC errors, and will
+ increment octet and packet counts in the table for all packets
+ with no MAC errors. Further, entries will only be added to
+ this table if their address pair exists in the nlMatrixSDTable
+ and will be deleted from this table if the address pair is
+ deleted from the nlMatrixSDTable."
+ ::= { alMatrix 1 }
+
+alMatrixSDEntry OBJECT-TYPE
+ SYNTAX AlMatrixSDEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A conceptual row in the alMatrixSDTable.
+
+ The hlMatrixControlIndex value in the index identifies the
+ hlMatrixControlEntry on whose behalf this entry was created.
+ The first protocolDirLocalIndex value in the index identifies
+ the network layer protocol of the nlMatrixSDSourceAddress and
+ nlMatrixSDDestAddress.
+ The nlMatrixSDSourceAddress value in the index identifies the
+ network layer address of the source host in this conversation.
+ The nlMatrixSDDestAddress value in the index identifies the
+ network layer address of the destination host in this
+ conversation.
+ The second protocolDirLocalIndex value in the index identifies
+ the protocol that is counted by this entry.
+
+ An example of the indexing of this entry is
+ alMatrixSDPkts.1.783495.18.4.128.2.6.6.4.128.2.6.7.34"
+ INDEX { hlMatrixControlIndex, alMatrixSDTimeMark,
+ protocolDirLocalIndex,
+ nlMatrixSDSourceAddress, nlMatrixSDDestAddress,
+ protocolDirLocalIndex }
+ ::= { alMatrixSDTable 1 }
+
+
+AlMatrixSDEntry ::= SEQUENCE {
+ alMatrixSDTimeMark TimeFilter,
+ alMatrixSDPkts ZeroBasedCounter32,
+ alMatrixSDOctets ZeroBasedCounter32,
+ alMatrixSDCreateTime LastCreateTime
+}
+
+alMatrixSDTimeMark OBJECT-TYPE
+ SYNTAX TimeFilter
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A TimeFilter for this entry. See the TimeFilter textual
+ convention to see how this works."
+ ::= { alMatrixSDEntry 1 }
+
+alMatrixSDPkts OBJECT-TYPE
+ SYNTAX ZeroBasedCounter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of packets of this protocol type without errors
+ transmitted from the source address to the destination address
+ since this entry was added to the alMatrixSDTable. Note that
+ this is the number of link-layer packets, so if a single
+ network-layer packet is fragmented into several link-layer
+ frames, this counter is incremented several times."
+ ::= { alMatrixSDEntry 2 }
+
+alMatrixSDOctets OBJECT-TYPE
+ SYNTAX ZeroBasedCounter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of octets in packets of this protocol type
+ transmitted from the source address to the destination address
+ since this entry was added to the alMatrixSDTable (excluding
+ framing bits but including FCS octets), excluding those octets
+ in packets that contained errors.
+
+ Note this doesn't count just those octets in the particular
+ protocol frames, but includes the entire packet that contained
+ the protocol."
+ ::= { alMatrixSDEntry 3 }
+
+alMatrixSDCreateTime OBJECT-TYPE
+ SYNTAX LastCreateTime
+ MAX-ACCESS read-only
+
+
+ STATUS current
+ DESCRIPTION
+ "The value of sysUpTime when this entry was last activated.
+ This can be used by the management station to ensure that the
+ entry has not been deleted and recreated between polls."
+ ::= { alMatrixSDEntry 4 }
+
+-- Traffic matrix tables from destination to source
+
+alMatrixDSTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF AlMatrixDSEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A list of application traffic matrix entries which collect
+ statistics for conversations of a particular protocol between
+ two network-level addresses. This table is indexed first by
+ the destination address and then by the source address to make
+ it convenient to collect all statistics to a particular
+ address.
+
+ The probe will populate this table for all protocols in the
+ protocol directory table whose value of
+ protocolDirMatrixConfig is equal to supportedOn(3), and
+ will delete any entries whose protocolDirEntry is deleted or
+ has a protocolDirMatrixConfig value of supportedOff(2).
+
+ The probe will add to this table all pairs of addresses for
+ all protocols seen in all packets with no MAC errors, and will
+ increment octet and packet counts in the table for all packets
+ with no MAC errors. Further, entries will only be added to
+ this table if their address pair exists in the nlMatrixDSTable
+ and will be deleted from this table if the address pair is
+ deleted from the nlMatrixDSTable."
+ ::= { alMatrix 2 }
+
+alMatrixDSEntry OBJECT-TYPE
+ SYNTAX AlMatrixDSEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A conceptual row in the alMatrixDSTable.
+
+ The hlMatrixControlIndex value in the index identifies the
+ hlMatrixControlEntry on whose behalf this entry was created.
+ The first protocolDirLocalIndex value in the index identifies
+ the network layer protocol of the alMatrixDSSourceAddress and
+ alMatrixDSDestAddress.
+
+
+ The nlMatrixDSDestAddress value in the index identifies the
+ network layer address of the destination host in this
+ conversation.
+ The nlMatrixDSSourceAddress value in the index identifies the
+ network layer address of the source host in this conversation.
+ The second protocolDirLocalIndex value in the index identifies
+ the protocol that is counted by this entry.
+
+ An example of the indexing of this entry is
+ alMatrixDSPkts.1.783495.18.4.128.2.6.7.4.128.2.6.6.34"
+ INDEX { hlMatrixControlIndex, alMatrixDSTimeMark,
+ protocolDirLocalIndex,
+ nlMatrixDSDestAddress, nlMatrixDSSourceAddress,
+ protocolDirLocalIndex }
+ ::= { alMatrixDSTable 1 }
+
+AlMatrixDSEntry ::= SEQUENCE {
+ alMatrixDSTimeMark TimeFilter,
+ alMatrixDSPkts ZeroBasedCounter32,
+ alMatrixDSOctets ZeroBasedCounter32,
+ alMatrixDSCreateTime LastCreateTime
+}
+
+alMatrixDSTimeMark OBJECT-TYPE
+ SYNTAX TimeFilter
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A TimeFilter for this entry. See the TimeFilter textual
+ convention to see how this works."
+ ::= { alMatrixDSEntry 1 }
+
+alMatrixDSPkts OBJECT-TYPE
+ SYNTAX ZeroBasedCounter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of packets of this protocol type without errors
+ transmitted from the source address to the destination address
+ since this entry was added to the alMatrixDSTable. Note that
+ this is the number of link-layer packets, so if a single
+ network-layer packet is fragmented into several link-layer
+ frames, this counter is incremented several times."
+ ::= { alMatrixDSEntry 2 }
+
+alMatrixDSOctets OBJECT-TYPE
+ SYNTAX ZeroBasedCounter32
+ MAX-ACCESS read-only
+
+
+ STATUS current
+ DESCRIPTION
+ "The number of octets in packets of this protocol type
+ transmitted from the source address to the destination address
+ since this entry was added to the alMatrixDSTable (excluding
+ framing bits but including FCS octets), excluding those octets
+ in packets that contained errors.
+
+ Note this doesn't count just those octets in the particular
+ protocol frames, but includes the entire packet that contained
+ the protocol."
+ ::= { alMatrixDSEntry 3 }
+
+alMatrixDSCreateTime OBJECT-TYPE
+ SYNTAX LastCreateTime
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The value of sysUpTime when this entry was last activated.
+ This can be used by the management station to ensure that the
+ entry has not been deleted and recreated between polls."
+ ::= { alMatrixDSEntry 4 }
+
+alMatrixTopNControlTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF AlMatrixTopNControlEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A set of parameters that control the creation of a
+ report of the top N matrix entries according to
+ a selected metric."
+ ::= { alMatrix 3 }
+
+alMatrixTopNControlEntry OBJECT-TYPE
+ SYNTAX AlMatrixTopNControlEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A conceptual row in the alMatrixTopNControlTable.
+
+ An example of the indexing of this table is
+ alMatrixTopNControlDuration.3"
+ INDEX { alMatrixTopNControlIndex }
+ ::= { alMatrixTopNControlTable 1 }
+
+AlMatrixTopNControlEntry ::= SEQUENCE {
+ alMatrixTopNControlIndex Integer32,
+ alMatrixTopNControlMatrixIndex Integer32,
+
+
+ alMatrixTopNControlRateBase INTEGER,
+ alMatrixTopNControlTimeRemaining Integer32,
+ alMatrixTopNControlGeneratedReports Counter32,
+ alMatrixTopNControlDuration Integer32,
+ alMatrixTopNControlRequestedSize Integer32,
+ alMatrixTopNControlGrantedSize Integer32,
+ alMatrixTopNControlStartTime TimeStamp,
+ alMatrixTopNControlOwner OwnerString,
+ alMatrixTopNControlStatus RowStatus
+}
+
+alMatrixTopNControlIndex OBJECT-TYPE
+ SYNTAX Integer32 (1..65535)
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "An index that uniquely identifies an entry
+ in the alMatrixTopNControlTable. Each such
+ entry defines one top N report prepared for
+ one interface."
+ ::= { alMatrixTopNControlEntry 1 }
+
+alMatrixTopNControlMatrixIndex OBJECT-TYPE
+ SYNTAX Integer32 (1..65535)
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "The alMatrix[SD/DS] table for which a top N report will be
+ prepared on behalf of this entry. The alMatrix[SD/DS] table
+ is identified by the value of the hlMatrixControlIndex
+ for that table - that value is used here to identify the
+ particular table.
+
+ This object may not be modified if the associated
+ alMatrixTopNControlStatus object is equal to active(1)."
+ ::= { alMatrixTopNControlEntry 2 }
+
+alMatrixTopNControlRateBase OBJECT-TYPE
+ SYNTAX INTEGER {
+ alMatrixTopNTerminalsPkts(1),
+ alMatrixTopNTerminalsOctets(2),
+ alMatrixTopNAllPkts(3),
+ alMatrixTopNAllOctets(4)
+ }
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "The variable for each alMatrix[SD/DS] entry that the
+
+
+ alMatrixTopNEntries are sorted by, as well as the
+ selector of the view of the matrix table that will be
+ used.
+
+ The values alMatrixTopNTerminalsPkts and
+ alMatrixTopNTerminalsOctets cause collection only from
+ protocols that have no child protocols that are counted. The
+ values alMatrixTopNAllPkts and alMatrixTopNAllOctets cause
+ collection from all alMatrix entries.
+
+ This object may not be modified if the associated
+ alMatrixTopNControlStatus object is equal to active(1)."
+ ::= { alMatrixTopNControlEntry 3 }
+
+alMatrixTopNControlTimeRemaining OBJECT-TYPE
+ SYNTAX Integer32 (0..2147483647)
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "The number of seconds left in the report currently
+ being collected. When this object is modified by
+ the management station, a new collection is started,
+ possibly aborting a currently running report. The
+ new value is used as the requested duration of this
+ report, and is immediately loaded into the associated
+ alMatrixTopNControlDuration object.
+ When the report finishes, the probe will automatically
+ start another collection with the same initial value
+ of alMatrixTopNControlTimeRemaining. Thus the management
+ station may simply read the resulting reports repeatedly,
+ checking the startTime and duration each time to ensure that a
+ report was not missed or that the report parameters were not
+ changed.
+
+ While the value of this object is non-zero, it decrements
+ by one per second until it reaches zero. At the time
+ that this object decrements to zero, the report is made
+ accessible in the alMatrixTopNTable, overwriting any report
+ that may be there.
+
+ When this object is modified by the management station, any
+ associated entries in the alMatrixTopNTable shall be deleted.
+
+ (Note that this is a different algorithm than the one used in
+ the hostTopNTable)."
+ DEFVAL { 1800 }
+ ::= { alMatrixTopNControlEntry 4 }
+
+
+
+alMatrixTopNControlGeneratedReports OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of reports that have been generated by this entry."
+ ::= { alMatrixTopNControlEntry 5 }
+
+alMatrixTopNControlDuration OBJECT-TYPE
+ SYNTAX Integer32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of seconds that this report has collected
+ during the last sampling interval.
+
+ When the associated alMatrixTopNControlTimeRemaining object
+ is set, this object shall be set by the probe to the
+ same value and shall not be modified until the next
+ time the alMatrixTopNControlTimeRemaining is set.
+
+ This value shall be zero if no reports have been
+ requested for this alMatrixTopNControlEntry."
+ ::= { alMatrixTopNControlEntry 6 }
+
+alMatrixTopNControlRequestedSize OBJECT-TYPE
+ SYNTAX Integer32 (0..2147483647)
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "The maximum number of matrix entries requested for this report.
+
+ When this object is created or modified, the probe
+ should set alMatrixTopNControlGrantedSize as closely to this
+ object as is possible for the particular probe
+ implementation and available resources."
+ DEFVAL { 150 }
+ ::= { alMatrixTopNControlEntry 7 }
+
+alMatrixTopNControlGrantedSize OBJECT-TYPE
+ SYNTAX Integer32 (0..2147483647)
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The maximum number of matrix entries in this report.
+
+ When the associated alMatrixTopNControlRequestedSize object
+ is created or modified, the probe should set this
+
+
+ object as closely to the requested value as is
+ possible for the particular implementation and
+ available resources. The probe must not lower this
+ value except as a result of a set to the associated
+ alMatrixTopNControlRequestedSize object.
+
+ If the value of alMatrixTopNControlRateBase is equal to
+ alMatrixTopNTerminalsPkts or alMatrixTopNAllPkts, when the
+ next topN report is generated, matrix entries with the highest
+ value of alMatrixTopNPktRate shall be placed in this table in
+ decreasing order of this rate until there is no more room or
+ until there are no more matrix entries.
+
+ If the value of alMatrixTopNControlRateBase is equal to
+ alMatrixTopNTerminalsOctets or alMatrixTopNAllOctets, when the
+ next topN report is generated, matrix entries with the highest
+ value of alMatrixTopNOctetRate shall be placed in this table
+ in decreasing order of this rate until there is no more room
+ or until there are no more matrix entries.
+
+ It is an implementation-specific matter how entries with the
+ same value of alMatrixTopNPktRate or alMatrixTopNOctetRate are
+ sorted. It is also an implementation-specific matter as to
+ whether or not zero-valued entries are available."
+ ::= { alMatrixTopNControlEntry 8 }
+
+alMatrixTopNControlStartTime OBJECT-TYPE
+ SYNTAX TimeStamp
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The value of sysUpTime when this top N report was
+ last started. In other words, this is the time that
+ the associated alMatrixTopNControlTimeRemaining object
+ was modified to start the requested report or the time
+ the report was last automatically (re)started.
+
+ This object may be used by the management station to
+ determine if a report was missed or not."
+ ::= { alMatrixTopNControlEntry 9 }
+
+alMatrixTopNControlOwner OBJECT-TYPE
+ SYNTAX OwnerString
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "The entity that configured this entry and is
+ therefore using the resources assigned to it."
+
+
+ ::= { alMatrixTopNControlEntry 10 }
+
+alMatrixTopNControlStatus OBJECT-TYPE
+ SYNTAX RowStatus
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "The status of this alMatrixTopNControlEntry.
+
+ An entry may not exist in the active state unless all
+ objects in the entry have an appropriate value.
+
+ If this object is not equal to active(1), all
+ associated entries in the alMatrixTopNTable shall be
+ deleted by the agent."
+ ::= { alMatrixTopNControlEntry 11 }
+
+alMatrixTopNTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF AlMatrixTopNEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A set of statistics for those application layer matrix
+ entries that have counted the highest number of octets or
+ packets."
+ ::= { alMatrix 4 }
+
+alMatrixTopNEntry OBJECT-TYPE
+ SYNTAX AlMatrixTopNEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A conceptual row in the alMatrixTopNTable.
+
+ The alMatrixTopNControlIndex value in the index identifies
+ the alMatrixTopNControlEntry on whose behalf this entry was
+ created.
+
+ An example of the indexing of this table is
+ alMatrixTopNPktRate.3.10"
+ INDEX { alMatrixTopNControlIndex, alMatrixTopNIndex }
+ ::= { alMatrixTopNTable 1 }
+
+AlMatrixTopNEntry ::= SEQUENCE {
+ alMatrixTopNIndex Integer32,
+ alMatrixTopNProtocolDirLocalIndex Integer32,
+ alMatrixTopNSourceAddress OCTET STRING,
+ alMatrixTopNDestAddress OCTET STRING,
+
+
+ alMatrixTopNAppProtocolDirLocalIndex Integer32,
+ alMatrixTopNPktRate Gauge32,
+ alMatrixTopNReversePktRate Gauge32,
+ alMatrixTopNOctetRate Gauge32,
+ alMatrixTopNReverseOctetRate Gauge32
+ }
+
+alMatrixTopNIndex OBJECT-TYPE
+ SYNTAX Integer32 (1..65535)
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "An index that uniquely identifies an entry in
+ the alMatrixTopNTable among those in the same report.
+ This index is between 1 and N, where N is the
+ number of entries in this report.
+
+ If the value of alMatrixTopNControlRateBase is equal to
+ alMatrixTopNTerminalsPkts or alMatrixTopNAllPkts, increasing
+ values of alMatrixTopNIndex shall be assigned to entries with
+ decreasing values of alMatrixTopNPktRate until index N is
+ assigned or there are no more alMatrixTopNEntries.
+
+ If the value of alMatrixTopNControlRateBase is equal to
+ alMatrixTopNTerminalsOctets or alMatrixTopNAllOctets,
+ increasing values of alMatrixTopNIndex shall be assigned to
+ entries with decreasing values of alMatrixTopNOctetRate until
+ index N is assigned or there are no more alMatrixTopNEntries."
+ ::= { alMatrixTopNEntry 1 }
+
+alMatrixTopNProtocolDirLocalIndex OBJECT-TYPE
+ SYNTAX Integer32 (1..2147483647)
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The protocolDirLocalIndex of the network layer protocol of
+ this entry's network address."
+ ::= { alMatrixTopNEntry 2 }
+
+alMatrixTopNSourceAddress OBJECT-TYPE
+ SYNTAX OCTET STRING
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The network layer address of the source host in this
+ conversation.
+ This is represented as an octet string with
+ specific semantics and length as identified
+
+
+ by the associated alMatrixTopNProtocolDirLocalIndex.
+
+ For example, if the alMatrixTopNProtocolDirLocalIndex
+ indicates an encapsulation of ip, this object is encoded as a
+ length octet of 4, followed by the 4 octets of the ip address,
+ in network byte order."
+ ::= { alMatrixTopNEntry 3 }
+
+alMatrixTopNDestAddress OBJECT-TYPE
+ SYNTAX OCTET STRING
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The network layer address of the destination host in this
+ conversation.
+
+ This is represented as an octet string with
+ specific semantics and length as identified
+ by the associated alMatrixTopNProtocolDirLocalIndex.
+
+ For example, if the alMatrixTopNProtocolDirLocalIndex
+ indicates an encapsulation of ip, this object is encoded as a
+ length octet of 4, followed by the 4 octets of the ip address,
+ in network byte order."
+ ::= { alMatrixTopNEntry 4 }
+
+alMatrixTopNAppProtocolDirLocalIndex OBJECT-TYPE
+ SYNTAX Integer32 (1..2147483647)
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The type of the protocol counted by this matrix entry."
+ ::= { alMatrixTopNEntry 5 }
+
+alMatrixTopNPktRate OBJECT-TYPE
+ SYNTAX Gauge32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of packets seen of this protocol from the source
+ host to the destination host during this sampling interval,
+ counted using the rules for counting the alMatrixSDPkts
+ object.
+
+ If the value of alMatrixTopNControlRateBase is
+ alMatrixTopNTerminalsPkts or alMatrixTopNAllPkts, this
+ variable will be used to sort this report."
+ ::= { alMatrixTopNEntry 6 }
+
+
+alMatrixTopNReversePktRate OBJECT-TYPE
+ SYNTAX Gauge32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of packets seen of this protocol from the
+ destination host to the source host during this sampling
+ interval, counted using the rules for counting the
+ alMatrixDSPkts object (note that the corresponding
+ alMatrixSDPkts object selected is the one whose source address
+ is equal to alMatrixTopNDestAddress and whose destination
+ address is equal to alMatrixTopNSourceAddress.)
+
+ Note that if the value of alMatrixTopNControlRateBase is equal
+ to alMatrixTopNTerminalsPkts or alMatrixTopNAllPkts, the sort
+ of topN entries is based entirely on alMatrixTopNPktRate, and
+ not on the value of this object."
+ ::= { alMatrixTopNEntry 7 }
+
+alMatrixTopNOctetRate OBJECT-TYPE
+ SYNTAX Gauge32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of octets seen of this protocol from the source
+ host to the destination host during this sampling interval,
+ counted using the rules for counting the alMatrixSDOctets
+ object.
+
+ If the value of alMatrixTopNControlRateBase is
+ alMatrixTopNTerminalsOctets or alMatrixTopNAllOctets, this
+ variable will be used to sort this report."
+ ::= { alMatrixTopNEntry 8 }
+
+alMatrixTopNReverseOctetRate OBJECT-TYPE
+ SYNTAX Gauge32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of octets seen of this protocol from the
+ destination host to the source host during this sampling
+ interval, counted using the rules for counting the
+ alMatrixDSOctets object (note that the corresponding
+ alMatrixSDOctets object selected is the one whose source
+ address is equal to alMatrixTopNDestAddress and whose
+ destination address is equal to alMatrixTopNSourceAddress.)
+
+ Note that if the value of alMatrixTopNControlRateBase is equal
+
+
+ to alMatrixTopNTerminalsOctets or alMatrixTopNAllOctets, the
+ sort of topN entries is based entirely on
+ alMatrixTopNOctetRate, and not on the value of this object."
+ ::= { alMatrixTopNEntry 9 }
+
+--
+-- User History Collection Group (usrHistory)
+--
+-- The usrHistory group combines mechanisms seen in the alarm and
+-- history groups to provide user-specified history collection,
+-- utilizing two additional control tables and one additional data
+-- table. This function has traditionally been done by NMS
+-- applications, via periodic polling. The usrHistory group allows
+-- this task to be offloaded to an RMON probe.
+--
+-- Data (an ASN.1 INTEGER based object) is collected in the same
+-- manner as any history data table (e.g. etherHistoryTable) except
+-- that the user specifies the MIB instances to be collected. Objects
+-- are collected in bucket-groups, with the intent that all MIB
+-- instances in the same bucket-group are collected as atomically as
+-- possible by the RMON probe.
+--
+-- The usrHistoryControlTable is a one-dimensional read-create table.
+-- Each row configures a collection of user history buckets, much
+-- the same as a historyControlEntry, except that the creation of a
+-- row in this table will cause one or more associated instances in
+-- the usrHistoryObjectTable to be created. The user specifies the
+-- number of bucket elements (rows in the usrHistoryObjectTable)
+-- requested, as well as the number of buckets requested.
+--
+-- The usrHistoryObjectTable is a 2-d read-write table.
+-- Each row configures a single MIB instance to be collected.
+-- All rows with the same major index constitute a bucket-group.
+--
+-- The usrHistoryTable is a 3-d read-only table containing
+-- the data of associated usrHistoryControlEntries. Each
+-- entry represents the value of a single MIB instance
+-- during a specific sampling interval (or the rate of
+-- change during the interval).
+--
+-- A sample value is stored in two objects - an absolute value and
+-- a status object. This allows numbers from -(2G-1) to +4G to be
+-- stored. The status object also indicates whether a sample is
+-- valid. This allows data collection to continue if periodic
+-- retrieval of a particular instance fails for any reason.
+--
+-- Row Creation Order Relationships
+--
+
+
+-- The static nature of the usrHistoryObjectTable creates
+-- some row creation/modification issues. The rows in this
+-- table need to be set before the associated
+-- usrHistoryControlEntry can be activated.
+--
+-- Note that the usrHistoryObject entries associated with a
+-- particular usrHistoryControlEntry are not required to
+-- be active before the control entry is activated. However,
+-- the usrHistory data entries associated with an inactive
+-- usrHistoryObject entry will be inactive (i.e.
+-- usrHistoryValStatus == valueNotAvailable).
+--
+
+usrHistoryControlTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF UsrHistoryControlEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A list of data-collection configuration entries."
+ ::= { usrHistory 1 }
+
+usrHistoryControlEntry OBJECT-TYPE
+ SYNTAX UsrHistoryControlEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A list of parameters that set up a group of user-defined
+ MIB objects to be sampled periodically (called a
+ bucket-group).
+
+ For example, an instance of usrHistoryControlInterval
+ might be named usrHistoryControlInterval.1"
+ INDEX { usrHistoryControlIndex }
+ ::= { usrHistoryControlTable 1 }
+
+UsrHistoryControlEntry ::= SEQUENCE {
+ usrHistoryControlIndex Integer32,
+ usrHistoryControlObjects Integer32,
+ usrHistoryControlBucketsRequested Integer32,
+ usrHistoryControlBucketsGranted Integer32,
+ usrHistoryControlInterval Integer32,
+ usrHistoryControlOwner OwnerString,
+ usrHistoryControlStatus RowStatus
+}
+
+usrHistoryControlIndex OBJECT-TYPE
+ SYNTAX Integer32 (1..65535)
+ MAX-ACCESS not-accessible
+
+
+ STATUS current
+ DESCRIPTION
+ "An index that uniquely identifies an entry in the
+ usrHistoryControlTable. Each such entry defines a
+ set of samples at a particular interval for a specified
+ set of MIB instances available from the managed system."
+ ::= { usrHistoryControlEntry 1 }
+
+usrHistoryControlObjects OBJECT-TYPE
+ SYNTAX Integer32 (1..65535)
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "The number of MIB objects to be collected
+ in the portion of usrHistoryTable associated with this
+ usrHistoryControlEntry.
+
+ This object may not be modified if the associated instance
+ of usrHistoryControlStatus is equal to active(1)."
+ ::= { usrHistoryControlEntry 2 }
+
+usrHistoryControlBucketsRequested OBJECT-TYPE
+ SYNTAX Integer32 (1..65535)
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "The requested number of discrete time intervals
+ over which data is to be saved in the part of the
+ usrHistoryTable associated with this usrHistoryControlEntry.
+
+ When this object is created or modified, the probe
+ should set usrHistoryControlBucketsGranted as closely to
+ this object as is possible for the particular probe
+ implementation and available resources."
+ DEFVAL { 50 }
+ ::= { usrHistoryControlEntry 3 }
+
+usrHistoryControlBucketsGranted OBJECT-TYPE
+ SYNTAX Integer32 (1..65535)
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of discrete sampling intervals
+ over which data shall be saved in the part of
+ the usrHistoryTable associated with this
+ usrHistoryControlEntry.
+
+ When the associated usrHistoryControlBucketsRequested
+
+
+ object is created or modified, the probe should set
+ this object as closely to the requested value as is
+ possible for the particular probe implementation and
+ available resources. The probe must not lower this
+ value except as a result of a modification to the associated
+ usrHistoryControlBucketsRequested object.
+
+ The associated usrHistoryControlBucketsRequested object
+ should be set before or at the same time as this object
+ to allow the probe to accurately estimate the resources
+ required for this usrHistoryControlEntry.
+
+ There will be times when the actual number of buckets
+ associated with this entry is less than the value of
+ this object. In this case, at the end of each sampling
+ interval, a new bucket will be added to the usrHistoryTable.
+
+ When the number of buckets reaches the value of this object
+ and a new bucket is to be added to the usrHistoryTable,
+ the oldest bucket associated with this usrHistoryControlEntry
+ shall be deleted by the agent so that the new bucket can be
+ added.
+
+ When the value of this object changes to a value less than
+ the current value, entries are deleted from the
+ usrHistoryTable associated with this usrHistoryControlEntry.
+ Enough of the oldest of these entries shall be deleted by the
+ agent so that their number remains less than or equal to the
+ new value of this object.
+
+ When the value of this object changes to a value greater
+ than the current value, the number of associated usrHistory
+ entries may be allowed to grow."
+ ::= { usrHistoryControlEntry 4 }
+
+
+usrHistoryControlInterval OBJECT-TYPE
+ SYNTAX Integer32 (1..2147483647)
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "The interval in seconds over which the data is
+ sampled for each bucket in the part of the usrHistory
+ table associated with this usrHistoryControlEntry.
+
+ Because the counters in a bucket may overflow at their
+ maximum value with no indication, a prudent manager will
+ take into account the possibility of overflow in any of
+
+
+ the associated counters. It is important to consider the
+ minimum time in which any counter could overflow on a
+ particular media type and set the usrHistoryControlInterval
+ object to a value less than this interval.
+
+ This object may not be modified if the associated
+ usrHistoryControlStatus object is equal to active(1)."
+ DEFVAL { 1800 }
+ ::= { usrHistoryControlEntry 5 }
+
+usrHistoryControlOwner OBJECT-TYPE
+ SYNTAX OwnerString
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "The entity that configured this entry and is
+ therefore using the resources assigned to it."
+ ::= { usrHistoryControlEntry 6 }
+
+usrHistoryControlStatus OBJECT-TYPE
+ SYNTAX RowStatus
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "The status of this variable history control entry.
+
+ An entry may not exist in the active state unless all
+ objects in the entry have an appropriate value.
+
+ If this object is not equal to active(1), all associated
+ entries in the usrHistoryTable shall be deleted."
+ ::= { usrHistoryControlEntry 7 }
+
+-- Object table
+
+usrHistoryObjectTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF UsrHistoryObjectEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A list of data-collection configuration entries."
+ ::= { usrHistory 2 }
+
+usrHistoryObjectEntry OBJECT-TYPE
+ SYNTAX UsrHistoryObjectEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+
+
+ "A list of MIB instances to be sampled periodically.
+
+ Entries in this table are created when an associated
+ usrHistoryControlObjects object is created.
+
+ The usrHistoryControlIndex value in the index is
+ that of the associated usrHistoryControlEntry.
+
+ For example, an instance of usrHistoryObjectVariable might be
+ usrHistoryObjectVariable.1.3"
+ INDEX { usrHistoryControlIndex, usrHistoryObjectIndex }
+ ::= { usrHistoryObjectTable 1 }
+
+UsrHistoryObjectEntry ::= SEQUENCE {
+ usrHistoryObjectIndex Integer32,
+ usrHistoryObjectVariable OBJECT IDENTIFIER,
+ usrHistoryObjectSampleType INTEGER
+}
+
+usrHistoryObjectIndex OBJECT-TYPE
+ SYNTAX Integer32 (1..65535)
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "An index used to uniquely identify an entry in the
+ usrHistoryObject table. Each such entry defines a
+ MIB instance to be collected periodically."
+ ::= { usrHistoryObjectEntry 1 }
+
+
+usrHistoryObjectVariable OBJECT-TYPE
+ SYNTAX OBJECT IDENTIFIER
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "The object identifier of the particular variable to be
+ sampled.
+
+ Only variables that resolve to an ASN.1 primitive type of
+ Integer32 (Integer32, Counter, Gauge, or TimeTicks) may be
+ sampled.
+
+ Because SNMP access control is articulated entirely in terms
+ of the contents of MIB views, no access control mechanism
+ exists that can restrict the value of this object to identify
+ only those objects that exist in a particular MIB view.
+ Because there is thus no acceptable means of restricting the
+ read access that could be obtained through the user history
+
+
+ mechanism, the probe must only grant write access to this
+ object in those views that have read access to all objects on
+ the probe.
+
+ During a set operation, if the supplied variable name is not
+ available in the selected MIB view, a badValue error must be
+ returned.
+
+ This object may not be modified if the associated
+ usrHistoryControlStatus object is equal to active(1)."
+ ::= { usrHistoryObjectEntry 2 }
+
+usrHistoryObjectSampleType OBJECT-TYPE
+ SYNTAX INTEGER {
+ absoluteValue(1),
+ deltaValue(2)
+ }
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "The method of sampling the selected variable for storage in
+ the usrHistoryTable.
+
+ If the value of this object is absoluteValue(1), the value of
+ the selected variable will be copied directly into the history
+ bucket.
+
+ If the value of this object is deltaValue(2), the value of the
+ selected variable at the last sample will be subtracted from
+ the current value, and the difference will be stored in the
+ history bucket. If the associated usrHistoryObjectVariable
+ instance could not be obtained at the previous sample
+ interval, then a delta sample is not possible, and the value
+ of the associated usrHistoryValStatus object for this interval
+ will be valueNotAvailable(1).
+
+ This object may not be modified if the associated
+ usrHistoryControlStatus object is equal to active(1)."
+ ::= { usrHistoryObjectEntry 3 }
+
+-- data table
+
+usrHistoryTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF UsrHistoryEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A list of user defined history entries."
+
+
+ ::= { usrHistory 3 }
+
+usrHistoryEntry OBJECT-TYPE
+ SYNTAX UsrHistoryEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A historical sample of user-defined variables. This sample
+ is associated with the usrHistoryControlEntry which set up the
+ parameters for a regular collection of these samples.
+
+ The usrHistoryControlIndex value in the index identifies the
+ usrHistoryControlEntry on whose behalf this entry was created.
+
+ The usrHistoryObjectIndex value in the index identifies the
+ usrHistoryObjectEntry on whose behalf this entry was created.
+
+ For example, an instance of usrHistoryAbsValue, which represents
+ the 14th sample of a variable collected as specified by
+ usrHistoryControlEntry.1 and usrHistoryObjectEntry.1.5,
+ would be named usrHistoryAbsValue.1.14.5"
+ INDEX { usrHistoryControlIndex, usrHistorySampleIndex,
+ usrHistoryObjectIndex }
+ ::= { usrHistoryTable 1 }
+
+UsrHistoryEntry ::= SEQUENCE {
+ usrHistorySampleIndex Integer32,
+ usrHistoryIntervalStart TimeStamp,
+ usrHistoryIntervalEnd TimeStamp,
+ usrHistoryAbsValue Gauge32,
+ usrHistoryValStatus INTEGER
+}
+
+usrHistorySampleIndex OBJECT-TYPE
+ SYNTAX Integer32 (1..2147483647)
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "An index that uniquely identifies the particular sample this
+ entry represents among all samples associated with the same
+ usrHistoryControlEntry. This index starts at 1 and increases
+ by one as each new sample is taken."
+ ::= { usrHistoryEntry 1 }
+
+usrHistoryIntervalStart OBJECT-TYPE
+ SYNTAX TimeStamp
+ MAX-ACCESS read-only
+ STATUS current
+
+
+ DESCRIPTION
+ "The value of sysUpTime at the start of the interval over
+ which this sample was measured. If the probe keeps track of
+ the time of day, it should start the first sample of the
+ history at a time such that when the next hour of the day
+ begins, a sample is started at that instant.
+
+ Note that following this rule may require the probe to delay
+ collecting the first sample of the history, as each sample
+ must be of the same interval. Also note that the sample which
+ is currently being collected is not accessible in this table
+ until the end of its interval."
+ ::= { usrHistoryEntry 2 }
+
+usrHistoryIntervalEnd OBJECT-TYPE
+ SYNTAX TimeStamp
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The value of sysUpTime at the end of the interval over which
+ this sample was measured."
+ ::= { usrHistoryEntry 3 }
+
+usrHistoryAbsValue OBJECT-TYPE
+ SYNTAX Gauge32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The absolute value (i.e. unsigned value) of the
+ user-specified statistic during the last sampling period. The
+ value during the current sampling period is not made available
+ until the period is completed.
+
+ To obtain the true value for this sampling interval, the
+ associated instance of usrHistoryValStatus must be checked,
+ and usrHistoryAbsValue adjusted as necessary.
+
+ If the MIB instance could not be accessed during the sampling
+ interval, then this object will have a value of zero and the
+ associated instance of usrHistoryValStatus will be set to
+ 'valueNotAvailable(1)'."
+ ::= { usrHistoryEntry 4 }
+
+
+usrHistoryValStatus OBJECT-TYPE
+ SYNTAX INTEGER {
+ valueNotAvailable(1),
+ valuePositive(2),
+
+
+ valueNegative(3)
+ }
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "This object indicates the validity and sign of the data in
+ the associated instance of usrHistoryAbsValue.
+
+ If the MIB instance could not be accessed during the sampling
+ interval, then 'valueNotAvailable(1)' will be returned.
+
+ If the sample is valid and actual value of the sample is
+ greater than or equal to zero then 'valuePositive(2)' is
+ returned.
+
+ If the sample is valid and the actual value of the sample is
+ less than zero, 'valueNegative(3)' will be returned. The
+ associated instance of usrHistoryAbsValue should be multiplied
+ by -1 to obtain the true sample value."
+ ::= { usrHistoryEntry 5 }
+
+-- The Probe Configuration Group
+--
+-- This group controls the configuration of various operating
+-- parameters of the probe.
+
+ControlString ::= TEXTUAL-CONVENTION
+ STATUS current
+ DESCRIPTION
+ "This data type is used to communicate with a modem or a
+ serial data switch. A ControlString contains embedded
+ commands to control how the device will interact with the
+ remote device through the serial interface. Commands are
+ represented as two character sequences beginning with
+ the `^' character.
+
+ The following commands are recognized by the device (note
+ that command characters are case sensitive):
+
+ ^s Send string that follows which is terminated by the
+ next command or the end of string.
+ ^c Delay for the number of seconds that follows. Toss
+ out any data received rather than storing it in a
+ buffer for parsing.
+ ^t Set timeout to the value represented by the decimal
+ digits that follow. The default timeout is 20
+ seconds. Note that this timeout may be overridden
+ by a smaller serialTimeout configured for the
+
+
+ associated serial interface (see serialConfigTable).
+ ^w Wait for the reply string that follows which is
+ terminated by the next command or the end of string.
+ Partial and case insensitive matching is applied, ie.
+ if the reply string (any case combination) is found
+ anywhere in the received string, then the a match is
+ found. If the current timeout elapses without a match,
+ then the remaining control string is ignored.
+ ^! The ^ character.
+ ^d Delay the number of seconds specified by the decimal
+ digits that follow.
+ ^b Send break for the number of milliseconds specified by
+ the decimal digits that follow. If no digits follow,
+ break will be enforced for 250 milliseconds by default.
+
+ The following ASCII control characters may be inserted into
+ the `^s' send string or the `^w' reply string:
+
+ ^@ 0x00
+ ^A 0x01
+ ..
+ ^M 0x0D
+ ..
+ ^Z 0x1A
+ ^[ 0x1B
+ ^ 0x1C
+ ^] 0x1D
+ ^^ 0x1E
+ ^_ 0x1F
+
+ Binary data may also be inserted into the data stream. The
+ control sequence for each byte of binary data is ^0x##, where
+ ## is the hexadecimal representation of the data byte. Two
+ ASCII characters (0-9, a-f, A-F) must follow the `^0x'
+ control prefix. For example, `^0x0D^0x0A' is interpreted as a
+ carriage return followed by a line feed."
+ SYNTAX DisplayString
+
+probeCapabilities OBJECT-TYPE
+ SYNTAX BITS {
+ etherStats(0),
+ historyControl(1),
+ etherHistory(2),
+ alarm(3),
+ hosts(4),
+ hostTopN(5),
+ matrix(6),
+ filter(7),
+
+
+ capture(8),
+ event(9),
+ tokenRingMLStats(10),
+ tokenRingPStats(11),
+ tokenRingMLHistory(12),
+ tokenRingPHistory(13),
+ ringStation(14),
+ ringStationOrder(15),
+ ringStationConfig(16),
+ sourceRouting(17),
+ protocolDirectory(18),
+ protocolDistribution(19),
+ addressMapping(20),
+ nlHost(21),
+ nlMatrix(22),
+ alHost(23),
+ alMatrix(24),
+ usrHistory(25),
+ probeConfig(26)
+ }
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "An indication of the RMON MIB groups supported
+ on at least one interface by this probe."
+ ::= { probeConfig 1 }
+
+probeSoftwareRev OBJECT-TYPE
+ SYNTAX DisplayString (SIZE(0..15))
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The software revision of this device. This string will have
+ a zero length if the revision is unknown."
+ ::= { probeConfig 2 }
+
+probeHardwareRev OBJECT-TYPE
+ SYNTAX DisplayString (SIZE(0..31))
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The hardware revision of this device. This string will have
+ a zero length if the revision is unknown."
+ ::= { probeConfig 3 }
+
+probeDateTime OBJECT-TYPE
+ SYNTAX OCTET STRING (SIZE (0 | 8 | 11))
+ MAX-ACCESS read-write
+
+
+ STATUS current
+ DESCRIPTION
+ "Probe's current date and time.
+
+ field octets contents range
+ ----- ------ -------- -----
+ 1 1-2 year 0..65536
+ 2 3 month 1..12
+ 3 4 day 1..31
+ 4 5 hour 0..23
+ 5 6 minutes 0..59
+ 6 7 seconds 0..60
+ (use 60 for leap-second)
+ 7 8 deci-seconds 0..9
+ 8 9 direction from UTC '+' / '-'
+ 9 10 hours from UTC 0..11
+ 10 11 minutes from UTC 0..59
+
+ For example, Tuesday May 26, 1992 at 1:30:15 PM
+ EDT would be displayed as:
+
+ 1992-5-26,13:30:15.0,-4:0
+
+ Note that if only local time is known, then
+ timezone information (fields 8-10) is not
+ present, and if no time information is known, the null
+ string is returned."
+ ::= { probeConfig 4 }
+
+probeResetControl OBJECT-TYPE
+ SYNTAX INTEGER {
+ running(1),
+ warmBoot(2),
+ coldBoot(3)
+ }
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "Setting this object to warmBoot(2) causes the device to
+ restart the application software with current configuration
+ parameters saved in non-volatile memory. Setting this
+ object to coldBoot(3) causes the device to reinitialize
+ configuration parameters in non-volatile memory to default
+ values and restart the application software. When the device
+ is running normally, this variable has a value of
+ running(1)."
+ ::= { probeConfig 5 }
+
+
+
+-- The following download objects do not restrict an implementation
+-- from implementing additional download mechanisms (controlled in an
+-- implementation-specific manner). Further, in the case where the RMON
+-- agent shares a processor with other types of systems, the
+-- implementation is not required to download those non-RMON functions
+-- with this mechanism.
+
+probeDownloadFile OBJECT-TYPE
+ SYNTAX DisplayString (SIZE(0..127))
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The file name to be downloaded from the TFTP server when a
+ download is next requested via this MIB. This value is set to
+ the zero length string when no file name has been specified."
+ ::= { probeConfig 6 }
+
+probeDownloadTFTPServer OBJECT-TYPE
+ SYNTAX IpAddress
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The IP address of the TFTP server that contains the boot
+ image to load when a download is next requested via this MIB.
+ This value is set to `0.0.0.0' when no IP address has been
+ specified."
+ ::= { probeConfig 7 }
+
+probeDownloadAction OBJECT-TYPE
+ SYNTAX INTEGER {
+ notDownloading(1),
+ downloadToPROM(2),
+ downloadToRAM(3)
+ }
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "When this object is set to downloadToRAM(2) or
+ downloadToPROM(3), the device will discontinue its
+ normal operation and begin download of the image specified
+ by probeDownloadFile from the server specified by
+ probeDownloadTFTPServer using the TFTP protocol. If
+ downloadToRAM(2) is specified, the new image is copied
+ to RAM only (the old image remains unaltered in the flash
+ EPROM). If downloadToPROM(3) is specified
+ the new image is written to the flash EPROM
+ memory after its checksum has been verified to be correct.
+ When the download process is completed, the device will
+
+
+ warm boot to restart the newly loaded application.
+ When the device is not downloading, this object will have
+ a value of notDownloading(1)."
+ ::= { probeConfig 8 }
+
+probeDownloadStatus OBJECT-TYPE
+ SYNTAX INTEGER {
+ downloadSuccess(1),
+ downloadStatusUnknown(2),
+ downloadGeneralError(3),
+ downloadNoResponseFromServer(4),
+ downloadChecksumError(5),
+ downloadIncompatibleImage(6),
+ downloadTftpFileNotFound(7),
+ downloadTftpAccessViolation(8)
+ }
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The status of the last download procedure, if any. This
+ object will have a value of downloadStatusUnknown(2) if no
+ download process has been performed."
+ ::= { probeConfig 9 }
+
+serialConfigTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF SerialConfigEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A table of serial interface configuration entries. This data
+ will be stored in non-volatile memory and preserved across
+ probe resets or power loss."
+ ::= { probeConfig 10 }
+
+serialConfigEntry OBJECT-TYPE
+ SYNTAX SerialConfigEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A set of configuration parameters for a particular
+ serial interface on this device. If the device has no serial
+ interfaces, this table is empty.
+
+ The index is composed of the ifIndex assigned to this serial
+ line interface."
+ INDEX { ifIndex }
+ ::= { serialConfigTable 1 }
+
+
+
+SerialConfigEntry ::= SEQUENCE {
+ serialMode INTEGER,
+ serialProtocol INTEGER,
+ serialTimeout Integer32 (1..65535),
+ serialModemInitString ControlString (SIZE (0..255)),
+ serialModemHangUpString ControlString (SIZE (0..255)),
+ serialModemConnectResp DisplayString (SIZE (0..255)),
+ serialModemNoConnectResp DisplayString (SIZE (0..255)),
+ serialDialoutTimeout Integer32 (1..65535),
+ serialStatus RowStatus
+}
+
+serialMode OBJECT-TYPE
+ SYNTAX INTEGER {
+ direct(1),
+ modem(2)
+ }
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "The type of incoming connection to expect on this serial
+ interface."
+ DEFVAL { direct }
+ ::= { serialConfigEntry 1 }
+
+serialProtocol OBJECT-TYPE
+ SYNTAX INTEGER {
+ other(1),
+ slip(2),
+ ppp(3)
+ }
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "The type of data link encapsulation to be used on this
+ serial interface."
+ DEFVAL { slip }
+ ::= { serialConfigEntry 2 }
+
+serialTimeout OBJECT-TYPE
+ SYNTAX Integer32 (1..65535)
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "This timeout value is used when the Management Station has
+ initiated the conversation over the serial link. This variable
+ represents the number of seconds of inactivity allowed before
+ terminating the connection on this serial interface. Use the
+
+
+ serialDialoutTimeout in the case where the probe has initiated
+ the connection for the purpose of sending a trap."
+ DEFVAL { 300 }
+ ::= { serialConfigEntry 3 }
+
+serialModemInitString OBJECT-TYPE
+ SYNTAX ControlString (SIZE (0..255))
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "A control string which controls how a modem attached to this
+ serial interface should be initialized. The initialization
+ is performed once during startup and again after each
+ connection is terminated if the associated serialMode has the
+ value of modem(2).
+
+ A control string that is appropriate for a wide variety of
+ modems is: '^s^MATE0Q0V1X4 S0=1 S2=43^M'."
+ ::= { serialConfigEntry 4 }
+
+serialModemHangUpString OBJECT-TYPE
+ SYNTAX ControlString (SIZE (0..255))
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "A control string which specifies how to disconnect a modem
+ connection on this serial interface. This object is only
+ meaningful if the associated serialMode has the value
+ of modem(2).
+ A control string that is appropriate for a wide variety of
+ modems is: '^d2^s+++^d2^sATH0^M^d2'."
+ ::= { serialConfigEntry 5 }
+
+serialModemConnectResp OBJECT-TYPE
+ SYNTAX DisplayString (SIZE (0..255))
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "An ASCII string containing substrings that describe the
+ expected modem connection response code and associated bps
+ rate. The substrings are delimited by the first character
+ in the string, for example:
+ /CONNECT/300/CONNECT 1200/1200/CONNECT 2400/2400/
+ CONNECT 4800/4800/CONNECT 9600/9600
+ will be interpreted as:
+ response code bps rate
+ CONNECT 300
+ CONNECT 1200 1200
+
+
+ CONNECT 2400 2400
+ CONNECT 4800 4800
+ CONNECT 9600 9600
+ The agent will use the information in this string to adjust
+ the bps rate of this serial interface once a modem connection
+ is established.
+
+ A value that is appropriate for a wide variety of modems is:
+ '/CONNECT/300/CONNECT 1200/1200/CONNECT 2400/2400/
+ CONNECT 4800/4800/CONNECT 9600/9600/CONNECT 14400/14400/
+ CONNECT 19200/19200/CONNECT 38400/38400/'."
+ ::= { serialConfigEntry 6 }
+
+serialModemNoConnectResp OBJECT-TYPE
+ SYNTAX DisplayString (SIZE (0..255))
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "An ASCII string containing response codes that may be
+ generated by a modem to report the reason why a connection
+ attempt has failed. The response codes are delimited by
+ the first character in the string, for example:
+ /NO CARRIER/BUSY/NO DIALTONE/NO ANSWER/ERROR/
+ If one of these response codes is received via this serial
+ interface while attempting to make a modem connection,
+ the agent will issue the hang up command as specified by
+ serialModemHangUpString.
+
+ A value that is appropriate for a wide variety of modems is:
+ '/NO CARRIER/BUSY/NO DIALTONE/NO ANSWER/ERROR/'."
+ ::= { serialConfigEntry 7 }
+
+serialDialoutTimeout OBJECT-TYPE
+ SYNTAX Integer32 (1..65535)
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "This timeout value is used when the probe initiates the
+ serial connection with the intention of contacting a
+ management station. This variable represents the number
+ of seconds of inactivity allowed before terminating the
+ connection on this serial interface."
+ DEFVAL { 20 }
+ ::= { serialConfigEntry 8 }
+
+serialStatus OBJECT-TYPE
+ SYNTAX RowStatus
+ MAX-ACCESS read-create
+
+
+ STATUS current
+ DESCRIPTION
+ "The status of this serialConfigEntry.
+
+ An entry may not exist in the active state unless all
+ objects in the entry have an appropriate value."
+ ::= { serialConfigEntry 9 }
+
+netConfigTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF NetConfigEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A table of netConfigEntries."
+ ::= { probeConfig 11 }
+
+netConfigEntry OBJECT-TYPE
+ SYNTAX NetConfigEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A set of configuration parameters for a particular
+ network interface on this device. If the device has no network
+ interface, this table is empty.
+
+ The index is composed of the ifIndex assigned to the
+ corresponding interface."
+ INDEX { ifIndex }
+ ::= { netConfigTable 1 }
+
+NetConfigEntry ::= SEQUENCE {
+ netConfigIPAddress IpAddress,
+ netConfigSubnetMask IpAddress,
+ netConfigStatus RowStatus
+}
+
+netConfigIPAddress OBJECT-TYPE
+ SYNTAX IpAddress
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "The IP address of this Net interface. The default value
+ for this object is 0.0.0.0. If either the netConfigIPAddress
+ or netConfigSubnetMask are 0.0.0.0, then when the device
+ boots, it may use BOOTP to try to figure out what these
+ values should be. If BOOTP fails, before the device
+ can talk on the network, this value must be configured
+ (e.g., through a terminal attached to the device). If BOOTP is
+
+
+ used, care should be taken to not send BOOTP broadcasts too
+ frequently and to eventually send very infrequently if no
+ replies are received."
+ ::= { netConfigEntry 1 }
+
+netConfigSubnetMask OBJECT-TYPE
+ SYNTAX IpAddress
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "The subnet mask of this Net interface. The default value
+ for this object is 0.0.0.0. If either the netConfigIPAddress
+ or netConfigSubnetMask are 0.0.0.0, then when the device
+ boots, it may use BOOTP to try to figure out what these
+ values should be. If BOOTP fails, before the device
+ can talk on the network, this value must be configured
+ (e.g., through a terminal attached to the device). If BOOTP is
+ used, care should be taken to not send BOOTP broadcasts too
+ frequently and to eventually send very infrequently if no
+ replies are received."
+ ::= { netConfigEntry 2 }
+
+netConfigStatus OBJECT-TYPE
+ SYNTAX RowStatus
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "The status of this netConfigEntry.
+
+ An entry may not exist in the active state unless all
+ objects in the entry have an appropriate value."
+ ::= { netConfigEntry 3 }
+
+netDefaultGateway OBJECT-TYPE
+ SYNTAX IpAddress
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "The IP Address of the default gateway. If this value is
+ undefined or unknown, it shall have the value 0.0.0.0."
+ ::= { probeConfig 12 }
+
+-- Trap Destination Table
+--
+-- This table defines the destination addresses for traps generated
+-- from the device. This table maps a community to one or more trap
+-- destination entries.
+--
+
+
+-- The same trap will be sent to all destinations specified in the
+-- entries that have the same trapDestCommunity as the eventCommunity
+-- (as defined by RMON MIB). Information in this table will be stored
+-- in non-volatile memory. If the device has gone through a hard
+-- restart, this information will be reset to its default state.
+
+trapDestTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF TrapDestEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A list of trap destination entries."
+ ::= { probeConfig 13 }
+
+trapDestEntry OBJECT-TYPE
+ SYNTAX TrapDestEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "This entry includes a destination IP address to which to send
+ traps for this community."
+ INDEX { trapDestIndex }
+ ::= { trapDestTable 1 }
+
+TrapDestEntry ::= SEQUENCE {
+ trapDestIndex Integer32,
+ trapDestCommunity OCTET STRING,
+ trapDestProtocol INTEGER,
+ trapDestAddress OCTET STRING,
+ trapDestOwner OwnerString,
+ trapDestStatus RowStatus
+}
+
+trapDestIndex OBJECT-TYPE
+ SYNTAX Integer32 (1..65535)
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A value that uniquely identifies this trapDestEntry."
+ ::= { trapDestEntry 1 }
+
+trapDestCommunity OBJECT-TYPE
+ SYNTAX OCTET STRING (SIZE(0..127))
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "A community to which this destination address belongs.
+ This entry is associated with any eventEntries in the RMON
+
+
+ MIB whose value of eventCommunity is equal to the value of
+ this object. Every time an associated event entry sends a
+ trap due to an event, that trap will be sent to each
+ address in the trapDestTable with a trapDestCommunity equal to
+ eventCommunity.
+
+ This object may not be modified if the associated
+ trapDestStatus object is equal to active(1)."
+ ::= { trapDestEntry 2 }
+
+trapDestProtocol OBJECT-TYPE
+ SYNTAX INTEGER {
+ ip(1),
+ ipx(2)
+ }
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "The protocol with which to send this trap."
+ ::= { trapDestEntry 3 }
+
+trapDestAddress OBJECT-TYPE
+ SYNTAX OCTET STRING
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "The address to send traps on behalf of this entry.
+
+ If the associated trapDestProtocol object is equal to ip(1),
+ the encoding of this object is the same as the snmpUDPAddress
+ textual convention in [RFC1906]:
+ -- for a SnmpUDPAddress of length 6:
+ --
+ -- octets contents encoding
+ -- 1-4 IP-address network-byte order
+ -- 5-6 UDP-port network-byte order
+
+ If the associated trapDestProtocol object is equal to ipx(2),
+ the encoding of this object is the same as the snmpIPXAddress
+ textual convention in [RFC1906]:
+ -- for a SnmpIPXAddress of length 12:
+ --
+ -- octets contents encoding
+ -- 1-4 network-number network-byte order
+ -- 5-10 physical-address network-byte order
+ -- 11-12 socket-number network-byte order
+
+ This object may not be modified if the associated
+
+
+ trapDestStatus object is equal to active(1)."
+ ::= { trapDestEntry 4 }
+
+trapDestOwner OBJECT-TYPE
+ SYNTAX OwnerString
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "The entity that configured this entry and is
+ therefore using the resources assigned to it."
+ ::= { trapDestEntry 5 }
+
+trapDestStatus OBJECT-TYPE
+ SYNTAX RowStatus
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "The status of this trap destination entry.
+
+ An entry may not exist in the active state unless all
+ objects in the entry have an appropriate value."
+ ::= { trapDestEntry 6 }
+
+-- Serial Connection Table
+--
+-- The device may communicate with a management station using
+-- SLIP. In order for the device to send traps via SLIP, it must
+-- be able to initiate a connection over the serial interface. The
+-- serialConnectionTable stores the parameters for such connection
+-- initiation.
+
+serialConnectionTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF SerialConnectionEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A list of serialConnectionEntries."
+ ::= { probeConfig 14 }
+
+serialConnectionEntry OBJECT-TYPE
+ SYNTAX SerialConnectionEntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "Configuration for a SLIP link over a serial line."
+ INDEX { serialConnectIndex }
+ ::= { serialConnectionTable 1 }
+
+
+
+SerialConnectionEntry ::= SEQUENCE {
+ serialConnectIndex Integer32,
+ serialConnectDestIpAddress IpAddress,
+ serialConnectType INTEGER,
+ serialConnectDialString ControlString,
+ serialConnectSwitchConnectSeq ControlString,
+ serialConnectSwitchDisconnectSeq ControlString,
+ serialConnectSwitchResetSeq ControlString,
+ serialConnectOwner OwnerString,
+ serialConnectStatus RowStatus
+}
+
+serialConnectIndex OBJECT-TYPE
+ SYNTAX Integer32 (1..65535)
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "A value that uniquely identifies this serialConnection
+ entry."
+ ::= { serialConnectionEntry 1 }
+
+serialConnectDestIpAddress OBJECT-TYPE
+ SYNTAX IpAddress
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "The IP Address that can be reached at the other end of this
+ serial connection.
+ This object may not be modified if the associated
+ serialConnectStatus object is equal to active(1)."
+ ::= { serialConnectionEntry 2 }
+
+
+serialConnectType OBJECT-TYPE
+ SYNTAX INTEGER {
+ direct(1),
+ modem(2),
+ switch(3),
+ modemSwitch(4)
+ }
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "The type of outgoing connection to make. If this object
+ has the value direct(1), then a direct serial connection
+ is assumed. If this object has the value modem(2),
+ then serialConnectDialString will be used to make a modem
+ connection. If this object has the value switch(3),
+
+
+ then serialConnectSwitchConnectSeq will be used to establish
+ the connection over a serial data switch, and
+ serialConnectSwitchDisconnectSeq will be used to terminate
+ the connection. If this object has the value
+ modem-switch(4), then a modem connection will be made first
+ followed by the switch connection.
+
+ This object may not be modified if the associated
+ serialConnectStatus object is equal to active(1)."
+
+ DEFVAL { direct }
+ ::= { serialConnectionEntry 3 }
+
+serialConnectDialString OBJECT-TYPE
+ SYNTAX ControlString (SIZE(0..255))
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "A control string which specifies how to dial the phone
+ number in order to establish a modem connection. The
+ string should include dialing prefix and suffix. For
+ example: ``^s^MATD9,888-1234^M'' will instruct the Probe
+ to send a carriage return followed by the dialing prefix
+ ``ATD'', the phone number ``9,888-1234'', and a carriage
+ return as the dialing suffix.
+ This object may not be modified if the associated
+ serialConnectStatus object is equal to active(1)."
+ ::= { serialConnectionEntry 4 }
+
+serialConnectSwitchConnectSeq OBJECT-TYPE
+ SYNTAX ControlString (SIZE(0..255))
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "A control string which specifies how to establish a
+ data switch connection.
+ This object may not be modified if the associated
+ serialConnectStatus object is equal to active(1)."
+ ::= { serialConnectionEntry 5 }
+
+serialConnectSwitchDisconnectSeq OBJECT-TYPE
+ SYNTAX ControlString (SIZE(0..255))
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "A control string which specifies how to terminate a
+ data switch connection.
+ This object may not be modified if the associated
+
+
+ serialConnectStatus object is equal to active(1)."
+ ::= { serialConnectionEntry 6 }
+
+serialConnectSwitchResetSeq OBJECT-TYPE
+ SYNTAX ControlString (SIZE(0..255))
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "A control string which specifies how to reset a data
+ switch in the event of a timeout.
+ This object may not be modified if the associated
+ serialConnectStatus object is equal to active(1)."
+ ::= { serialConnectionEntry 7 }
+
+serialConnectOwner OBJECT-TYPE
+ SYNTAX OwnerString
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "The entity that configured this entry and is
+ therefore using the resources assigned to it."
+ ::= { serialConnectionEntry 8 }
+
+serialConnectStatus OBJECT-TYPE
+ SYNTAX RowStatus
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "The status of this serialConnectionEntry.
+
+ If the manager attempts to set this object to active(1) when
+ the serialConnectType is set to modem(2) or modem-switch(4)
+ and the serialConnectDialString is a zero-length string or
+ cannot be correctly parsed as a ConnectString, the set
+ request will be rejected with badValue(3).
+
+ If the manager attempts to set this object to active(1) when
+ the serialConnectType is set to switch(3) or modem-switch(4)
+ and the serialConnectSwitchConnectSeq,
+ the serialConnectSwitchDisconnectSeq, or
+ the serialConnectSwitchResetSeq are zero-length strings
+ or cannot be correctly parsed as ConnectStrings, the set
+ request will be rejected with badValue(3).
+
+ An entry may not exist in the active state unless all
+ objects in the entry have an appropriate value."
+ ::= { serialConnectionEntry 9 }
+
+
+
+--
+-- Extensions to the RMON 1 MIB for RMON 2 devices
+--
+-- These extensions include the standard LastCreateTime Textual
+-- Convention for all control tables, as well as an augmentation of
+-- the filter entry that provides variable-length offsets into
+-- packets.
+
+
+-- Each of the following, except for filterDroppedFrames, is a
+-- read-only object which, if implemented, automatically appears when
+-- the RMON1 row it is associated with is created.
+
+etherStats2Table OBJECT-TYPE
+ SYNTAX SEQUENCE OF EtherStats2Entry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "Contains the RMON-2 augmentations to RMON-1."
+ ::= { statistics 4 }
+
+etherStats2Entry OBJECT-TYPE
+ SYNTAX EtherStats2Entry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "Contains the RMON-2 augmentations to RMON-1."
+ AUGMENTS { etherStatsEntry }
+ ::= { etherStats2Table 1 }
+
+EtherStats2Entry ::= SEQUENCE {
+ etherStatsDroppedFrames Counter32,
+ etherStatsCreateTime LastCreateTime
+}
+
+etherStatsDroppedFrames OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The total number of frames which were received by the probe
+ and therefore not accounted for in the *StatsDropEvents, but
+ for which the probe chose not to count for this entry for
+ whatever reason. Most often, this event occurs when the probe
+ is out of some resources and decides to shed load from this
+ collection.
+
+ This count does not include packets that were not counted
+
+
+ because they had MAC-layer errors.
+
+ Note that, unlike the dropEvents counter, this number is the
+ exact number of frames dropped."
+ ::= { etherStats2Entry 1 }
+
+etherStatsCreateTime OBJECT-TYPE
+ SYNTAX LastCreateTime
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The value of sysUpTime when this control entry was last
+ activated. This can be used by the management station to
+ ensure that the table has not been deleted and recreated
+ between polls."
+ ::= { etherStats2Entry 2 }
+
+historyControl2Table OBJECT-TYPE
+ SYNTAX SEQUENCE OF HistoryControl2Entry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "Contains the RMON-2 augmentations to RMON-1."
+ ::= { history 5 }
+
+historyControl2Entry OBJECT-TYPE
+ SYNTAX HistoryControl2Entry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "Contains the RMON-2 augmentations to RMON-1."
+ AUGMENTS { historyControlEntry }
+ ::= { historyControl2Table 1 }
+
+HistoryControl2Entry ::= SEQUENCE {
+ historyControlDroppedFrames Counter32
+}
+
+historyControlDroppedFrames OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The total number of frames which were received by the probe
+ and therefore not accounted for in the *StatsDropEvents, but
+ for which the probe chose not to count for this entry for
+ whatever reason. Most often, this event occurs when the probe
+ is out of some resources and decides to shed load from this
+
+
+ collection.
+
+ This count does not include packets that were not counted
+ because they had MAC-layer errors.
+
+ Note that, unlike the dropEvents counter, this number is the
+ exact number of frames dropped."
+ ::= { historyControl2Entry 1 }
+
+hostControl2Table OBJECT-TYPE
+ SYNTAX SEQUENCE OF HostControl2Entry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "Contains the RMON-2 augmentations to RMON-1."
+ ::= { hosts 4 }
+
+hostControl2Entry OBJECT-TYPE
+ SYNTAX HostControl2Entry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "Contains the RMON-2 augmentations to RMON-1."
+ AUGMENTS { hostControlEntry }
+ ::= { hostControl2Table 1 }
+
+HostControl2Entry ::= SEQUENCE {
+ hostControlDroppedFrames Counter32,
+ hostControlCreateTime LastCreateTime
+}
+
+hostControlDroppedFrames OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The total number of frames which were received by the probe
+ and therefore not accounted for in the *StatsDropEvents, but
+ for which the probe chose not to count for this entry for
+ whatever reason. Most often, this event occurs when the probe
+ is out of some resources and decides to shed load from this
+ collection.
+
+ This count does not include packets that were not counted
+ because they had MAC-layer errors.
+
+ Note that, unlike the dropEvents counter, this number is the
+ exact number of frames dropped."
+
+
+ ::= { hostControl2Entry 1 }
+
+hostControlCreateTime OBJECT-TYPE
+ SYNTAX LastCreateTime
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The value of sysUpTime when this control entry was last
+ activated. This can be used by the management station to
+ ensure that the table has not been deleted and recreated
+ between polls."
+ ::= { hostControl2Entry 2 }
+
+matrixControl2Table OBJECT-TYPE
+ SYNTAX SEQUENCE OF MatrixControl2Entry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "Contains the RMON-2 augmentations to RMON-1."
+ ::= { matrix 4 }
+
+matrixControl2Entry OBJECT-TYPE
+ SYNTAX MatrixControl2Entry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "Contains the RMON-2 augmentations to RMON-1."
+ AUGMENTS { matrixControlEntry }
+ ::= { matrixControl2Table 1 }
+
+MatrixControl2Entry ::= SEQUENCE {
+ matrixControlDroppedFrames Counter32,
+ matrixControlCreateTime LastCreateTime
+}
+
+matrixControlDroppedFrames OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The total number of frames which were received by the probe
+ and therefore not accounted for in the *StatsDropEvents, but
+ for which the probe chose not to count for this entry for
+ whatever reason. Most often, this event occurs when the probe
+ is out of some resources and decides to shed load from this
+ collection.
+
+ This count does not include packets that were not counted
+
+
+ because they had MAC-layer errors.
+
+ Note that, unlike the dropEvents counter, this number is the
+ exact number of frames dropped."
+ ::= { matrixControl2Entry 1 }
+
+matrixControlCreateTime OBJECT-TYPE
+ SYNTAX LastCreateTime
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The value of sysUpTime when this control entry was last
+ activated. This can be used by the management station to
+ ensure that the table has not been deleted and recreated
+ between polls."
+ ::= { matrixControl2Entry 2 }
+
+channel2Table OBJECT-TYPE
+ SYNTAX SEQUENCE OF Channel2Entry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "Contains the RMON-2 augmentations to RMON-1."
+ ::= { filter 3 }
+
+channel2Entry OBJECT-TYPE
+ SYNTAX Channel2Entry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "Contains the RMON-2 augmentations to RMON-1."
+ AUGMENTS { channelEntry }
+ ::= { channel2Table 1 }
+
+Channel2Entry ::= SEQUENCE {
+ channelDroppedFrames Counter32,
+ channelCreateTime LastCreateTime
+}
+
+channelDroppedFrames OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The total number of frames which were received by the probe
+ and therefore not accounted for in the *StatsDropEvents, but
+ for which the probe chose not to count for this entry for
+ whatever reason. Most often, this event occurs when the probe
+
+
+ is out of some resources and decides to shed load from this
+ collection.
+
+ This count does not include packets that were not counted
+ because they had MAC-layer errors.
+
+ Note that, unlike the dropEvents counter, this number is the
+ exact number of frames dropped."
+ ::= { channel2Entry 1 }
+
+channelCreateTime OBJECT-TYPE
+ SYNTAX LastCreateTime
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The value of sysUpTime when this control entry was last
+ activated. This can be used by the management station to
+ ensure that the table has not been deleted and recreated
+ between polls."
+ ::= { channel2Entry 2 }
+
+tokenRingMLStats2Table OBJECT-TYPE
+ SYNTAX SEQUENCE OF TokenRingMLStats2Entry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "Contains the RMON-2 augmentations to RMON-1."
+ ::= { statistics 5 }
+
+tokenRingMLStats2Entry OBJECT-TYPE
+ SYNTAX TokenRingMLStats2Entry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "Contains the RMON-2 augmentations to RMON-1."
+ AUGMENTS { tokenRingMLStatsEntry }
+ ::= { tokenRingMLStats2Table 1 }
+
+TokenRingMLStats2Entry ::= SEQUENCE {
+ tokenRingMLStatsDroppedFrames Counter32,
+ tokenRingMLStatsCreateTime LastCreateTime
+}
+
+tokenRingMLStatsDroppedFrames OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+
+
+ "The total number of frames which were received by the probe
+ and therefore not accounted for in the *StatsDropEvents, but
+ for which the probe chose not to count for this entry for
+ whatever reason. Most often, this event occurs when the probe
+ is out of some resources and decides to shed load from this
+ collection.
+
+ This count does not include packets that were not counted
+ because they had MAC-layer errors.
+
+ Note that, unlike the dropEvents counter, this number is the
+ exact number of frames dropped."
+ ::= { tokenRingMLStats2Entry 1 }
+
+tokenRingMLStatsCreateTime OBJECT-TYPE
+ SYNTAX LastCreateTime
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The value of sysUpTime when this control entry was last activated.
+ This can be used by the management station to ensure that the
+ table has not been deleted and recreated between polls."
+ ::= { tokenRingMLStats2Entry 2 }
+
+tokenRingPStats2Table OBJECT-TYPE
+ SYNTAX SEQUENCE OF TokenRingPStats2Entry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "Contains the RMON-2 augmentations to RMON-1."
+ ::= { statistics 6 }
+
+tokenRingPStats2Entry OBJECT-TYPE
+ SYNTAX TokenRingPStats2Entry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "Contains the RMON-2 augmentations to RMON-1."
+ AUGMENTS { tokenRingPStatsEntry }
+ ::= { tokenRingPStats2Table 1 }
+
+TokenRingPStats2Entry ::= SEQUENCE {
+ tokenRingPStatsDroppedFrames Counter32,
+ tokenRingPStatsCreateTime LastCreateTime
+}
+
+tokenRingPStatsDroppedFrames OBJECT-TYPE
+ SYNTAX Counter32
+
+
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The total number of frames which were received by the probe
+ and therefore not accounted for in the *StatsDropEvents, but
+ for which the probe chose not to count for this entry for
+ whatever reason. Most often, this event occurs when the probe
+ is out of some resources and decides to shed load from this
+ collection.
+
+ This count does not include packets that were not counted
+ because they had MAC-layer errors.
+
+ Note that, unlike the dropEvents counter, this number is the
+ exact number of frames dropped."
+ ::= { tokenRingPStats2Entry 1 }
+
+tokenRingPStatsCreateTime OBJECT-TYPE
+ SYNTAX LastCreateTime
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The value of sysUpTime when this control entry was last activated.
+ This can be used by the management station to ensure that the
+ table has not been deleted and recreated between polls."
+ ::= { tokenRingPStats2Entry 2 }
+
+ringStationControl2Table OBJECT-TYPE
+ SYNTAX SEQUENCE OF RingStationControl2Entry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "Contains the RMON-2 augmentations to RMON-1."
+ ::= { tokenRing 7 }
+
+ringStationControl2Entry OBJECT-TYPE
+ SYNTAX RingStationControl2Entry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "Contains the RMON-2 augmentations to RMON-1."
+ AUGMENTS { ringStationControlEntry }
+ ::= { ringStationControl2Table 1 }
+
+RingStationControl2Entry ::= SEQUENCE {
+ ringStationControlDroppedFrames Counter32,
+ ringStationControlCreateTime LastCreateTime
+}
+
+
+ringStationControlDroppedFrames OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The total number of frames which were received by the probe
+ and therefore not accounted for in the *StatsDropEvents, but
+ for which the probe chose not to count for this entry for
+ whatever reason. Most often, this event occurs when the probe
+ is out of some resources and decides to shed load from this
+ collection.
+
+ This count does not include packets that were not counted
+ because they had MAC-layer errors.
+
+ Note that, unlike the dropEvents counter, this number is the
+ exact number of frames dropped."
+ ::= { ringStationControl2Entry 1 }
+
+ringStationControlCreateTime OBJECT-TYPE
+ SYNTAX LastCreateTime
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The value of sysUpTime when this control entry was last activated.
+ This can be used by the management station to ensure that the
+ table has not been deleted and recreated between polls."
+ ::= { ringStationControl2Entry 2 }
+
+sourceRoutingStats2Table OBJECT-TYPE
+ SYNTAX SEQUENCE OF SourceRoutingStats2Entry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "Contains the RMON-2 augmentations to RMON-1."
+ ::= { tokenRing 8 }
+
+sourceRoutingStats2Entry OBJECT-TYPE
+ SYNTAX SourceRoutingStats2Entry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "Contains the RMON-2 augmentations to RMON-1."
+ AUGMENTS { sourceRoutingStatsEntry }
+ ::= { sourceRoutingStats2Table 1 }
+
+SourceRoutingStats2Entry ::= SEQUENCE {
+ sourceRoutingStatsDroppedFrames Counter32,
+
+
+ sourceRoutingStatsCreateTime LastCreateTime
+}
+
+sourceRoutingStatsDroppedFrames OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The total number of frames which were received by the probe
+ and therefore not accounted for in the *StatsDropEvents, but
+ for which the probe chose not to count for this entry for
+ whatever reason. Most often, this event occurs when the probe
+ is out of some resources and decides to shed load from this
+ collection.
+
+ This count does not include packets that were not counted
+ because they had MAC-layer errors.
+
+ Note that, unlike the dropEvents counter, this number is the
+ exact number of frames dropped."
+ ::= { sourceRoutingStats2Entry 1 }
+
+sourceRoutingStatsCreateTime OBJECT-TYPE
+ SYNTAX LastCreateTime
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The value of sysUpTime when this control entry was last activated.
+ This can be used by the management station to ensure that the
+ table has not been deleted and recreated between polls."
+ ::= { sourceRoutingStats2Entry 2 }
+
+filter2Table OBJECT-TYPE
+ SYNTAX SEQUENCE OF Filter2Entry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "Provides a variable-length packet filter feature to the
+ RMON-1 filter table."
+ ::= { filter 4 }
+
+filter2Entry OBJECT-TYPE
+ SYNTAX Filter2Entry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "Provides a variable-length packet filter feature to the
+ RMON-1 filter table."
+
+
+ AUGMENTS { filterEntry }
+ ::= { filter2Table 1 }
+
+Filter2Entry ::= SEQUENCE {
+ filterProtocolDirDataLocalIndex Integer32,
+ filterProtocolDirLocalIndex Integer32
+}
+
+filterProtocolDirDataLocalIndex OBJECT-TYPE
+ SYNTAX Integer32 (0..2147483647)
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "When this object is set to a non-zero value, the filter that
+ it is associated with performs the following operations on
+ every packet:
+
+ 1) - If the packet doesn't match the protocol directory entry
+ identified by this object, discard the packet and exit
+ (i.e., discard the packet if it is not of the identified
+ protocol).
+ 2) - If the associated filterProtocolDirLocalIndex is non-zero
+ and the packet doesn't match the protocol directory
+ entry identified by that object, discard the packet and
+ exit
+ 3) - If the packet matches, perform the regular filter
+ algorithm as if the beginning of this named protocol is
+ the beginning of the packet, potentially applying the
+ filterOffset value to move further into the packet."
+ DEFVAL { 0 }
+ ::= { filter2Entry 1 }
+
+filterProtocolDirLocalIndex OBJECT-TYPE
+ SYNTAX Integer32 (0..2147483647)
+ MAX-ACCESS read-create
+ STATUS current
+ DESCRIPTION
+ "When this object is set to a non-zero value, the filter that
+ it is associated with will discard the packet if the packet
+ doesn't match this protocol directory entry."
+ DEFVAL { 0 }
+ ::= { filter2Entry 2 }
+
+-- Conformance Macros
+
+rmon2MIBCompliances OBJECT IDENTIFIER ::= { rmonConformance 1 }
+rmon2MIBGroups OBJECT IDENTIFIER ::= { rmonConformance 2 }
+
+
+
+rmon2MIBCompliance MODULE-COMPLIANCE
+ STATUS current
+ DESCRIPTION
+ "Describes the requirements for conformance to
+ the RMON2 MIB"
+ MODULE -- this module
+ MANDATORY-GROUPS { protocolDirectoryGroup,
+ protocolDistributionGroup,
+ addressMapGroup,
+ nlHostGroup,
+ nlMatrixGroup,
+ usrHistoryGroup,
+ probeInformationGroup }
+
+ GROUP rmon1EnhancementGroup
+ DESCRIPTION
+ "The rmon1EnhancementGroup is mandatory for systems which
+ implement RMON [RFC1757]"
+ ::= { rmon2MIBCompliances 1 }
+
+rmon2MIBApplicationLayerCompliance MODULE-COMPLIANCE
+ STATUS current
+ DESCRIPTION
+ "Describes the requirements for conformance to
+ the RMON2 MIB with Application Layer Enhancements."
+ MODULE -- this module
+ MANDATORY-GROUPS { protocolDirectoryGroup,
+ protocolDistributionGroup,
+ addressMapGroup,
+ nlHostGroup,
+ nlMatrixGroup,
+ alHostGroup,
+ alMatrixGroup,
+ usrHistoryGroup,
+ probeInformationGroup }
+
+ GROUP rmon1EnhancementGroup
+ DESCRIPTION
+ "The rmon1EnhancementGroup is mandatory for systems which
+ implement RMON [RFC1757]"
+ ::= { rmon2MIBCompliances 2 }
+
+
+protocolDirectoryGroup OBJECT-GROUP
+ OBJECTS { protocolDirLastChange,
+ protocolDirLocalIndex, protocolDirDescr,
+ protocolDirType, protocolDirAddressMapConfig,
+ protocolDirHostConfig, protocolDirMatrixConfig,
+
+
+ protocolDirOwner, protocolDirStatus }
+ STATUS current
+ DESCRIPTION
+ "Lists the inventory of protocols the probe has the capability
+ of monitoring and allows the addition, deletion, and
+ configuration of entries in this list."
+ ::= { rmon2MIBGroups 1 }
+
+protocolDistributionGroup OBJECT-GROUP
+ OBJECTS { protocolDistControlDataSource,
+ protocolDistControlDroppedFrames,
+ protocolDistControlCreateTime,
+ protocolDistControlOwner, protocolDistControlStatus,
+ protocolDistStatsPkts, protocolDistStatsOctets }
+ STATUS current
+ DESCRIPTION
+ "Collects the relative amounts of octets and packets for the
+ different protocols detected on a network segment."
+ ::= { rmon2MIBGroups 2 }
+
+addressMapGroup OBJECT-GROUP
+ OBJECTS { addressMapInserts, addressMapDeletes,
+ addressMapMaxDesiredEntries,
+ addressMapControlDataSource,
+ addressMapControlDroppedFrames,
+ addressMapControlOwner, addressMapControlStatus,
+ addressMapPhysicalAddress,
+ addressMapLastChange }
+ STATUS current
+ DESCRIPTION
+ "Lists MAC address to network address bindings discovered by
+ the probe and what interface they were last seen on."
+ ::= { rmon2MIBGroups 3 }
+
+nlHostGroup OBJECT-GROUP
+ OBJECTS { hlHostControlDataSource,
+ hlHostControlNlDroppedFrames, hlHostControlNlInserts,
+ hlHostControlNlDeletes,
+ hlHostControlNlMaxDesiredEntries,
+ hlHostControlAlDroppedFrames, hlHostControlAlInserts,
+ hlHostControlAlDeletes,
+ hlHostControlAlMaxDesiredEntries, hlHostControlOwner,
+ hlHostControlStatus, nlHostInPkts, nlHostOutPkts,
+ nlHostInOctets, nlHostOutOctets,
+ nlHostOutMacNonUnicastPkts, nlHostCreateTime }
+ STATUS current
+ DESCRIPTION
+ "Counts the amount of traffic sent from and to each network
+
+
+ address discovered by the probe. Note that while the
+ hlHostControlTable also has objects that control an optional
+ alHostTable, implementation of the alHostTable is not required
+ to fully implement this group."
+ ::= { rmon2MIBGroups 4 }
+
+nlMatrixGroup OBJECT-GROUP
+ OBJECTS { hlMatrixControlDataSource,
+ hlMatrixControlNlDroppedFrames,
+ hlMatrixControlNlInserts, hlMatrixControlNlDeletes,
+ hlMatrixControlNlMaxDesiredEntries,
+ hlMatrixControlAlDroppedFrames,
+ hlMatrixControlAlInserts, hlMatrixControlAlDeletes,
+ hlMatrixControlAlMaxDesiredEntries,
+ hlMatrixControlOwner, hlMatrixControlStatus,
+ nlMatrixSDPkts, nlMatrixSDOctets, nlMatrixSDCreateTime,
+ nlMatrixDSPkts, nlMatrixDSOctets, nlMatrixDSCreateTime,
+ nlMatrixTopNControlMatrixIndex,
+ nlMatrixTopNControlRateBase,
+ nlMatrixTopNControlTimeRemaining,
+ nlMatrixTopNControlGeneratedReports,
+ nlMatrixTopNControlDuration,
+ nlMatrixTopNControlRequestedSize,
+ nlMatrixTopNControlGrantedSize,
+ nlMatrixTopNControlStartTime,
+ nlMatrixTopNControlOwner, nlMatrixTopNControlStatus,
+ nlMatrixTopNProtocolDirLocalIndex,
+ nlMatrixTopNSourceAddress, nlMatrixTopNDestAddress,
+ nlMatrixTopNPktRate, nlMatrixTopNReversePktRate,
+ nlMatrixTopNOctetRate, nlMatrixTopNReverseOctetRate }
+ STATUS current
+ DESCRIPTION
+ "Counts the amount of traffic sent between each pair of
+ network addresses discovered by the probe. Note that while the
+ hlMatrixControlTable also has objects that control optional
+ alMatrixTables, implementation of the alMatrixTables is not
+ required to fully implement this group."
+ ::= { rmon2MIBGroups 5 }
+
+alHostGroup OBJECT-GROUP
+ OBJECTS { alHostInPkts, alHostOutPkts,
+ alHostInOctets, alHostOutOctets, alHostCreateTime }
+ STATUS current
+ DESCRIPTION
+ "Counts the amount of traffic, by protocol, sent from and to
+ each network address discovered by the probe. Implementation
+ of this group requires implementation of the Network Layer
+ Host Group."
+
+
+ ::= { rmon2MIBGroups 6 }
+
+alMatrixGroup OBJECT-GROUP
+ OBJECTS { alMatrixSDPkts, alMatrixSDOctets, alMatrixSDCreateTime,
+ alMatrixDSPkts, alMatrixDSOctets, alMatrixDSCreateTime,
+ alMatrixTopNControlMatrixIndex,
+ alMatrixTopNControlRateBase,
+ alMatrixTopNControlTimeRemaining,
+ alMatrixTopNControlGeneratedReports,
+ alMatrixTopNControlDuration,
+ alMatrixTopNControlRequestedSize,
+ alMatrixTopNControlGrantedSize,
+ alMatrixTopNControlStartTime,
+ alMatrixTopNControlOwner, alMatrixTopNControlStatus,
+ alMatrixTopNProtocolDirLocalIndex,
+ alMatrixTopNSourceAddress, alMatrixTopNDestAddress,
+ alMatrixTopNAppProtocolDirLocalIndex,
+ alMatrixTopNPktRate, alMatrixTopNReversePktRate,
+ alMatrixTopNOctetRate, alMatrixTopNReverseOctetRate }
+ STATUS current
+ DESCRIPTION
+ "Counts the amount of traffic, by protocol, sent between each
+ pair of network addresses discovered by the
+ probe. Implementation of this group requires implementation of
+ the Network Layer Matrix Group."
+ ::= { rmon2MIBGroups 7 }
+
+usrHistoryGroup OBJECT-GROUP
+ OBJECTS { usrHistoryControlObjects,
+ usrHistoryControlBucketsRequested,
+ usrHistoryControlBucketsGranted,
+ usrHistoryControlInterval,
+ usrHistoryControlOwner, usrHistoryControlStatus,
+ usrHistoryObjectVariable, usrHistoryObjectSampleType,
+ usrHistoryIntervalStart, usrHistoryIntervalEnd,
+ usrHistoryAbsValue, usrHistoryValStatus }
+ STATUS current
+ DESCRIPTION
+ "The usrHistoryGroup provides user-defined collection of
+ historical information from MIB objects on the probe."
+ ::= { rmon2MIBGroups 8 }
+
+probeInformationGroup OBJECT-GROUP
+ OBJECTS { probeCapabilities,
+ probeSoftwareRev, probeHardwareRev, probeDateTime }
+ STATUS current
+ DESCRIPTION
+ "This group describes various operating parameters of the
+
+
+ probe as well as controlling the local time of the probe."
+ ::= { rmon2MIBGroups 9 }
+
+probeConfigurationGroup OBJECT-GROUP
+ OBJECTS { probeResetControl, probeDownloadFile,
+ probeDownloadTFTPServer, probeDownloadAction,
+ probeDownloadStatus,
+ serialMode, serialProtocol, serialTimeout,
+ serialModemInitString, serialModemHangUpString,
+ serialModemConnectResp, serialModemNoConnectResp,
+ serialDialoutTimeout, serialStatus,
+ netConfigIPAddress, netConfigSubnetMask,
+ netConfigStatus, netDefaultGateway,
+ trapDestCommunity, trapDestProtocol, trapDestAddress,
+ trapDestOwner, trapDestStatus,
+ serialConnectDestIpAddress, serialConnectType,
+ serialConnectDialString, serialConnectSwitchConnectSeq,
+ serialConnectSwitchDisconnectSeq,
+ serialConnectSwitchResetSeq,
+ serialConnectOwner, serialConnectStatus }
+ STATUS current
+ DESCRIPTION
+ "This group controls the configuration of various operating
+ parameters of the probe."
+ ::= { rmon2MIBGroups 10 }
+
+rmon1EnhancementGroup OBJECT-GROUP
+ OBJECTS { historyControlDroppedFrames, hostControlDroppedFrames,
+ hostControlCreateTime, matrixControlDroppedFrames,
+ matrixControlCreateTime, channelDroppedFrames,
+ channelCreateTime, filterProtocolDirDataLocalIndex,
+ filterProtocolDirLocalIndex }
+ STATUS current
+ DESCRIPTION
+ "This group adds some enhancements to RMON-1 that help
+ management stations."
+ ::= { rmon2MIBGroups 11 }
+
+rmon1EthernetEnhancementGroup OBJECT-GROUP
+ OBJECTS { etherStatsDroppedFrames, etherStatsCreateTime }
+ STATUS current
+ DESCRIPTION
+ "This group adds some enhancements to RMON-1 that help
+ management stations."
+ ::= { rmon2MIBGroups 12 }
+
+rmon1TokenRingEnhancementGroup OBJECT-GROUP
+ OBJECTS { tokenRingMLStatsDroppedFrames,
+
+
+ tokenRingMLStatsCreateTime,
+ tokenRingPStatsDroppedFrames, tokenRingPStatsCreateTime,
+ ringStationControlDroppedFrames,
+ ringStationControlCreateTime,
+ sourceRoutingStatsDroppedFrames,
+ sourceRoutingStatsCreateTime }
+ STATUS current
+ DESCRIPTION
+ "This group adds some enhancements to RMON-1 that help
+ management stations."
+ ::= { rmon2MIBGroups 13 }
+END
+
+
diff --git a/lib/snmp/test/test-mibs/SNMPv2-MIB.mib b/lib/snmp/test/test-mibs/SNMPv2-MIB.mib
new file mode 100644
index 0000000000..0c5418b9ce
--- /dev/null
+++ b/lib/snmp/test/test-mibs/SNMPv2-MIB.mib
@@ -0,0 +1,777 @@
+SNMPv2-MIB DEFINITIONS ::= BEGIN
+
+IMPORTS
+ MODULE-IDENTITY, OBJECT-TYPE, NOTIFICATION-TYPE,
+ TimeTicks, Counter32, snmpModules, mib-2
+ FROM SNMPv2-SMI
+ DisplayString, TestAndIncr, TimeStamp
+ FROM SNMPv2-TC
+ MODULE-COMPLIANCE, OBJECT-GROUP, NOTIFICATION-GROUP
+ FROM SNMPv2-CONF;
+
+snmpMIB MODULE-IDENTITY
+ LAST-UPDATED "9511090000Z"
+ ORGANIZATION "IETF SNMPv2 Working Group"
+ CONTACT-INFO
+ " Marshall T. Rose
+
+ Postal: Dover Beach Consulting, Inc.
+ 420 Whisman Court
+ Mountain View, CA 94043-2186
+ US
+
+ Tel: +1 415 968 1052
+
+ DESCRIPTION
+ "The MIB module for SNMPv2 entities."
+ REVISION "9304010000Z"
+ DESCRIPTION
+ "The initial revision of this MIB module was published as
+ RFC 1450."
+ ::= { snmpModules 1 }
+
+
+snmpMIBObjects OBJECT IDENTIFIER ::= { snmpMIB 1 }
+
+-- ::= { snmpMIBObjects 1 } this OID is obsolete
+-- ::= { snmpMIBObjects 2 } this OID is obsolete
+-- ::= { snmpMIBObjects 3 } this OID is obsolete
+
+
+-- the System group
+--
+-- a collection of objects common to all managed systems.
+
+system OBJECT IDENTIFIER ::= { mib-2 1 }
+
+sysDescr OBJECT-TYPE
+ SYNTAX DisplayString (SIZE (0..255))
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "A textual description of the entity. This value should
+ include the full name and version identification of the
+ system's hardware type, software operating-system, and
+ networking software."
+ ::= { system 1 }
+
+sysObjectID OBJECT-TYPE
+
+
+ SYNTAX OBJECT IDENTIFIER
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The vendor's authoritative identification of the network
+ management subsystem contained in the entity. This value is
+ allocated within the SMI enterprises subtree (1.3.6.1.4.1)
+ and provides an easy and unambiguous means for determining
+ `what kind of box' is being managed. For example, if vendor
+ `Flintstones, Inc.' was assigned the subtree
+ 1.3.6.1.4.1.4242, it could assign the identifier
+ 1.3.6.1.4.1.4242.1.1 to its `Fred Router'."
+ ::= { system 2 }
+
+sysUpTime OBJECT-TYPE
+ SYNTAX TimeTicks
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The time (in hundredths of a second) since the network
+ management portion of the system was last re-initialized."
+ ::= { system 3 }
+
+sysContact OBJECT-TYPE
+ SYNTAX DisplayString (SIZE (0..255))
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The textual identification of the contact person for this
+ managed node, together with information on how to contact
+ this person. If no contact information is known, the value
+ is the zero-length string."
+ ::= { system 4 }
+
+sysName OBJECT-TYPE
+ SYNTAX DisplayString (SIZE (0..255))
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "An administratively-assigned name for this managed node.
+ By convention, this is the node's fully-qualified domain
+ name. If the name is unknown, the value is the zero-length
+ string."
+ ::= { system 5 }
+
+sysLocation OBJECT-TYPE
+ SYNTAX DisplayString (SIZE (0..255))
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The physical location of this node (e.g., `telephone
+ closet, 3rd floor'). If the location is unknown, the value
+ is the zero-length string."
+ ::= { system 6 }
+
+sysServices OBJECT-TYPE
+ SYNTAX INTEGER (0..127)
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "A value which indicates the set of services that this
+ entity may potentially offers. The value is a sum. This
+ sum initially takes the value zero, Then, for each layer, L,
+ in the range 1 through 7, that this node performs
+ transactions for, 2 raised to (L - 1) is added to the sum.
+ For example, a node which performs only routing functions
+ would have a value of 4 (2^(3-1)). In contrast, a node
+ which is a host offering application services would have a
+ value of 72 (2^(4-1) + 2^(7-1)). Note that in the context
+ of the Internet suite of protocols, values should be
+ calculated accordingly:
+
+ layer functionality
+ 1 physical (e.g., repeaters)
+ 2 datalink/subnetwork (e.g., bridges)
+ 3 internet (e.g., supports the IP)
+ 4 end-to-end (e.g., supports the TCP)
+ 7 applications (e.g., supports the SMTP)
+
+ For systems including OSI protocols, layers 5 and 6 may also
+ be counted."
+ ::= { system 7 }
+
+
+-- object resource information
+--
+-- a collection of objects which describe the SNMPv2 entity's
+-- (statically and dynamically configurable) support of
+-- various MIB modules.
+
+sysORLastChange OBJECT-TYPE
+ SYNTAX TimeStamp
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The value of sysUpTime at the time of the most recent
+ change in state or value of any instance of sysORID."
+ ::= { system 8 }
+
+sysORTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF SysOREntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "The (conceptual) table listing the capabilities of the
+ local SNMPv2 entity acting in an agent role with respect to
+ various MIB modules. SNMPv2 entities having dynamically-
+ configurable support of MIB modules will have a
+ dynamically-varying number of conceptual rows."
+ ::= { system 9 }
+
+sysOREntry OBJECT-TYPE
+ SYNTAX SysOREntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "An entry (conceptual row) in the sysORTable."
+ INDEX { sysORIndex }
+ ::= { sysORTable 1 }
+
+SysOREntry ::= SEQUENCE {
+ sysORIndex INTEGER,
+ sysORID OBJECT IDENTIFIER,
+ sysORDescr DisplayString,
+ sysORUpTime TimeStamp
+}
+
+sysORIndex OBJECT-TYPE
+ SYNTAX INTEGER (1..2147483647)
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "The auxiliary variable used for identifying instances of
+ the columnar objects in the sysORTable."
+ ::= { sysOREntry 1 }
+
+sysORID OBJECT-TYPE
+ SYNTAX OBJECT IDENTIFIER
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "An authoritative identification of a capabilities statement
+ with respect to various MIB modules supported by the local
+ SNMPv2 entity acting in an agent role."
+
+ ::= { sysOREntry 2 }
+
+sysORDescr OBJECT-TYPE
+ SYNTAX DisplayString
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "A textual description of the capabilities identified by the
+ corresponding instance of sysORID."
+ ::= { sysOREntry 3 }
+
+sysORUpTime OBJECT-TYPE
+ SYNTAX TimeStamp
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The value of sysUpTime at the time this conceptual row was
+ last instanciated."
+ ::= { sysOREntry 4 }
+
+
+-- the SNMP group
+--
+-- a collection of objects providing basic instrumentation and
+-- control of an SNMP entity.
+
+snmp OBJECT IDENTIFIER ::= { mib-2 11 }
+
+snmpInPkts OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The total number of messages delivered to the SNMP entity
+ from the transport service."
+ ::= { snmp 1 }
+
+snmpInBadVersions OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The total number of SNMP messages which were delivered to
+ the SNMP entity and were for an unsupported SNMP version."
+ ::= { snmp 3 }
+
+snmpInBadCommunityNames OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The total number of SNMP messages delivered to the SNMP
+ entity which used a SNMP community name not known to said
+ entity."
+ ::= { snmp 4 }
+
+snmpInBadCommunityUses OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The total number of SNMP messages delivered to the SNMP
+ entity which represented an SNMP operation which was not
+ allowed by the SNMP community named in the message."
+ ::= { snmp 5 }
+
+snmpInASNParseErrs OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The total number of ASN.1 or BER errors encountered by the
+ SNMP entity when decoding received SNMP messages."
+ ::= { snmp 6 }
+
+snmpEnableAuthenTraps OBJECT-TYPE
+ SYNTAX INTEGER { enabled(1), disabled(2) }
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "Indicates whether the SNMP entity is permitted to generate
+ authenticationFailure traps. The value of this object
+ overrides any configuration information; as such, it
+ provides a means whereby all authenticationFailure traps may
+ be disabled.
+
+ Note that it is strongly recommended that this object be
+ stored in non-volatile memory so that it remains constant
+ across re-initializations of the network management system."
+ ::= { snmp 30 }
+
+snmpSilentDrops OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The total number of GetRequest-PDUs, GetNextRequest-PDUs,
+ GetBulkRequest-PDUs, SetRequest-PDUs, and InformRequest-PDUs
+ delivered to the SNMP entity which were silently dropped
+ because the size of a reply containing an alternate
+ Response-PDU with an empty variable-bindings field was
+ greater than either a local constraint or the maximum
+ message size associated with the originator of the request."
+ ::= { snmp 31 }
+
+snmpProxyDrops OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The total number of GetRequest-PDUs, GetNextRequest-PDUs,
+ GetBulkRequest-PDUs, SetRequest-PDUs, and InformRequest-PDUs
+ delivered to the SNMP entity which were silently dropped
+ because the transmission of the (possibly translated)
+ message to a proxy target failed in a manner (other than a
+ time-out) such that no Response-PDU could be returned."
+ ::= { snmp 32 }
+
+
+-- information for notifications
+--
+-- a collection of objects which allow the SNMPv2 entity, when
+-- acting in an agent role, to be configured to generate
+-- SNMPv2-Trap-PDUs.
+
+snmpTrap OBJECT IDENTIFIER ::= { snmpMIBObjects 4 }
+
+
+snmpTrapOID OBJECT-TYPE
+ SYNTAX OBJECT IDENTIFIER
+ MAX-ACCESS accessible-for-notify
+ STATUS current
+ DESCRIPTION
+ "The authoritative identification of the notification
+ currently being sent. This variable occurs as the second
+ varbind in every SNMPv2-Trap-PDU and InformRequest-PDU."
+ ::= { snmpTrap 1 }
+
+-- ::= { snmpTrap 2 } this OID is obsolete
+
+snmpTrapEnterprise OBJECT-TYPE
+ SYNTAX OBJECT IDENTIFIER
+ MAX-ACCESS accessible-for-notify
+ STATUS current
+ DESCRIPTION
+ "The authoritative identification of the enterprise
+ associated with the trap currently being sent. When a
+ SNMPv2 proxy agent is mapping an RFC1157 Trap-PDU into a
+ SNMPv2-Trap-PDU, this variable occurs as the last varbind."
+ ::= { snmpTrap 3 }
+
+-- ::= { snmpTrap 4 } this OID is obsolete
+
+
+-- well-known traps
+
+snmpTraps OBJECT IDENTIFIER ::= { snmpMIBObjects 5 }
+
+coldStart NOTIFICATION-TYPE
+ STATUS current
+ DESCRIPTION
+ "A coldStart trap signifies that the SNMPv2 entity, acting
+ in an agent role, is reinitializing itself and that its
+ configuration may have been altered."
+ ::= { snmpTraps 1 }
+
+tst OBJECT IDENTIFIER ::= { system 0 }
+
+testTrapv22 NOTIFICATION-TYPE
+ STATUS current
+ DESCRIPTION
+ "This trap is exactly the v2 correspondance of testTrap2 in
+ TestTrap mib."
+ ::= { system 0 1 }
+
+
+warmStart NOTIFICATION-TYPE
+ STATUS current
+ DESCRIPTION
+ "A warmStart trap signifies that the SNMPv2 entity, acting
+ in an agent role, is reinitializing itself such that its
+ configuration is unaltered."
+ ::= { snmpTraps 2 }
+
+-- Note the linkDown NOTIFICATION-TYPE ::= { snmpTraps 3 }
+-- and the linkUp NOTIFICATION-TYPE ::= { snmpTraps 4 }
+-- are defined in RFC 1573
+
+authenticationFailure NOTIFICATION-TYPE
+ STATUS current
+ DESCRIPTION
+ "An authenticationFailure trap signifies that the SNMPv2
+ entity, acting in an agent role, has received a protocol
+ message that is not properly authenticated. While all
+ implementations of the SNMPv2 must be capable of generating
+ this trap, the snmpEnableAuthenTraps object indicates
+ whether this trap will be generated."
+ ::= { snmpTraps 5 }
+
+-- Note the egpNeighborLoss NOTIFICATION-TYPE ::= { snmpTraps 6 }
+-- is defined in RFC 1213
+-- the set group
+--
+-- a collection of objects which allow several cooperating
+-- SNMPv2 entities, all acting in a manager role, to
+-- coordinate their use of the SNMPv2 set operation.
+
+snmpSet OBJECT IDENTIFIER ::= { snmpMIBObjects 6 }
+
+
+snmpSetSerialNo OBJECT-TYPE
+ SYNTAX TestAndIncr
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "An advisory lock used to allow several cooperating SNMPv2
+ entities, all acting in a manager role, to coordinate their
+ use of the SNMPv2 set operation.
+
+ This object is used for coarse-grain coordination. To
+ achieve fine-grain coordination, one or more similar objects
+ might be defined within each MIB group, as appropriate."
+ ::= { snmpSet 1 }
+
+
+-- conformance information
+
+snmpMIBConformance
+ OBJECT IDENTIFIER ::= { snmpMIB 2 }
+
+snmpMIBCompliances
+ OBJECT IDENTIFIER ::= { snmpMIBConformance 1 }
+snmpMIBGroups OBJECT IDENTIFIER ::= { snmpMIBConformance 2 }
+
+
+-- compliance statements
+
+-- ::= { snmpMIBCompliances 1 } this OID is obsolete
+
+snmpBasicCompliance MODULE-COMPLIANCE
+ STATUS current
+ DESCRIPTION
+ "The compliance statement for SNMPv2 entities which
+ implement the SNMPv2 MIB."
+ MODULE -- this module
+ MANDATORY-GROUPS { snmpGroup, snmpSetGroup, systemGroup,
+ snmpBasicNotificationsGroup }
+
+ GROUP snmpCommunityGroup
+ DESCRIPTION
+ "This group is mandatory for SNMPv2 entities which
+ support community-based authentication."
+
+ ::= { snmpMIBCompliances 2 }
+
+
+-- units of conformance
+
+-- ::= { snmpMIBGroups 1 } this OID is obsolete
+-- ::= { snmpMIBGroups 2 } this OID is obsolete
+-- ::= { snmpMIBGroups 3 } this OID is obsolete
+-- ::= { snmpMIBGroups 4 } this OID is obsolete
+
+snmpGroup OBJECT-GROUP
+ OBJECTS { snmpInPkts,
+ snmpInBadVersions,
+ snmpInASNParseErrs,
+ snmpSilentDrops,
+ snmpProxyDrops,
+ snmpEnableAuthenTraps }
+ STATUS current
+ DESCRIPTION
+ "A collection of objects providing basic instrumentation and
+ control of an SNMPv2 entity."
+ ::= { snmpMIBGroups 8 }
+
+snmpCommunityGroup OBJECT-GROUP
+ OBJECTS { snmpInBadCommunityNames,
+ snmpInBadCommunityUses }
+ STATUS current
+ DESCRIPTION
+ "A collection of objects providing basic instrumentation of
+ a SNMPv2 entity which supports community-based
+ authentication."
+ ::= { snmpMIBGroups 9 }
+
+snmpSetGroup OBJECT-GROUP
+ OBJECTS { snmpSetSerialNo }
+ STATUS current
+ DESCRIPTION
+ "A collection of objects which allow several cooperating
+ SNMPv2 entities, all acting in a manager role, to coordinate
+ their use of the SNMPv2 set operation."
+ ::= { snmpMIBGroups 5 }
+
+systemGroup OBJECT-GROUP
+ OBJECTS { sysDescr, sysObjectID, sysUpTime,
+ sysContact, sysName, sysLocation,
+ sysServices,
+ sysORLastChange, sysORID,
+ sysORUpTime, sysORDescr }
+ STATUS current
+ DESCRIPTION
+ "The system group defines objects which are common to all
+ managed systems."
+ ::= { snmpMIBGroups 6 }
+
+snmpBasicNotificationsGroup NOTIFICATION-GROUP
+ NOTIFICATIONS { coldStart, authenticationFailure }
+ STATUS current
+ DESCRIPTION
+ "The two notifications which an SNMPv2 entity is required to
+ implement."
+ ::= { snmpMIBGroups 7 }
+
+
+-- definitions in RFC 1213 made obsolete by the inclusion of a
+-- subset of the snmp group in this MIB
+
+snmpOutPkts OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS obsolete
+ DESCRIPTION
+ "The total number of SNMP Messages which were
+ passed from the SNMP protocol entity to the
+ transport service."
+ ::= { snmp 2 }
+
+-- { snmp 7 } is not used
+
+snmpInTooBigs OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS obsolete
+ DESCRIPTION
+ "The total number of SNMP PDUs which were
+ delivered to the SNMP protocol entity and for
+ which the value of the error-status field is
+ `tooBig'."
+ ::= { snmp 8 }
+
+snmpInNoSuchNames OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS obsolete
+ DESCRIPTION
+ "The total number of SNMP PDUs which were
+ delivered to the SNMP protocol entity and for
+ which the value of the error-status field is
+ `noSuchName'."
+ ::= { snmp 9 }
+
+snmpInBadValues OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS obsolete
+ DESCRIPTION
+ "The total number of SNMP PDUs which were
+ delivered to the SNMP protocol entity and for
+ which the value of the error-status field is
+ `badValue'."
+ ::= { snmp 10 }
+
+snmpInReadOnlys OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS obsolete
+ DESCRIPTION
+ "The total number valid SNMP PDUs which were
+ delivered to the SNMP protocol entity and for
+ which the value of the error-status field is
+ `readOnly'. It should be noted that it is a
+ protocol error to generate an SNMP PDU which
+ contains the value `readOnly' in the error-status
+ field, as such this object is provided as a means
+ of detecting incorrect implementations of the
+ SNMP."
+ ::= { snmp 11 }
+
+snmpInGenErrs OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS obsolete
+ DESCRIPTION
+ "The total number of SNMP PDUs which were
+ delivered to the SNMP protocol entity and for
+ which the value of the error-status field is
+ `genErr'."
+ ::= { snmp 12 }
+
+snmpInTotalReqVars OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS obsolete
+ DESCRIPTION
+ "The total number of MIB objects which have been
+ retrieved successfully by the SNMP protocol entity
+ as the result of receiving valid SNMP Get-Request
+ and Get-Next PDUs."
+ ::= { snmp 13 }
+
+snmpInTotalSetVars OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS obsolete
+ DESCRIPTION
+ "The total number of MIB objects which have been
+ altered successfully by the SNMP protocol entity
+ as the result of receiving valid SNMP Set-Request
+ PDUs."
+ ::= { snmp 14 }
+
+snmpInGetRequests OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS obsolete
+ DESCRIPTION
+ "The total number of SNMP Get-Request PDUs which
+ have been accepted and processed by the SNMP
+ protocol entity."
+ ::= { snmp 15 }
+
+snmpInGetNexts OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS obsolete
+ DESCRIPTION
+ "The total number of SNMP Get-Next PDUs which have
+ been accepted and processed by the SNMP protocol
+ entity."
+ ::= { snmp 16 }
+
+snmpInSetRequests OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS obsolete
+ DESCRIPTION
+ "The total number of SNMP Set-Request PDUs which
+ have been accepted and processed by the SNMP
+ protocol entity."
+ ::= { snmp 17 }
+
+snmpInGetResponses OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS obsolete
+ DESCRIPTION
+ "The total number of SNMP Get-Response PDUs which
+ have been accepted and processed by the SNMP
+ protocol entity."
+ ::= { snmp 18 }
+
+snmpInTraps OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS obsolete
+ DESCRIPTION
+ "The total number of SNMP Trap PDUs which have
+ been accepted and processed by the SNMP protocol
+ entity."
+ ::= { snmp 19 }
+
+snmpOutTooBigs OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS obsolete
+ DESCRIPTION
+ "The total number of SNMP PDUs which were
+ generated by the SNMP protocol entity and for
+ which the value of the error-status field is
+ `tooBig.'"
+ ::= { snmp 20 }
+
+snmpOutNoSuchNames OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS obsolete
+ DESCRIPTION
+ "The total number of SNMP PDUs which were
+ generated by the SNMP protocol entity and for
+ which the value of the error-status is
+ `noSuchName'."
+ ::= { snmp 21 }
+
+snmpOutBadValues OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS obsolete
+ DESCRIPTION
+ "The total number of SNMP PDUs which were
+ generated by the SNMP protocol entity and for
+ which the value of the error-status field is
+ `badValue'."
+ ::= { snmp 22 }
+
+
+-- { snmp 23 } is not used
+
+snmpOutGenErrs OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS obsolete
+ DESCRIPTION
+ "The total number of SNMP PDUs which were
+ generated by the SNMP protocol entity and for
+ which the value of the error-status field is
+ `genErr'."
+ ::= { snmp 24 }
+
+snmpOutGetRequests OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS obsolete
+ DESCRIPTION
+ "The total number of SNMP Get-Request PDUs which
+ have been generated by the SNMP protocol entity."
+ ::= { snmp 25 }
+
+snmpOutGetNexts OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS obsolete
+ DESCRIPTION
+ "The total number of SNMP Get-Next PDUs which have
+ been generated by the SNMP protocol entity."
+ ::= { snmp 26 }
+
+snmpOutSetRequests OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS obsolete
+ DESCRIPTION
+ "The total number of SNMP Set-Request PDUs which
+ have been generated by the SNMP protocol entity."
+ ::= { snmp 27 }
+
+snmpOutGetResponses OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS obsolete
+ DESCRIPTION
+ "The total number of SNMP Get-Response PDUs which
+ have been generated by the SNMP protocol entity."
+ ::= { snmp 28 }
+
+snmpOutTraps OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS obsolete
+ DESCRIPTION
+ "The total number of SNMP Trap PDUs which have
+ been generated by the SNMP protocol entity."
+ ::= { snmp 29 }
+
+snmpObsoleteGroup OBJECT-GROUP
+ OBJECTS { snmpOutPkts, snmpInTooBigs, snmpInNoSuchNames,
+ snmpInBadValues, snmpInReadOnlys, snmpInGenErrs,
+ snmpInTotalReqVars, snmpInTotalSetVars,
+ snmpInGetRequests, snmpInGetNexts, snmpInSetRequests,
+ snmpInGetResponses, snmpInTraps, snmpOutTooBigs,
+ snmpOutNoSuchNames, snmpOutBadValues, snmpOutGenErrs,
+ snmpOutGetRequests, snmpOutGetNexts, snmpOutSetRequests,
+ snmpOutGetResponses, snmpOutTraps }
+ STATUS obsolete
+ DESCRIPTION
+ "A collection of objects from RFC 1213 made obsolete by this
+ MIB."
+ ::= { snmpMIBGroups 10 }
+
+END
diff --git a/lib/snmp/test/test-mibs/SNMPv2-TC.mib b/lib/snmp/test/test-mibs/SNMPv2-TC.mib
new file mode 100644
index 0000000000..fd6a728ab5
--- /dev/null
+++ b/lib/snmp/test/test-mibs/SNMPv2-TC.mib
@@ -0,0 +1,799 @@
+SNMPv2-TC DEFINITIONS ::= BEGIN
+
+snmpMIB MODULE-IDENTITY
+ LAST-UPDATED "9511090000Z"
+ ORGANIZATION "ES"
+ CONTACT-INFO
+ "eklas@erlang"
+ DESCRIPTION
+ "The MIB module for SNMPv2 entities."
+ ::= { snmpModules 1 }
+
+
+DisplayString ::= TEXTUAL-CONVENTION
+ DISPLAY-HINT "255a"
+ STATUS current
+ DESCRIPTION
+ "Represents textual information taken from the NVT ASCII
+ character set, as defined in pages 4, 10-11 of RFC 854.
+
+ To summarize RFC 854, the NVT ASCII repertoire specifies:
+
+ - the use of character codes 0-127 (decimal)
+
+ - the graphics characters (32-126) are interpreted as
+ US ASCII
+
+ - NUL, LF, CR, BEL, BS, HT, VT and FF have the special
+ meanings specified in RFC 854
+
+ - the other 25 codes have no standard interpretation
+
+ - the sequence 'CR LF' means newline
+
+ - the sequence 'CR NUL' means carriage-return
+
+ - an 'LF' not preceded by a 'CR' means moving to the
+ same column on the next line.
+
+ - the sequence 'CR x' for any x other than LF or NUL is
+ illegal. (Note that this also means that a string may
+ end with either 'CR LF' or 'CR NUL', but not with CR.)
+
+ Any object defined using this syntax may not exceed 255
+ characters in length."
+ SYNTAX OCTET STRING (SIZE (0..255))
+
+
+PhysAddress ::= TEXTUAL-CONVENTION
+ DISPLAY-HINT "1x:"
+ STATUS current
+ DESCRIPTION
+ "Represents media- or physical-level addresses."
+ SYNTAX OCTET STRING
+
+
+MacAddress ::= TEXTUAL-CONVENTION
+ DISPLAY-HINT "1x:"
+ STATUS current
+ DESCRIPTION
+ "Represents an 802 MAC address represented in the
+ `canonical' order defined by IEEE 802.1a, i.e., as if it
+ were transmitted least significant bit first, even though
+ 802.5 (in contrast to other 802.x protocols) requires MAC
+ addresses to be transmitted most significant bit first."
+ SYNTAX OCTET STRING (SIZE (6))
+
+
+TruthValue ::= TEXTUAL-CONVENTION
+ STATUS current
+ DESCRIPTION
+ "Represents a boolean value."
+ SYNTAX INTEGER { true(1), false(2) }
+
+TestAndIncr ::= TEXTUAL-CONVENTION
+ STATUS current
+ DESCRIPTION
+ "Represents integer-valued information used for atomic
+ operations. When the management protocol is used to specify
+ that an object instance having this syntax is to be
+ modified, the new value supplied via the management protocol
+ must precisely match the value presently held by the
+ instance. If not, the management protocol set operation
+ fails with an error of `inconsistentValue'. Otherwise, if
+ the current value is the maximum value of 2^31-1 (2147483647
+ decimal), then the value held by the instance is wrapped to
+ zero; otherwise, the value held by the instance is
+ incremented by one. (Note that regardless of whether the
+ management protocol set operation succeeds, the variable-
+ binding in the request and response PDUs are identical.)
+
+ The value of the ACCESS clause for objects having this
+ syntax is either `read-write' or `read-create'. When an
+ instance of a columnar object having this syntax is created,
+ any value may be supplied via the management protocol.
+
+ When the network management portion of the system is re-
+ initialized, the value of every object instance having this
+ syntax must either be incremented from its value prior to
+ the re-initialization, or (if the value prior to the re-
+ initialization is unknown) be set to a pseudo-randomly
+ generated value."
+ SYNTAX INTEGER (0..2147483647)
+
+
+AutonomousType ::= TEXTUAL-CONVENTION
+ STATUS current
+ DESCRIPTION
+ "Represents an independently extensible type identification
+ value. It may, for example, indicate a particular sub-tree
+ with further MIB definitions, or define a particular type of
+ protocol or hardware."
+ SYNTAX OBJECT IDENTIFIER
+
+
+InstancePointer ::= TEXTUAL-CONVENTION
+ STATUS obsolete
+ DESCRIPTION
+ "A pointer to either a specific instance of a MIB object or
+ a conceptual row of a MIB table in the managed device. In
+ the latter case, by convention, it is the name of the
+ particular instance of the first accessible columnar object
+ in the conceptual row.
+
+ The two uses of this textual convention are replaced by
+ VariablePointer and RowPointer, respectively."
+ SYNTAX OBJECT IDENTIFIER
+
+
+VariablePointer ::= TEXTUAL-CONVENTION
+ STATUS current
+ DESCRIPTION
+ "A pointer to a specific object instance. For example,
+ sysContact.0 or ifInOctets.3."
+ SYNTAX OBJECT IDENTIFIER
+
+
+RowPointer ::= TEXTUAL-CONVENTION
+ STATUS current
+ DESCRIPTION
+ "Represents a pointer to a conceptual row. The value is the
+ name of the instance of the first accessible columnar object
+ in the conceptual row.
+
+ For example, ifIndex.3 would point to the 3rd row in the
+ ifTable (note that if ifIndex were not-accessible, then
+ ifDescr.3 would be used instead)."
+ SYNTAX OBJECT IDENTIFIER
+
+
+RowStatus ::= TEXTUAL-CONVENTION
+ STATUS current
+ DESCRIPTION
+ "The RowStatus textual convention is used to manage the
+
+
+
+
+ creation and deletion of conceptual rows, and is used as the
+ value of the SYNTAX clause for the status column of a
+ conceptual row (as described in Section 7.7.1 of [2].)
+
+ The status column has six defined values:
+
+ - `active', which indicates that the conceptual row is
+ available for use by the managed device;
+
+ - `notInService', which indicates that the conceptual
+ row exists in the agent, but is unavailable for use by
+ the managed device (see NOTE below);
+
+ - `notReady', which indicates that the conceptual row
+ exists in the agent, but is missing information
+ necessary in order to be available for use by the
+ managed device;
+
+ - `createAndGo', which is supplied by a management
+ station wishing to create a new instance of a
+ conceptual row and to have its status automatically set
+ to active, making it available for use by the managed
+ device;
+
+ - `createAndWait', which is supplied by a management
+ station wishing to create a new instance of a
+ conceptual row (but not make it available for use by
+ the managed device); and,
+
+ - `destroy', which is supplied by a management station
+ wishing to delete all of the instances associated with
+ an existing conceptual row.
+
+ Whereas five of the six values (all except `notReady') may
+ be specified in a management protocol set operation, only
+ three values will be returned in response to a management
+ protocol retrieval operation: `notReady', `notInService' or
+ `active'. That is, when queried, an existing conceptual row
+ has only three states: it is either available for use by
+ the managed device (the status column has value `active');
+ it is not available for use by the managed device, though
+ the agent has sufficient information to make it so (the
+ status column has value `notInService'); or, it is not
+ available for use by the managed device, and an attempt to
+ make it so would fail because the agent has insufficient
+ information (the state column has value `notReady').
+
+
+
+
+
+
+ NOTE WELL
+
+ This textual convention may be used for a MIB table,
+ irrespective of whether the values of that table's
+ conceptual rows are able to be modified while it is
+ active, or whether its conceptual rows must be taken
+ out of service in order to be modified. That is, it is
+ the responsibility of the DESCRIPTION clause of the
+ status column to specify whether the status column must
+ not be `active' in order for the value of some other
+ column of the same conceptual row to be modified. If
+ such a specification is made, affected columns may be
+ changed by an SNMP set PDU if the RowStatus would not
+ be equal to `active' either immediately before or after
+ processing the PDU. In other words, if the PDU also
+ contained a varbind that would change the RowStatus
+ value, the column in question may be changed if the
+ RowStatus was not equal to `active' as the PDU was
+ received, or if the varbind sets the status to a value
+ other than 'active'.
+
+
+ Also note that whenever any elements of a row exist, the
+ RowStatus column must also exist.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ To summarize the effect of having a conceptual row with a
+ status column having a SYNTAX clause value of RowStatus,
+ consider the following state diagram:
+
+
+ STATE
+ +--------------+-----------+-------------+-------------
+ | A | B | C | D
+ | |status col.|status column|
+ |status column | is | is |status column
+ ACTION |does not exist| notReady | notInService| is active
+--------------+--------------+-----------+-------------+-------------
+set status |noError ->D|inconsist- |inconsistent-|inconsistent-
+column to | or | entValue| Value| Value
+createAndGo |inconsistent- | | |
+ | Value| | |
+--------------+--------------+-----------+-------------+-------------
+set status |noError see 1|inconsist- |inconsistent-|inconsistent-
+column to | or | entValue| Value| Value
+createAndWait |wrongValue | | |
+--------------+--------------+-----------+-------------+-------------
+set status |inconsistent- |inconsist- |noError |noError
+column to | Value| entValue| |
+active | | | |
+ | | or | |
+ | | | |
+ | |see 2 ->D| ->D| ->D
+--------------+--------------+-----------+-------------+-------------
+set status |inconsistent- |inconsist- |noError |noError ->C
+column to | Value| entValue| |
+notInService | | | |
+ | | or | | or
+ | | | |
+ | |see 3 ->C| ->C|wrongValue
+--------------+--------------+-----------+-------------+-------------
+set status |noError |noError |noError |noError
+column to | | | |
+destroy | ->A| ->A| ->A| ->A
+--------------+--------------+-----------+-------------+-------------
+set any other |see 4 |noError |noError |see 5
+column to some| | | |
+value | | see 1| ->C| ->D
+--------------+--------------+-----------+-------------+-------------
+
+ (1) goto B or C, depending on information available to the
+ agent.
+
+
+
+
+
+
+ (2) if other variable bindings included in the same PDU,
+ provide values for all columns which are missing but
+ required, then return noError and goto D.
+
+ (3) if other variable bindings included in the same PDU,
+ provide values for all columns which are missing but
+ required, then return noError and goto C.
+
+ (4) at the discretion of the agent, the return value may be
+ either:
+
+ inconsistentName: because the agent does not choose to
+ create such an instance when the corresponding
+ RowStatus instance does not exist, or
+
+ inconsistentValue: if the supplied value is
+ inconsistent with the state of some other MIB object's
+ value, or
+
+ noError: because the agent chooses to create the
+ instance.
+
+ If noError is returned, then the instance of the status
+ column must also be created, and the new state is B or C,
+ depending on the information available to the agent. If
+ inconsistentName or inconsistentValue is returned, the row
+ remains in state A.
+
+ (5) depending on the MIB definition for the column/table,
+ either noError or inconsistentValue may be returned.
+
+ NOTE: Other processing of the set request may result in a
+ response other than noError being returned, e.g.,
+ wrongValue, noCreation, etc.
+
+
+ Conceptual Row Creation
+
+ There are four potential interactions when creating a
+ conceptual row: selecting an instance-identifier which is
+ not in use; creating the conceptual row; initializing any
+ objects for which the agent does not supply a default; and,
+ making the conceptual row available for use by the managed
+ device.
+
+
+
+
+
+
+
+
+ Interaction 1: Selecting an Instance-Identifier
+
+ The algorithm used to select an instance-identifier varies
+ for each conceptual row. In some cases, the instance-
+ identifier is semantically significant, e.g., the
+ destination address of a route, and a management station
+ selects the instance-identifier according to the semantics.
+
+ In other cases, the instance-identifier is used solely to
+ distinguish conceptual rows, and a management station
+ without specific knowledge of the conceptual row might
+ examine the instances present in order to determine an
+ unused instance-identifier. (This approach may be used, but
+ it is often highly sub-optimal; however, it is also a
+ questionable practice for a naive management station to
+ attempt conceptual row creation.)
+
+ Alternately, the MIB module which defines the conceptual row
+ might provide one or more objects which provide assistance
+ in determining an unused instance-identifier. For example,
+ if the conceptual row is indexed by an integer-value, then
+ an object having an integer-valued SYNTAX clause might be
+ defined for such a purpose, allowing a management station to
+ issue a management protocol retrieval operation. In order
+ to avoid unnecessary collisions between competing management
+ stations, `adjacent' retrievals of this object should be
+ different.
+
+ Finally, the management station could select a pseudo-random
+ number to use as the index. In the event that this index
+ was already in use and an inconsistentValue was returned in
+ response to the management protocol set operation, the
+ management station should simply select a new pseudo-random
+ number and retry the operation.
+
+ A MIB designer should choose between the two latter
+ algorithms based on the size of the table (and therefore the
+ efficiency of each algorithm). For tables in which a large
+ number of entries are expected, it is recommended that a MIB
+ object be defined that returns an acceptable index for
+ creation. For tables with small numbers of entries, it is
+ recommended that the latter pseudo-random index mechanism be
+ used.
+
+
+
+
+
+
+
+
+
+ Interaction 2: Creating the Conceptual Row
+
+ Once an unused instance-identifier has been selected, the
+ management station determines if it wishes to create and
+ activate the conceptual row in one transaction or in a
+ negotiated set of interactions.
+
+ Interaction 2a: Creating and Activating the Conceptual Row
+
+ The management station must first determine the column
+ requirements, i.e., it must determine those columns for
+ which it must or must not provide values. Depending on the
+ complexity of the table and the management station's
+ knowledge of the agent's capabilities, this determination
+ can be made locally by the management station. Alternately,
+ the management station issues a management protocol get
+ operation to examine all columns in the conceptual row that
+ it wishes to create. In response, for each column, there
+ are three possible outcomes:
+
+ - a value is returned, indicating that some other
+ management station has already created this conceptual
+ row. We return to interaction 1.
+
+ - the exception `noSuchInstance' is returned,
+ indicating that the agent implements the object-type
+ associated with this column, and that this column in at
+ least one conceptual row would be accessible in the MIB
+ view used by the retrieval were it to exist. For those
+ columns to which the agent provides read-create access,
+ the `noSuchInstance' exception tells the management
+ station that it should supply a value for this column
+ when the conceptual row is to be created.
+
+ - the exception `noSuchObject' is returned, indicating
+ that the agent does not implement the object-type
+ associated with this column or that there is no
+ conceptual row for which this column would be
+ accessible in the MIB view used by the retrieval. As
+ such, the management station can not issue any
+ management protocol set operations to create an
+ instance of this column.
+
+ Once the column requirements have been determined, a
+ management protocol set operation is accordingly issued.
+ This operation also sets the new instance of the status
+ column to `createAndGo'.
+
+
+
+
+
+ When the agent processes the set operation, it verifies that
+ it has sufficient information to make the conceptual row
+ available for use by the managed device. The information
+ available to the agent is provided by two sources: the
+ management protocol set operation which creates the
+ conceptual row, and, implementation-specific defaults
+ supplied by the agent (note that an agent must provide
+ implementation-specific defaults for at least those objects
+ which it implements as read-only). If there is sufficient
+ information available, then the conceptual row is created, a
+ `noError' response is returned, the status column is set to
+ `active', and no further interactions are necessary (i.e.,
+ interactions 3 and 4 are skipped). If there is insufficient
+ information, then the conceptual row is not created, and the
+ set operation fails with an error of `inconsistentValue'.
+ On this error, the management station can issue a management
+ protocol retrieval operation to determine if this was
+ because it failed to specify a value for a required column,
+ or, because the selected instance of the status column
+ already existed. In the latter case, we return to
+ interaction 1. In the former case, the management station
+ can re-issue the set operation with the additional
+ information, or begin interaction 2 again using
+ `createAndWait' in order to negotiate creation of the
+ conceptual row.
+
+ NOTE WELL
+
+ Regardless of the method used to determine the column
+ requirements, it is possible that the management
+ station might deem a column necessary when, in fact,
+ the agent will not allow that particular columnar
+ instance to be created or written. In this case, the
+ management protocol set operation will fail with an
+ error such as `noCreation' or `notWritable'. In this
+ case, the management station decides whether it needs
+ to be able to set a value for that particular columnar
+ instance. If not, the management station re-issues the
+ management protocol set operation, but without setting
+ a value for that particular columnar instance;
+ otherwise, the management station aborts the row
+ creation algorithm.
+
+ Interaction 2b: Negotiating the Creation of the Conceptual
+ Row
+
+ The management station issues a management protocol set
+ operation which sets the desired instance of the status
+
+
+
+
+ column to `createAndWait'. If the agent is unwilling to
+ process a request of this sort, the set operation fails with
+ an error of `wrongValue'. (As a consequence, such an agent
+ must be prepared to accept a single management protocol set
+ operation, i.e., interaction 2a above, containing all of the
+ columns indicated by its column requirements.) Otherwise,
+ the conceptual row is created, a `noError' response is
+ returned, and the status column is immediately set to either
+ `notInService' or `notReady', depending on whether it has
+ sufficient information to make the conceptual row available
+ for use by the managed device. If there is sufficient
+ information available, then the status column is set to
+ `notInService'; otherwise, if there is insufficient
+ information, then the status column is set to `notReady'.
+ Regardless, we proceed to interaction 3.
+
+ Interaction 3: Initializing non-defaulted Objects
+
+ The management station must now determine the column
+ requirements. It issues a management protocol get operation
+ to examine all columns in the created conceptual row. In
+ the response, for each column, there are three possible
+ outcomes:
+
+ - a value is returned, indicating that the agent
+ implements the object-type associated with this column
+ and had sufficient information to provide a value. For
+ those columns to which the agent provides read-create
+ access (and for which the agent allows their values to
+ be changed after their creation), a value return tells
+ the management station that it may issue additional
+ management protocol set operations, if it desires, in
+ order to change the value associated with this column.
+
+ - the exception `noSuchInstance' is returned,
+ indicating that the agent implements the object-type
+ associated with this column, and that this column in at
+ least one conceptual row would be accessible in the MIB
+ view used by the retrieval were it to exist. However,
+ the agent does not have sufficient information to
+ provide a value, and until a value is provided, the
+ conceptual row may not be made available for use by the
+ managed device. For those columns to which the agent
+ provides read-create access, the `noSuchInstance'
+ exception tells the management station that it must
+ issue additional management protocol set operations, in
+ order to provide a value associated with this column.
+
+
+
+
+
+ - the exception `noSuchObject' is returned, indicating
+ that the agent does not implement the object-type
+ associated with this column or that there is no
+ conceptual row for which this column would be
+ accessible in the MIB view used by the retrieval. As
+ such, the management station can not issue any
+ management protocol set operations to create an
+ instance of this column.
+
+ If the value associated with the status column is
+ `notReady', then the management station must first deal with
+ all `noSuchInstance' columns, if any. Having done so, the
+ value of the status column becomes `notInService', and we
+ proceed to interaction 4.
+
+ Interaction 4: Making the Conceptual Row Available
+
+ Once the management station is satisfied with the values
+ associated with the columns of the conceptual row, it issues
+ a management protocol set operation to set the status column
+ to `active'. If the agent has sufficient information to
+ make the conceptual row available for use by the managed
+ device, the management protocol set operation succeeds (a
+ `noError' response is returned). Otherwise, the management
+ protocol set operation fails with an error of
+ `inconsistentValue'.
+
+
+ NOTE WELL
+
+ A conceptual row having a status column with value
+ `notInService' or `notReady' is unavailable to the
+ managed device. As such, it is possible for the
+ managed device to create its own instances during the
+ time between the management protocol set operation
+ which sets the status column to `createAndWait' and the
+ management protocol set operation which sets the status
+ column to `active'. In this case, when the management
+ protocol set operation is issued to set the status
+ column to `active', the values held in the agent
+ supersede those used by the managed device.
+
+ If the management station is prevented from setting the
+ status column to `active' (e.g., due to management station
+ or network failure) the conceptual row will be left in the
+ `notInService' or `notReady' state, consuming resources
+ indefinitely. The agent must detect conceptual rows that
+ have been in either state for an abnormally long period of
+
+
+
+
+ time and remove them. It is the responsibility of the
+ DESCRIPTION clause of the status column to indicate what an
+ abnormally long period of time would be. This period of
+ time should be long enough to allow for human response time
+ (including `think time') between the creation of the
+ conceptual row and the setting of the status to `active'.
+ In the absense of such information in the DESCRIPTION
+ clause, it is suggested that this period be approximately 5
+ minutes in length. This removal action applies not only to
+ newly-created rows, but also to previously active rows which
+ are set to, and left in, the notInService state for a
+ prolonged period exceeding that which is considered normal
+ for such a conceptual row.
+
+
+ Conceptual Row Suspension
+
+ When a conceptual row is `active', the management station
+ may issue a management protocol set operation which sets the
+ instance of the status column to `notInService'. If the
+ agent is unwilling to do so, the set operation fails with an
+ error of `wrongValue'. Otherwise, the conceptual row is
+ taken out of service, and a `noError' response is returned.
+ It is the responsibility of the DESCRIPTION clause of the
+ status column to indicate under what circumstances the
+ status column should be taken out of service (e.g., in order
+ for the value of some other column of the same conceptual
+ row to be modified).
+
+
+ Conceptual Row Deletion
+
+ For deletion of conceptual rows, a management protocol set
+ operation is issued which sets the instance of the status
+ column to `destroy'. This request may be made regardless of
+ the current value of the status column (e.g., it is possible
+ to delete conceptual rows which are either `notReady',
+ `notInService' or `active'.) If the operation succeeds,
+ then all instances associated with the conceptual row are
+ immediately removed."
+
+
+ SYNTAX INTEGER {
+ -- the following two values are states:
+ -- these values may be read or written
+ active(1),
+ notInService(2),
+
+
+
+
+
+ -- the following value is a state:
+ -- this value may be read, but not written
+ notReady(3),
+
+ -- the following three values are
+ -- actions: these values may be written,
+ -- but are never read
+ createAndGo(4),
+ createAndWait(5),
+ destroy(6)
+ }
+
+
+TimeStamp ::= TEXTUAL-CONVENTION
+ STATUS current
+ DESCRIPTION
+ "The value of the sysUpTime object at which a specific
+ occurrence happened. The specific occurrence must be
+ defined in the description of any object defined using this
+ type."
+ SYNTAX TimeTicks
+
+
+TimeInterval ::= TEXTUAL-CONVENTION
+ STATUS current
+ DESCRIPTION
+ "A period of time, measured in units of 0.01 seconds."
+ SYNTAX INTEGER (0..2147483647)
+
+
+DateAndTime ::= TEXTUAL-CONVENTION
+ DISPLAY-HINT "2d-1d-1d,1d:1d:1d.1d,1a1d:1d"
+ STATUS current
+ DESCRIPTION
+ "A date-time specification.
+
+ field octets contents range
+ ----- ------ -------- -----
+ 1 1-2 year 0..65536
+ 2 3 month 1..12
+ 3 4 day 1..31
+ 4 5 hour 0..23
+ 5 6 minutes 0..59
+ 6 7 seconds 0..60
+ (use 60 for leap-second)
+ 7 8 deci-seconds 0..9
+ 8 9 direction from UTC '+' / '-'
+ 9 10 hours from UTC 0..11
+
+
+
+
+ 10 11 minutes from UTC 0..59
+
+ For example, Tuesday May 26, 1992 at 1:30:15 PM EDT would be
+ displayed as:
+
+ 1992-5-26,13:30:15.0,-4:0
+
+ Note that if only local time is known, then timezone
+ information (fields 8-10) is not present."
+ SYNTAX OCTET STRING (SIZE (8 | 11))
+
+
+StorageType ::= TEXTUAL-CONVENTION
+ STATUS current
+ DESCRIPTION
+ "Describes the memory realization of a conceptual row. A
+ row which is volatile(2) is lost upon reboot. A row which
+ is either nonVolatile(3), permanent(4) or readOnly(5), is
+ backed up by stable storage. A row which is permanent(4)
+ can be changed but not deleted. A row which is readOnly(5)
+ cannot be changed nor deleted.
+
+ If the value of an object with this syntax is either
+ permanent(4) or readOnly(5), it cannot be modified.
+ Conversely, if the value is either other(1), volatile(2) or
+ nonVolatile(3), it cannot be modified to be permanent(4) or
+ readOnly(5).
+
+ Every usage of this textual convention is required to
+ specify the columnar objects which a permanent(4) row must
+ at a minimum allow to be writable."
+ SYNTAX INTEGER {
+ other(1), -- eh?
+ volatile(2), -- e.g., in RAM
+ nonVolatile(3), -- e.g., in NVRAM
+ permanent(4), -- e.g., partially in ROM
+ readOnly(5) -- e.g., completely in ROM
+ }
+
+
+TDomain ::= TEXTUAL-CONVENTION
+ STATUS current
+ DESCRIPTION
+ "Denotes a kind of transport service.
+
+ Some possible values, such as snmpUDPDomain, are defined in
+ 'Transport Mappings for Version 2 of the Simple Network
+ Management Protocol (SNMPv2)'."
+
+
+
+
+ SYNTAX OBJECT IDENTIFIER
+
+
+TAddress ::= TEXTUAL-CONVENTION
+ STATUS current
+ DESCRIPTION
+ "Denotes a transport service address.
+
+ For snmpUDPDomain, a TAddress is 6 octets long, the initial 4
+ octets containing the IP-address in network-byte order and the
+ last 2 containing the UDP port in network-byte order. Consult
+ 'Transport Mappings for Version 2 of the Simple Network
+ Management Protocol (SNMPv2)' for further information on
+ snmpUDPDomain."
+ SYNTAX OCTET STRING (SIZE (1..255))
+
+
+END
diff --git a/lib/snmp/test/test-mibs/SNMPv2-USEC-MIB.mib b/lib/snmp/test/test-mibs/SNMPv2-USEC-MIB.mib
new file mode 100644
index 0000000000..c6dd7750c2
--- /dev/null
+++ b/lib/snmp/test/test-mibs/SNMPv2-USEC-MIB.mib
@@ -0,0 +1,251 @@
+SNMPv2-USEC-MIB DEFINITIONS ::= BEGIN
+
+IMPORTS
+ MODULE-IDENTITY, OBJECT-TYPE, Counter32, Unsigned32,
+ snmpModules
+ FROM SNMPv2-SMI
+ TEXTUAL-CONVENTION
+ FROM SNMPv2-TC
+ MODULE-COMPLIANCE, OBJECT-GROUP
+ FROM SNMPv2-CONF;
+
+
+usecMIB MODULE-IDENTITY
+ LAST-UPDATED "9601120000Z"
+ ORGANIZATION "IETF SNMPv2 Working Group"
+ CONTACT-INFO
+ " Glenn W. Waters
+
+ Postal: Bell-Northern Research, Ltd.
+ P.O. Box 3511, Station C
+ Ottawa, ON, K1Y 4H7
+ Canada
+
+ Tel: +1 613 763 3933
+
+ DESCRIPTION
+ "The MIB module for SNMPv2 entities implementing the user-
+ based security model."
+ ::= { snmpModules 6 }
+
+
+usecMIBObjects OBJECT IDENTIFIER ::= { usecMIB 1 }
+
+
+-- Textual Conventions
+
+AgentID ::= TEXTUAL-CONVENTION
+ STATUS current
+ DESCRIPTION
+ "An agent's administratively-unique identifier.
+
+ The value for this object may not be all zeros or all 'ff'H.
+
+ The initial value for this object may be configured via an
+ operator console entry or via an algorithmic function. In
+ the later case, the following guidelines are recommended:
+
+ 1) The first four octets are set to the binary equivalent
+ of the agent's SNMP network management private
+ enterprise number as assigned by the Internet Assigned
+ Numbers Authority (IANA). For example, if Acme
+ Networks has been assigned { enterprises 696 }, the
+ first four octets would be assigned '000002b8'H.
+
+ 2) The remaining eight octets are the cookie whose
+ contents are determined via one or more enterprise-
+ specific methods. Such methods must be designed so as
+ to maximize the possibility that the value of this
+ object will be unique in the agent's administrative
+ domain. For example, the cookie may be the IP address
+ of the agent, or the MAC address of one of the
+ interfaces, with each address suitably padded with
+ random octets. If multiple methods are defined, then
+ it is recommended that the cookie be further divided
+ into one octet that indicates the method being used and
+ seven octets which are a function of the method."
+ SYNTAX OCTET STRING (SIZE (12))
+
+
+-- the USEC Basic group
+--
+-- a collection of objects providing basic instrumentation of
+-- the SNMPv2 entity implementing the user-based security model
+
+
+usecAgent OBJECT IDENTIFIER ::= { usecMIBObjects 1 }
+
+agentID OBJECT-TYPE
+ SYNTAX AgentID
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The agent's administratively-unique identifier."
+ ::= { usecAgent 1 }
+
+agentBoots OBJECT-TYPE
+ SYNTAX Unsigned32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of times that the agent has re-initialized
+ itself since its initial configuration."
+ ::= { usecAgent 2 }
+
+agentTime OBJECT-TYPE
+ SYNTAX Unsigned32 (0..2147483647)
+ UNITS "seconds"
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The number of seconds since the agent last incremented the
+ agentBoots object."
+ ::= { usecAgent 3 }
+
+agentSize OBJECT-TYPE
+ SYNTAX INTEGER (484..65507)
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The maximum length in octets of an SNMPv2 message which
+ this agent will accept using any transport mapping."
+ ::= { usecAgent 4 }
+
+
+-- USEC statistics
+--
+-- a collection of objects providing basic instrumentation of
+-- the SNMPv2 entity implementing the user-based security model
+
+usecStats OBJECT IDENTIFIER ::= { usecMIBObjects 2 }
+
+
+usecStatsUnsupportedQoS OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The total number of packets received by the SNMPv2 entity
+ which were dropped because they requested a quality-of-
+ service that was unknown to the agent or otherwise
+ unavailable."
+ ::= { usecStats 1 }
+
+usecStatsNotInWindows OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The total number of packets received by the SNMPv2 entity
+ which were dropped because they appeared outside of the
+ agent's window."
+ ::= { usecStats 2 }
+
+
+usecStatsUnknownUserNames OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The total number of packets received by the SNMPv2 entity
+ which were dropped because they referenced a user that was
+ not known to the agent."
+ ::= { usecStats 3 }
+
+usecStatsWrongDigestValues OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The total number of packets received by the SNMPv2 entity
+ which were dropped because they didn't contain the expected
+ digest value."
+ ::= { usecStats 4 }
+
+usecStatsUnknownContexts OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The total number of packets received by the SNMPv2 entity
+ which were dropped because they referenced a context that
+ was not known to the agent."
+ ::= { usecStats 5 }
+
+usecStatsBadParameters OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The total number of packets received by the SNMPv2 entity
+ which were dropped because the <parameters> field was
+ improperly encoded or had invalid syntax."
+ ::= { usecStats 6 }
+
+usecStatsUnauthorizedOperations OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The total number of packets received by the SNMPv2 entity
+ which were dropped because the PDU type referred to an
+ operation that is invalid or not authorized."
+
+ ::= { usecStats 7 }
+
+
+-- conformance information
+
+usecMIBConformance
+ OBJECT IDENTIFIER ::= { usecMIB 2 }
+
+usecMIBCompliances
+ OBJECT IDENTIFIER ::= { usecMIBConformance 1 }
+usecMIBGroups OBJECT IDENTIFIER ::= { usecMIBConformance 2 }
+
+
+-- compliance statements
+
+usecMIBCompliance MODULE-COMPLIANCE
+ STATUS current
+ DESCRIPTION
+ "The compliance statement for SNMPv2 entities which
+ implement the SNMPv2 USEC model."
+ MODULE -- this module
+ MANDATORY-GROUPS { usecBasicGroup,
+ usecStatsGroup }
+ ::= { usecMIBCompliances 1 }
+
+
+-- units of conformance
+
+usecBasicGroup OBJECT-GROUP
+ OBJECTS { agentID,
+ agentBoots,
+ agentTime,
+ agentSize }
+ STATUS current
+ DESCRIPTION
+ "A collection of objects providing identification, clocks,
+ and capabilities of an SNMPv2 entity which implements the
+ SNMPv2 USEC model."
+ ::= { usecMIBGroups 1 }
+
+usecStatsGroup OBJECT-GROUP
+ OBJECTS { usecStatsUnsupportedQoS,
+ usecStatsNotInWindows,
+ usecStatsUnknownUserNames,
+ usecStatsWrongDigestValues,
+ usecStatsUnknownContexts,
+ usecStatsBadParameters,
+ usecStatsUnauthorizedOperations }
+
+
+ STATUS current
+ DESCRIPTION
+ "A collection of objects providing basic error statistics of
+ an SNMPv2 entity which implements the SNMPv2 USEC model."
+ ::= { usecMIBGroups 2 }
+
+END
diff --git a/lib/snmp/test/test-mibs/SNMPv2-test.mib b/lib/snmp/test/test-mibs/SNMPv2-test.mib
new file mode 100644
index 0000000000..b02be09138
--- /dev/null
+++ b/lib/snmp/test/test-mibs/SNMPv2-test.mib
@@ -0,0 +1,777 @@
+SNMPv2-test DEFINITIONS ::= BEGIN
+
+IMPORTS
+ MODULE-IDENTITY, OBJECT-TYPE, NOTIFICATION-TYPE,
+ TimeTicks, Counter32, snmpModules, mib-2
+ FROM SNMPv2-SMI
+ DisplayString, TestAndIncr, TimeStamp
+ FROM SNMPv2-TC
+ MODULE-COMPLIANCE, OBJECT-GROUP, NOTIFICATION-GROUP
+ FROM SNMPv2-CONF;
+
+snmpMIB MODULE-IDENTITY
+ LAST-UPDATED "9511090000Z"
+ ORGANIZATION "IETF SNMPv2 Working Group"
+ CONTACT-INFO
+ " Marshall T. Rose
+
+ Postal: Dover Beach Consulting, Inc.
+ 420 Whisman Court
+ Mountain View, CA 94043-2186
+ US
+
+ Tel: +1 415 968 1052
+
+ DESCRIPTION
+ "The MIB module for SNMPv2 entities."
+ REVISION "9304010000Z"
+ DESCRIPTION
+ "The initial revision of this MIB module was published as
+ RFC 1450."
+ ::= { snmpModules 1 }
+
+
+snmpMIBObjects OBJECT IDENTIFIER ::= { snmpMIB 1 }
+
+-- ::= { snmpMIBObjects 1 } this OID is obsolete
+-- ::= { snmpMIBObjects 2 } this OID is obsolete
+-- ::= { snmpMIBObjects 3 } this OID is obsolete
+
+
+-- the System group
+--
+-- a collection of objects common to all managed systems.
+
+system OBJECT IDENTIFIER ::= { mib-2 1 }
+
+sysDescr OBJECT-TYPE
+ SYNTAX DisplayString (SIZE (0..255))
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "A textual description of the entity. This value should
+ include the full name and version identification of the
+ system's hardware type, software operating-system, and
+ networking software."
+ ::= { system 1 }
+
+sysObjectID OBJECT-TYPE
+
+
+ SYNTAX OBJECT IDENTIFIER
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The vendor's authoritative identification of the network
+ management subsystem contained in the entity. This value is
+ allocated within the SMI enterprises subtree (1.3.6.1.4.1)
+ and provides an easy and unambiguous means for determining
+ `what kind of box' is being managed. For example, if vendor
+ `Flintstones, Inc.' was assigned the subtree
+ 1.3.6.1.4.1.4242, it could assign the identifier
+ 1.3.6.1.4.1.4242.1.1 to its `Fred Router'."
+ ::= { system 2 }
+
+sysUpTime OBJECT-TYPE
+ SYNTAX TimeTicks
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The time (in hundredths of a second) since the network
+ management portion of the system was last re-initialized."
+ ::= { system 3 }
+
+sysContact OBJECT-TYPE
+ SYNTAX DisplayString (SIZE (0..255))
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The textual identification of the contact person for this
+ managed node, together with information on how to contact
+ this person. If no contact information is known, the value
+ is the zero-length string."
+ ::= { system 4 }
+
+sysName OBJECT-TYPE
+ SYNTAX DisplayString (SIZE (0..255))
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "An administratively-assigned name for this managed node.
+ By convention, this is the node's fully-qualified domain
+ name. If the name is unknown, the value is the zero-length
+ string."
+ ::= { system 5 }
+
+sysLocation OBJECT-TYPE
+ SYNTAX DisplayString (SIZE (0..255))
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The physical location of this node (e.g., `telephone
+ closet, 3rd floor'). If the location is unknown, the value
+ is the zero-length string."
+ ::= { system 6 }
+
+sysServices OBJECT-TYPE
+ SYNTAX INTEGER (0..127)
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "A value which indicates the set of services that this
+ entity may potentially offers. The value is a sum. This
+ sum initially takes the value zero, Then, for each layer, L,
+ in the range 1 through 7, that this node performs
+ transactions for, 2 raised to (L - 1) is added to the sum.
+ For example, a node which performs only routing functions
+ would have a value of 4 (2^(3-1)). In contrast, a node
+ which is a host offering application services would have a
+ value of 72 (2^(4-1) + 2^(7-1)). Note that in the context
+ of the Internet suite of protocols, values should be
+ calculated accordingly:
+
+ layer functionality
+ 1 physical (e.g., repeaters)
+ 2 datalink/subnetwork (e.g., bridges)
+ 3 internet (e.g., supports the IP)
+ 4 end-to-end (e.g., supports the TCP)
+ 7 applications (e.g., supports the SMTP)
+
+ For systems including OSI protocols, layers 5 and 6 may also
+ be counted."
+ ::= { system 7 }
+
+
+-- object resource information
+--
+-- a collection of objects which describe the SNMPv2 entity's
+-- (statically and dynamically configurable) support of
+-- various MIB modules.
+
+sysORLastChange OBJECT-TYPE
+ SYNTAX TimeStamp
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The value of sysUpTime at the time of the most recent
+ change in state or value of any instance of sysORID."
+ ::= { system 8 }
+
+sysQ OBJECT-TYPE
+ SYNTAX BITS {q(0), a(1), b(2), c(3)}
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "The auxiliar the SYNTAX."
+ DEFVAL { { a, b } }
+ ::= { system 11 }
+
+
+sysORTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF SysOREntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "The (conceptual) table listing the capabilities of the
+ local SNMPv2 entity acting in an agent role with respect to
+ various MIB modules. SNMPv2 entities having dynamically-
+ configurable support of MIB modules will have a
+ dynamically-varying number of conceptual rows."
+ ::= { system 9 }
+
+sysOREntry OBJECT-TYPE
+ SYNTAX SysOREntry
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "An entry (conceptual row) in the sysORTable."
+ INDEX { sysORIndex }
+ ::= { sysORTable 1 }
+
+SysOREntry ::= SEQUENCE {
+ sysORIndex INTEGER,
+ sysORID OBJECT IDENTIFIER,
+ sysORDescr DisplayString,
+ sysORUpTime TimeStamp
+}
+
+sysORIndex OBJECT-TYPE
+ SYNTAX INTEGER
+ MAX-ACCESS not-accessible
+ STATUS current
+ DESCRIPTION
+ "The auxiliary variable used for identifying instances of
+ the columnar objects in the sysORTable."
+ ::= { sysOREntry 1 }
+
+sysORID OBJECT-TYPE
+ SYNTAX OBJECT IDENTIFIER
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "An authoritative identification of a capabilities statement
+ with respect to various MIB modules supported by the local
+ SNMPv2 entity acting in an agent role."
+
+ ::= { sysOREntry 2 }
+
+sysORDescr OBJECT-TYPE
+ SYNTAX DisplayString
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "A textual description of the capabilities identified by the
+ corresponding instance of sysORID."
+ ::= { sysOREntry 3 }
+
+sysORUpTime OBJECT-TYPE
+ SYNTAX TimeStamp
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The value of sysUpTime at the time this conceptual row was
+ last instanciated."
+ ::= { sysOREntry 4 }
+
+
+-- the SNMP group
+--
+-- a collection of objects providing basic instrumentation and
+-- control of an SNMP entity.
+
+snmp OBJECT IDENTIFIER ::= { mib-2 11 }
+
+snmpInPkts OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The total number of messages delivered to the SNMP entity
+ from the transport service."
+ ::= { snmp 1 }
+
+snmpInBadVersions OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The total number of SNMP messages which were delivered to
+ the SNMP entity and were for an unsupported SNMP version."
+ ::= { snmp 3 }
+
+snmpInBadCommunityNames OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The total number of SNMP messages delivered to the SNMP
+ entity which used a SNMP community name not known to said
+ entity."
+ ::= { snmp 4 }
+
+snmpInBadCommunityUses OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The total number of SNMP messages delivered to the SNMP
+ entity which represented an SNMP operation which was not
+ allowed by the SNMP community named in the message."
+ ::= { snmp 5 }
+
+snmpInASNParseErrs OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The total number of ASN.1 or BER errors encountered by the
+ SNMP entity when decoding received SNMP messages."
+ ::= { snmp 6 }
+
+snmpEnableAuthenTraps OBJECT-TYPE
+ SYNTAX INTEGER { enabled(1), disabled(2) }
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "Indicates whether the SNMP entity is permitted to generate
+ authenticationFailure traps. The value of this object
+ overrides any configuration information; as such, it
+ provides a means whereby all authenticationFailure traps may
+ be disabled.
+
+ Note that it is strongly recommended that this object be
+ stored in non-volatile memory so that it remains constant
+ across re-initializations of the network management system."
+ ::= { snmp 30 }
+
+snmpSilentDrops OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The total number of GetRequest-PDUs, GetNextRequest-PDUs,
+ GetBulkRequest-PDUs, SetRequest-PDUs, and InformRequest-PDUs
+ delivered to the SNMP entity which were silently dropped
+ because the size of a reply containing an alternate
+ Response-PDU with an empty variable-bindings field was
+ greater than either a local constraint or the maximum
+ message size associated with the originator of the request."
+ ::= { snmp 31 }
+
+snmpProxyDrops OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS current
+ DESCRIPTION
+ "The total number of GetRequest-PDUs, GetNextRequest-PDUs,
+ GetBulkRequest-PDUs, SetRequest-PDUs, and InformRequest-PDUs
+ delivered to the SNMP entity which were silently dropped
+ because the transmission of the (possibly translated)
+ message to a proxy target failed in a manner (other than a
+ time-out) such that no Response-PDU could be returned."
+ ::= { snmp 32 }
+
+
+-- information for notifications
+--
+-- a collection of objects which allow the SNMPv2 entity, when
+-- acting in an agent role, to be configured to generate
+-- SNMPv2-Trap-PDUs.
+
+snmpTrap OBJECT IDENTIFIER ::= { snmpMIBObjects 4 }
+
+
+snmpTrapOID OBJECT-TYPE
+ SYNTAX OBJECT IDENTIFIER
+ MAX-ACCESS accessible-for-notify
+ STATUS current
+ DESCRIPTION
+ "The authoritative identification of the notification
+ currently being sent. This variable occurs as the second
+ varbind in every SNMPv2-Trap-PDU and InformRequest-PDU."
+ ::= { snmpTrap 1 }
+
+-- ::= { snmpTrap 2 } this OID is obsolete
+
+snmpTrapEnterprise OBJECT-TYPE
+ SYNTAX OBJECT IDENTIFIER
+ MAX-ACCESS accessible-for-notify
+ STATUS current
+ DESCRIPTION
+ "The authoritative identification of the enterprise
+ associated with the trap currently being sent. When a
+ SNMPv2 proxy agent is mapping an RFC1157 Trap-PDU into a
+ SNMPv2-Trap-PDU, this variable occurs as the last varbind."
+ ::= { snmpTrap 3 }
+
+-- ::= { snmpTrap 4 } this OID is obsolete
+
+
+-- well-known traps
+
+snmpTraps OBJECT IDENTIFIER ::= { snmpMIBObjects 5 }
+
+coldStart NOTIFICATION-TYPE
+ STATUS current
+ DESCRIPTION
+ "A coldStart trap signifies that the SNMPv2 entity, acting
+ in an agent role, is reinitializing itself and that its
+ configuration may have been altered."
+ ::= { snmpTraps 1 }
+
+warmStart NOTIFICATION-TYPE
+ STATUS current
+ DESCRIPTION
+ "A warmStart trap signifies that the SNMPv2 entity, acting
+ in an agent role, is reinitializing itself such that its
+ configuration is unaltered."
+ ::= { snmpTraps 2 }
+
+-- Note the linkDown NOTIFICATION-TYPE ::= { snmpTraps 3 }
+-- and the linkUp NOTIFICATION-TYPE ::= { snmpTraps 4 }
+-- are defined in RFC 1573
+
+authenticationFailure NOTIFICATION-TYPE
+ STATUS current
+ DESCRIPTION
+ "An authenticationFailure trap signifies that the SNMPv2
+ entity, acting in an agent role, has received a protocol
+ message that is not properly authenticated. While all
+ implementations of the SNMPv2 must be capable of generating
+ this trap, the snmpEnableAuthenTraps object indicates
+ whether this trap will be generated."
+ ::= { snmpTraps 5 }
+
+-- Note the egpNeighborLoss NOTIFICATION-TYPE ::= { snmpTraps 6 }
+-- is defined in RFC 1213
+-- the set group
+--
+-- a collection of objects which allow several cooperating
+-- SNMPv2 entities, all acting in a manager role, to
+-- coordinate their use of the SNMPv2 set operation.
+
+snmpSet OBJECT IDENTIFIER ::= { snmpMIBObjects 6 }
+
+
+snmpSetSerialNo OBJECT-TYPE
+ SYNTAX TestAndIncr
+ MAX-ACCESS read-write
+ STATUS current
+ DESCRIPTION
+ "An advisory lock used to allow several cooperating SNMPv2
+ entities, all acting in a manager role, to coordinate their
+ use of the SNMPv2 set operation.
+
+ This object is used for coarse-grain coordination. To
+ achieve fine-grain coordination, one or more similar objects
+ might be defined within each MIB group, as appropriate."
+ ::= { snmpSet 1 }
+
+
+-- conformance information
+
+snmpMIBConformance
+ OBJECT IDENTIFIER ::= { snmpMIB 2 }
+
+snmpMIBCompliances
+ OBJECT IDENTIFIER ::= { snmpMIBConformance 1 }
+snmpMIBGroups OBJECT IDENTIFIER ::= { snmpMIBConformance 2 }
+
+
+-- compliance statements
+
+-- ::= { snmpMIBCompliances 1 } this OID is obsolete
+
+snmpBasicCompliance MODULE-COMPLIANCE
+ STATUS current
+ DESCRIPTION
+ "The compliance statement for SNMPv2 entities which
+ implement the SNMPv2 MIB."
+ MODULE -- this module
+ MANDATORY-GROUPS { snmpGroup, snmpSetGroup, systemGroup,
+ snmpBasicNotificationsGroup }
+
+ GROUP snmpCommunityGroup
+ DESCRIPTION
+ "This group is mandatory for SNMPv2 entities which
+ support community-based authentication."
+
+ ::= { snmpMIBCompliances 2 }
+
+
+-- units of conformance
+
+-- ::= { snmpMIBGroups 1 } this OID is obsolete
+-- ::= { snmpMIBGroups 2 } this OID is obsolete
+-- ::= { snmpMIBGroups 3 } this OID is obsolete
+-- ::= { snmpMIBGroups 4 } this OID is obsolete
+
+snmpGroup OBJECT-GROUP
+ OBJECTS { snmpInPkts,
+ snmpInBadVersions,
+ snmpInASNParseErrs,
+ snmpSilentDrops,
+ snmpProxyDrops,
+ snmpEnableAuthenTraps }
+ STATUS current
+ DESCRIPTION
+ "A collection of objects providing basic instrumentation and
+ control of an SNMPv2 entity."
+ ::= { snmpMIBGroups 8 }
+
+snmpCommunityGroup OBJECT-GROUP
+ OBJECTS { snmpInBadCommunityNames,
+ snmpInBadCommunityUses }
+ STATUS current
+ DESCRIPTION
+ "A collection of objects providing basic instrumentation of
+ a SNMPv2 entity which supports community-based
+ authentication."
+ ::= { snmpMIBGroups 9 }
+
+snmpSetGroup OBJECT-GROUP
+ OBJECTS { snmpSetSerialNo }
+ STATUS current
+ DESCRIPTION
+ "A collection of objects which allow several cooperating
+ SNMPv2 entities, all acting in a manager role, to coordinate
+ their use of the SNMPv2 set operation."
+ ::= { snmpMIBGroups 5 }
+
+systemGroup OBJECT-GROUP
+ OBJECTS { sysDescr, sysObjectID, sysUpTime,
+ sysContact, sysName, sysLocation,
+ sysServices,
+ sysORLastChange, sysORID,
+ sysORUpTime, sysORDescr }
+ STATUS current
+ DESCRIPTION
+ "The system group defines objects which are common to all
+ managed systems."
+ ::= { snmpMIBGroups 6 }
+
+snmpBasicNotificationsGroup NOTIFICATION-GROUP
+ NOTIFICATIONS { coldStart, authenticationFailure }
+ STATUS current
+ DESCRIPTION
+ "The two notifications which an SNMPv2 entity is required to
+ implement."
+ ::= { snmpMIBGroups 7 }
+
+
+-- definitions in RFC 1213 made obsolete by the inclusion of a
+-- subset of the snmp group in this MIB
+
+snmpOutPkts OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS obsolete
+ DESCRIPTION
+ "The total number of SNMP Messages which were
+ passed from the SNMP protocol entity to the
+ transport service."
+ ::= { snmp 2 }
+
+-- { snmp 7 } is not used
+
+snmpInTooBigs OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS obsolete
+ DESCRIPTION
+ "The total number of SNMP PDUs which were
+ delivered to the SNMP protocol entity and for
+ which the value of the error-status field is
+ `tooBig'."
+ ::= { snmp 8 }
+
+snmpInNoSuchNames OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS obsolete
+ DESCRIPTION
+ "The total number of SNMP PDUs which were
+ delivered to the SNMP protocol entity and for
+ which the value of the error-status field is
+ `noSuchName'."
+ ::= { snmp 9 }
+
+snmpInBadValues OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS obsolete
+ DESCRIPTION
+ "The total number of SNMP PDUs which were
+ delivered to the SNMP protocol entity and for
+ which the value of the error-status field is
+ `badValue'."
+ ::= { snmp 10 }
+
+snmpInReadOnlys OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS obsolete
+ DESCRIPTION
+ "The total number valid SNMP PDUs which were
+ delivered to the SNMP protocol entity and for
+ which the value of the error-status field is
+ `readOnly'. It should be noted that it is a
+ protocol error to generate an SNMP PDU which
+ contains the value `readOnly' in the error-status
+ field, as such this object is provided as a means
+ of detecting incorrect implementations of the
+ SNMP."
+ ::= { snmp 11 }
+
+snmpInGenErrs OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS obsolete
+ DESCRIPTION
+ "The total number of SNMP PDUs which were
+ delivered to the SNMP protocol entity and for
+ which the value of the error-status field is
+ `genErr'."
+ ::= { snmp 12 }
+
+snmpInTotalReqVars OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS obsolete
+ DESCRIPTION
+ "The total number of MIB objects which have been
+ retrieved successfully by the SNMP protocol entity
+ as the result of receiving valid SNMP Get-Request
+ and Get-Next PDUs."
+ ::= { snmp 13 }
+
+snmpInTotalSetVars OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS obsolete
+ DESCRIPTION
+ "The total number of MIB objects which have been
+ altered successfully by the SNMP protocol entity
+ as the result of receiving valid SNMP Set-Request
+ PDUs."
+ ::= { snmp 14 }
+
+snmpInGetRequests OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS obsolete
+ DESCRIPTION
+ "The total number of SNMP Get-Request PDUs which
+ have been accepted and processed by the SNMP
+ protocol entity."
+ ::= { snmp 15 }
+
+snmpInGetNexts OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS obsolete
+ DESCRIPTION
+ "The total number of SNMP Get-Next PDUs which have
+ been accepted and processed by the SNMP protocol
+ entity."
+ ::= { snmp 16 }
+
+snmpInSetRequests OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS obsolete
+ DESCRIPTION
+ "The total number of SNMP Set-Request PDUs which
+ have been accepted and processed by the SNMP
+ protocol entity."
+ ::= { snmp 17 }
+
+snmpInGetResponses OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS obsolete
+ DESCRIPTION
+ "The total number of SNMP Get-Response PDUs which
+ have been accepted and processed by the SNMP
+ protocol entity."
+ ::= { snmp 18 }
+
+snmpInTraps OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS obsolete
+ DESCRIPTION
+ "The total number of SNMP Trap PDUs which have
+ been accepted and processed by the SNMP protocol
+ entity."
+ ::= { snmp 19 }
+
+snmpOutTooBigs OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS obsolete
+ DESCRIPTION
+ "The total number of SNMP PDUs which were
+ generated by the SNMP protocol entity and for
+ which the value of the error-status field is
+ `tooBig.'"
+ ::= { snmp 20 }
+
+snmpOutNoSuchNames OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS obsolete
+ DESCRIPTION
+ "The total number of SNMP PDUs which were
+ generated by the SNMP protocol entity and for
+ which the value of the error-status is
+ `noSuchName'."
+ ::= { snmp 21 }
+
+snmpOutBadValues OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS obsolete
+ DESCRIPTION
+ "The total number of SNMP PDUs which were
+ generated by the SNMP protocol entity and for
+ which the value of the error-status field is
+ `badValue'."
+ ::= { snmp 22 }
+
+
+-- { snmp 23 } is not used
+
+snmpOutGenErrs OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS obsolete
+ DESCRIPTION
+ "The total number of SNMP PDUs which were
+ generated by the SNMP protocol entity and for
+ which the value of the error-status field is
+ `genErr'."
+ ::= { snmp 24 }
+
+snmpOutGetRequests OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS obsolete
+ DESCRIPTION
+ "The total number of SNMP Get-Request PDUs which
+ have been generated by the SNMP protocol entity."
+ ::= { snmp 25 }
+
+snmpOutGetNexts OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS obsolete
+ DESCRIPTION
+ "The total number of SNMP Get-Next PDUs which have
+ been generated by the SNMP protocol entity."
+ ::= { snmp 26 }
+
+snmpOutSetRequests OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS obsolete
+ DESCRIPTION
+ "The total number of SNMP Set-Request PDUs which
+ have been generated by the SNMP protocol entity."
+ ::= { snmp 27 }
+
+snmpOutGetResponses OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS obsolete
+ DESCRIPTION
+ "The total number of SNMP Get-Response PDUs which
+ have been generated by the SNMP protocol entity."
+ ::= { snmp 28 }
+
+snmpOutTraps OBJECT-TYPE
+ SYNTAX Counter32
+ MAX-ACCESS read-only
+ STATUS obsolete
+ DESCRIPTION
+ "The total number of SNMP Trap PDUs which have
+ been generated by the SNMP protocol entity."
+ ::= { snmp 29 }
+
+snmpObsoleteGroup OBJECT-GROUP
+ OBJECTS { snmpOutPkts, snmpInTooBigs, snmpInNoSuchNames,
+ snmpInBadValues, snmpInReadOnlys, snmpInGenErrs,
+ snmpInTotalReqVars, snmpInTotalSetVars,
+ snmpInGetRequests, snmpInGetNexts, snmpInSetRequests,
+ snmpInGetResponses, snmpInTraps, snmpOutTooBigs,
+ snmpOutNoSuchNames, snmpOutBadValues, snmpOutGenErrs,
+ snmpOutGetRequests, snmpOutGetNexts, snmpOutSetRequests,
+ snmpOutGetResponses, snmpOutTraps }
+ STATUS obsolete
+ DESCRIPTION
+ "A collection of objects from RFC 1213 made obsolete by this
+ MIB."
+ ::= { snmpMIBGroups 10 }
+
+END
diff --git a/lib/snmp/test/test-mibs/STANDARD-MIB.mib b/lib/snmp/test/test-mibs/STANDARD-MIB.mib
new file mode 100644
index 0000000000..3b444ce8aa
--- /dev/null
+++ b/lib/snmp/test/test-mibs/STANDARD-MIB.mib
@@ -0,0 +1,518 @@
+STANDARD-MIB DEFINITIONS ::= BEGIN
+
+ IMPORTS
+ Counter, TimeTicks, IpAddress
+ FROM RFC1155-SMI
+ OBJECT-TYPE
+ FROM RFC-1212
+ mgmt, NetworkAddress, IpAddress, Counter, Gauge,
+ TimeTicks
+ FROM RFC1155-SMI
+ DisplayString, mib-2
+ FROM RFC1213-MIB
+ OBJECT-TYPE
+ FROM RFC-1212;
+
+
+ -- Standard Datatypes
+
+ -- Represents a boolean value (from rfc1443)
+ TruthValue ::= INTEGER { true(1), false(2) }
+
+ -- From SNMPv2 (rfc1443)
+ RowStatus ::=
+ INTEGER {
+ -- the following two values are states:
+ -- these values may be read or written
+ active(1),
+ notInService(2),
+
+ -- the following value is a state:
+ -- this value may be read, but not written
+ notReady(3),
+
+ -- the following three values are
+ -- actions: these values may be written,
+ -- but are never read
+ createAndGo(4),
+ createAndWait(5),
+ destroy(6)
+ }
+
+
+ system OBJECT IDENTIFIER ::= { mib-2 1 }
+ snmp OBJECT IDENTIFIER ::= { mib-2 11 }
+
+
+ -- the System group
+
+ -- Implementation of the System group is mandatory for all
+ -- systems. If an agent is not configured to have a value
+ -- for any of these variables, a string of length 0 is
+ -- returned.
+
+ sysDescr OBJECT-TYPE
+ SYNTAX DisplayString (SIZE (0..255))
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "A textual description of the entity. This value
+ should include the full name and version
+ identification of the system's hardware type,
+ software operating-system, and networking
+ software. It is mandatory that this only contain
+ printable ASCII characters."
+ ::= { system 1 }
+
+ sysObjectID OBJECT-TYPE
+ SYNTAX OBJECT IDENTIFIER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The vendor's authoritative identification of the
+ network management subsystem contained in the
+ entity. This value is allocated within the SMI
+ enterprises subtree (1.3.6.1.4.1) and provides an
+ easy and unambiguous means for determining `what
+ kind of box' is being managed. For example, if
+ vendor `Flintstones, Inc.' was assigned the
+ subtree 1.3.6.1.4.1.4242, it could assign the
+ identifier 1.3.6.1.4.1.4242.1.1 to its `Fred
+ Router'."
+ ::= { system 2 }
+
+ sysUpTime OBJECT-TYPE
+ SYNTAX TimeTicks
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The time (in hundredths of a second) since the
+ network management portion of the system was last
+ re-initialized."
+ ::= { system 3 }
+
+ sysContact OBJECT-TYPE
+ SYNTAX DisplayString (SIZE (0..255))
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The textual identification of the contact person
+ for this managed node, together with information
+ on how to contact this person."
+ ::= { system 4 }
+
+ sysName OBJECT-TYPE
+ SYNTAX DisplayString (SIZE (0..255))
+
+
+
+
+
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "An administratively-assigned name for this
+ managed node. By convention, this is the node's
+ fully-qualified domain name."
+ ::= { system 5 }
+
+ sysLocation OBJECT-TYPE
+ SYNTAX DisplayString (SIZE (0..255))
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The physical location of this node (e.g.,
+ `telephone closet, 3rd floor')."
+ ::= { system 6 }
+
+ sysServices OBJECT-TYPE
+ SYNTAX INTEGER (0..127)
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "A value which indicates the set of services that
+ this entity primarily offers.
+
+ The value is a sum. This sum initially takes the
+ value zero, Then, for each layer, L, in the range
+ 1 through 7, that this node performs transactions
+ for, 2 raised to (L - 1) is added to the sum. For
+ example, a node which performs primarily routing
+ functions would have a value of 4 (2^(3-1)). In
+ contrast, a node which is a host offering
+ application services would have a value of 72
+ (2^(4-1) + 2^(7-1)). Note that in the context of
+ the Internet suite of protocols, values should be
+ calculated accordingly:
+
+ layer functionality
+ 1 physical (e.g., repeaters)
+ 2 datalink/subnetwork (e.g., bridges)
+ 3 internet (e.g., IP gateways)
+ 4 end-to-end (e.g., IP hosts)
+ 7 applications (e.g., mail relays)
+
+ For systems including OSI protocols, layers 5 and
+ 6 may also be counted."
+ ::= { system 7 }
+
+
+ -- the SNMP group
+
+ -- Implementation of the SNMP group is mandatory for all
+ -- systems which support an SNMP protocol entity. Some of
+ -- the objects defined below will be zero-valued in those
+ -- SNMP implementations that are optimized to support only
+ -- those functions specific to either a management agent or
+ -- a management station. In particular, it should be
+ -- observed that the objects below refer to an SNMP entity,
+ -- and there may be several SNMP entities residing on a
+ -- managed node (e.g., if the node is hosting acting as
+ -- a management station).
+
+ snmpInPkts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of Messages delivered to the
+ SNMP entity from the transport service."
+ ::= { snmp 1 }
+
+ snmpOutPkts OBJECT-TYPE
+ SYNTAX Counter
+
+
+
+
+
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Messages which were
+ passed from the SNMP protocol entity to the
+ transport service."
+ ::= { snmp 2 }
+
+ snmpInBadVersions OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Messages which were
+ delivered to the SNMP protocol entity and were for
+ an unsupported SNMP version."
+ ::= { snmp 3 }
+
+ snmpInBadCommunityNames OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Messages delivered to
+ the SNMP protocol entity which used a SNMP
+ community name not known to said entity."
+ ::= { snmp 4 }
+
+ snmpInBadCommunityUses OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Messages delivered to
+ the SNMP protocol entity which represented an SNMP
+ operation which was not allowed by the SNMP
+ community named in the Message."
+ ::= { snmp 5 }
+
+ snmpInASNParseErrs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of ASN.1 or BER errors
+ encountered by the SNMP protocol entity when
+ decoding received SNMP Messages."
+ ::= { snmp 6 }
+
+
+
+
+
+ -- { snmp 7 } is not used
+
+ snmpInTooBigs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP PDUs which were
+ delivered to the SNMP protocol entity and for
+ which the value of the error-status field is
+ `tooBig'."
+ ::= { snmp 8 }
+
+ snmpInNoSuchNames OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP PDUs which were
+ delivered to the SNMP protocol entity and for
+ which the value of the error-status field is
+ `noSuchName'."
+ ::= { snmp 9 }
+
+ snmpInBadValues OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP PDUs which were
+ delivered to the SNMP protocol entity and for
+ which the value of the error-status field is
+ `badValue'."
+ ::= { snmp 10 }
+
+ snmpInReadOnlys OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number valid SNMP PDUs which were
+ delivered to the SNMP protocol entity and for
+ which the value of the error-status field is
+ `readOnly'. It should be noted that it is a
+ protocol error to generate an SNMP PDU which
+ contains the value `readOnly' in the error-status
+ field, as such this object is provided as a means
+ of detecting incorrect implementations of the
+
+
+
+
+
+ SNMP."
+ ::= { snmp 11 }
+
+ snmpInGenErrs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP PDUs which were
+ delivered to the SNMP protocol entity and for
+ which the value of the error-status field is
+ `genErr'."
+ ::= { snmp 12 }
+
+ snmpInTotalReqVars OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of MIB objects which have been
+ retrieved successfully by the SNMP protocol entity
+ as the result of receiving valid SNMP Get-Request
+ and Get-Next PDUs."
+ ::= { snmp 13 }
+
+ snmpInTotalSetVars OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of MIB objects which have been
+ altered successfully by the SNMP protocol entity
+ as the result of receiving valid SNMP Set-Request
+ PDUs."
+ ::= { snmp 14 }
+
+ snmpInGetRequests OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Get-Request PDUs which
+ have been accepted and processed by the SNMP
+ protocol entity."
+ ::= { snmp 15 }
+
+ snmpInGetNexts OBJECT-TYPE
+ SYNTAX Counter
+
+
+
+
+
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Get-Next PDUs which have
+ been accepted and processed by the SNMP protocol
+ entity."
+ ::= { snmp 16 }
+
+ snmpInSetRequests OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Set-Request PDUs which
+ have been accepted and processed by the SNMP
+ protocol entity."
+ ::= { snmp 17 }
+
+ snmpInGetResponses OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Get-Response PDUs which
+ have been accepted and processed by the SNMP
+ protocol entity."
+ ::= { snmp 18 }
+
+ snmpInTraps OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Trap PDUs which have
+ been accepted and processed by the SNMP protocol
+ entity."
+ ::= { snmp 19 }
+
+ snmpOutTooBigs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP PDUs which were
+ generated by the SNMP protocol entity and for
+ which the value of the error-status field is
+ `tooBig.'"
+ ::= { snmp 20 }
+
+
+
+
+
+ snmpOutNoSuchNames OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP PDUs which were
+ generated by the SNMP protocol entity and for
+ which the value of the error-status is
+ `noSuchName'."
+ ::= { snmp 21 }
+
+ snmpOutBadValues OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP PDUs which were
+ generated by the SNMP protocol entity and for
+ which the value of the error-status field is
+ `badValue'."
+ ::= { snmp 22 }
+
+ -- { snmp 23 } is not used
+
+ snmpOutGenErrs OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP PDUs which were
+ generated by the SNMP protocol entity and for
+ which the value of the error-status field is
+ `genErr'."
+ ::= { snmp 24 }
+
+ snmpOutGetRequests OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Get-Request PDUs which
+ have been generated by the SNMP protocol entity."
+ ::= { snmp 25 }
+
+ snmpOutGetNexts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+
+
+
+
+
+ DESCRIPTION
+ "The total number of SNMP Get-Next PDUs which have
+ been generated by the SNMP protocol entity."
+ ::= { snmp 26 }
+
+ snmpOutSetRequests OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Set-Request PDUs which
+ have been generated by the SNMP protocol entity."
+ ::= { snmp 27 }
+
+ snmpOutGetResponses OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Get-Response PDUs which
+ have been generated by the SNMP protocol entity."
+ ::= { snmp 28 }
+
+ snmpOutTraps OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of SNMP Trap PDUs which have
+ been generated by the SNMP protocol entity."
+ ::= { snmp 29 }
+
+ snmpEnableAuthenTraps OBJECT-TYPE
+ SYNTAX INTEGER { enabled(1), disabled(2) }
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "Indicates whether the SNMP agent process is
+ permitted to generate authentication-failure
+ traps. The value of this object overrides any
+ configuration information; as such, it provides a
+ means whereby all authentication-failure traps may
+ be disabled.
+
+ Note that it is strongly recommended that this
+ object be stored in non-volatile memory so that it
+ remains constant between re-initializations of the
+ network management system."
+ ::= { snmp 30 }
+
+ authenticationFailure TRAP-TYPE
+ ENTERPRISE snmp
+ DESCRIPTION
+ "An authenticationFailure trap signifies that
+ the sending protocol entity is the addressee
+ of a protocol message that is not properly
+ authenticated. While implementations of the
+ SNMP must be capable of generating this trap,
+ they must also be capable of suppressing the
+ emission of such traps via an implementation-
+ specific mechanism."
+ ::= 4
+
+ END
+
diff --git a/lib/snmp/test/test-mibs/TOKEN-RING-RMON-MIB.mib b/lib/snmp/test/test-mibs/TOKEN-RING-RMON-MIB.mib
new file mode 100644
index 0000000000..4ad1d88865
--- /dev/null
+++ b/lib/snmp/test/test-mibs/TOKEN-RING-RMON-MIB.mib
@@ -0,0 +1,2406 @@
+ TOKEN-RING-RMON-MIB DEFINITIONS ::= BEGIN
+
+ IMPORTS
+ Counter, TimeTicks FROM RFC1155-SMI
+ OBJECT-TYPE FROM RFC-1212
+ OwnerString, EntryStatus, -- Textual Conventions
+ rmon, statistics, history
+ FROM RFC1271-MIB;
+
+
+ -- All representations of MAC addresses in this MIB
+ -- Module use, as a textual convention (i.e. this
+ -- convention does not affect their encoding), the
+ -- data type:
+
+ MacAddress ::= OCTET STRING (SIZE (6)) -- a 6 octet
+ -- address in
+ -- the "canonical"
+ -- order
+ -- defined by IEEE 802.1a, i.e., as if it were
+ -- transmitted least significant bit first, even though
+ -- 802.5 (in contrast to other 802.x protocols) requires
+ -- MAC addresses to be transmitted most significant bit
+ -- first.
+
+ TimeInterval ::= INTEGER
+ -- A period of time, measured in units of 0.01 seconds.
+
+ -- This MIB module uses the extended OBJECT-TYPE macro as
+ -- defined in [2].
+
+ -- Token Ring Remote Network Monitoring MIB
+
+ tokenRing OBJECT IDENTIFIER ::= { rmon 10 }
+
+
+ -- The Token Ring Mac-Layer Statistics Group
+ --
+ -- Implementation of this group is optional
+
+ tokenRingMLStatsTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF TokenRingMLStatsEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A list of Mac-Layer Token Ring statistics
+
+
+ entries."
+ ::= { statistics 2 }
+
+ tokenRingMLStatsEntry OBJECT-TYPE
+ SYNTAX TokenRingMLStatsEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A collection of Mac-Layer statistics kept for a
+ particular Token Ring interface."
+ INDEX { tokenRingMLStatsIndex }
+ ::= { tokenRingMLStatsTable 1 }
+
+ -- As an example, an instance of the
+ -- tokenRingMLStatsMacOctets object
+ -- might be named tokenRingMLStatsMacOctets.1
+
+ TokenRingMLStatsEntry ::= SEQUENCE {
+ tokenRingMLStatsIndex INTEGER,
+ tokenRingMLStatsDataSource OBJECT IDENTIFIER,
+ tokenRingMLStatsDropEvents Counter,
+ tokenRingMLStatsMacOctets Counter,
+ tokenRingMLStatsMacPkts Counter,
+ tokenRingMLStatsRingPurgeEvents Counter,
+ tokenRingMLStatsRingPurgePkts Counter,
+ tokenRingMLStatsBeaconEvents Counter,
+ tokenRingMLStatsBeaconTime TimeInterval,
+ tokenRingMLStatsBeaconPkts Counter,
+ tokenRingMLStatsClaimTokenEvents Counter,
+ tokenRingMLStatsClaimTokenPkts Counter,
+ tokenRingMLStatsNAUNChanges Counter,
+ tokenRingMLStatsLineErrors Counter,
+ tokenRingMLStatsInternalErrors Counter,
+ tokenRingMLStatsBurstErrors Counter,
+ tokenRingMLStatsACErrors Counter,
+ tokenRingMLStatsAbortErrors Counter,
+ tokenRingMLStatsLostFrameErrors Counter,
+ tokenRingMLStatsCongestionErrors Counter,
+ tokenRingMLStatsFrameCopiedErrors Counter,
+ tokenRingMLStatsFrequencyErrors Counter,
+ tokenRingMLStatsTokenErrors Counter,
+ tokenRingMLStatsSoftErrorReports Counter,
+ tokenRingMLStatsRingPollEvents Counter,
+ tokenRingMLStatsOwner OwnerString,
+ tokenRingMLStatsStatus EntryStatus
+ }
+
+
+
+
+ tokenRingMLStatsIndex OBJECT-TYPE
+ SYNTAX INTEGER (1..65535)
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The value of this object uniquely identifies this
+ tokenRingMLStats entry."
+ ::= { tokenRingMLStatsEntry 1 }
+
+ tokenRingMLStatsDataSource OBJECT-TYPE
+ SYNTAX OBJECT IDENTIFIER
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "This object identifies the source of the data
+ that this tokenRingMLStats entry is configured to
+ analyze. This source can be any tokenRing
+ interface on this device. In order to identify a
+ particular interface, this object shall identify
+ the instance of the ifIndex object, defined in
+ MIB-II [3], for the desired interface. For
+ example, if an entry were to receive data from
+ interface #1, this object would be set to
+ ifIndex.1.
+
+ The statistics in this group reflect all error
+ reports on the local network segment attached to
+ the identified interface.
+
+ This object may not be modified if the associated
+ tokenRingMLStatsStatus object is equal to
+ valid(1)."
+ ::= { tokenRingMLStatsEntry 2 }
+
+ tokenRingMLStatsDropEvents OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of events in which packets were
+ dropped by the probe due to lack of resources.
+ Note that this number is not necessarily the
+ number of packets dropped; it is just the number
+ of times this condition has been detected. This
+ value is the same as the corresponding
+ tokenRingPStatsDropEvents."
+ ::= { tokenRingMLStatsEntry 3 }
+
+
+
+ tokenRingMLStatsMacOctets OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of octets of data in MAC packets
+ (excluding those that were not good frames)
+ received on the network (excluding framing bits
+ but including FCS octets)."
+ ::= { tokenRingMLStatsEntry 4 }
+
+ tokenRingMLStatsMacPkts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of MAC packets (excluding
+ packets that were not good frames) received."
+ ::= { tokenRingMLStatsEntry 5 }
+
+ tokenRingMLStatsRingPurgeEvents OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of times that the ring enters
+ the ring purge state from normal ring state. The
+ ring purge state that comes in response to the
+ claim token or beacon state is not counted."
+ ::= { tokenRingMLStatsEntry 6 }
+
+ tokenRingMLStatsRingPurgePkts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of ring purge MAC packets
+ detected by probe."
+ ::= { tokenRingMLStatsEntry 7 }
+
+ tokenRingMLStatsBeaconEvents OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of times that the ring enters a
+ beaconing state (beaconFrameStreamingState,
+ beaconBitStreamingState,
+
+
+ beaconSetRecoveryModeState, or
+ beaconRingSignalLossState) from a non-beaconing
+ state. Note that a change of the source address
+ of the beacon packet does not constitute a new
+ beacon event."
+ ::= { tokenRingMLStatsEntry 8 }
+
+ tokenRingMLStatsBeaconTime OBJECT-TYPE
+ SYNTAX TimeInterval
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total amount of time that the ring has been
+ in the beaconing state."
+ ::= { tokenRingMLStatsEntry 9 }
+
+ tokenRingMLStatsBeaconPkts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of beacon MAC packets detected
+ by the probe."
+ ::= { tokenRingMLStatsEntry 10 }
+
+ tokenRingMLStatsClaimTokenEvents OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of times that the ring enters
+ the claim token state from normal ring state or
+ ring purge state. The claim token state that
+ comes in response to a beacon state is not
+ counted."
+ ::= { tokenRingMLStatsEntry 11 }
+
+ tokenRingMLStatsClaimTokenPkts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of claim token MAC packets
+ detected by the probe."
+ ::= { tokenRingMLStatsEntry 12 }
+
+
+
+
+
+ tokenRingMLStatsNAUNChanges OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of NAUN changes detected by the
+ probe."
+ ::= { tokenRingMLStatsEntry 13 }
+
+ tokenRingMLStatsLineErrors OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of line errors reported in error
+ reporting packets detected by the probe."
+ ::= { tokenRingMLStatsEntry 14 }
+
+ tokenRingMLStatsInternalErrors OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of adapter internal errors
+ reported in error reporting packets detected by
+ the probe."
+ ::= { tokenRingMLStatsEntry 15 }
+
+ tokenRingMLStatsBurstErrors OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of burst errors reported in
+ error reporting packets detected by the probe."
+ ::= { tokenRingMLStatsEntry 16 }
+
+ tokenRingMLStatsACErrors OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of AC (Address Copied) errors
+ reported in error reporting packets detected by
+ the probe."
+ ::= { tokenRingMLStatsEntry 17 }
+
+
+
+
+ tokenRingMLStatsAbortErrors OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of abort delimiters reported in
+ error reporting packets detected by the probe."
+ ::= { tokenRingMLStatsEntry 18 }
+
+ tokenRingMLStatsLostFrameErrors OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of lost frame errors reported in
+ error reporting packets detected by the probe."
+ ::= { tokenRingMLStatsEntry 19 }
+
+ tokenRingMLStatsCongestionErrors OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of receive congestion errors
+ reported in error reporting packets detected by
+ the probe."
+ ::= { tokenRingMLStatsEntry 20 }
+
+ tokenRingMLStatsFrameCopiedErrors OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of frame copied errors reported
+ in error reporting packets detected by the probe."
+ ::= { tokenRingMLStatsEntry 21 }
+
+ tokenRingMLStatsFrequencyErrors OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of frequency errors reported in
+ error reporting packets detected by the probe."
+ ::= { tokenRingMLStatsEntry 22 }
+
+
+
+
+
+ tokenRingMLStatsTokenErrors OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of token errors reported in
+ error reporting packets detected by the probe."
+ ::= { tokenRingMLStatsEntry 23 }
+
+ tokenRingMLStatsSoftErrorReports OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of soft error report frames
+ detected by the probe."
+ ::= { tokenRingMLStatsEntry 24 }
+
+ tokenRingMLStatsRingPollEvents OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of ring poll events detected by
+ the probe (i.e. the number of ring polls initiated
+ by the active monitor that were detected)."
+ ::= { tokenRingMLStatsEntry 25 }
+
+ tokenRingMLStatsOwner OBJECT-TYPE
+ SYNTAX OwnerString
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The entity that configured this entry and is
+ therefore using the resources assigned to it."
+ ::= { tokenRingMLStatsEntry 26 }
+
+ tokenRingMLStatsStatus OBJECT-TYPE
+ SYNTAX EntryStatus
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The status of this tokenRingMLStats entry."
+ ::= { tokenRingMLStatsEntry 27 }
+
+
+
+
+
+
+ -- The Token Ring Promiscuous Statistics Group
+ --
+ -- Implementation of this group is optional
+
+ tokenRingPStatsTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF TokenRingPStatsEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A list of promiscuous Token Ring statistics
+ entries."
+ ::= { statistics 3 }
+
+ tokenRingPStatsEntry OBJECT-TYPE
+ SYNTAX TokenRingPStatsEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A collection of promiscuous statistics kept for
+ non-MAC packets on a particular Token Ring
+ interface."
+ INDEX { tokenRingPStatsIndex }
+ ::= { tokenRingPStatsTable 1 }
+
+ -- As an example, an instance of the
+ -- tokenRingPStatsDataOctets object
+ -- might be named tokenRingPStatsDataOctets.1
+
+ TokenRingPStatsEntry ::= SEQUENCE {
+ tokenRingPStatsIndex INTEGER,
+ tokenRingPStatsDataSource OBJECT IDENTIFIER,
+ tokenRingPStatsDropEvents Counter,
+ tokenRingPStatsDataOctets Counter,
+ tokenRingPStatsDataPkts Counter,
+ tokenRingPStatsDataBroadcastPkts Counter,
+ tokenRingPStatsDataMulticastPkts Counter,
+ tokenRingPStatsDataPkts18to63Octets Counter,
+ tokenRingPStatsDataPkts64to127Octets Counter,
+ tokenRingPStatsDataPkts128to255Octets Counter,
+ tokenRingPStatsDataPkts256to511Octets Counter,
+ tokenRingPStatsDataPkts512to1023Octets Counter,
+ tokenRingPStatsDataPkts1024to2047Octets Counter,
+ tokenRingPStatsDataPkts2048to4095Octets Counter,
+ tokenRingPStatsDataPkts4096to8191Octets Counter,
+ tokenRingPStatsDataPkts8192to18000Octets Counter,
+ tokenRingPStatsDataPktsGreaterThan18000Octets Counter,
+ tokenRingPStatsOwner OwnerString,
+ tokenRingPStatsStatus EntryStatus
+
+
+ }
+
+ tokenRingPStatsIndex OBJECT-TYPE
+ SYNTAX INTEGER (1..65535)
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The value of this object uniquely identifies this
+ tokenRingPStats entry."
+ ::= { tokenRingPStatsEntry 1 }
+
+ tokenRingPStatsDataSource OBJECT-TYPE
+ SYNTAX OBJECT IDENTIFIER
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "This object identifies the source of the data
+ that this tokenRingPStats entry is configured to
+ analyze. This source can be any tokenRing
+ interface on this device. In order to identify a
+ particular interface, this object shall identify
+ the instance of the ifIndex object, defined in
+ MIB-II [3], for the desired interface. For
+ example, if an entry were to receive data from
+ interface #1, this object would be set to
+ ifIndex.1.
+
+ The statistics in this group reflect all non-MAC
+ packets on the local network segment attached to
+ the identified interface.
+
+ This object may not be modified if the associated
+ tokenRingPStatsStatus object is equal to
+ valid(1)."
+ ::= { tokenRingPStatsEntry 2 }
+
+ tokenRingPStatsDropEvents OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of events in which packets were
+ dropped by the probe due to lack of resources.
+ Note that this number is not necessarily the
+ number of packets dropped; it is just the number
+ of times this condition has been detected. This
+ value is the same as the corresponding
+ tokenRingMLStatsDropEvents"
+
+
+ ::= { tokenRingPStatsEntry 3 }
+
+ tokenRingPStatsDataOctets OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of octets of data in good frames
+ received on the network (excluding framing bits
+ but including FCS octets) in non-MAC packets."
+ ::= { tokenRingPStatsEntry 4 }
+
+ tokenRingPStatsDataPkts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of non-MAC packets in good
+ frames. received."
+ ::= { tokenRingPStatsEntry 5 }
+
+ tokenRingPStatsDataBroadcastPkts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of good non-MAC frames received
+ that were directed to an LLC broadcast address
+ (0xFFFFFFFFFFFF or 0xC000FFFFFFFF)."
+ ::= { tokenRingPStatsEntry 6 }
+
+ tokenRingPStatsDataMulticastPkts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of good non-MAC frames received
+ that were directed to a local or global multicast
+ or functional address. Note that this number does
+ not include packets directed to the broadcast
+ address."
+ ::= { tokenRingPStatsEntry 7 }
+
+ tokenRingPStatsDataPkts18to63Octets OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+
+
+ "The total number of good non-MAC frames received
+ that were between 18 and 63 octets in length
+ inclusive, excluding framing bits but including
+ FCS octets."
+ ::= { tokenRingPStatsEntry 8 }
+
+ tokenRingPStatsDataPkts64to127Octets OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of good non-MAC frames received
+ that were between 64 and 127 octets in length
+ inclusive, excluding framing bits but including
+ FCS octets."
+ ::= { tokenRingPStatsEntry 9 }
+
+ tokenRingPStatsDataPkts128to255Octets OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of good non-MAC frames received
+ that were between 128 and 255 octets in length
+ inclusive, excluding framing bits but including
+ FCS octets."
+ ::= { tokenRingPStatsEntry 10 }
+
+ tokenRingPStatsDataPkts256to511Octets OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of good non-MAC frames received
+ that were between 256 and 511 octets in length
+ inclusive, excluding framing bits but including
+ FCS octets."
+ ::= { tokenRingPStatsEntry 11 }
+
+ tokenRingPStatsDataPkts512to1023Octets OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of good non-MAC frames received
+ that were between 512 and 1023 octets in length
+ inclusive, excluding framing bits but including
+ FCS octets."
+
+
+ ::= { tokenRingPStatsEntry 12 }
+
+ tokenRingPStatsDataPkts1024to2047Octets OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of good non-MAC frames received
+ that were between 1024 and 2047 octets in length
+ inclusive, excluding framing bits but including
+ FCS octets."
+ ::= { tokenRingPStatsEntry 13 }
+
+ tokenRingPStatsDataPkts2048to4095Octets OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of good non-MAC frames received
+ that were between 2048 and 4095 octets in length
+ inclusive, excluding framing bits but including
+ FCS octets."
+ ::= { tokenRingPStatsEntry 14 }
+
+ tokenRingPStatsDataPkts4096to8191Octets OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of good non-MAC frames received
+ that were between 4096 and 8191 octets in length
+ inclusive, excluding framing bits but including
+ FCS octets."
+ ::= { tokenRingPStatsEntry 15 }
+
+ tokenRingPStatsDataPkts8192to18000Octets OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of good non-MAC frames received
+ that were between 8192 and 18000 octets in length
+ inclusive, excluding framing bits but including
+ FCS octets."
+ ::= { tokenRingPStatsEntry 16 }
+
+ tokenRingPStatsDataPktsGreaterThan18000Octets OBJECT-TYPE
+ SYNTAX Counter
+
+
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of good non-MAC frames received
+ that were greater than 18000 octets in length,
+ excluding framing bits but including FCS octets."
+ ::= { tokenRingPStatsEntry 17 }
+
+ tokenRingPStatsOwner OBJECT-TYPE
+ SYNTAX OwnerString
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The entity that configured this entry and is
+ therefore using the resources assigned to it."
+ ::= { tokenRingPStatsEntry 18 }
+
+ tokenRingPStatsStatus OBJECT-TYPE
+ SYNTAX EntryStatus
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The status of this tokenRingPStats entry."
+ ::= { tokenRingPStatsEntry 19 }
+
+
+ -- The Token Ring History Groups
+
+ -- When an entry in the historyControlTable is created that
+ -- identifies a token ring interface as its
+ -- historyControlDataSource, the probe shall create
+ -- corresponding entries in the tokenRingMLHistoryTable
+ -- and/or the tokenRingPHistoryTable, depending on which
+ -- groups it supports.
+
+
+ -- The Token Ring Mac-Layer History Group
+ --
+ -- Implementation of this group is optional.
+ -- Implementation of this group requires implementation of
+ -- the historyControl group from RFC1271.
+
+ tokenRingMLHistoryTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF TokenRingMLHistoryEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A list of Mac-Layer Token Ring statistics
+
+
+ entries."
+ ::= { history 3 }
+
+ tokenRingMLHistoryEntry OBJECT-TYPE
+ SYNTAX TokenRingMLHistoryEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A collection of Mac-Layer statistics kept for a
+ particular Token Ring interface."
+ INDEX { tokenRingMLHistoryIndex,
+ tokenRingMLHistorySampleIndex }
+ ::= { tokenRingMLHistoryTable 1 }
+
+ -- As an example, an instance of the
+ -- tokenRingMLHistoryMacOctets
+ -- object might be named tokenRingMLHistoryMacOctets.1.27
+
+ TokenRingMLHistoryEntry ::= SEQUENCE {
+ tokenRingMLHistoryIndex INTEGER,
+ tokenRingMLHistorySampleIndex INTEGER,
+ tokenRingMLHistoryIntervalStart TimeTicks,
+ tokenRingMLHistoryDropEvents Counter,
+ tokenRingMLHistoryMacOctets Counter,
+ tokenRingMLHistoryMacPkts Counter,
+ tokenRingMLHistoryRingPurgeEvents Counter,
+ tokenRingMLHistoryRingPurgePkts Counter,
+ tokenRingMLHistoryBeaconEvents Counter,
+ tokenRingMLHistoryBeaconTime TimeInterval,
+ tokenRingMLHistoryBeaconPkts Counter,
+ tokenRingMLHistoryClaimTokenEvents Counter,
+ tokenRingMLHistoryClaimTokenPkts Counter,
+ tokenRingMLHistoryNAUNChanges Counter,
+ tokenRingMLHistoryLineErrors Counter,
+ tokenRingMLHistoryInternalErrors Counter,
+ tokenRingMLHistoryBurstErrors Counter,
+ tokenRingMLHistoryACErrors Counter,
+ tokenRingMLHistoryAbortErrors Counter,
+ tokenRingMLHistoryLostFrameErrors Counter,
+ tokenRingMLHistoryCongestionErrors Counter,
+ tokenRingMLHistoryFrameCopiedErrors Counter,
+ tokenRingMLHistoryFrequencyErrors Counter,
+ tokenRingMLHistoryTokenErrors Counter,
+ tokenRingMLHistorySoftErrorReports Counter,
+ tokenRingMLHistoryRingPollEvents Counter,
+ tokenRingMLHistoryActiveStations INTEGER
+ }
+
+
+
+ tokenRingMLHistoryIndex OBJECT-TYPE
+ SYNTAX INTEGER (1..65535)
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The history of which this entry is a part. The
+ history identified by a particular value of this
+ index is the same history as identified by the
+ same value of historyControlIndex."
+ ::= { tokenRingMLHistoryEntry 1 }
+
+ tokenRingMLHistorySampleIndex OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "An index that uniquely identifies the particular
+ Mac-Layer sample this entry represents among all
+ Mac-Layer samples associated with the same
+ historyControlEntry. This index starts at 1 and
+ increases by one as each new sample is taken."
+ ::= { tokenRingMLHistoryEntry 2 }
+
+ tokenRingMLHistoryIntervalStart OBJECT-TYPE
+ SYNTAX TimeTicks
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The value of sysUpTime at the start of the
+ interval over which this sample was measured. If
+ the probe keeps track of the time of day, it
+ should start the first sample of the history at a
+ time such that when the next hour of the day
+ begins, a sample is started at that instant. Note
+ that following this rule may require the probe to
+ delay collecting the first sample of the history,
+ as each sample must be of the same interval. Also
+ note that the sample which is currently being
+ collected is not accessible in this table until
+ the end of its interval."
+ ::= { tokenRingMLHistoryEntry 3 }
+
+ tokenRingMLHistoryDropEvents OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of events in which packets were
+
+
+ dropped by the probe due to lack of resources
+ during this sampling interval. Note that this
+ number is not necessarily the number of packets
+ dropped, it is just the number of times this
+ condition has been detected."
+ ::= { tokenRingMLHistoryEntry 4 }
+
+ tokenRingMLHistoryMacOctets OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of octets of data in MAC packets
+ (excluding those that were not good frames)
+ received on the network during this sampling
+ interval (excluding framing bits but including FCS
+ octets)."
+ ::= { tokenRingMLHistoryEntry 5 }
+
+ tokenRingMLHistoryMacPkts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of MAC packets (excluding those
+ that were not good frames) received during this
+ sampling interval."
+ ::= { tokenRingMLHistoryEntry 6 }
+
+ tokenRingMLHistoryRingPurgeEvents OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of times that the ring entered
+ the ring purge state from normal ring state during
+ this sampling interval. The ring purge state that
+ comes from the claim token or beacon state is not
+ counted."
+ ::= { tokenRingMLHistoryEntry 7 }
+
+ tokenRingMLHistoryRingPurgePkts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of Ring Purge MAC packets
+ detected by the probe during this sampling
+
+
+ interval."
+ ::= { tokenRingMLHistoryEntry 8 }
+
+ tokenRingMLHistoryBeaconEvents OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of times that the ring enters a
+ beaconing state (beaconFrameStreamingState,
+ beaconBitStreamingState,
+ beaconSetRecoveryModeState, or
+ beaconRingSignalLossState) during this sampling
+ interval. Note that a change of the source
+ address of the beacon packet does not constitute a
+ new beacon event."
+ ::= { tokenRingMLHistoryEntry 9 }
+
+ tokenRingMLHistoryBeaconTime OBJECT-TYPE
+ SYNTAX TimeInterval
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The amount of time that the ring has been in the
+ beaconing state during this sampling interval."
+ ::= { tokenRingMLHistoryEntry 10 }
+
+ tokenRingMLHistoryBeaconPkts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of beacon MAC packets detected
+ by the probe during this sampling interval."
+ ::= { tokenRingMLHistoryEntry 11 }
+
+ tokenRingMLHistoryClaimTokenEvents OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of times that the ring enters
+ the claim token state from normal ring state or
+ ring purge state during this sampling interval.
+ The claim token state that comes from the beacon
+ state is not counted."
+ ::= { tokenRingMLHistoryEntry 12 }
+
+
+
+ tokenRingMLHistoryClaimTokenPkts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of claim token MAC packets
+ detected by the probe during this sampling
+ interval."
+ ::= { tokenRingMLHistoryEntry 13 }
+
+ tokenRingMLHistoryNAUNChanges OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of NAUN changes detected by the
+ probe during this sampling interval."
+ ::= { tokenRingMLHistoryEntry 14 }
+
+ tokenRingMLHistoryLineErrors OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of line errors reported in error
+ reporting packets detected by the probe during
+ this sampling interval."
+ ::= { tokenRingMLHistoryEntry 15 }
+
+ tokenRingMLHistoryInternalErrors OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of adapter internal errors
+ reported in error reporting packets detected by
+ the probe during this sampling interval."
+ ::= { tokenRingMLHistoryEntry 16 }
+
+ tokenRingMLHistoryBurstErrors OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of burst errors reported in
+ error reporting packets detected by the probe
+ during this sampling interval."
+ ::= { tokenRingMLHistoryEntry 17 }
+
+
+ tokenRingMLHistoryACErrors OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of AC (Address Copied) errors
+ reported in error reporting packets detected by
+ the probe during this sampling interval."
+ ::= { tokenRingMLHistoryEntry 18 }
+
+ tokenRingMLHistoryAbortErrors OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of abort delimiters reported in
+ error reporting packets detected by the probe
+ during this sampling interval."
+ ::= { tokenRingMLHistoryEntry 19 }
+
+ tokenRingMLHistoryLostFrameErrors OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of lost frame errors reported in
+ error reporting packets detected by the probe
+ during this sampling interval."
+ ::= { tokenRingMLHistoryEntry 20 }
+
+ tokenRingMLHistoryCongestionErrors OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of receive congestion errors
+ reported in error reporting packets detected by
+ the probe during this sampling interval."
+ ::= { tokenRingMLHistoryEntry 21 }
+
+ tokenRingMLHistoryFrameCopiedErrors OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of frame copied errors reported
+ in error reporting packets detected by the probe
+ during this sampling interval."
+
+
+ ::= { tokenRingMLHistoryEntry 22 }
+
+ tokenRingMLHistoryFrequencyErrors OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of frequency errors reported in
+ error reporting packets detected by the probe
+ during this sampling interval."
+ ::= { tokenRingMLHistoryEntry 23 }
+
+ tokenRingMLHistoryTokenErrors OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of token errors reported in
+ error reporting packets detected by the probe
+ during this sampling interval."
+ ::= { tokenRingMLHistoryEntry 24 }
+
+ tokenRingMLHistorySoftErrorReports OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of soft error report frames
+ detected by the probe during this sampling
+ interval."
+ ::= { tokenRingMLHistoryEntry 25 }
+
+ tokenRingMLHistoryRingPollEvents OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of ring poll events detected by
+ the probe during this sampling interval."
+ ::= { tokenRingMLHistoryEntry 26 }
+
+ tokenRingMLHistoryActiveStations OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The maximum number of active stations on the ring
+ detected by the probe during this sampling
+
+
+ interval."
+ ::= { tokenRingMLHistoryEntry 27}
+
+
+ -- The Token Ring Promiscuous History Group
+ --
+ -- Implementation of this group is optional.
+ -- Implementation of this group requires the implementation
+ -- of the historyControl group from RFC1271.
+
+ tokenRingPHistoryTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF TokenRingPHistoryEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A list of promiscuous Token Ring statistics
+ entries."
+ ::= { history 4 }
+
+ tokenRingPHistoryEntry OBJECT-TYPE
+ SYNTAX TokenRingPHistoryEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A collection of promiscuous statistics kept for a
+ particular Token Ring interface."
+ INDEX { tokenRingPHistoryIndex,
+ tokenRingPHistorySampleIndex }
+ ::= { tokenRingPHistoryTable 1 }
+
+ -- As an example, an instance of the
+ -- tokenRingPHistoryDataPkts object
+ -- might be named tokenRingPHistoryDataPkts.1.27
+
+ TokenRingPHistoryEntry ::= SEQUENCE {
+ tokenRingPHistoryIndex INTEGER,
+ tokenRingPHistorySampleIndex INTEGER,
+ tokenRingPHistoryIntervalStart TimeTicks,
+ tokenRingPHistoryDropEvents Counter,
+ tokenRingPHistoryDataOctets Counter,
+ tokenRingPHistoryDataPkts Counter,
+ tokenRingPHistoryDataBroadcastPkts Counter,
+ tokenRingPHistoryDataMulticastPkts Counter,
+ tokenRingPHistoryDataPkts18to63Octets Counter,
+ tokenRingPHistoryDataPkts64to127Octets Counter,
+ tokenRingPHistoryDataPkts128to255Octets Counter,
+ tokenRingPHistoryDataPkts256to511Octets Counter,
+ tokenRingPHistoryDataPkts512to1023Octets Counter,
+
+
+ tokenRingPHistoryDataPkts1024to2047Octets Counter,
+ tokenRingPHistoryDataPkts2048to4095Octets Counter,
+ tokenRingPHistoryDataPkts4096to8191Octets Counter,
+ tokenRingPHistoryDataPkts8192to18000Octets Counter,
+ tokenRingPHistoryDataPktsGreaterThan18000Octets Counter
+ }
+
+ tokenRingPHistoryIndex OBJECT-TYPE
+ SYNTAX INTEGER (1..65535)
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The history of which this entry is a part. The
+ history identified by a particular value of this
+ index is the same history as identified by the
+ same value of historyControlIndex."
+ ::= { tokenRingPHistoryEntry 1 }
+
+ tokenRingPHistorySampleIndex OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "An index that uniquely identifies the particular
+ sample this entry represents among all samples
+ associated with the same historyControlEntry.
+ This index starts at 1 and increases by one as
+ each new sample is taken."
+ ::= { tokenRingPHistoryEntry 2 }
+
+ tokenRingPHistoryIntervalStart OBJECT-TYPE
+ SYNTAX TimeTicks
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The value of sysUpTime at the start of the
+ interval over which this sample was measured. If
+ the probe keeps track of the time of day, it
+ should start the first sample of the history at a
+ time such that when the next hour of the day
+ begins, a sample is started at that instant. Note
+ that following this rule may require the probe to
+ delay collecting the first sample of the history,
+ as each sample must be of the same interval. Also
+ note that the sample which is currently being
+ collected is not accessible in this table until
+ the end of its interval."
+ ::= { tokenRingPHistoryEntry 3 }
+
+
+ tokenRingPHistoryDropEvents OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of events in which packets were
+ dropped by the probe due to lack of resources
+ during this sampling interval. Note that this
+ number is not necessarily the number of packets
+ dropped, it is just the number of times this
+ condition has been detected."
+ ::= { tokenRingPHistoryEntry 4 }
+
+ tokenRingPHistoryDataOctets OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of octets of data in good frames
+ received on the network (excluding framing bits
+ but including FCS octets) in non-MAC packets
+ during this sampling interval."
+ ::= { tokenRingPHistoryEntry 5 }
+
+ tokenRingPHistoryDataPkts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of good non-MAC frames received
+ during this sampling interval."
+ ::= { tokenRingPHistoryEntry 6 }
+
+ tokenRingPHistoryDataBroadcastPkts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of good non-MAC frames received
+ during this sampling interval that were directed
+ to an LLC broadcast address (0xFFFFFFFFFFFF or
+ 0xC000FFFFFFFF)."
+ ::= { tokenRingPHistoryEntry 7 }
+
+ tokenRingPHistoryDataMulticastPkts OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+
+
+ DESCRIPTION
+ "The total number of good non-MAC frames received
+ during this sampling interval that were directed
+ to a local or global multicast or functional
+ address. Note that this number does not include
+ packets directed to the broadcast address."
+ ::= { tokenRingPHistoryEntry 8 }
+
+ tokenRingPHistoryDataPkts18to63Octets OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of good non-MAC frames received
+ during this sampling interval that were between 18
+ and 63 octets in length inclusive, excluding
+ framing bits but including FCS octets."
+ ::= { tokenRingPHistoryEntry 9 }
+
+ tokenRingPHistoryDataPkts64to127Octets OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of good non-MAC frames received
+ during this sampling interval that were between 64
+ and 127 octets in length inclusive, excluding
+ framing bits but including FCS octets."
+ ::= { tokenRingPHistoryEntry 10 }
+
+ tokenRingPHistoryDataPkts128to255Octets OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of good non-MAC frames received
+ during this sampling interval that were between
+ 128 and 255 octets in length inclusive, excluding
+ framing bits but including FCS octets."
+ ::= { tokenRingPHistoryEntry 11 }
+
+ tokenRingPHistoryDataPkts256to511Octets OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of good non-MAC frames received
+ during this sampling interval that were between
+
+
+ 256 and 511 octets in length inclusive, excluding
+ framing bits but including FCS octets."
+ ::= { tokenRingPHistoryEntry 12 }
+
+ tokenRingPHistoryDataPkts512to1023Octets OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of good non-MAC frames received
+ during this sampling interval that were between
+ 512 and 1023 octets in length inclusive, excluding
+ framing bits but including FCS octets."
+ ::= { tokenRingPHistoryEntry 13 }
+
+ tokenRingPHistoryDataPkts1024to2047Octets OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of good non-MAC frames received
+ during this sampling interval that were between
+ 1024 and 2047 octets in length inclusive,
+ excluding framing bits but including FCS octets."
+ ::= { tokenRingPHistoryEntry 14 }
+
+ tokenRingPHistoryDataPkts2048to4095Octets OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of good non-MAC frames received
+ during this sampling interval that were between
+ 2048 and 4095 octets in length inclusive,
+ excluding framing bits but including FCS octets."
+ ::= { tokenRingPHistoryEntry 15 }
+
+ tokenRingPHistoryDataPkts4096to8191Octets OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of good non-MAC frames received
+ during this sampling interval that were between
+ 4096 and 8191 octets in length inclusive,
+ excluding framing bits but including FCS octets."
+ ::= { tokenRingPHistoryEntry 16 }
+
+
+
+ tokenRingPHistoryDataPkts8192to18000Octets OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of good non-MAC frames received
+ during this sampling interval that were between
+ 8192 and 18000 octets in length inclusive,
+ excluding framing bits but including FCS octets."
+ ::= { tokenRingPHistoryEntry 17 }
+
+ tokenRingPHistoryDataPktsGreaterThan18000Octets OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of good non-MAC frames received
+ during this sampling interval that were greater
+ than 18000 octets in length, excluding framing
+ bits but including FCS octets."
+ ::= { tokenRingPHistoryEntry 18 }
+
+
+ -- The Token Ring Ring Station Group
+ --
+ -- Implementation of this group is optional
+ --
+ -- Although the ringStationTable stores entries only for
+ -- those stations physically attached to the local ring and
+ -- the number of stations attached to a ring is limited, a
+ -- probe may still need to free resources when resources
+ -- grow tight. In such a situation, it is suggested that
+ -- the probe free only inactive stations, and to
+ -- first free the stations that have been inactive for the
+ -- longest time.
+
+ ringStationControlTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF RingStationControlEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A list of ringStation table control entries."
+ ::= { tokenRing 1 }
+
+ ringStationControlEntry OBJECT-TYPE
+ SYNTAX RingStationControlEntry
+ ACCESS not-accessible
+ STATUS mandatory
+
+
+ DESCRIPTION
+ "A list of parameters that set up the discovery of
+ stations on a particular interface and the
+ collection of statistics about these stations."
+ INDEX { ringStationControlIfIndex }
+ ::= { ringStationControlTable 1 }
+
+ -- As an example, an instance of the
+ -- ringStationControlIfIndex object
+ -- might be named ringStationControlIfIndex.1
+
+ RingStationControlEntry ::= SEQUENCE {
+ ringStationControlIfIndex INTEGER,
+ ringStationControlTableSize INTEGER,
+ ringStationControlActiveStations INTEGER,
+ ringStationControlRingState INTEGER,
+ ringStationControlBeaconSender MacAddress,
+ ringStationControlBeaconNAUN MacAddress,
+ ringStationControlActiveMonitor MacAddress,
+ ringStationControlOrderChanges Counter,
+ ringStationControlOwner OwnerString,
+ ringStationControlStatus EntryStatus
+ }
+
+ ringStationControlIfIndex OBJECT-TYPE
+ SYNTAX INTEGER (1..65535)
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The value of this object uniquely identifies the
+ interface on this remote network monitoring device
+ from which ringStation data is collected. The
+ interface identified by a particular value of this
+ object is the same interface as identified by the
+ same value of the ifIndex object, defined in MIB-
+ II [3]."
+ ::= { ringStationControlEntry 1 }
+
+ ringStationControlTableSize OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of ringStationEntries in the
+ ringStationTable associated with this
+ ringStationControlEntry."
+ ::= { ringStationControlEntry 2 }
+
+
+
+ ringStationControlActiveStations OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of active ringStationEntries in the
+ ringStationTable associated with this
+ ringStationControlEntry."
+ ::= { ringStationControlEntry 3 }
+
+ ringStationControlRingState OBJECT-TYPE
+ SYNTAX INTEGER {
+ normalOperation(1),
+ ringPurgeState(2),
+ claimTokenState(3),
+ beaconFrameStreamingState(4),
+ beaconBitStreamingState(5),
+ beaconRingSignalLossState(6),
+ beaconSetRecoveryModeState(7)
+ }
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The current status of this ring."
+ ::= { ringStationControlEntry 4 }
+
+ ringStationControlBeaconSender OBJECT-TYPE
+ SYNTAX MacAddress
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The address of the sender of the last beacon
+ frame received by the probe on this ring. If no
+ beacon frames have been received, this object
+ shall be equal to six octets of zero."
+ ::= { ringStationControlEntry 5 }
+
+ ringStationControlBeaconNAUN OBJECT-TYPE
+ SYNTAX MacAddress
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The address of the NAUN in the last beacon frame
+ received by the probe on this ring. If no beacon
+ frames have been received, this object shall be
+ equal to six octets of zero."
+ ::= { ringStationControlEntry 6 }
+
+
+
+ ringStationControlActiveMonitor OBJECT-TYPE
+ SYNTAX MacAddress
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The address of the Active Monitor on this
+ segment. If this address is unknown, this object
+ shall be equal to six octets of zero."
+ ::= { ringStationControlEntry 7 }
+
+ ringStationControlOrderChanges OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of add and delete events in the
+ ringStationOrderTable optionally associated with
+ this ringStationControlEntry."
+ ::= { ringStationControlEntry 8 }
+
+ ringStationControlOwner OBJECT-TYPE
+ SYNTAX OwnerString
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The entity that configured this entry and is
+ therefore using the resources assigned to it."
+ ::= { ringStationControlEntry 9 }
+
+ ringStationControlStatus OBJECT-TYPE
+ SYNTAX EntryStatus
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The status of this ringStationControl entry.
+
+ If this object is not equal to valid(1), all
+ associated entries in the ringStationTable shall
+ be deleted by the agent."
+ ::= { ringStationControlEntry 10 }
+
+ ringStationTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF RingStationEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A list of ring station entries. An entry will
+ exist for each station that is now or has
+
+
+ previously been detected as physically present on
+ this ring."
+ ::= { tokenRing 2 }
+
+ ringStationEntry OBJECT-TYPE
+ SYNTAX RingStationEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A collection of statistics for a particular
+ station that has been discovered on a ring
+ monitored by this device."
+ INDEX { ringStationIfIndex, ringStationMacAddress }
+ ::= { ringStationTable 1 }
+
+ -- As an example, an instance of the
+ -- ringStationStationStatus object might be named
+ -- ringStationStationStatus.1.16.0.90.0.64.131
+
+ RingStationEntry ::= SEQUENCE {
+ ringStationIfIndex INTEGER,
+ ringStationMacAddress MacAddress,
+ ringStationLastNAUN MacAddress,
+ ringStationStationStatus INTEGER,
+ ringStationLastEnterTime TimeTicks,
+ ringStationLastExitTime TimeTicks,
+ ringStationDuplicateAddresses Counter,
+ ringStationInLineErrors Counter,
+ ringStationOutLineErrors Counter,
+ ringStationInternalErrors Counter,
+ ringStationInBurstErrors Counter,
+ ringStationOutBurstErrors Counter,
+ ringStationACErrors Counter,
+ ringStationAbortErrors Counter,
+ ringStationLostFrameErrors Counter,
+ ringStationCongestionErrors Counter,
+ ringStationFrameCopiedErrors Counter,
+ ringStationFrequencyErrors Counter,
+ ringStationTokenErrors Counter,
+ ringStationInBeaconErrors Counter,
+ ringStationOutBeaconErrors Counter,
+ ringStationInsertions Counter
+ }
+
+ ringStationIfIndex OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+
+
+ DESCRIPTION
+ "The value of this object uniquely identifies the
+ interface on this remote network monitoring device
+ on which this station was detected. The interface
+ identified by a particular value of this object is
+ the same interface as identified by the same value
+ of the ifIndex object, defined in MIB-II [3]."
+ ::= { ringStationEntry 1 }
+
+ ringStationMacAddress OBJECT-TYPE
+ SYNTAX MacAddress
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The physical address of this station."
+ ::= { ringStationEntry 2 }
+
+ ringStationLastNAUN OBJECT-TYPE
+ SYNTAX MacAddress
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The physical address of last known NAUN of this
+ station."
+ ::= { ringStationEntry 3 }
+
+ ringStationStationStatus OBJECT-TYPE
+ SYNTAX INTEGER {
+ active(1), -- actively participating in ring poll.
+ inactive(2), -- Not participating in ring poll
+ forcedRemoval(3) -- Forced off ring by network
+ -- management.
+ }
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The status of this station on the ring."
+ ::= { ringStationEntry 4 }
+
+ ringStationLastEnterTime OBJECT-TYPE
+ SYNTAX TimeTicks
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The value of sysUpTime at the time this station
+ last entered the ring. If the time is unknown,
+ this value shall be zero."
+ ::= { ringStationEntry 5 }
+
+
+ ringStationLastExitTime OBJECT-TYPE
+ SYNTAX TimeTicks
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The value of sysUpTime at the time the probe
+ detected that this station last exited the ring.
+ If the time is unknown, this value shall be zero."
+ ::= { ringStationEntry 6 }
+
+ ringStationDuplicateAddresses OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of times this station experienced a
+ duplicate address error."
+ ::= { ringStationEntry 7 }
+
+ ringStationInLineErrors OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of line errors reported by this
+ station in error reporting packets detected by the
+ probe."
+ ::= { ringStationEntry 8 }
+
+ ringStationOutLineErrors OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of line errors reported in error
+ reporting packets sent by the nearest active
+ downstream neighbor of this station and detected
+ by the probe."
+ ::= { ringStationEntry 9 }
+
+ ringStationInternalErrors OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of adapter internal errors
+ reported by this station in error reporting
+ packets detected by the probe."
+
+
+ ::= { ringStationEntry 10 }
+
+ ringStationInBurstErrors OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of burst errors reported by this
+ station in error reporting packets detected by the
+ probe."
+ ::= { ringStationEntry 11 }
+
+ ringStationOutBurstErrors OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of burst errors reported in
+ error reporting packets sent by the nearest active
+ downstream neighbor of this station and detected
+ by the probe."
+ ::= { ringStationEntry 12 }
+
+ ringStationACErrors OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of AC (Address Copied) errors
+ reported in error reporting packets sent by the
+ nearest active downstream neighbor of this station
+ and detected by the probe."
+ ::= { ringStationEntry 13 }
+
+ ringStationAbortErrors OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of abort delimiters reported by
+ this station in error reporting packets detected
+ by the probe."
+ ::= { ringStationEntry 14 }
+
+ ringStationLostFrameErrors OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+
+
+ DESCRIPTION
+ "The total number of lost frame errors reported by
+ this station in error reporting packets detected
+ by the probe."
+ ::= { ringStationEntry 15 }
+
+ ringStationCongestionErrors OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of receive congestion errors
+ reported by this station in error reporting
+ packets detected by the probe."
+ ::= { ringStationEntry 16 }
+
+ ringStationFrameCopiedErrors OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of frame copied errors reported
+ by this station in error reporting packets
+ detected by the probe."
+ ::= { ringStationEntry 17 }
+
+ ringStationFrequencyErrors OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of frequency errors reported by
+ this station in error reporting packets detected
+ by the probe."
+ ::= { ringStationEntry 18 }
+
+ ringStationTokenErrors OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of token errors reported by this
+ station in error reporting frames detected by the
+ probe."
+ ::= { ringStationEntry 19 }
+
+ ringStationInBeaconErrors OBJECT-TYPE
+ SYNTAX Counter
+
+
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of beacon frames sent by this
+ station and detected by the probe."
+ ::= { ringStationEntry 20 }
+
+ ringStationOutBeaconErrors OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of beacon frames detected by the
+ probe that name this station as the NAUN."
+ ::= { ringStationEntry 21 }
+
+ ringStationInsertions OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The number of times the probe detected this
+ station inserting onto the ring."
+ ::= { ringStationEntry 22 }
+
+
+ -- The Token Ring Ring Station Order Group
+ --
+ -- Implementation of this group is optional
+ --
+
+ -- The ringStationOrderTable
+
+ ringStationOrderTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF RingStationOrderEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A list of ring station entries for stations in
+ the ring poll, ordered by their ring-order."
+ ::= { tokenRing 3 }
+
+ ringStationOrderEntry OBJECT-TYPE
+ SYNTAX RingStationOrderEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A collection of statistics for a particular
+
+
+ station that is active on a ring monitored by this
+ device. This table will contain information for
+ every interface that has a
+ ringStationControlStatus equal to valid."
+ INDEX { ringStationOrderIfIndex,
+ ringStationOrderOrderIndex }
+ ::= { ringStationOrderTable 1 }
+
+ -- As an example, an instance of the
+ -- ringStationOrderMacAddress object might be named
+ -- ringStationOrderMacAddress.1.14
+
+ RingStationOrderEntry ::= SEQUENCE {
+ ringStationOrderIfIndex INTEGER,
+ ringStationOrderOrderIndex INTEGER,
+ ringStationOrderMacAddress MacAddress
+ }
+
+ ringStationOrderIfIndex OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The value of this object uniquely identifies the
+ interface on this remote network monitoring device
+ on which this station was detected. The interface
+ identified by a particular value of this object is
+ the same interface as identified by the same value
+ of the ifIndex object, defined in MIB-II [3]."
+ ::= { ringStationOrderEntry 1 }
+
+ ringStationOrderOrderIndex OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "This index denotes the location of this station
+ with respect to other stations on the ring. This
+ index is one more than the number of hops
+ downstream that this station is from the rmon
+ probe. The rmon probe itself gets the value one."
+ ::= { ringStationOrderEntry 2 }
+
+ ringStationOrderMacAddress OBJECT-TYPE
+ SYNTAX MacAddress
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+
+
+ "The physical address of this station."
+ ::= { ringStationOrderEntry 3 }
+
+
+ -- The Token Ring Ring Station Config Group
+ --
+ -- Implementation of this group is optional.
+ -- The ring station config group manages token ring nodes
+ -- through active means.
+
+ ringStationConfigControlTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF RingStationConfigControlEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A list of ring station configuration control
+ entries."
+ ::= { tokenRing 4 }
+
+ ringStationConfigControlEntry OBJECT-TYPE
+ SYNTAX RingStationConfigControlEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "This entry controls active management of stations
+ by the probe. One entry exists in this table for
+ each active station in the ringStationTable."
+ INDEX { ringStationConfigControlIfIndex,
+ ringStationConfigControlMacAddress }
+ ::= { ringStationConfigControlTable 1 }
+
+ -- As an example, an instance of the
+ -- ringStationConfigControlRemove object might be named
+ -- ringStationConfigControlRemove.1.16.0.90.0.64.131
+
+ RingStationConfigControlEntry ::= SEQUENCE {
+ ringStationConfigControlIfIndex INTEGER,
+ ringStationConfigControlMacAddress MacAddress,
+ ringStationConfigControlRemove INTEGER,
+ ringStationConfigControlUpdateStats INTEGER
+ }
+
+ ringStationConfigControlIfIndex OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The value of this object uniquely identifies the
+
+
+ interface on this remote network monitoring device
+ on which this station was detected. The interface
+ identified by a particular value of this object is
+ the same interface as identified by the same value
+ of the ifIndex object, defined in MIB-II [3]."
+ ::= { ringStationConfigControlEntry 1 }
+
+ ringStationConfigControlMacAddress OBJECT-TYPE
+ SYNTAX MacAddress
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The physical address of this station."
+ ::= { ringStationConfigControlEntry 2 }
+
+ ringStationConfigControlRemove OBJECT-TYPE
+ SYNTAX INTEGER {
+ stable(1),
+ removing(2)
+ }
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "Setting this object to `removing(2)' causes a
+ Remove Station MAC frame to be sent. The agent
+ will set this object to `stable(1)' after
+ processing the request."
+ ::= { ringStationConfigControlEntry 3 }
+
+ ringStationConfigControlUpdateStats OBJECT-TYPE
+ SYNTAX INTEGER {
+ stable(1),
+ updating(2)
+ }
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "Setting this object to `updating(2)' causes the
+ configuration information associate with this
+ entry to be updated. The agent will set this
+ object to `stable(1)' after processing the
+ request."
+ ::= { ringStationConfigControlEntry 4 }
+
+
+
+
+
+
+
+ -- The ringStationConfig Table
+ --
+ -- Entries exist in this table after an active
+ -- configuration query has completed successfully for
+ -- a station. This query is initiated by the associated
+ -- ringStationConfigControlUpdateStats variable.
+
+ ringStationConfigTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF RingStationConfigEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A list of configuration entries for stations on a
+ ring monitored by this probe."
+ ::= { tokenRing 5 }
+
+ ringStationConfigEntry OBJECT-TYPE
+ SYNTAX RingStationConfigEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A collection of statistics for a particular
+ station that has been discovered on a ring
+ monitored by this probe."
+ INDEX { ringStationConfigIfIndex,
+ ringStationConfigMacAddress }
+ ::= { ringStationConfigTable 1 }
+
+ -- As an example, an instance of the
+ -- ringStationConfigLocation object might be named
+ -- ringStationConfigLocation.1.16.0.90.0.64.131
+
+ RingStationConfigEntry ::= SEQUENCE {
+ ringStationConfigIfIndex INTEGER,
+ ringStationConfigMacAddress MacAddress,
+ ringStationConfigUpdateTime TimeTicks,
+ ringStationConfigLocation OCTET STRING,
+ ringStationConfigMicrocode OCTET STRING,
+ ringStationConfigGroupAddress OCTET STRING,
+ ringStationConfigFunctionalAddress OCTET STRING
+ }
+
+ ringStationConfigIfIndex OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The value of this object uniquely identifies the
+
+
+ interface on this remote network monitoring device
+ on which this station was detected. The interface
+ identified by a particular value of this object is
+ the same interface as identified by the same value
+ of the ifIndex object, defined in MIB-II [3]."
+ ::= { ringStationConfigEntry 1 }
+
+ ringStationConfigMacAddress OBJECT-TYPE
+ SYNTAX MacAddress
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The physical address of this station."
+ ::= { ringStationConfigEntry 2 }
+
+ ringStationConfigUpdateTime OBJECT-TYPE
+ SYNTAX TimeTicks
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The value of sysUpTime at the time this
+ configuration information was last updated
+ (completely)."
+ ::= { ringStationConfigEntry 3 }
+
+ ringStationConfigLocation OBJECT-TYPE
+ SYNTAX OCTET STRING (SIZE(4))
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The assigned physical location of this station."
+ ::= { ringStationConfigEntry 4 }
+
+ ringStationConfigMicrocode OBJECT-TYPE
+ SYNTAX OCTET STRING (SIZE(10))
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The microcode EC level of this station."
+ ::= { ringStationConfigEntry 5 }
+
+ ringStationConfigGroupAddress OBJECT-TYPE
+ SYNTAX OCTET STRING (SIZE(4))
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The low-order 4 octets of the group address
+ recognized by this station."
+
+
+ ::= { ringStationConfigEntry 6 }
+
+ ringStationConfigFunctionalAddress OBJECT-TYPE
+ SYNTAX OCTET STRING (SIZE(4))
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "the functional addresses recognized by this
+ station."
+ ::= { ringStationConfigEntry 7 }
+
+
+ -- The Token Ring Source Routing group
+ --
+ -- Implementation of this group is optional.
+ -- The data in this group is collected from the source
+ -- routing information potentially present in any token ring
+ -- packet. This information will be valid only in a pure
+ -- source route bridging environment. In a transparent
+ -- bridging or a mixed bridging environment, this
+ -- information may not be accurate.
+
+ sourceRoutingStatsTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF SourceRoutingStatsEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A list of source routing statistics entries."
+ ::= { tokenRing 6 }
+
+ sourceRoutingStatsEntry OBJECT-TYPE
+ SYNTAX SourceRoutingStatsEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A collection of source routing statistics kept
+ for a particular Token Ring interface."
+ INDEX { sourceRoutingStatsIfIndex }
+ ::= { sourceRoutingStatsTable 1 }
+
+ -- As an example, an instance of the
+ -- sourceRoutingStatsInFrames object might be named
+ -- sourceRoutingStatsInFrames.1
+
+ SourceRoutingStatsEntry ::= SEQUENCE {
+ sourceRoutingStatsIfIndex INTEGER,
+ sourceRoutingStatsRingNumber INTEGER,
+ sourceRoutingStatsInFrames Counter,
+
+
+ -- in to our net
+
+ sourceRoutingStatsOutFrames Counter,
+ -- out from our net
+
+ sourceRoutingStatsThroughFrames Counter,
+ -- through our net
+
+ sourceRoutingStatsAllRoutesBroadcastFrames Counter,
+ sourceRoutingStatsSingleRouteBroadcastFrames Counter,
+ sourceRoutingStatsInOctets Counter,
+ sourceRoutingStatsOutOctets Counter,
+ sourceRoutingStatsThroughOctets Counter,
+ sourceRoutingStatsAllRoutesBroadcastOctets Counter,
+ sourceRoutingStatsSingleRoutesBroadcastOctets Counter,
+ sourceRoutingStatsLocalLLCFrames Counter,
+ sourceRoutingStats1HopFrames Counter,
+ sourceRoutingStats2HopsFrames Counter,
+ sourceRoutingStats3HopsFrames Counter,
+ sourceRoutingStats4HopsFrames Counter,
+ sourceRoutingStats5HopsFrames Counter,
+ sourceRoutingStats6HopsFrames Counter,
+ sourceRoutingStats7HopsFrames Counter,
+ sourceRoutingStats8HopsFrames Counter,
+ sourceRoutingStatsMoreThan8HopsFrames Counter,
+ sourceRoutingStatsOwner OwnerString,
+ sourceRoutingStatsStatus EntryStatus
+ }
+
+ sourceRoutingStatsIfIndex OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The value of this object uniquely identifies the
+ interface on this remote network monitoring device
+ on which source routing statistics will be
+ detected. The interface identified by a
+ particular value of this object is the same
+ interface as identified by the same value of the
+ ifIndex object, defined in MIB-II [3]."
+ ::= { sourceRoutingStatsEntry 1 }
+
+ sourceRoutingStatsRingNumber OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+
+
+ "The ring number of the ring monitored by this
+ entry. When any object in this entry is created,
+ the probe will attempt to discover the ring
+ number. Only after the ring number is discovered
+ will this object be created. After creating an
+ object in this entry, the management station
+ should poll this object to detect when it is
+ created. Only after this object is created can
+ the management station set the
+ sourceRoutingStatsStatus entry to valid(1)."
+ ::= { sourceRoutingStatsEntry 2 }
+
+ sourceRoutingStatsInFrames OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The count of frames sent into this ring from
+ another ring."
+ ::= { sourceRoutingStatsEntry 3 }
+
+ sourceRoutingStatsOutFrames OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The count of frames sent from this ring to
+ another ring."
+ ::= { sourceRoutingStatsEntry 4 }
+
+ sourceRoutingStatsThroughFrames OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The count of frames sent from another ring,
+ through this ring, to another ring."
+ ::= { sourceRoutingStatsEntry 5 }
+
+ sourceRoutingStatsAllRoutesBroadcastFrames OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of good frames received that
+ were All Routes Broadcast."
+ ::= { sourceRoutingStatsEntry 6 }
+
+
+
+ sourceRoutingStatsSingleRouteBroadcastFrames OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of good frames received that
+ were Single Route Broadcast."
+ ::= { sourceRoutingStatsEntry 7 }
+
+ sourceRoutingStatsInOctets OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The count of octets in good frames sent into this
+ ring from another ring."
+ ::= { sourceRoutingStatsEntry 8 }
+
+ sourceRoutingStatsOutOctets OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The count of octets in good frames sent from this
+ ring to another ring."
+ ::= { sourceRoutingStatsEntry 9 }
+
+ sourceRoutingStatsThroughOctets OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The count of octets in good frames sent another
+ ring, through this ring, to another ring."
+ ::= { sourceRoutingStatsEntry 10 }
+
+ sourceRoutingStatsAllRoutesBroadcastOctets OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of octets in good frames
+ received that were All Routes Broadcast."
+ ::= { sourceRoutingStatsEntry 11 }
+
+ sourceRoutingStatsSingleRoutesBroadcastOctets OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+
+
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of octets in good frames
+ received that were Single Route Broadcast."
+ ::= { sourceRoutingStatsEntry 12 }
+
+ sourceRoutingStatsLocalLLCFrames OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of frames received who had no
+ RIF field (or had a RIF field that only included
+ the local ring's number) and were not All Route
+ Broadcast Frames."
+ ::= { sourceRoutingStatsEntry 13 }
+
+ sourceRoutingStats1HopFrames OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of frames received whose route
+ had 1 hop, were not All Route Broadcast Frames,
+ and whose source or destination were on this ring
+ (i.e. frames that had a RIF field and had this
+ ring number in the first or last entry of the RIF
+ field)."
+ ::= { sourceRoutingStatsEntry 14 }
+
+ sourceRoutingStats2HopsFrames OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of frames received whose route
+ had 2 hops, were not All Route Broadcast Frames,
+ and whose source or destination were on this ring
+ (i.e. frames that had a RIF field and had this
+ ring number in the first or last entry of the RIF
+ field)."
+ ::= { sourceRoutingStatsEntry 15 }
+
+ sourceRoutingStats3HopsFrames OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+
+
+ "The total number of frames received whose route
+ had 3 hops, were not All Route Broadcast Frames,
+ and whose source or destination were on this ring
+ (i.e. frames that had a RIF field and had this
+ ring number in the first or last entry of the RIF
+ field)."
+ ::= { sourceRoutingStatsEntry 16 }
+
+ sourceRoutingStats4HopsFrames OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of frames received whose route
+ had 4 hops, were not All Route Broadcast Frames,
+ and whose source or destination were on this ring
+ (i.e. frames that had a RIF field and had this
+ ring number in the first or last entry of the RIF
+ field)."
+ ::= { sourceRoutingStatsEntry 17 }
+
+ sourceRoutingStats5HopsFrames OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of frames received whose route
+ had 5 hops, were not All Route Broadcast Frames,
+ and whose source or destination were on this ring
+ (i.e. frames that had a RIF field and had this
+ ring number in the first or last entry of the RIF
+ field)."
+ ::= { sourceRoutingStatsEntry 18 }
+
+ sourceRoutingStats6HopsFrames OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of frames received whose route
+ had 6 hops, were not All Route Broadcast Frames,
+ and whose source or destination were on this ring
+ (i.e. frames that had a RIF field and had this
+ ring number in the first or last entry of the RIF
+ field)."
+ ::= { sourceRoutingStatsEntry 19 }
+
+ sourceRoutingStats7HopsFrames OBJECT-TYPE
+
+
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of frames received whose route
+ had 7 hops, were not All Route Broadcast Frames,
+ and whose source or destination were on this ring
+ (i.e. frames that had a RIF field and had this
+ ring number in the first or last entry of the RIF
+ field)."
+ ::= { sourceRoutingStatsEntry 20 }
+
+ sourceRoutingStats8HopsFrames OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of frames received whose route
+ had 8 hops, were not All Route Broadcast Frames,
+ and whose source or destination were on this ring
+ (i.e. frames that had a RIF field and had this
+ ring number in the first or last entry of the RIF
+ field)."
+ ::= { sourceRoutingStatsEntry 21 }
+
+ sourceRoutingStatsMoreThan8HopsFrames OBJECT-TYPE
+ SYNTAX Counter
+ ACCESS read-only
+ STATUS mandatory
+ DESCRIPTION
+ "The total number of frames received whose route
+ had more than 8 hops, were not All Route Broadcast
+ Frames, and whose source or destination were on
+ this ring (i.e. frames that had a RIF field and
+ had this ring number in the first or last entry of
+ the RIF field)."
+ ::= { sourceRoutingStatsEntry 22 }
+
+ sourceRoutingStatsOwner OBJECT-TYPE
+ SYNTAX OwnerString
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The entity that configured this entry and is
+ therefore using the resources assigned to it."
+ ::= { sourceRoutingStatsEntry 23 }
+
+ sourceRoutingStatsStatus OBJECT-TYPE
+
+
+ SYNTAX EntryStatus
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The status of this sourceRoutingStats entry."
+ ::= { sourceRoutingStatsEntry 24 }
+
+ END
diff --git a/lib/snmp/test/test-mibs/Table1-error.mib b/lib/snmp/test/test-mibs/Table1-error.mib
new file mode 100644
index 0000000000..d2d38c14ef
--- /dev/null
+++ b/lib/snmp/test/test-mibs/Table1-error.mib
@@ -0,0 +1,97 @@
+ Table1-error DEFINITIONS ::= BEGIN
+
+ IMPORTS
+ OBJECT-TYPE
+ FROM RFC-1212;
+
+ klas1 OBJECT IDENTIFIER ::= { private 7 }
+
+ RowStatus ::=
+ INTEGER {
+ -- the following two values are states:
+ -- these values may be read or written
+ active(1),
+ notInService(2),
+
+ -- the following value is a state:
+ -- this value may be read, but not written
+ notReady(3),
+
+ -- the following three values are
+ -- actions: these values may be written,
+ -- but are never read
+ createAndGo(4),
+ createAndWait(5),
+ destroy(6)
+ }
+
+
+ friendsTable OBJECT-TYPE
+ SYNTAX SEQUENCE OF FriendsEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "A list of klas friends."
+ ::= { klas1 4 }
+
+ friendsEntry OBJECT-TYPE
+ SYNTAX FriendsEntry
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "nope"
+ INDEX { fIndex }
+ ::= { friendsTable 1 }
+
+ FriendsEntry ::=
+ SEQUENCE {
+ fIndex
+ INTEGER,
+ fName
+ OCTET STRING,
+ fStatus
+ INTEGER }
+
+ fName OBJECT-TYPE
+ SYNTAX OCTET STRING (SIZE (0..255))
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "Name of friend"
+ ::= { friendsEntry 2 }
+
+-- this is perhaps not really an error.
+-- a _nice_ compiler should allow columns to be defined in any order.
+
+ fIndex OBJECT-TYPE
+ SYNTAX INTEGER
+ ACCESS not-accessible
+ STATUS mandatory
+ DESCRIPTION
+ "number of friend"
+ ::= { friendsEntry 1 }
+
+ fStatus OBJECT-TYPE
+ SYNTAX RowStatus
+ ACCESS read-write
+ STATUS mandatory
+ DESCRIPTION
+ "The status of this conceptual row."
+ ::= { friendsEntry 3 }
+
+ authenticationFajlure TRAP-TYPE
+ ENTERPRISE klas1
+ DESCRIPTION
+ "An authenticationFailure trap signifies that
+ the sending protocol entity is the addressee
+ of a protocol message that is not properly
+ authenticated. While implementations of the
+ SNMP must be capable of generating this trap,
+ they must also be capable of suppressing the
+ emission of such traps via an implementation-
+ specific mechanism."
+ ::= 4
+
+
+ END
+
diff --git a/lib/snmp/test/test-mibs/Type-error.mib b/lib/snmp/test/test-mibs/Type-error.mib
new file mode 100644
index 0000000000..6361679d47
--- /dev/null
+++ b/lib/snmp/test/test-mibs/Type-error.mib
@@ -0,0 +1,11 @@
+Type-error DEFINITIONS ::= BEGIN
+
+ IMPORTS
+ OBJECT-TYPE
+ FROM RFC-1212;
+
+ Q ::= INTEGER
+ Q ::= INTEGER
+
+ END
+
diff --git a/lib/snmp/test/test1.erl b/lib/snmp/test/test1.erl
new file mode 100644
index 0000000000..b26b03d4ce
--- /dev/null
+++ b/lib/snmp/test/test1.erl
@@ -0,0 +1,72 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1997-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%
+%%
+
+-module(test1).
+
+-compile(export_all).
+
+bits1(get) ->
+ {value, [b0, b2]}.
+bits1(set, _) ->
+ noError.
+
+bits2(get) ->
+ {value, 2#11000000110}.
+bits2(set, _) ->
+ noError.
+
+bits3(get) ->
+ {value, [b0, b4]}. % error!
+
+bits4(get) ->
+ {value, 2#1000}. % error!
+
+opaque_obj(get) ->
+ {value, "opaque-data"}.
+
+cnt64(get) ->
+ {value, 18446744073709551615}.
+
+multiStr(get) ->
+ i("multiStr(get) -> entry"),
+ global:re_register_name(snmp_multi_tester, self()),
+ i("multiStr(get) -> registered, now await continue"),
+ receive
+ continue ->
+ i("multiStr(get) -> received continue"),
+ ok
+ end,
+ {value, "ok"}.
+
+multiStr(set, "block") ->
+ global:re_register_name(snmp_multi_tester, self()),
+ receive
+ continue -> ok
+ end,
+ noError;
+multiStr(set, _Value) ->
+ noError.
+
+
+i(F) ->
+ i(F, []).
+
+i(F, A) ->
+ io:format("~p ~w:" ++ F ++ "~n", [self(), ?MODULE | A]).
+
diff --git a/lib/snmp/test/test2.erl b/lib/snmp/test/test2.erl
new file mode 100644
index 0000000000..dc010cfa11
--- /dev/null
+++ b/lib/snmp/test/test2.erl
@@ -0,0 +1,80 @@
+%%
+%% %CopyrightBegin%
+%%
+%% Copyright Ericsson AB 1997-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%
+%%
+
+-module(test2).
+
+-compile(export_all).
+
+%%-----------------------------------------------------------------
+%% Implements the Test2 MIB. Used to test processing
+%% of requests.
+%%-----------------------------------------------------------------
+tDescr(get, 2) ->
+ {noValue, noSuchName};
+tDescr(get, 3) ->
+ {noValue, noSuchInstance};
+tDescr(get, 4) ->
+ {noValue, noSuchObject}.
+
+tDescr(is_set_ok, "badValue", 2) ->
+ badValue;
+tDescr(is_set_ok, "inconsistentValue", 2) ->
+ inconsistentValue;
+tDescr(is_set_ok, "resourceUnavailable", 2) ->
+ resourceUnavailable;
+tDescr(is_set_ok, "inconsistentName", 2) ->
+ inconsistentName;
+tDescr(is_set_ok, "is_set_ok_fail", 2) ->
+ genErr;
+tDescr(set, "commit_fail", 2) ->
+ commitFailed.
+
+tGenErr(get, 1) ->
+ genErr;
+tGenErr(get, 2) ->
+ 1=2;
+tGenErr(get, 3) ->
+ {value, "not an integer, I know"}.
+
+tInt(is_set_ok, 5, 3) ->
+ wrongValue.
+
+
+tTable(is_set_ok, [1,1], [{2, "noCreation"}]) ->
+ {noCreation, 2};
+tTable(is_set_ok, [1,2], [{2, "inconsistentName"}]) ->
+ {inconsistentName, 2};
+tTable(get_next, _RowIndex, Cols) ->
+ lists:map(fun(_) -> endOfTable end, Cols).
+
+%% Only 2 reqs are valid:
+%% gn([[tCnt2, 1]])
+%% gn([[tCnt2, 2]])
+%% ... or as:
+%% gb(0, 2, [[tCnt2,1]])
+tTable2(get_next, [1], [2]) ->
+ [{[2,2], 100}];
+tTable2(get_next, [2], [2]) ->
+ [endOfTable].
+
+
+
+
+tTooBig(get) ->
+ {value, "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"}.
diff --git a/lib/snmp/vsn.mk b/lib/snmp/vsn.mk
new file mode 100644
index 0000000000..e7a93f026d
--- /dev/null
+++ b/lib/snmp/vsn.mk
@@ -0,0 +1,169 @@
+#-*-makefile-*- ; force emacs to enter makefile-mode
+
+# %CopyrightBegin%
+#
+# Copyright Ericsson AB 1997-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%
+
+SNMP_VSN = 4.15
+PRE_VSN =
+APP_VSN = "snmp-$(SNMP_VSN)$(PRE_VSN)"
+
+TICKETS = OTP-8229 OTP-8249
+
+TICKETS_4_14 = OTP-8223 OTP-8228 OTP-8237
+
+TICKETS_4_13_5 = OTP-8116 OTP-8120 OTP-8181 OTP-8182
+
+TICKETS_4_13_4 = OTP-8044 OTP-8062 OTP-8098
+
+TICKETS_4_13_3 = OTP-8015 OTP-8020
+
+TICKETS_4_13_2 = OTP-7961 OTP-7977 OTP-7983 OTP-7989
+
+TICKETS_4_13_1 = OTP-7902
+
+TICKETS_4_13 = OTP-7571 OTP-7735 OTP-7836 OTP-7851
+
+TICKETS_4_12_2 = OTP-7868
+
+TICKETS_4_12_1 = OTP-7695 OTP-7698
+
+TICKETS_4_12 = OTP-7346 OTP-7525
+
+TICKETS_4_11_2 = OTP-7570 OTP-7575
+
+TICKETS_4_11_1 = OTP-7390 OTP-7412 OTP-7426 OTP-7432
+
+TICKETS_4_11 = OTP-7201 OTP-7287 OTP-7319 OTP-7369 OTP-7371 OTP-7377 OTP-7381
+
+TICKETS_4_10_3 = OTP-7219
+
+TICKETS_4_10_2 = OTP-7152 OTP-7153 OTP-7157 OTP-7158 OTP-7159 OTP-7160
+
+TICKETS_4_10_1 = OTP-7083 OTP-7109 OTP-7110 OTP-7119 OTP-7121 OTP-7123
+
+TICKETS_4_10 = OTP-6649 OTP-6841 OTP-6898 OTP-6945
+
+TICKETS_4_9_6 = OTP-6840 OTP-6843
+
+TICKETS_4_9_5 = OTP-6805 OTP-6815
+
+TICKETS_4_9_4 = OTP-6784 OTP-6771
+
+TICKETS_4_9_3 = OTP-6605 OTP-6712 OTP-6713
+
+TICKETS_4_9_2 = OTP-6571
+
+TICKETS_4_9_1 = OTP-6566 OTP-6569
+
+TICKETS_4_9 = \
+ OTP-6317 \
+ OTP-6318 \
+ OTP-6383 \
+ OTP-6487 \
+ OTP-6515 \
+ OTP-6518 \
+ OTP-6529 \
+ OTP-6532 \
+ OTP-6533 \
+ OTP-6540
+
+TICKETS_4_8_4 = OTP-6408
+
+TICKETS_4_8_3 = OTP-6337 OTP-6340
+
+TICKETS_4_8_2 = OTP-6214 OTP-6247 OTP-6293
+
+TICKETS_4_8_1 = OTP-6176 OTP-6177
+
+TICKETS_4_8 = OTP-6137 OTP-6149 OTP-6150 OTP-6164
+
+TICKETS_4_7_4 = \
+ OTP-6042 \
+ OTP-6044 \
+ OTP-6049 \
+ OTP-6062 \
+ OTP-6068 \
+ OTP-6074 \
+ OTP-6077 \
+ OTP-6081
+
+TICKETS_4_7_3 = \
+ OTP-6031 \
+ OTP-6032
+
+TICKETS_4_7_2 = \
+ OTP-5992 \
+ OTP-6024
+
+TICKETS_4_7_1 = \
+ OTP-5963 \
+ OTP-5968 \
+ OTP-5969
+
+TICKETS_4_7 = \
+ OTP-5870 \
+ OTP-5934 \
+ OTP-5935 \
+ OTP-5937
+
+TICKETS_4_6_1 = \
+ OTP-5834 \
+ OTP-5838
+
+TICKETS_4_6 = \
+ OTP-5763 \
+ OTP-5771 \
+ OTP-5787 \
+ OTP-5797 \
+ OTP-5829
+
+TICKETS_4_5 = \
+ OTP-5581 \
+ OTP-5726 \
+ OTP-5727 \
+ OTP-5732 \
+ OTP-5733 \
+ OTP-5740 \
+ OTP-5742
+
+TICKETS_4_4_1 = \
+ OTP-5719 \
+ OTP-5720
+
+TICKETS_4_4 = \
+ OTP-5666 \
+ OTP-5668 \
+ OTP-5669 \
+ OTP-5675 \
+ OTP-5676 \
+ OTP-5678 \
+ OTP-5703
+
+TICKETS_4_3 = \
+ OTP-5636 \
+ OTP-5637 \
+ OTP-5490
+
+TICKETS_4_2 = \
+ OTP-5574 \
+ OTP-5578 \
+ OTP-5579 \
+ OTP-5580 \
+ OTP-5590 \
+ OTP-5591 \
+ OTP-5592
+